mirror of
https://github.com/openai/codex.git
synced 2026-11-05 20:10:33 +00:00
Add hooks for interrupted turns (#40511)
## 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
This commit is contained in:
committed by
copyberry
parent
9b2ef38f54
commit
cbfd999db7
@@ -2098,7 +2098,8 @@
|
||||
"userPromptSubmit",
|
||||
"subagentStart",
|
||||
"subagentStop",
|
||||
"stop"
|
||||
"stop",
|
||||
"interrupt"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+9
-1
@@ -12463,7 +12463,8 @@
|
||||
"userPromptSubmit",
|
||||
"subagentStart",
|
||||
"subagentStop",
|
||||
"stop"
|
||||
"stop",
|
||||
"interrupt"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -13586,6 +13587,13 @@
|
||||
},
|
||||
"ManagedHooksRequirements": {
|
||||
"properties": {
|
||||
"Interrupt": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PermissionRequest": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/ConfiguredHookMatcherGroup"
|
||||
|
||||
+9
-1
@@ -8552,7 +8552,8 @@
|
||||
"userPromptSubmit",
|
||||
"subagentStart",
|
||||
"subagentStop",
|
||||
"stop"
|
||||
"stop",
|
||||
"interrupt"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -9736,6 +9737,13 @@
|
||||
},
|
||||
"ManagedHooksRequirements": {
|
||||
"properties": {
|
||||
"Interrupt": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PermissionRequest": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
|
||||
+7
@@ -720,6 +720,13 @@
|
||||
},
|
||||
"ManagedHooksRequirements": {
|
||||
"properties": {
|
||||
"Interrupt": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PermissionRequest": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
|
||||
+2
-1
@@ -17,7 +17,8 @@
|
||||
"userPromptSubmit",
|
||||
"subagentStart",
|
||||
"subagentStop",
|
||||
"stop"
|
||||
"stop",
|
||||
"interrupt"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
"userPromptSubmit",
|
||||
"subagentStart",
|
||||
"subagentStop",
|
||||
"stop"
|
||||
"stop",
|
||||
"interrupt"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
"userPromptSubmit",
|
||||
"subagentStart",
|
||||
"subagentStop",
|
||||
"stop"
|
||||
"stop",
|
||||
"interrupt"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -120,7 +120,8 @@
|
||||
"userPromptSubmit",
|
||||
"subagentStart",
|
||||
"subagentStop",
|
||||
"stop"
|
||||
"stop",
|
||||
"interrupt"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -2,4 +2,4 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type HookEventName = "preToolUse" | "permissionRequest" | "postToolUse" | "preCompact" | "postCompact" | "sessionStart" | "sessionEnd" | "userPromptSubmit" | "subagentStart" | "subagentStop" | "stop";
|
||||
export type HookEventName = "preToolUse" | "permissionRequest" | "postToolUse" | "preCompact" | "postCompact" | "sessionStart" | "sessionEnd" | "userPromptSubmit" | "subagentStart" | "subagentStop" | "stop" | "interrupt";
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfiguredHookMatcherGroup } from "./ConfiguredHookMatcherGroup";
|
||||
|
||||
export type ManagedHooksRequirements = { managedDir: string | null, windowsManagedDir: string | null, PreToolUse: Array<ConfiguredHookMatcherGroup>, PermissionRequest: Array<ConfiguredHookMatcherGroup>, PostToolUse: Array<ConfiguredHookMatcherGroup>, PreCompact: Array<ConfiguredHookMatcherGroup>, PostCompact: Array<ConfiguredHookMatcherGroup>, SessionStart: Array<ConfiguredHookMatcherGroup>, SessionEnd: Array<ConfiguredHookMatcherGroup>, UserPromptSubmit: Array<ConfiguredHookMatcherGroup>, SubagentStart: Array<ConfiguredHookMatcherGroup>, SubagentStop: Array<ConfiguredHookMatcherGroup>, Stop: Array<ConfiguredHookMatcherGroup>, };
|
||||
export type ManagedHooksRequirements = { managedDir: string | null, windowsManagedDir: string | null, PreToolUse: Array<ConfiguredHookMatcherGroup>, PermissionRequest: Array<ConfiguredHookMatcherGroup>, PostToolUse: Array<ConfiguredHookMatcherGroup>, PreCompact: Array<ConfiguredHookMatcherGroup>, PostCompact: Array<ConfiguredHookMatcherGroup>, SessionStart: Array<ConfiguredHookMatcherGroup>, SessionEnd: Array<ConfiguredHookMatcherGroup>, UserPromptSubmit: Array<ConfiguredHookMatcherGroup>, SubagentStart: Array<ConfiguredHookMatcherGroup>, SubagentStop: Array<ConfiguredHookMatcherGroup>, Stop: Array<ConfiguredHookMatcherGroup>, Interrupt: Array<ConfiguredHookMatcherGroup>, };
|
||||
|
||||
@@ -589,6 +589,9 @@ pub struct ManagedHooksRequirements {
|
||||
#[serde(rename = "Stop")]
|
||||
#[ts(rename = "Stop")]
|
||||
pub stop: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "Interrupt", default)]
|
||||
#[ts(rename = "Interrupt")]
|
||||
pub interrupt: Vec<ConfiguredHookMatcherGroup>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
|
||||
@@ -17,7 +17,7 @@ use serde::Serialize;
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookEventName from CoreHookEventName {
|
||||
PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, SessionStart, SessionEnd, UserPromptSubmit, SubagentStart, SubagentStop, Stop
|
||||
PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, SessionStart, SessionEnd, UserPromptSubmit, SubagentStart, SubagentStop, Stop, Interrupt
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -72,6 +72,30 @@ fn test_absolute_path() -> AbsolutePathBuf {
|
||||
absolute_path("readable")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn managed_hooks_requirements_default_interrupt_to_empty() {
|
||||
let value = json!({
|
||||
"managedDir": null,
|
||||
"windowsManagedDir": null,
|
||||
"PreToolUse": [],
|
||||
"PermissionRequest": [],
|
||||
"PostToolUse": [],
|
||||
"PreCompact": [],
|
||||
"PostCompact": [],
|
||||
"SessionStart": [],
|
||||
"SessionEnd": [],
|
||||
"UserPromptSubmit": [],
|
||||
"SubagentStart": [],
|
||||
"SubagentStop": [],
|
||||
"Stop": []
|
||||
});
|
||||
|
||||
let parsed: ManagedHooksRequirements =
|
||||
serde_json::from_value(value).expect("deserialize managed hooks requirements");
|
||||
|
||||
assert_eq!(parsed.interrupt, Vec::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_agent_config_detect_response_defaults_connectors_for_older_servers() {
|
||||
let response = serde_json::from_value::<ExternalAgentConfigDetectResponse>(json!({
|
||||
|
||||
Reference in New Issue
Block a user