Files
codex/codex-rs/hooks/src/lib.rs
T
Vivian Fang 70b3bb6d88 Add observation-only model request lifecycle hooks (#55144)
## What changed

- Add `PreModelRequest` and `PostModelRequest` hooks around model request attempts, including retries. Pass model, session, turn, and optional subagent context; report completion, failure, or cancellation with errors and token usage when available.
- Treat hook output as diagnostic data without allowing it to veto requests or alter model context. Wait for synchronous post-request hooks before dispatching tools, while asynchronous hooks allow streaming tool dispatch to continue.
- Apply memory-consolidation hook filtering and expose the new events through configuration, protocol schemas, generated clients, and the hooks browser.

## Testing

Add integration coverage for failures and retries, ignored control directives, cancellation, synchronous and asynchronous tool ordering, interrupted-turn resume and token accounting, and memory-consolidation filtering. Update hook schema fixtures and hooks browser snapshots.

GitOrigin-RevId: 6ed7b39fc8bb94cf467e350d07d97fcc729c21ce
2026-10-18 22:43:56 +00:00

135 lines
4.5 KiB
Rust

mod config_rules;
mod context;
mod declarations;
mod engine;
pub(crate) mod events;
mod legacy_notify;
mod mcp;
mod output_spill;
mod registry;
mod schema;
mod types;
use codex_protocol::protocol::HookEventName;
pub use config_rules::hook_states_from_stack;
pub use declarations::PluginHookDeclaration;
pub use declarations::plugin_hook_declarations;
pub use engine::HookListEntry;
pub use engine::HookListEntryHandler;
pub use engine::dispatcher::hook_execution_mode_label;
pub use engine::dispatcher::hook_handler_type_label;
pub use events::common::SubagentHookContext;
/// Hook event names as they appear in hooks JSON and config files.
pub const HOOK_EVENT_NAMES: [&str; 14] = [
"PreModelRequest",
"PostModelRequest",
"PreToolUse",
"PermissionRequest",
"PostToolUse",
"PreCompact",
"PostCompact",
"SessionStart",
"SessionEnd",
"UserPromptSubmit",
"SubagentStart",
"SubagentStop",
"Stop",
"Interrupt",
];
/// Hook event names whose matcher fields are meaningful during dispatch.
///
/// Other events can appear in hooks JSON, but Codex ignores their matcher
/// fields because those events do not dispatch against a tool, compaction
/// trigger, session-start source, or session-end reason.
pub const HOOK_EVENT_NAMES_WITH_MATCHERS: [&str; 9] = [
"PreToolUse",
"PermissionRequest",
"PostToolUse",
"PreCompact",
"PostCompact",
"SessionStart",
"SessionEnd",
"SubagentStart",
"SubagentStop",
];
pub use context::HookContext;
pub use events::compact::PostCompactRequest;
pub use events::compact::PreCompactOutcome;
pub use events::compact::PreCompactRequest;
pub use events::compact::StatelessHookOutcome;
pub use events::interrupt::InterruptOutcome;
pub use events::interrupt::InterruptRequest;
pub use events::permission_request::PermissionRequestDecision;
pub use events::permission_request::PermissionRequestOutcome;
pub use events::permission_request::PermissionRequestRequest;
pub use events::post_tool_use::PostToolUseOutcome;
pub use events::post_tool_use::PostToolUseRequest;
pub use events::pre_tool_use::PreToolUseOutcome;
pub use events::pre_tool_use::PreToolUseRequest;
pub use events::session_end::SessionEndOutcome;
pub use events::session_end::SessionEndRequest;
pub use events::session_start::SessionStartOutcome;
pub use events::session_start::SessionStartRequest;
pub use events::session_start::SessionStartSource;
pub use events::session_start::StartHookTarget;
pub use events::stop::StopHookTarget;
pub use events::stop::StopOutcome;
pub use events::stop::StopRequest;
pub use events::user_prompt_submit::UserPromptSubmitOutcome;
pub use events::user_prompt_submit::UserPromptSubmitRequest;
pub use legacy_notify::legacy_notify_json;
pub use mcp::HookMcpCall;
pub use mcp::HookMcpExecutor;
pub use mcp::HookMcpOutput;
pub use registry::HookListOutcome;
pub use registry::Hooks;
pub use registry::HooksConfig;
pub use registry::list_hooks;
pub use schema::write_schema_fixtures;
pub use types::Hook;
pub use types::HookEvent;
pub use types::HookEventAfterAgent;
pub use types::HookPayload;
pub use types::HookResponse;
pub use types::HookResult;
/// Returns the hook event label used in persisted hook-state keys.
pub fn hook_event_key_label(event_name: HookEventName) -> &'static str {
match event_name {
HookEventName::PreToolUse => "pre_tool_use",
HookEventName::PermissionRequest => "permission_request",
HookEventName::PostToolUse => "post_tool_use",
HookEventName::PreCompact => "pre_compact",
HookEventName::PostCompact => "post_compact",
HookEventName::PreModelRequest => "pre_model_request",
HookEventName::PostModelRequest => "post_model_request",
HookEventName::SessionStart => "session_start",
HookEventName::SessionEnd => "session_end",
HookEventName::UserPromptSubmit => "user_prompt_submit",
HookEventName::SubagentStart => "subagent_start",
HookEventName::SubagentStop => "subagent_stop",
HookEventName::Stop => "stop",
HookEventName::Interrupt => "interrupt",
}
}
/// Builds the persisted config-state key for one discovered hook handler.
pub fn hook_key(
key_source: &str,
event_name: HookEventName,
group_index: usize,
handler_index: usize,
) -> String {
format!(
"{key_source}:{}:{group_index}:{handler_index}",
hook_event_key_label(event_name)
)
}
pub use events::model_request::ModelRequestHookEvent;
pub use events::model_request::ModelRequestHookInput;
pub use events::model_request::ModelRequestStatus;