mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Add SubagentStop hook (#22873)
# What <img width="1792" height="1024" alt="image" src="https://github.com/user-attachments/assets/8f81d232-5813-4994-a61d-e42a05a93a3e" /> `SubagentStop` runs when a thread-spawned subagent turn is about to finish. Thread-spawned subagents use `SubagentStop` instead of the normal root-agent `Stop` hook. Configured handlers match on `agent_type`. Hook input includes the normal stop fields plus: - `agent_id`: the child thread id. - `agent_type`: the resolved subagent type. - `agent_transcript_path`: the child subagent transcript path. - `transcript_path`: the parent thread transcript path. - `last_assistant_message`: the final assistant message from the child turn, when available. - `stop_hook_active`: `true` when the child is already continuing because an earlier stop-like hook blocked completion. `SubagentStop` shares the same completion-control semantics as `Stop`, scoped to the child turn: - No decision allows the child turn to finish. - `decision: "block"` with a non-empty `reason` records that reason as hook feedback and continues the child with that prompt. - `continue: false` stops the child turn. If `stopReason` is present, Codex surfaces it as the stop reason. # Lifecycle Scope Only thread-spawned subagents run `SubagentStop`. Internal/system subagents such as Review, Compact, MemoryConsolidation, and Other do not run normal `Stop` hooks and do not run `SubagentStop`. This avoids exposing synthetic matcher labels for internal implementation paths. # Stack 1. #22782: add `SubagentStart`. 2. This PR: add `SubagentStop`. 3. #22882: add subagent identity to normal hook inputs.
This commit is contained in:
committed by
GitHub
Unverified
parent
40ad7be2b5
commit
eee3e60db3
@@ -47,6 +47,8 @@ pub struct HookEventsToml {
|
||||
pub user_prompt_submit: Vec<MatcherGroup>,
|
||||
#[serde(rename = "SubagentStart", default)]
|
||||
pub subagent_start: Vec<MatcherGroup>,
|
||||
#[serde(rename = "SubagentStop", default)]
|
||||
pub subagent_stop: Vec<MatcherGroup>,
|
||||
#[serde(rename = "Stop", default)]
|
||||
pub stop: Vec<MatcherGroup>,
|
||||
}
|
||||
@@ -62,6 +64,7 @@ impl HookEventsToml {
|
||||
session_start,
|
||||
user_prompt_submit,
|
||||
subagent_start,
|
||||
subagent_stop,
|
||||
stop,
|
||||
} = self;
|
||||
pre_tool_use.is_empty()
|
||||
@@ -72,6 +75,7 @@ impl HookEventsToml {
|
||||
&& session_start.is_empty()
|
||||
&& user_prompt_submit.is_empty()
|
||||
&& subagent_start.is_empty()
|
||||
&& subagent_stop.is_empty()
|
||||
&& stop.is_empty()
|
||||
}
|
||||
|
||||
@@ -85,6 +89,7 @@ impl HookEventsToml {
|
||||
session_start,
|
||||
user_prompt_submit,
|
||||
subagent_start,
|
||||
subagent_stop,
|
||||
stop,
|
||||
} = self;
|
||||
[
|
||||
@@ -96,6 +101,7 @@ impl HookEventsToml {
|
||||
session_start,
|
||||
user_prompt_submit,
|
||||
subagent_start,
|
||||
subagent_stop,
|
||||
stop,
|
||||
]
|
||||
.into_iter()
|
||||
@@ -104,7 +110,7 @@ impl HookEventsToml {
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn into_matcher_groups(self) -> [(HookEventName, Vec<MatcherGroup>); 9] {
|
||||
pub fn into_matcher_groups(self) -> [(HookEventName, Vec<MatcherGroup>); 10] {
|
||||
[
|
||||
(HookEventName::PreToolUse, self.pre_tool_use),
|
||||
(HookEventName::PermissionRequest, self.permission_request),
|
||||
@@ -114,6 +120,7 @@ impl HookEventsToml {
|
||||
(HookEventName::SessionStart, self.session_start),
|
||||
(HookEventName::UserPromptSubmit, self.user_prompt_submit),
|
||||
(HookEventName::SubagentStart, self.subagent_start),
|
||||
(HookEventName::SubagentStop, self.subagent_stop),
|
||||
(HookEventName::Stop, self.stop),
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user