mirror of
https://github.com/openai/codex.git
synced 2026-09-16 12:13:30 +00:00
## What changed - Add an `Interrupt` hook event that runs for an active top-level turn before its interrupted abort event is emitted. - Flush the turn transcript before invoking the hook and provide the session, turn, transcript, working directory, model, and permission mode in its input. - Support command and MCP handlers, including asynchronous commands, with a one-second default timeout and a three-second maximum. - Expose the event through hook configuration, managed requirements, app-server notifications, generated schemas, analytics, and the TUI hook views. ## Testing - Cover handler discovery, timeout normalization, output parsing, protocol compatibility, TUI rendering, and interrupt execution ordering. GitOrigin-RevId: 163fa7c098d94ac2775f6d137f8e916f8ea9b6eb
169 lines
7.9 KiB
Rust
169 lines
7.9 KiB
Rust
use std::sync::OnceLock;
|
|
|
|
use serde_json::Value;
|
|
|
|
#[allow(dead_code)]
|
|
pub(crate) struct GeneratedHookSchemas {
|
|
pub post_tool_use_command_input: Value,
|
|
pub post_tool_use_command_output: Value,
|
|
pub permission_request_command_input: Value,
|
|
pub permission_request_command_output: Value,
|
|
pub post_compact_command_input: Value,
|
|
pub post_compact_command_output: Value,
|
|
pub pre_tool_use_command_input: Value,
|
|
pub pre_tool_use_command_output: Value,
|
|
pub pre_compact_command_input: Value,
|
|
pub pre_compact_command_output: Value,
|
|
pub session_start_command_input: Value,
|
|
pub session_start_command_output: Value,
|
|
pub session_end_command_input: Value,
|
|
pub subagent_start_command_input: Value,
|
|
pub subagent_start_command_output: Value,
|
|
pub subagent_stop_command_input: Value,
|
|
pub subagent_stop_command_output: Value,
|
|
pub user_prompt_submit_command_input: Value,
|
|
pub user_prompt_submit_command_output: Value,
|
|
pub stop_command_input: Value,
|
|
pub stop_command_output: Value,
|
|
pub interrupt_command_input: Value,
|
|
pub interrupt_command_output: Value,
|
|
}
|
|
|
|
pub(crate) fn generated_hook_schemas() -> &'static GeneratedHookSchemas {
|
|
static SCHEMAS: OnceLock<GeneratedHookSchemas> = OnceLock::new();
|
|
SCHEMAS.get_or_init(|| GeneratedHookSchemas {
|
|
post_tool_use_command_input: parse_json_schema(
|
|
"post-tool-use.command.input",
|
|
include_str!("../../schema/generated/post-tool-use.command.input.schema.json"),
|
|
),
|
|
post_tool_use_command_output: parse_json_schema(
|
|
"post-tool-use.command.output",
|
|
include_str!("../../schema/generated/post-tool-use.command.output.schema.json"),
|
|
),
|
|
permission_request_command_input: parse_json_schema(
|
|
"permission-request.command.input",
|
|
include_str!("../../schema/generated/permission-request.command.input.schema.json"),
|
|
),
|
|
permission_request_command_output: parse_json_schema(
|
|
"permission-request.command.output",
|
|
include_str!("../../schema/generated/permission-request.command.output.schema.json"),
|
|
),
|
|
post_compact_command_input: parse_json_schema(
|
|
"post-compact.command.input",
|
|
include_str!("../../schema/generated/post-compact.command.input.schema.json"),
|
|
),
|
|
post_compact_command_output: parse_json_schema(
|
|
"post-compact.command.output",
|
|
include_str!("../../schema/generated/post-compact.command.output.schema.json"),
|
|
),
|
|
pre_tool_use_command_input: parse_json_schema(
|
|
"pre-tool-use.command.input",
|
|
include_str!("../../schema/generated/pre-tool-use.command.input.schema.json"),
|
|
),
|
|
pre_tool_use_command_output: parse_json_schema(
|
|
"pre-tool-use.command.output",
|
|
include_str!("../../schema/generated/pre-tool-use.command.output.schema.json"),
|
|
),
|
|
pre_compact_command_input: parse_json_schema(
|
|
"pre-compact.command.input",
|
|
include_str!("../../schema/generated/pre-compact.command.input.schema.json"),
|
|
),
|
|
pre_compact_command_output: parse_json_schema(
|
|
"pre-compact.command.output",
|
|
include_str!("../../schema/generated/pre-compact.command.output.schema.json"),
|
|
),
|
|
session_start_command_input: parse_json_schema(
|
|
"session-start.command.input",
|
|
include_str!("../../schema/generated/session-start.command.input.schema.json"),
|
|
),
|
|
session_start_command_output: parse_json_schema(
|
|
"session-start.command.output",
|
|
include_str!("../../schema/generated/session-start.command.output.schema.json"),
|
|
),
|
|
session_end_command_input: parse_json_schema(
|
|
"session-end.command.input",
|
|
include_str!("../../schema/generated/session-end.command.input.schema.json"),
|
|
),
|
|
subagent_start_command_input: parse_json_schema(
|
|
"subagent-start.command.input",
|
|
include_str!("../../schema/generated/subagent-start.command.input.schema.json"),
|
|
),
|
|
subagent_start_command_output: parse_json_schema(
|
|
"subagent-start.command.output",
|
|
include_str!("../../schema/generated/subagent-start.command.output.schema.json"),
|
|
),
|
|
subagent_stop_command_input: parse_json_schema(
|
|
"subagent-stop.command.input",
|
|
include_str!("../../schema/generated/subagent-stop.command.input.schema.json"),
|
|
),
|
|
subagent_stop_command_output: parse_json_schema(
|
|
"subagent-stop.command.output",
|
|
include_str!("../../schema/generated/subagent-stop.command.output.schema.json"),
|
|
),
|
|
user_prompt_submit_command_input: parse_json_schema(
|
|
"user-prompt-submit.command.input",
|
|
include_str!("../../schema/generated/user-prompt-submit.command.input.schema.json"),
|
|
),
|
|
user_prompt_submit_command_output: parse_json_schema(
|
|
"user-prompt-submit.command.output",
|
|
include_str!("../../schema/generated/user-prompt-submit.command.output.schema.json"),
|
|
),
|
|
stop_command_input: parse_json_schema(
|
|
"stop.command.input",
|
|
include_str!("../../schema/generated/stop.command.input.schema.json"),
|
|
),
|
|
stop_command_output: parse_json_schema(
|
|
"stop.command.output",
|
|
include_str!("../../schema/generated/stop.command.output.schema.json"),
|
|
),
|
|
interrupt_command_input: parse_json_schema(
|
|
"interrupt.command.input",
|
|
include_str!("../../schema/generated/interrupt.command.input.schema.json"),
|
|
),
|
|
interrupt_command_output: parse_json_schema(
|
|
"interrupt.command.output",
|
|
include_str!("../../schema/generated/interrupt.command.output.schema.json"),
|
|
),
|
|
})
|
|
}
|
|
|
|
fn parse_json_schema(name: &str, schema: &str) -> Value {
|
|
serde_json::from_str(schema)
|
|
.unwrap_or_else(|err| panic!("invalid generated hooks schema {name}: {err}"))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::generated_hook_schemas;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[test]
|
|
fn loads_generated_hook_schemas() {
|
|
let schemas = generated_hook_schemas();
|
|
|
|
assert_eq!(schemas.post_tool_use_command_input["type"], "object");
|
|
assert_eq!(schemas.post_tool_use_command_output["type"], "object");
|
|
assert_eq!(schemas.permission_request_command_input["type"], "object");
|
|
assert_eq!(schemas.permission_request_command_output["type"], "object");
|
|
assert_eq!(schemas.post_compact_command_input["type"], "object");
|
|
assert_eq!(schemas.post_compact_command_output["type"], "object");
|
|
assert_eq!(schemas.pre_tool_use_command_input["type"], "object");
|
|
assert_eq!(schemas.pre_tool_use_command_output["type"], "object");
|
|
assert_eq!(schemas.pre_compact_command_input["type"], "object");
|
|
assert_eq!(schemas.pre_compact_command_output["type"], "object");
|
|
assert_eq!(schemas.session_start_command_input["type"], "object");
|
|
assert_eq!(schemas.session_start_command_output["type"], "object");
|
|
assert_eq!(schemas.session_end_command_input["type"], "object");
|
|
assert_eq!(schemas.subagent_start_command_input["type"], "object");
|
|
assert_eq!(schemas.subagent_start_command_output["type"], "object");
|
|
assert_eq!(schemas.subagent_stop_command_input["type"], "object");
|
|
assert_eq!(schemas.subagent_stop_command_output["type"], "object");
|
|
assert_eq!(schemas.user_prompt_submit_command_input["type"], "object");
|
|
assert_eq!(schemas.user_prompt_submit_command_output["type"], "object");
|
|
assert_eq!(schemas.stop_command_input["type"], "object");
|
|
assert_eq!(schemas.stop_command_output["type"], "object");
|
|
assert_eq!(schemas.interrupt_command_input["type"], "object");
|
|
assert_eq!(schemas.interrupt_command_output["type"], "object");
|
|
}
|
|
}
|