diff --git a/codex-rs/ext/extension-api/src/capabilities/events.rs b/codex-rs/ext/extension-api/src/capabilities/events.rs new file mode 100644 index 0000000000..d8fda1aea7 --- /dev/null +++ b/codex-rs/ext/extension-api/src/capabilities/events.rs @@ -0,0 +1,19 @@ +use codex_protocol::protocol::Event; + +/// Host-provided fire-and-forget sink for extension-generated events. +/// +/// Extensions construct protocol events with the correlation id appropriate for +/// the callback they are handling, then leave persistence, ordering, transport +/// fanout, and logging decisions to the host. +pub trait ExtensionEventSink: Send + Sync { + /// Queue one protocol event for host-owned delivery. + fn emit(&self, event: Event); +} + +/// Event sink used when the host does not expose extension event emission. +#[derive(Debug, Default, Clone, Copy)] +pub struct NoopExtensionEventSink; + +impl ExtensionEventSink for NoopExtensionEventSink { + fn emit(&self, _event: Event) {} +} diff --git a/codex-rs/ext/extension-api/src/capabilities/mod.rs b/codex-rs/ext/extension-api/src/capabilities/mod.rs index bcc33da975..cd23146542 100644 --- a/codex-rs/ext/extension-api/src/capabilities/mod.rs +++ b/codex-rs/ext/extension-api/src/capabilities/mod.rs @@ -1,4 +1,7 @@ mod agent; +mod events; pub use agent::AgentSpawnFuture; pub use agent::AgentSpawner; +pub use events::ExtensionEventSink; +pub use events::NoopExtensionEventSink; diff --git a/codex-rs/ext/extension-api/src/lib.rs b/codex-rs/ext/extension-api/src/lib.rs index e8be7e0309..fe33d42128 100644 --- a/codex-rs/ext/extension-api/src/lib.rs +++ b/codex-rs/ext/extension-api/src/lib.rs @@ -5,6 +5,8 @@ mod state; pub use capabilities::AgentSpawnFuture; pub use capabilities::AgentSpawner; +pub use capabilities::ExtensionEventSink; +pub use capabilities::NoopExtensionEventSink; pub use codex_tools::FunctionCallError; pub use codex_tools::JsonToolOutput; pub use codex_tools::ResponsesApiTool; diff --git a/codex-rs/ext/extension-api/src/registry.rs b/codex-rs/ext/extension-api/src/registry.rs index f00e996315..41d0967126 100644 --- a/codex-rs/ext/extension-api/src/registry.rs +++ b/codex-rs/ext/extension-api/src/registry.rs @@ -5,6 +5,8 @@ use crate::ApprovalReviewFuture; use crate::ConfigContributor; use crate::ContextContributor; use crate::ExtensionData; +use crate::ExtensionEventSink; +use crate::NoopExtensionEventSink; use crate::ThreadLifecycleContributor; use crate::TokenUsageContributor; use crate::ToolContributor; @@ -13,6 +15,7 @@ use crate::TurnLifecycleContributor; /// Mutable registry used while hosts register typed runtime contributions. pub struct ExtensionRegistryBuilder { + event_sink: Arc, thread_lifecycle_contributors: Vec>>, turn_lifecycle_contributors: Vec>, config_contributors: Vec>>, @@ -26,6 +29,7 @@ pub struct ExtensionRegistryBuilder { impl Default for ExtensionRegistryBuilder { fn default() -> Self { Self { + event_sink: Arc::new(NoopExtensionEventSink), thread_lifecycle_contributors: Vec::new(), turn_lifecycle_contributors: Vec::new(), config_contributors: Vec::new(), @@ -44,6 +48,19 @@ impl ExtensionRegistryBuilder { Self::default() } + /// Creates an empty registry builder with a host-provided event sink. + pub fn with_event_sink(event_sink: Arc) -> Self { + Self { + event_sink, + ..Self::default() + } + } + + /// Returns the host event sink to pass into extension constructors. + pub fn event_sink(&self) -> Arc { + Arc::clone(&self.event_sink) + } + /// Registers one approval-review contributor. pub fn approval_review_contributor(&mut self, contributor: Arc) { self.approval_review_contributors.push(contributor); @@ -90,6 +107,7 @@ impl ExtensionRegistryBuilder { /// Finishes construction and returns the immutable registry. pub fn build(self) -> ExtensionRegistry { ExtensionRegistry { + event_sink: self.event_sink, thread_lifecycle_contributors: self.thread_lifecycle_contributors, turn_lifecycle_contributors: self.turn_lifecycle_contributors, config_contributors: self.config_contributors, @@ -104,6 +122,7 @@ impl ExtensionRegistryBuilder { /// Immutable typed registry produced after extensions are installed. pub struct ExtensionRegistry { + event_sink: Arc, thread_lifecycle_contributors: Vec>>, turn_lifecycle_contributors: Vec>, config_contributors: Vec>>, @@ -115,6 +134,11 @@ pub struct ExtensionRegistry { } impl ExtensionRegistry { + /// Returns the host event sink retained by this registry. + pub fn event_sink(&self) -> Arc { + Arc::clone(&self.event_sink) + } + /// Returns the registered thread-lifecycle contributors. pub fn thread_lifecycle_contributors(&self) -> &[Arc>] { &self.thread_lifecycle_contributors