mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
[codex] Remove legacy after tool use hooks (#21805)
## Why The legacy `AfterToolUse` hook path was still wired through core tool dispatch even though the hooks registry never populated any handlers for it. The supported hook surface is `PostToolUse`, so the old infrastructure was dead code on the hot path. ## What changed - Removed the legacy `AfterToolUse` dispatch from `codex-core` tool execution. - Removed the unused legacy hook payload types and exports from `codex-hooks`. - Simplified legacy notify handling now that `HookEvent` only carries `AfterAgent`. ## Validation - `cargo test -p codex-hooks` - `cargo test -p codex-core registry`
This commit is contained in:
@@ -37,9 +37,6 @@ pub fn legacy_notify_json(payload: &HookPayload) -> Result<String, serde_json::E
|
||||
last_assistant_message: event.last_assistant_message.clone(),
|
||||
})
|
||||
}
|
||||
HookEvent::AfterToolUse { .. } => Err(serde_json::Error::io(std::io::Error::other(
|
||||
"legacy notify payload is only supported for after_agent",
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,13 +69,9 @@ pub use schema::write_schema_fixtures;
|
||||
pub use types::Hook;
|
||||
pub use types::HookEvent;
|
||||
pub use types::HookEventAfterAgent;
|
||||
pub use types::HookEventAfterToolUse;
|
||||
pub use types::HookPayload;
|
||||
pub use types::HookResponse;
|
||||
pub use types::HookResult;
|
||||
pub use types::HookToolInput;
|
||||
pub use types::HookToolInputLocalShell;
|
||||
pub use types::HookToolKind;
|
||||
|
||||
/// Returns the hook event label used in persisted hook-state keys.
|
||||
pub fn hook_event_key_label(event_name: HookEventName) -> &'static str {
|
||||
|
||||
@@ -46,7 +46,6 @@ pub struct HookListOutcome {
|
||||
#[derive(Clone)]
|
||||
pub struct Hooks {
|
||||
after_agent: Vec<Hook>,
|
||||
after_tool_use: Vec<Hook>,
|
||||
engine: ClaudeHooksEngine,
|
||||
}
|
||||
|
||||
@@ -76,7 +75,6 @@ impl Hooks {
|
||||
);
|
||||
Self {
|
||||
after_agent,
|
||||
after_tool_use: Vec::new(),
|
||||
engine,
|
||||
}
|
||||
}
|
||||
@@ -88,7 +86,6 @@ impl Hooks {
|
||||
fn hooks_for_event(&self, hook_event: &HookEvent) -> &[Hook] {
|
||||
match hook_event {
|
||||
HookEvent::AfterAgent { .. } => &self.after_agent,
|
||||
HookEvent::AfterToolUse { .. } => &self.after_tool_use,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ use chrono::DateTime;
|
||||
use chrono::SecondsFormat;
|
||||
use chrono::Utc;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::models::SandboxPermissions;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use futures::future::BoxFuture;
|
||||
use serde::Serialize;
|
||||
@@ -81,62 +80,6 @@ pub struct HookEventAfterAgent {
|
||||
pub last_assistant_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum HookToolKind {
|
||||
Function,
|
||||
Custom,
|
||||
LocalShell,
|
||||
Mcp,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct HookToolInputLocalShell {
|
||||
pub command: Vec<String>,
|
||||
pub workdir: Option<String>,
|
||||
pub timeout_ms: Option<u64>,
|
||||
pub sandbox_permissions: Option<SandboxPermissions>,
|
||||
pub prefix_rule: Option<Vec<String>>,
|
||||
pub justification: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
#[serde(tag = "input_type", rename_all = "snake_case")]
|
||||
pub enum HookToolInput {
|
||||
Function {
|
||||
arguments: String,
|
||||
},
|
||||
Custom {
|
||||
input: String,
|
||||
},
|
||||
LocalShell {
|
||||
params: HookToolInputLocalShell,
|
||||
},
|
||||
Mcp {
|
||||
server: String,
|
||||
tool: String,
|
||||
arguments: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct HookEventAfterToolUse {
|
||||
pub turn_id: String,
|
||||
pub call_id: String,
|
||||
pub tool_name: String,
|
||||
pub tool_kind: HookToolKind,
|
||||
pub tool_input: HookToolInput,
|
||||
pub executed: bool,
|
||||
pub success: bool,
|
||||
pub duration_ms: u64,
|
||||
pub mutating: bool,
|
||||
pub sandbox: String,
|
||||
pub sandbox_policy: String,
|
||||
pub output_preview: String,
|
||||
}
|
||||
|
||||
fn serialize_triggered_at<S>(value: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -151,10 +94,6 @@ pub enum HookEvent {
|
||||
#[serde(flatten)]
|
||||
event: HookEventAfterAgent,
|
||||
},
|
||||
AfterToolUse {
|
||||
#[serde(flatten)]
|
||||
event: HookEventAfterToolUse,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -162,7 +101,6 @@ mod tests {
|
||||
use chrono::TimeZone;
|
||||
use chrono::Utc;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::models::SandboxPermissions;
|
||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
use codex_utils_absolute_path::test_support::test_path_buf;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -170,11 +108,7 @@ mod tests {
|
||||
|
||||
use super::HookEvent;
|
||||
use super::HookEventAfterAgent;
|
||||
use super::HookEventAfterToolUse;
|
||||
use super::HookPayload;
|
||||
use super::HookToolInput;
|
||||
use super::HookToolInputLocalShell;
|
||||
use super::HookToolKind;
|
||||
|
||||
#[test]
|
||||
fn hook_payload_serializes_stable_wire_shape() {
|
||||
@@ -215,78 +149,4 @@ mod tests {
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn after_tool_use_payload_serializes_stable_wire_shape() {
|
||||
let session_id = ThreadId::new();
|
||||
let cwd = test_path_buf("/tmp").abs();
|
||||
let payload = HookPayload {
|
||||
session_id,
|
||||
cwd: cwd.clone(),
|
||||
client: None,
|
||||
triggered_at: Utc
|
||||
.with_ymd_and_hms(2025, 1, 1, 0, 0, 0)
|
||||
.single()
|
||||
.expect("valid timestamp"),
|
||||
hook_event: HookEvent::AfterToolUse {
|
||||
event: HookEventAfterToolUse {
|
||||
turn_id: "turn-2".to_string(),
|
||||
call_id: "call-1".to_string(),
|
||||
tool_name: "local_shell".to_string(),
|
||||
tool_kind: HookToolKind::LocalShell,
|
||||
tool_input: HookToolInput::LocalShell {
|
||||
params: HookToolInputLocalShell {
|
||||
command: vec!["cargo".to_string(), "fmt".to_string()],
|
||||
workdir: Some("codex-rs".to_string()),
|
||||
timeout_ms: Some(60_000),
|
||||
sandbox_permissions: Some(SandboxPermissions::UseDefault),
|
||||
justification: None,
|
||||
prefix_rule: None,
|
||||
},
|
||||
},
|
||||
executed: true,
|
||||
success: true,
|
||||
duration_ms: 42,
|
||||
mutating: true,
|
||||
sandbox: "none".to_string(),
|
||||
sandbox_policy: "danger-full-access".to_string(),
|
||||
output_preview: "ok".to_string(),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let actual = serde_json::to_value(payload).expect("serialize hook payload");
|
||||
let expected = json!({
|
||||
"session_id": session_id.to_string(),
|
||||
"cwd": cwd.display().to_string(),
|
||||
"triggered_at": "2025-01-01T00:00:00Z",
|
||||
"hook_event": {
|
||||
"event_type": "after_tool_use",
|
||||
"turn_id": "turn-2",
|
||||
"call_id": "call-1",
|
||||
"tool_name": "local_shell",
|
||||
"tool_kind": "local_shell",
|
||||
"tool_input": {
|
||||
"input_type": "local_shell",
|
||||
"params": {
|
||||
"command": ["cargo", "fmt"],
|
||||
"workdir": "codex-rs",
|
||||
"timeout_ms": 60000,
|
||||
"sandbox_permissions": "use_default",
|
||||
"justification": null,
|
||||
"prefix_rule": null,
|
||||
},
|
||||
},
|
||||
"executed": true,
|
||||
"success": true,
|
||||
"duration_ms": 42,
|
||||
"mutating": true,
|
||||
"sandbox": "none",
|
||||
"sandbox_policy": "danger-full-access",
|
||||
"output_preview": "ok",
|
||||
},
|
||||
});
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user