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:
jif-oai authored and GitHub committed 2026-05-13 13:47:27 +02:00
1 parent e831db7a96
commit 27e67a8c2a
7 files changed
+180 -2

No files matched your search

@@ -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.