[codex] Add interruptible sleep tool (#28429)

## Why

Models sometimes need to pause briefly while waiting for external work,
but using a shell command for that delay ties the wait to a process and
does not naturally resume when new turn input arrives.

## What changed

- add a built-in `sleep` tool behind the under-development `sleep_tool`
feature
- accept a bounded `duration_ms` argument, matching the millisecond
convention used by unified exec
- end the sleep early when either steered user input or mailbox input
arrives
- include elapsed wall-clock time in completed and interrupted outputs
- emit a dedicated core `SleepItem` through `item/started` and
`item/completed`
- expose the sleep item as app-server v2 `ThreadItem::Sleep` and retain
it in reconstructed thread history
- regenerate the configuration schema for the new feature flag
- regenerate app-server JSON and TypeScript schema fixtures

## Test plan

- `just test -p codex-core sleep_tool_follows_feature_gate`
- `just test -p codex-core any_new_input_interrupts_sleep`
- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server
sleep_emits_started_and_completed_items`
This commit is contained in:
pakrym-oai
2026-06-15 21:39:21 -07:00
committed by GitHub
Unverified
parent 022f1221e8
commit 08901fc8e1
37 changed files with 1099 additions and 19 deletions
+9
View File
@@ -47,6 +47,7 @@ pub enum TurnItem {
Reasoning(ReasoningItem),
WebSearch(WebSearchItem),
ImageView(ImageViewItem),
Sleep(SleepItem),
ImageGeneration(ImageGenerationItem),
FileChange(FileChangeItem),
McpToolCall(McpToolCallItem),
@@ -140,6 +141,12 @@ pub struct ImageViewItem {
pub path: AbsolutePathBuf,
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq, Eq)]
pub struct SleepItem {
pub id: String,
pub duration_ms: u64,
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq)]
pub struct ImageGenerationItem {
pub id: String,
@@ -576,6 +583,7 @@ impl TurnItem {
TurnItem::Reasoning(item) => item.id.clone(),
TurnItem::WebSearch(item) => item.id.clone(),
TurnItem::ImageView(item) => item.id.clone(),
TurnItem::Sleep(item) => item.id.clone(),
TurnItem::ImageGeneration(item) => item.id.clone(),
TurnItem::FileChange(item) => item.id.clone(),
TurnItem::McpToolCall(item) => item.id.clone(),
@@ -596,6 +604,7 @@ impl TurnItem {
path: item.path.clone(),
})]
}
TurnItem::Sleep(_) => Vec::new(),
TurnItem::ImageGeneration(item) => vec![item.as_legacy_event()],
TurnItem::FileChange(item) => item
.as_legacy_end_event(String::new())