mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Make extension lifecycle hooks async (#23291)
## Why Extension lifecycle hooks sit on the host/extension boundary, but the current trait surface only allows synchronous callbacks. That forces extensions that need to seed, rehydrate, observe, or flush extension-owned state during thread and turn transitions to either block inside the callback or move async work into separate host plumbing. This PR makes those lifecycle callbacks awaitable so extension implementations can perform async work directly at the lifecycle point where the host already has the relevant session, thread, or turn stores available. ## What changed - Makes `ThreadLifecycleContributor` and `TurnLifecycleContributor` async in `codex-extension-api`. - Awaits thread start/resume/stop and turn start/stop/abort lifecycle callbacks from `codex-core`. - Updates the guardian and memories extensions to implement the async lifecycle trait surface. - Updates the existing lifecycle tests to use async contributor implementations. - Adds `async-trait` to the crates that now expose or implement these async object-safe lifecycle traits. ## Testing - Existing `codex-core` lifecycle tests were updated to cover async implementations for thread stop and turn abort ordering.
This commit is contained in:
@@ -36,16 +36,17 @@ pub trait ContextContributor: Send + Sync {
|
||||
/// Implementations should use these callbacks to seed, rehydrate, or flush
|
||||
/// extension-private thread state. Heavy dependencies belong on the extension
|
||||
/// value created by the host, not in these inputs.
|
||||
pub trait ThreadLifecycleContributor<C>: Send + Sync {
|
||||
#[async_trait::async_trait]
|
||||
pub trait ThreadLifecycleContributor<C: Sync>: Send + Sync {
|
||||
/// Called after thread-scoped extension stores are created, before later
|
||||
/// contributors can read from them.
|
||||
fn on_thread_start(&self, _input: ThreadStartInput<'_, C>) {}
|
||||
async fn on_thread_start(&self, _input: ThreadStartInput<'_, C>) {}
|
||||
|
||||
/// Called after the host constructs a runtime from persisted history.
|
||||
fn on_thread_resume(&self, _input: ThreadResumeInput<'_>) {}
|
||||
async fn on_thread_resume(&self, _input: ThreadResumeInput<'_>) {}
|
||||
|
||||
/// Called before the host drops the thread runtime and thread-scoped store.
|
||||
fn on_thread_stop(&self, _input: ThreadStopInput<'_>) {}
|
||||
async fn on_thread_stop(&self, _input: ThreadStopInput<'_>) {}
|
||||
}
|
||||
|
||||
/// Contributor for host-owned turn lifecycle gates.
|
||||
@@ -53,16 +54,17 @@ pub trait ThreadLifecycleContributor<C>: Send + Sync {
|
||||
/// 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.
|
||||
#[async_trait::async_trait]
|
||||
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<'_>) {}
|
||||
async 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<'_>) {}
|
||||
async fn on_turn_stop(&self, _input: TurnStopInput<'_>) {}
|
||||
|
||||
/// Called after the host aborts a running turn.
|
||||
fn on_turn_abort(&self, _input: TurnAbortInput<'_>) {}
|
||||
async fn on_turn_abort(&self, _input: TurnAbortInput<'_>) {}
|
||||
}
|
||||
|
||||
/// Contributor for host-owned configuration changes.
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::TurnItemContributor;
|
||||
use crate::TurnLifecycleContributor;
|
||||
|
||||
/// Mutable registry used while hosts register typed runtime contributions.
|
||||
pub struct ExtensionRegistryBuilder<C> {
|
||||
pub struct ExtensionRegistryBuilder<C: Sync> {
|
||||
thread_lifecycle_contributors: Vec<Arc<dyn ThreadLifecycleContributor<C>>>,
|
||||
turn_lifecycle_contributors: Vec<Arc<dyn TurnLifecycleContributor>>,
|
||||
config_contributors: Vec<Arc<dyn ConfigContributor<C>>>,
|
||||
@@ -23,7 +23,7 @@ pub struct ExtensionRegistryBuilder<C> {
|
||||
approval_review_contributors: Vec<Arc<dyn ApprovalReviewContributor>>,
|
||||
}
|
||||
|
||||
impl<C> Default for ExtensionRegistryBuilder<C> {
|
||||
impl<C: Sync> Default for ExtensionRegistryBuilder<C> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
thread_lifecycle_contributors: Vec::new(),
|
||||
@@ -38,7 +38,7 @@ impl<C> Default for ExtensionRegistryBuilder<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> ExtensionRegistryBuilder<C> {
|
||||
impl<C: Sync> ExtensionRegistryBuilder<C> {
|
||||
/// Creates an empty registry builder.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
@@ -103,7 +103,7 @@ impl<C> ExtensionRegistryBuilder<C> {
|
||||
}
|
||||
|
||||
/// Immutable typed registry produced after extensions are installed.
|
||||
pub struct ExtensionRegistry<C> {
|
||||
pub struct ExtensionRegistry<C: Sync> {
|
||||
thread_lifecycle_contributors: Vec<Arc<dyn ThreadLifecycleContributor<C>>>,
|
||||
turn_lifecycle_contributors: Vec<Arc<dyn TurnLifecycleContributor>>,
|
||||
config_contributors: Vec<Arc<dyn ConfigContributor<C>>>,
|
||||
@@ -114,7 +114,7 @@ pub struct ExtensionRegistry<C> {
|
||||
approval_review_contributors: Vec<Arc<dyn ApprovalReviewContributor>>,
|
||||
}
|
||||
|
||||
impl<C> ExtensionRegistry<C> {
|
||||
impl<C: Sync> ExtensionRegistry<C> {
|
||||
/// Returns the registered thread-lifecycle contributors.
|
||||
pub fn thread_lifecycle_contributors(&self) -> &[Arc<dyn ThreadLifecycleContributor<C>>] {
|
||||
&self.thread_lifecycle_contributors
|
||||
@@ -165,6 +165,6 @@ impl<C> ExtensionRegistry<C> {
|
||||
}
|
||||
|
||||
/// Creates an empty shared registry for hosts that do not register contributions.
|
||||
pub fn empty_extension_registry<C>() -> Arc<ExtensionRegistry<C>> {
|
||||
pub fn empty_extension_registry<C: Sync>() -> Arc<ExtensionRegistry<C>> {
|
||||
Arc::new(ExtensionRegistryBuilder::new().build())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user