Run executor hooks for interrupted turns (#41432)

## Why

Executor-scoped cleanup hooks need to observe an interrupted turn as well as a
normally completed one.

## What changed

- Allow bundled executor plugins to register the allowlisted `Interrupt` hook
  alongside `Stop`, while preserving multiple allowed hook entries from the
  selected executor environment.
- Run interrupt hooks with the interrupted turn's last step discovery and turn
  metadata. Turns without a step context do not reuse discovery from an earlier
  turn.
- Keep executor-scoped interrupt hooks asynchronous and omit public hook
  lifecycle events for them, matching executor `Stop` hook behavior.

## Testing

Added coverage for hook filtering and registration, interrupt execution and
metadata propagation, environment selection, and turns without a step context.

GitOrigin-RevId: f0c536b3382a37cf3bf693c4573d21f6f66ace4e
This commit is contained in:
Krish Chainani authored and copyberry committed 2026-08-28 23:03:05 +00:00
1 parent 0d22692962
commit c2abf869d5
9 files changed
+473 -165

No files matched your search

+20 -13
View File
@@ -125,20 +125,27 @@ impl HookEventsToml {
.sum()
}
pub fn into_matcher_groups(self) -> [(HookEventName, Vec<MatcherGroup>); 12] {
pub fn into_matcher_groups(mut self) -> [(HookEventName, Vec<MatcherGroup>); 12] {
self.matcher_groups_mut()
.map(|(event, groups)| (event, std::mem::take(groups)))
}
pub fn matcher_groups_mut(&mut self) -> [(HookEventName, &mut Vec<MatcherGroup>); 12] {
use HookEventName as Event;
[
(HookEventName::PreToolUse, self.pre_tool_use),
(HookEventName::PermissionRequest, self.permission_request),
(HookEventName::PostToolUse, self.post_tool_use),
(HookEventName::PreCompact, self.pre_compact),
(HookEventName::PostCompact, self.post_compact),
(HookEventName::SessionStart, self.session_start),
(HookEventName::SessionEnd, self.session_end),
(HookEventName::UserPromptSubmit, self.user_prompt_submit),
(HookEventName::SubagentStart, self.subagent_start),
(HookEventName::SubagentStop, self.subagent_stop),
(HookEventName::Stop, self.stop),
(HookEventName::Interrupt, self.interrupt),
(Event::PreToolUse, &mut self.pre_tool_use),
(Event::PermissionRequest, &mut self.permission_request),
(Event::PostToolUse, &mut self.post_tool_use),
(Event::PreCompact, &mut self.pre_compact),
(Event::PostCompact, &mut self.post_compact),
(Event::SessionStart, &mut self.session_start),
(Event::SessionEnd, &mut self.session_end),
(Event::UserPromptSubmit, &mut self.user_prompt_submit),
(Event::SubagentStart, &mut self.subagent_start),
(Event::SubagentStop, &mut self.subagent_stop),
(Event::Stop, &mut self.stop),
(Event::Interrupt, &mut self.interrupt),
]
}
}