codex_extension_api/
registry.rs1use std::sync::Arc;
2
3use codex_protocol::protocol::ReviewDecision;
4
5use crate::ApprovalReviewContributor;
6use crate::ConfigContributor;
7use crate::ContextContributor;
8use crate::ExtensionData;
9use crate::ExtensionEventSink;
10use crate::McpServerContributor;
11use crate::NoopExtensionEventSink;
12use crate::SkillInvocationContributor;
13use crate::ThreadLifecycleContributor;
14use crate::TokenUsageContributor;
15use crate::ToolContributor;
16use crate::ToolLifecycleContributor;
17use crate::TurnInputContributor;
18use crate::TurnItemContributor;
19use crate::TurnLifecycleContributor;
20
21pub struct ExtensionRegistryBuilder<C: Sync> {
23 event_sink: Arc<dyn ExtensionEventSink>,
24 thread_lifecycle_contributors: Vec<Arc<dyn ThreadLifecycleContributor<C>>>,
25 turn_lifecycle_contributors: Vec<Arc<dyn TurnLifecycleContributor>>,
26 config_contributors: Vec<Arc<dyn ConfigContributor<C>>>,
27 token_usage_contributors: Vec<Arc<dyn TokenUsageContributor>>,
28 skill_invocation_contributors: Vec<Arc<dyn SkillInvocationContributor>>,
29 context_contributors: Vec<Arc<dyn ContextContributor>>,
30 mcp_server_contributors: Vec<Arc<dyn McpServerContributor<C>>>,
31 turn_input_contributors: Vec<Arc<dyn TurnInputContributor>>,
32 tool_contributors: Vec<Arc<dyn ToolContributor>>,
33 tool_lifecycle_contributors: Vec<Arc<dyn ToolLifecycleContributor>>,
34 turn_item_contributors: Vec<Arc<dyn TurnItemContributor>>,
35 approval_review_contributors: Vec<Arc<dyn ApprovalReviewContributor>>,
36}
37
38impl<C: Sync> Default for ExtensionRegistryBuilder<C> {
39 fn default() -> Self {
40 Self {
41 event_sink: Arc::new(NoopExtensionEventSink),
42 thread_lifecycle_contributors: Vec::new(),
43 turn_lifecycle_contributors: Vec::new(),
44 config_contributors: Vec::new(),
45 token_usage_contributors: Vec::new(),
46 skill_invocation_contributors: Vec::new(),
47 approval_review_contributors: Vec::new(),
48 context_contributors: Vec::new(),
49 mcp_server_contributors: Vec::new(),
50 turn_input_contributors: Vec::new(),
51 tool_contributors: Vec::new(),
52 tool_lifecycle_contributors: Vec::new(),
53 turn_item_contributors: Vec::new(),
54 }
55 }
56}
57
58impl<C: Sync> ExtensionRegistryBuilder<C> {
59 pub fn new() -> Self {
61 Self::default()
62 }
63
64 pub fn with_event_sink(event_sink: Arc<dyn ExtensionEventSink>) -> Self {
66 Self {
67 event_sink,
68 ..Self::default()
69 }
70 }
71
72 pub fn event_sink(&self) -> Arc<dyn ExtensionEventSink> {
74 Arc::clone(&self.event_sink)
75 }
76
77 pub fn approval_review_contributor(&mut self, contributor: Arc<dyn ApprovalReviewContributor>) {
79 self.approval_review_contributors.push(contributor);
80 }
81
82 pub fn thread_lifecycle_contributor(
84 &mut self,
85 contributor: Arc<dyn ThreadLifecycleContributor<C>>,
86 ) {
87 self.thread_lifecycle_contributors.push(contributor);
88 }
89
90 pub fn turn_lifecycle_contributor(&mut self, contributor: Arc<dyn TurnLifecycleContributor>) {
92 self.turn_lifecycle_contributors.push(contributor);
93 }
94
95 pub fn config_contributor(&mut self, contributor: Arc<dyn ConfigContributor<C>>) {
97 self.config_contributors.push(contributor);
98 }
99
100 pub fn token_usage_contributor(&mut self, contributor: Arc<dyn TokenUsageContributor>) {
102 self.token_usage_contributors.push(contributor);
103 }
104
105 pub fn skill_invocation_contributor(
107 &mut self,
108 contributor: Arc<dyn SkillInvocationContributor>,
109 ) {
110 self.skill_invocation_contributors.push(contributor);
111 }
112
113 pub fn prompt_contributor(&mut self, contributor: Arc<dyn ContextContributor>) {
115 self.context_contributors.push(contributor);
116 }
117
118 pub fn mcp_server_contributor(&mut self, contributor: Arc<dyn McpServerContributor<C>>) {
120 self.mcp_server_contributors.push(contributor);
121 }
122
123 pub fn turn_input_contributor(&mut self, contributor: Arc<dyn TurnInputContributor>) {
125 self.turn_input_contributors.push(contributor);
126 }
127
128 pub fn tool_contributor(&mut self, contributor: Arc<dyn ToolContributor>) {
130 self.tool_contributors.push(contributor);
131 }
132
133 pub fn tool_lifecycle_contributor(&mut self, contributor: Arc<dyn ToolLifecycleContributor>) {
135 self.tool_lifecycle_contributors.push(contributor);
136 }
137
138 pub fn turn_item_contributor(&mut self, contributor: Arc<dyn TurnItemContributor>) {
140 self.turn_item_contributors.push(contributor);
141 }
142
143 pub fn build(self) -> ExtensionRegistry<C> {
145 ExtensionRegistry {
146 event_sink: self.event_sink,
147 thread_lifecycle_contributors: self.thread_lifecycle_contributors,
148 turn_lifecycle_contributors: self.turn_lifecycle_contributors,
149 config_contributors: self.config_contributors,
150 token_usage_contributors: self.token_usage_contributors,
151 skill_invocation_contributors: self.skill_invocation_contributors,
152 approval_review_contributors: self.approval_review_contributors,
153 context_contributors: self.context_contributors,
154 mcp_server_contributors: self.mcp_server_contributors,
155 turn_input_contributors: self.turn_input_contributors,
156 tool_contributors: self.tool_contributors,
157 tool_lifecycle_contributors: self.tool_lifecycle_contributors,
158 turn_item_contributors: self.turn_item_contributors,
159 }
160 }
161}
162
163pub struct ExtensionRegistry<C: Sync> {
165 event_sink: Arc<dyn ExtensionEventSink>,
166 thread_lifecycle_contributors: Vec<Arc<dyn ThreadLifecycleContributor<C>>>,
167 turn_lifecycle_contributors: Vec<Arc<dyn TurnLifecycleContributor>>,
168 config_contributors: Vec<Arc<dyn ConfigContributor<C>>>,
169 token_usage_contributors: Vec<Arc<dyn TokenUsageContributor>>,
170 skill_invocation_contributors: Vec<Arc<dyn SkillInvocationContributor>>,
171 context_contributors: Vec<Arc<dyn ContextContributor>>,
172 mcp_server_contributors: Vec<Arc<dyn McpServerContributor<C>>>,
173 turn_input_contributors: Vec<Arc<dyn TurnInputContributor>>,
174 tool_contributors: Vec<Arc<dyn ToolContributor>>,
175 tool_lifecycle_contributors: Vec<Arc<dyn ToolLifecycleContributor>>,
176 turn_item_contributors: Vec<Arc<dyn TurnItemContributor>>,
177 approval_review_contributors: Vec<Arc<dyn ApprovalReviewContributor>>,
178}
179
180impl<C: Sync> ExtensionRegistry<C> {
181 pub fn event_sink(&self) -> Arc<dyn ExtensionEventSink> {
183 Arc::clone(&self.event_sink)
184 }
185
186 pub fn thread_lifecycle_contributors(&self) -> &[Arc<dyn ThreadLifecycleContributor<C>>] {
188 &self.thread_lifecycle_contributors
189 }
190
191 pub fn turn_lifecycle_contributors(&self) -> &[Arc<dyn TurnLifecycleContributor>] {
193 &self.turn_lifecycle_contributors
194 }
195
196 pub fn config_contributors(&self) -> &[Arc<dyn ConfigContributor<C>>] {
198 &self.config_contributors
199 }
200
201 pub fn token_usage_contributors(&self) -> &[Arc<dyn TokenUsageContributor>] {
203 &self.token_usage_contributors
204 }
205
206 pub fn skill_invocation_contributors(&self) -> &[Arc<dyn SkillInvocationContributor>] {
208 &self.skill_invocation_contributors
209 }
210
211 pub async fn approval_review(
214 &self,
215 session_store: &ExtensionData,
216 thread_store: &ExtensionData,
217 prompt: &str,
218 ) -> Option<ReviewDecision> {
219 for contributor in &self.approval_review_contributors {
220 if let Some(decision) = contributor
221 .contribute(session_store, thread_store, prompt)
222 .await
223 {
224 return Some(decision);
225 }
226 }
227
228 None
229 }
230
231 pub fn context_contributors(&self) -> &[Arc<dyn ContextContributor>] {
233 &self.context_contributors
234 }
235
236 pub fn mcp_server_contributors(&self) -> &[Arc<dyn McpServerContributor<C>>] {
238 &self.mcp_server_contributors
239 }
240
241 pub fn turn_input_contributors(&self) -> &[Arc<dyn TurnInputContributor>] {
243 &self.turn_input_contributors
244 }
245
246 pub fn tool_contributors(&self) -> &[Arc<dyn ToolContributor>] {
248 &self.tool_contributors
249 }
250
251 pub fn tool_lifecycle_contributors(&self) -> &[Arc<dyn ToolLifecycleContributor>] {
253 &self.tool_lifecycle_contributors
254 }
255
256 pub fn turn_item_contributors(&self) -> &[Arc<dyn TurnItemContributor>] {
258 &self.turn_item_contributors
259 }
260}
261
262pub fn empty_extension_registry<C: Sync>() -> Arc<ExtensionRegistry<C>> {
264 Arc::new(ExtensionRegistryBuilder::new().build())
265}