From d2ebb8d8caf6bc487466ee50f61eaa2dc53fa091 Mon Sep 17 00:00:00 2001 From: jif-oai Date: Wed, 27 May 2026 15:17:23 +0200 Subject: [PATCH] feat: add thread idle lifecycle hook (#24744) ## Why Extensions can currently observe thread start, resume, and stop, but they do not have a lifecycle point for the host to say that immediately pending thread work has drained. That makes idle follow-up behavior harder to express as extension-owned logic instead of host-specific plumbing. This adds an explicit idle lifecycle hook so an extension can react when a thread becomes idle while the host keeps ownership of whether any submitted follow-up input starts a turn, is queued, or is ignored. ## What changed - Added `ThreadIdleInput` with access to the session-scoped and thread-scoped extension stores. - Added a default `on_thread_idle` method to `ThreadLifecycleContributor`. - Re-exported `ThreadIdleInput` from the extension API surface. ## Testing Not run; this only extends the extension API trait surface with a default hook and exported input type. --- codex-rs/ext/extension-api/src/contributors.rs | 8 ++++++++ .../extension-api/src/contributors/thread_lifecycle.rs | 8 ++++++++ codex-rs/ext/extension-api/src/lib.rs | 1 + 3 files changed, 17 insertions(+) diff --git a/codex-rs/ext/extension-api/src/contributors.rs b/codex-rs/ext/extension-api/src/contributors.rs index 2113fdef8e..fda295b7f7 100644 --- a/codex-rs/ext/extension-api/src/contributors.rs +++ b/codex-rs/ext/extension-api/src/contributors.rs @@ -16,6 +16,7 @@ mod turn_lifecycle; pub use prompt::PromptFragment; pub use prompt::PromptSlot; +pub use thread_lifecycle::ThreadIdleInput; pub use thread_lifecycle::ThreadResumeInput; pub use thread_lifecycle::ThreadStartInput; pub use thread_lifecycle::ThreadStopInput; @@ -51,6 +52,13 @@ pub trait ThreadLifecycleContributor: Send + Sync { /// Called after the host constructs a runtime from persisted history. async fn on_thread_resume(&self, _input: ThreadResumeInput<'_>) {} + /// Called after the host has drained immediately pending thread work. + /// + /// Implementations may use host capabilities captured by the extension to + /// submit follow-up input. The host remains responsible for deciding + /// whether that input starts a turn, is queued, or is ignored. + async fn on_thread_idle(&self, _input: ThreadIdleInput<'_>) {} + /// Called before the host drops the thread runtime and thread-scoped store. async fn on_thread_stop(&self, _input: ThreadStopInput<'_>) {} } diff --git a/codex-rs/ext/extension-api/src/contributors/thread_lifecycle.rs b/codex-rs/ext/extension-api/src/contributors/thread_lifecycle.rs index d50f5a1e2f..07c7e7fa81 100644 --- a/codex-rs/ext/extension-api/src/contributors/thread_lifecycle.rs +++ b/codex-rs/ext/extension-api/src/contributors/thread_lifecycle.rs @@ -18,6 +18,14 @@ pub struct ThreadResumeInput<'a> { pub thread_store: &'a ExtensionData, } +/// Input supplied when the host has no immediately pending thread work. +pub struct ThreadIdleInput<'a> { + /// Store scoped to the host session runtime. + pub session_store: &'a ExtensionData, + /// Store scoped to this thread runtime. + pub thread_store: &'a ExtensionData, +} + /// Input supplied when the host stops a thread runtime. pub struct ThreadStopInput<'a> { /// Store scoped to the host session runtime. diff --git a/codex-rs/ext/extension-api/src/lib.rs b/codex-rs/ext/extension-api/src/lib.rs index f3c3dc526e..80ca67e290 100644 --- a/codex-rs/ext/extension-api/src/lib.rs +++ b/codex-rs/ext/extension-api/src/lib.rs @@ -27,6 +27,7 @@ pub use contributors::ConfigContributor; pub use contributors::ContextContributor; pub use contributors::PromptFragment; pub use contributors::PromptSlot; +pub use contributors::ThreadIdleInput; pub use contributors::ThreadLifecycleContributor; pub use contributors::ThreadResumeInput; pub use contributors::ThreadStartInput;