mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat: add turn lifecycle contributors (#22480)
## Why Extensions can already contribute prompt, tool, turn-item, and thread-lifecycle behavior, but there was no explicit host-owned hook for per-turn setup and cleanup. That makes extension-private turn state awkward: an extension either has to stash it outside the turn lifecycle or depend on core runtime objects. This adds a small turn lifecycle boundary. Extensions receive stable identifiers plus the existing session, thread, and turn `ExtensionData` stores, while core keeps owning task scheduling, cancellation, and turn teardown. ## What Changed - Added `TurnLifecycleContributor` with `on_turn_start`, `on_turn_stop`, and `on_turn_abort` callbacks in `codex-rs/ext/extension-api`. - Added typed `TurnStartInput`, `TurnStopInput`, and `TurnAbortInput` payloads that expose `thread_id`, `turn_id`, `session_store`, `thread_store`, and `turn_store`. - Registered and re-exported turn lifecycle contributors through `ExtensionRegistry` and `ExtensionRegistryBuilder`. - Wired `Session` to emit turn start, stop, and abort callbacks from the existing turn/task lifecycle paths. - Carried the turn-scoped `ExtensionData` through `RunningTask` and `RemovedTask` so stop/abort callbacks receive the same turn store created at turn start. ## Verification - Not run locally.
This commit is contained in:
@@ -9,6 +9,7 @@ use crate::ExtensionData;
|
||||
mod prompt;
|
||||
mod thread_lifecycle;
|
||||
mod tools;
|
||||
mod turn_lifecycle;
|
||||
|
||||
pub use prompt::PromptFragment;
|
||||
pub use prompt::PromptSlot;
|
||||
@@ -18,6 +19,9 @@ pub use thread_lifecycle::ThreadStopInput;
|
||||
pub use tools::ExtensionToolExecutor;
|
||||
pub use tools::ExtensionToolFuture;
|
||||
pub use tools::ExtensionToolOutput;
|
||||
pub use turn_lifecycle::TurnAbortInput;
|
||||
pub use turn_lifecycle::TurnStartInput;
|
||||
pub use turn_lifecycle::TurnStopInput;
|
||||
|
||||
/// Extension contribution that adds prompt fragments during prompt assembly.
|
||||
pub trait ContextContributor: Send + Sync {
|
||||
@@ -45,6 +49,23 @@ pub trait ThreadLifecycleContributor<C>: Send + Sync {
|
||||
fn on_thread_stop(&self, _input: ThreadStopInput<'_>) {}
|
||||
}
|
||||
|
||||
/// Contributor for host-owned turn lifecycle gates.
|
||||
///
|
||||
/// Implementations should use these callbacks to seed, observe, or clear
|
||||
/// extension-private turn state. The host exposes stable identifiers and
|
||||
/// extension stores instead of core runtime objects.
|
||||
pub trait TurnLifecycleContributor: Send + Sync {
|
||||
/// Called after turn-scoped extension stores are created, before the task
|
||||
/// for the turn starts running.
|
||||
fn on_turn_start(&self, _input: TurnStartInput<'_>) {}
|
||||
|
||||
/// Called before the host drops the completed turn runtime and turn store.
|
||||
fn on_turn_stop(&self, _input: TurnStopInput<'_>) {}
|
||||
|
||||
/// Called after the host aborts a running turn.
|
||||
fn on_turn_abort(&self, _input: TurnAbortInput<'_>) {}
|
||||
}
|
||||
|
||||
/// Extension contribution that exposes native tools owned by a feature.
|
||||
pub trait ToolContributor: Send + Sync {
|
||||
/// Returns the native tools visible for the supplied extension stores.
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::TurnAbortReason;
|
||||
|
||||
use crate::ExtensionData;
|
||||
|
||||
/// Input supplied when the host starts a turn.
|
||||
pub struct TurnStartInput<'a> {
|
||||
/// Identifier for the thread containing this turn.
|
||||
pub thread_id: ThreadId,
|
||||
/// Identifier for the turn that is starting.
|
||||
pub turn_id: &'a str,
|
||||
/// Store scoped to the host session runtime.
|
||||
pub session_store: &'a ExtensionData,
|
||||
/// Store scoped to this thread runtime.
|
||||
pub thread_store: &'a ExtensionData,
|
||||
/// Store scoped to this turn runtime.
|
||||
pub turn_store: &'a ExtensionData,
|
||||
}
|
||||
|
||||
/// Input supplied when the host completes a turn.
|
||||
pub struct TurnStopInput<'a> {
|
||||
/// Identifier for the thread containing this turn.
|
||||
pub thread_id: ThreadId,
|
||||
/// Identifier for the turn that is stopping.
|
||||
pub turn_id: &'a str,
|
||||
/// Store scoped to the host session runtime.
|
||||
pub session_store: &'a ExtensionData,
|
||||
/// Store scoped to this thread runtime.
|
||||
pub thread_store: &'a ExtensionData,
|
||||
/// Store scoped to this turn runtime.
|
||||
pub turn_store: &'a ExtensionData,
|
||||
}
|
||||
|
||||
/// Input supplied when the host aborts a turn.
|
||||
pub struct TurnAbortInput<'a> {
|
||||
/// Identifier for the thread containing this turn.
|
||||
pub thread_id: ThreadId,
|
||||
/// Identifier for the turn that is aborting.
|
||||
pub turn_id: &'a str,
|
||||
/// Reason the host aborted the turn.
|
||||
pub reason: TurnAbortReason,
|
||||
/// Store scoped to the host session runtime.
|
||||
pub session_store: &'a ExtensionData,
|
||||
/// Store scoped to this thread runtime.
|
||||
pub thread_store: &'a ExtensionData,
|
||||
/// Store scoped to this turn runtime.
|
||||
pub turn_store: &'a ExtensionData,
|
||||
}
|
||||
@@ -26,8 +26,12 @@ pub use contributors::ThreadResumeInput;
|
||||
pub use contributors::ThreadStartInput;
|
||||
pub use contributors::ThreadStopInput;
|
||||
pub use contributors::ToolContributor;
|
||||
pub use contributors::TurnAbortInput;
|
||||
pub use contributors::TurnItemContributionFuture;
|
||||
pub use contributors::TurnItemContributor;
|
||||
pub use contributors::TurnLifecycleContributor;
|
||||
pub use contributors::TurnStartInput;
|
||||
pub use contributors::TurnStopInput;
|
||||
pub use registry::ExtensionRegistry;
|
||||
pub use registry::ExtensionRegistryBuilder;
|
||||
pub use registry::empty_extension_registry;
|
||||
|
||||
@@ -7,10 +7,12 @@ use crate::ExtensionData;
|
||||
use crate::ThreadLifecycleContributor;
|
||||
use crate::ToolContributor;
|
||||
use crate::TurnItemContributor;
|
||||
use crate::TurnLifecycleContributor;
|
||||
|
||||
/// Mutable registry used while hosts register typed runtime contributions.
|
||||
pub struct ExtensionRegistryBuilder<C> {
|
||||
thread_lifecycle_contributors: Vec<Arc<dyn ThreadLifecycleContributor<C>>>,
|
||||
turn_lifecycle_contributors: Vec<Arc<dyn TurnLifecycleContributor>>,
|
||||
context_contributors: Vec<Arc<dyn ContextContributor>>,
|
||||
tool_contributors: Vec<Arc<dyn ToolContributor>>,
|
||||
turn_item_contributors: Vec<Arc<dyn TurnItemContributor>>,
|
||||
@@ -21,6 +23,7 @@ impl<C> Default for ExtensionRegistryBuilder<C> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
thread_lifecycle_contributors: Vec::new(),
|
||||
turn_lifecycle_contributors: Vec::new(),
|
||||
approval_review_contributors: Vec::new(),
|
||||
context_contributors: Vec::new(),
|
||||
tool_contributors: Vec::new(),
|
||||
@@ -48,6 +51,11 @@ impl<C> ExtensionRegistryBuilder<C> {
|
||||
self.thread_lifecycle_contributors.push(contributor);
|
||||
}
|
||||
|
||||
/// Registers one turn-lifecycle contributor.
|
||||
pub fn turn_lifecycle_contributor(&mut self, contributor: Arc<dyn TurnLifecycleContributor>) {
|
||||
self.turn_lifecycle_contributors.push(contributor);
|
||||
}
|
||||
|
||||
/// Registers one prompt contributor.
|
||||
pub fn prompt_contributor(&mut self, contributor: Arc<dyn ContextContributor>) {
|
||||
self.context_contributors.push(contributor);
|
||||
@@ -67,6 +75,7 @@ impl<C> ExtensionRegistryBuilder<C> {
|
||||
pub fn build(self) -> ExtensionRegistry<C> {
|
||||
ExtensionRegistry {
|
||||
thread_lifecycle_contributors: self.thread_lifecycle_contributors,
|
||||
turn_lifecycle_contributors: self.turn_lifecycle_contributors,
|
||||
approval_review_contributors: self.approval_review_contributors,
|
||||
context_contributors: self.context_contributors,
|
||||
tool_contributors: self.tool_contributors,
|
||||
@@ -78,6 +87,7 @@ impl<C> ExtensionRegistryBuilder<C> {
|
||||
/// Immutable typed registry produced after extensions are installed.
|
||||
pub struct ExtensionRegistry<C> {
|
||||
thread_lifecycle_contributors: Vec<Arc<dyn ThreadLifecycleContributor<C>>>,
|
||||
turn_lifecycle_contributors: Vec<Arc<dyn TurnLifecycleContributor>>,
|
||||
context_contributors: Vec<Arc<dyn ContextContributor>>,
|
||||
tool_contributors: Vec<Arc<dyn ToolContributor>>,
|
||||
turn_item_contributors: Vec<Arc<dyn TurnItemContributor>>,
|
||||
@@ -90,6 +100,11 @@ impl<C> ExtensionRegistry<C> {
|
||||
&self.thread_lifecycle_contributors
|
||||
}
|
||||
|
||||
/// Returns the registered turn-lifecycle contributors.
|
||||
pub fn turn_lifecycle_contributors(&self) -> &[Arc<dyn TurnLifecycleContributor>] {
|
||||
&self.turn_lifecycle_contributors
|
||||
}
|
||||
|
||||
/// Claims the first rendered approval-review prompt accepted by an
|
||||
/// installed contributor.
|
||||
pub fn approval_review<'a>(
|
||||
|
||||
Reference in New Issue
Block a user