1#![allow(unused)]
8
9use crate::extensions::types::{
10 AgentEvent, AgentToolResult, BashEvent, BeforeProviderRequestEvent, Command, ContextEmitResult,
11 ContextEvent, ExtensionError, ExtensionErrorListener, ExtensionErrorRecord, ExtensionManifest,
12 ExtensionState, InputEvent, InputEventResult, ModelSelectEvent, ProviderRequestEmitResult,
13 SessionBeforeCompactEvent, SessionBeforeEmitResult, SessionBeforeForkEvent,
14 SessionBeforeSwitchEvent, SessionBeforeTreeEvent, SessionCompactEvent, SessionShutdownEvent,
15 SessionTreeEvent, ThinkingLevelSelectEvent, ToolCallEmitResult, ToolResultEmitResult,
16};
17
18use crate::CompactionContext;
19use crate::extensions::Extension;
20use crate::extensions::context::ExtensionContext;
21use crate::store::settings::Settings;
22
23use parking_lot::RwLock;
24use serde_json::Value;
25use std::collections::HashMap;
26use std::fmt;
27use std::future::Future;
28use std::path::PathBuf;
29use std::pin::Pin;
30use std::sync::Arc;
31
32type ToolType = dyn oxi_agent::AgentTool;
33type ToolArc = Arc<ToolType>;
34
35struct LoadedExtension {
40 extension: Arc<dyn Extension>,
41 enabled: bool,
42}
43
44pub struct ExtensionRegistry {
46 entries: HashMap<String, LoadedExtension>,
47 errors: Arc<RwLock<Vec<ExtensionErrorRecord>>>,
48}
49
50impl Default for ExtensionRegistry {
51 fn default() -> Self {
52 Self::new()
53 }
54}
55
56impl ExtensionRegistry {
57 pub fn new() -> Self {
59 Self {
60 entries: HashMap::new(),
61 errors: Arc::new(RwLock::new(Vec::new())),
62 }
63 }
64
65 pub fn register(&mut self, ext: Arc<dyn Extension>) {
67 let name = ext.name().to_string();
68 tracing::info!(name = %name, "extension registered");
69 self.entries.insert(
70 name,
71 LoadedExtension {
72 extension: ext,
73 enabled: true,
74 },
75 );
76 }
77
78 pub fn unregister(&mut self, name: &str) -> bool {
80 if let Some(entry) = self.entries.remove(name) {
81 self.call_hook_safe(name, "on_unload", || {
82 entry.extension.on_unload();
83 });
84 tracing::info!(name = %name, "extension unregistered");
85 true
86 } else {
87 false
88 }
89 }
90
91 pub fn disable(&mut self, name: &str) -> Result<(), ExtensionError> {
93 let ext = {
94 let entry = self
95 .entries
96 .get_mut(name)
97 .ok_or_else(|| ExtensionError::NotFound {
98 name: name.to_string(),
99 })?;
100 if !entry.enabled {
101 return Ok(());
102 }
103 entry.enabled = false;
104 Arc::clone(&entry.extension)
105 };
106 self.call_hook_safe(name, "on_unload", || {
107 ext.on_unload();
108 });
109 tracing::info!(name = %name, "extension disabled");
110 Ok(())
111 }
112
113 pub fn enable(&mut self, name: &str, ctx: &ExtensionContext) -> Result<(), ExtensionError> {
115 let ext = {
116 let entry = self
117 .entries
118 .get_mut(name)
119 .ok_or_else(|| ExtensionError::NotFound {
120 name: name.to_string(),
121 })?;
122 if entry.enabled {
123 return Ok(());
124 }
125 entry.enabled = true;
126 Arc::clone(&entry.extension)
127 };
128 self.call_hook_safe(name, "on_load", || {
129 ext.on_load(ctx);
130 });
131 tracing::info!(name = %name, "extension enabled");
132 Ok(())
133 }
134
135 pub fn is_enabled(&self, name: &str) -> bool {
137 self.entries.get(name).map(|e| e.enabled).unwrap_or(false)
138 }
139
140 pub fn all_tools(&self) -> Vec<ToolArc> {
142 self.entries
143 .values()
144 .filter(|e| e.enabled)
145 .flat_map(|e| e.extension.register_tools())
146 .collect()
147 }
148
149 pub fn all_commands(&self) -> Vec<Command> {
151 self.entries
152 .values()
153 .filter(|e| e.enabled)
154 .flat_map(|e| e.extension.register_commands())
155 .collect()
156 }
157
158 pub fn emit_load(&self, ctx: &ExtensionContext) {
160 for entry in self.entries.values().filter(|e| e.enabled) {
161 let name = entry.extension.name();
162 self.call_hook_safe(name, "on_load", || {
163 entry.extension.on_load(ctx);
164 });
165 }
166 }
167
168 pub fn emit_unload(&self) {
170 for entry in self.entries.values().filter(|e| e.enabled) {
171 let name = entry.extension.name();
172 self.call_hook_safe(name, "on_unload", || {
173 entry.extension.on_unload();
174 });
175 }
176 }
177
178 pub fn emit_message_sent(&self, msg: &str) {
180 for entry in self.entries.values().filter(|e| e.enabled) {
181 let name = entry.extension.name();
182 self.call_hook_safe(name, "on_message_sent", || {
183 entry.extension.on_message_sent(msg);
184 });
185 }
186 }
187
188 pub fn emit_message_received(&self, msg: &str) {
190 for entry in self.entries.values().filter(|e| e.enabled) {
191 let name = entry.extension.name();
192 self.call_hook_safe(name, "on_message_received", || {
193 entry.extension.on_message_received(msg);
194 });
195 }
196 }
197
198 pub fn emit_tool_call(&self, tool: &str, params: &Value) {
200 for entry in self.entries.values().filter(|e| e.enabled) {
201 let name = entry.extension.name();
202 self.call_hook_safe(name, "on_tool_call", || {
203 entry.extension.on_tool_call(tool, params);
204 });
205 }
206 }
207
208 pub fn emit_tool_result(&self, tool: &str, result: &AgentToolResult) {
210 for entry in self.entries.values().filter(|e| e.enabled) {
211 let name = entry.extension.name();
212 self.call_hook_safe(name, "on_tool_result", || {
213 entry.extension.on_tool_result(tool, result);
214 });
215 }
216 }
217
218 pub fn emit_session_start(&self, session_id: &str) {
220 for entry in self.entries.values().filter(|e| e.enabled) {
221 let name = entry.extension.name();
222 self.call_hook_safe(name, "on_session_start", || {
223 entry.extension.on_session_start(session_id);
224 });
225 }
226 }
227
228 pub fn emit_session_end(&self, session_id: &str) {
230 for entry in self.entries.values().filter(|e| e.enabled) {
231 let name = entry.extension.name();
232 self.call_hook_safe(name, "on_session_end", || {
233 entry.extension.on_session_end(session_id);
234 });
235 }
236 }
237
238 pub fn emit_settings_changed(&self, settings: &Settings) {
240 for entry in self.entries.values().filter(|e| e.enabled) {
241 let name = entry.extension.name();
242 self.call_hook_safe(name, "on_settings_changed", || {
243 entry.extension.on_settings_changed(settings);
244 });
245 }
246 }
247
248 pub fn emit_event(&self, event: &AgentEvent) {
250 for entry in self.entries.values().filter(|e| e.enabled) {
251 let name = entry.extension.name();
252 self.call_hook_safe(name, "on_event", || {
253 entry.extension.on_event(event);
254 });
255 }
256 }
257
258 pub fn emit_error(&self, error: &anyhow::Error) -> Vec<(String, anyhow::Error)> {
260 let mut errors = Vec::new();
261 for entry in self.entries.values().filter(|e| e.enabled) {
262 let name = entry.extension.name();
263 if let Err(e) = entry.extension.on_error(error) {
264 tracing::warn!(extension = name, error = %e, "on_error hook failed");
265 errors.push((name.to_string(), e));
266 }
267 }
268 errors
269 }
270
271 pub fn emit_session_shutdown(&self, event: &SessionShutdownEvent) {
273 for entry in self.entries.values().filter(|e| e.enabled) {
274 let name = entry.extension.name();
275 self.call_hook_safe(name, "session_shutdown", || {
276 entry.extension.session_shutdown(event);
277 });
278 }
279 }
280
281 pub fn get(&self, name: &str) -> Option<Arc<dyn Extension>> {
283 self.entries.get(name).map(|e| Arc::clone(&e.extension))
284 }
285
286 pub fn names(&self) -> impl Iterator<Item = &str> {
288 self.entries.keys().map(|s| s.as_str())
289 }
290
291 pub fn extensions(&self) -> impl Iterator<Item = &Arc<dyn Extension>> {
293 self.entries.values().map(|e| &e.extension)
294 }
295
296 pub fn manifest(&self, name: &str) -> Option<ExtensionManifest> {
298 self.entries.get(name).map(|e| e.extension.manifest())
299 }
300
301 pub fn len(&self) -> usize {
303 self.entries.len()
304 }
305 pub fn is_empty(&self) -> bool {
307 self.entries.is_empty()
308 }
309 pub fn errors(&self) -> Vec<ExtensionErrorRecord> {
311 self.errors.read().clone()
312 }
313 pub fn clear_errors(&self) {
315 self.errors.write().clear();
316 }
317
318 fn call_hook_safe<F>(&self, ext_name: &str, hook: &str, f: F)
319 where
320 F: FnOnce(),
321 {
322 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
323 if let Err(payload) = result {
324 let msg = if let Some(s) = payload.downcast_ref::<&str>() {
325 s.to_string()
326 } else if let Some(s) = payload.downcast_ref::<String>() {
327 s.clone()
328 } else {
329 "unknown panic".to_string()
330 };
331 tracing::error!(extension = ext_name, hook = hook, error = %msg, "Extension hook panicked");
332 self.errors.write().push(ExtensionErrorRecord::new(
333 ext_name,
334 hook,
335 format!("panic: {}", msg),
336 ));
337 }
338 }
339}
340
341impl fmt::Debug for ExtensionRegistry {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 f.debug_struct("ExtensionRegistry")
344 .field("count", &self.entries.len())
345 .finish()
346 }
347}
348
349pub struct ExtensionRunner {
355 registry: ExtensionRegistry,
356 states: HashMap<String, ExtensionState>,
357 order: Vec<String>,
358 error_listeners: Vec<Arc<ExtensionErrorListener>>,
359 cwd: PathBuf,
360}
361
362impl Default for ExtensionRunner {
363 fn default() -> Self {
364 Self::new(PathBuf::from("."))
365 }
366}
367
368impl ExtensionRunner {
369 pub fn new(cwd: PathBuf) -> Self {
371 Self {
372 registry: ExtensionRegistry::new(),
373 states: HashMap::new(),
374 order: Vec::new(),
375 error_listeners: Vec::new(),
376 cwd,
377 }
378 }
379
380 pub fn on_error<F>(&mut self, listener: F) -> ExtensionErrorHandle
382 where
383 F: Fn(&ExtensionErrorRecord) + Send + Sync + 'static,
384 {
385 let arc: Arc<ExtensionErrorListener> = Arc::new(listener);
386 self.error_listeners.push(Arc::clone(&arc));
387 ExtensionErrorHandle {
388 listener: Some(arc),
389 }
390 }
391
392 pub fn emit_error_record(&self, record: ExtensionErrorRecord) {
394 for listener in &self.error_listeners {
395 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
396 listener(&record);
397 }));
398 }
399 self.registry.errors.write().push(record);
400 }
401
402 pub fn register(&mut self, ext: Arc<dyn Extension>, ctx: &ExtensionContext) {
404 let name = ext.name().to_string();
405 self.registry.register(ext);
406 self.set_state(&name, ExtensionState::Active);
407 self.registry.call_hook_safe(&name, "on_load", || {
408 if let Some(e) = self.registry.get(&name) {
409 e.on_load(ctx);
410 }
411 });
412 }
413
414 pub fn unload_extension(&mut self, name: &str) -> bool {
416 let had = self.registry.unregister(name);
417 if had {
418 self.set_state(name, ExtensionState::Unloaded);
419 tracing::info!(name = %name, "extension unloaded");
420 }
421 had
422 }
423
424 fn set_state(&mut self, name: &str, state: ExtensionState) {
425 self.states.insert(name.to_string(), state);
426 if state == ExtensionState::Active && !self.order.contains(&name.to_string()) {
427 self.order.push(name.to_string());
428 }
429 if state == ExtensionState::Unloaded {
430 self.order.retain(|n| n != name);
431 }
432 }
433
434 pub fn state(&self, name: &str) -> ExtensionState {
436 self.states
437 .get(name)
438 .copied()
439 .unwrap_or(ExtensionState::Unloaded)
440 }
441 pub fn states(&self) -> &HashMap<String, ExtensionState> {
443 &self.states
444 }
445 pub fn extension_order(&self) -> &[String] {
447 &self.order
448 }
449
450 pub fn disable(&mut self, name: &str) -> Result<(), ExtensionError> {
452 self.registry.disable(name)?;
453 self.set_state(name, ExtensionState::Disabled);
454 Ok(())
455 }
456 pub fn enable(&mut self, name: &str, ctx: &ExtensionContext) -> Result<(), ExtensionError> {
458 self.registry.enable(name, ctx)?;
459 self.set_state(name, ExtensionState::Active);
460 Ok(())
461 }
462 pub fn is_enabled(&self, name: &str) -> bool {
464 self.registry.is_enabled(name)
465 }
466
467 pub fn has_handlers(&self, _event_type: &str) -> bool {
469 self.has_enabled_extensions()
470 }
471 pub fn has_enabled_extensions(&self) -> bool {
473 self.registry.extensions().any(|_| true)
474 && self
475 .order
476 .iter()
477 .any(|name| self.state(name) == ExtensionState::Active)
478 }
479
480 pub fn all_tools(&self) -> Vec<ToolArc> {
482 let mut tools = Vec::new();
483 for name in &self.order {
484 if self.state(name) != ExtensionState::Active {
485 continue;
486 }
487 if let Some(ext) = self.registry.get(name) {
488 tools.extend(ext.register_tools());
489 }
490 }
491 tools
492 }
493
494 pub fn all_commands(&self) -> Vec<Command> {
496 let mut commands = Vec::new();
497 for name in &self.order {
498 if self.state(name) != ExtensionState::Active {
499 continue;
500 }
501 if let Some(ext) = self.registry.get(name) {
502 commands.extend(ext.register_commands());
503 }
504 }
505 commands
506 }
507
508 pub fn wrap_tool(&self, tool: ToolArc) -> ToolArc {
510 Arc::new(WrappedTool {
511 inner: tool,
512 runner_state: Arc::new(RwLock::new(RunnerState {
513 errors: self.registry.errors.clone(),
514 error_listeners: self.error_listeners.clone(),
515 })),
516 })
517 }
518
519 pub fn wrap_tools(&self, tools: Vec<ToolArc>) -> Vec<ToolArc> {
521 tools.into_iter().map(|t| self.wrap_tool(t)).collect()
522 }
523
524 pub fn emit_tool_call(&self, tool_name: &str, params: &Value) -> ToolCallEmitResult {
526 let mut result = ToolCallEmitResult::default();
527 for name in &self.order {
528 if self.state(name) != ExtensionState::Active {
529 continue;
530 }
531 if let Some(ext) = self.registry.get(name) {
532 if let Err(e) = ext.on_before_tool_call(tool_name, params) {
533 let err_str = e.to_string();
534 result.errors.push((name.clone(), err_str.clone()));
535 self.emit_error_record(ExtensionErrorRecord::new(
536 name,
537 "on_before_tool_call",
538 &err_str,
539 ));
540 }
541 self.registry.call_hook_safe(name, "on_tool_call", || {
542 ext.on_tool_call(tool_name, params);
543 });
544 }
545 }
546 result
547 }
548
549 pub fn emit_tool_result_event(
551 &self,
552 tool_name: &str,
553 tool_result: &AgentToolResult,
554 ) -> ToolResultEmitResult {
555 let mut result = ToolResultEmitResult::default();
556 for name in &self.order {
557 if self.state(name) != ExtensionState::Active {
558 continue;
559 }
560 if let Some(ext) = self.registry.get(name) {
561 if let Err(e) = ext.on_after_tool_call(tool_name, tool_result) {
562 result.errors.push((name.clone(), e.to_string()));
563 }
564 self.registry.call_hook_safe(name, "on_tool_result", || {
565 ext.on_tool_result(tool_name, tool_result);
566 });
567 }
568 }
569 result
570 }
571
572 pub fn emit_input_event(&self, event: &mut InputEvent) -> InputEventResult {
574 let mut final_result = InputEventResult::Continue;
575 for name in &self.order {
576 if self.state(name) != ExtensionState::Active {
577 continue;
578 }
579 if let Some(ext) = self.registry.get(name) {
580 let result =
581 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| ext.input(event)));
582 match result {
583 Ok(InputEventResult::Handled) => return InputEventResult::Handled,
584 Ok(InputEventResult::Transform { text }) => {
585 event.text = text.clone();
586 final_result = InputEventResult::Transform { text };
587 }
588 Ok(InputEventResult::Continue) => {}
589 Err(payload) => {
590 let msg = if let Some(s) = payload.downcast_ref::<&str>() {
591 s.to_string()
592 } else if let Some(s) = payload.downcast_ref::<String>() {
593 s.clone()
594 } else {
595 "unknown panic".to_string()
596 };
597 self.emit_error_record(ExtensionErrorRecord::new(
598 name,
599 "input",
600 format!("panic: {}", msg),
601 ));
602 }
603 }
604 }
605 }
606 final_result
607 }
608
609 pub fn emit_context_event(&self, messages: Vec<oxi_sdk::Message>) -> ContextEmitResult {
611 let mut current_messages = messages;
612 let mut errors = Vec::new();
613 let mut modified = false;
614 for name in &self.order {
615 if self.state(name) != ExtensionState::Active {
616 continue;
617 }
618 if let Some(ext) = self.registry.get(name) {
619 let prev_len = current_messages.len();
620 let mut event = ContextEvent {
621 messages: current_messages.clone(),
622 };
623 if let Err(e) = ext.context(&mut event) {
624 errors.push((name.clone(), e.to_string()));
625 } else if event.messages.len() != prev_len {
626 current_messages = event.messages;
627 modified = true;
628 }
629 }
630 }
631 ContextEmitResult {
632 modified,
633 messages: current_messages,
634 errors,
635 }
636 }
637
638 pub fn emit_before_provider_request_event(&self, payload: Value) -> ProviderRequestEmitResult {
640 let mut current_payload = payload;
641 let mut modified = false;
642 let mut errors = Vec::new();
643 for name in &self.order {
644 if self.state(name) != ExtensionState::Active {
645 continue;
646 }
647 if let Some(ext) = self.registry.get(name) {
648 let mut event = BeforeProviderRequestEvent {
649 payload: current_payload.clone(),
650 };
651 if let Err(e) = ext.before_provider_request(&mut event) {
652 errors.push((name.clone(), e.to_string()));
653 } else if event.payload != current_payload {
654 current_payload = event.payload;
655 modified = true;
656 }
657 }
658 }
659 ProviderRequestEmitResult {
660 modified,
661 payload: current_payload,
662 errors,
663 }
664 }
665
666 pub fn emit_session_before_switch_event(
668 &self,
669 event: &SessionBeforeSwitchEvent,
670 ) -> SessionBeforeEmitResult {
671 let mut result = SessionBeforeEmitResult::default();
672 for name in &self.order {
673 if self.state(name) != ExtensionState::Active {
674 continue;
675 }
676 if let Some(ext) = self.registry.get(name)
677 && let Err(e) = ext.session_before_switch(event)
678 {
679 result.cancelled = true;
680 result.cancelled_by = Some(name.clone());
681 result.errors.push((name.clone(), e.to_string()));
682 return result;
683 }
684 }
685 result
686 }
687
688 pub fn emit_session_before_fork_event(
690 &self,
691 event: &SessionBeforeForkEvent,
692 ) -> SessionBeforeEmitResult {
693 let mut result = SessionBeforeEmitResult::default();
694 for name in &self.order {
695 if self.state(name) != ExtensionState::Active {
696 continue;
697 }
698 if let Some(ext) = self.registry.get(name)
699 && let Err(e) = ext.session_before_fork(event)
700 {
701 result.cancelled = true;
702 result.cancelled_by = Some(name.clone());
703 result.errors.push((name.clone(), e.to_string()));
704 return result;
705 }
706 }
707 result
708 }
709
710 pub fn emit_session_before_compact_event(
712 &self,
713 event: &SessionBeforeCompactEvent,
714 ) -> SessionBeforeEmitResult {
715 let mut result = SessionBeforeEmitResult::default();
716 for name in &self.order {
717 if self.state(name) != ExtensionState::Active {
718 continue;
719 }
720 if let Some(ext) = self.registry.get(name)
721 && let Err(e) = ext.session_before_compact(event)
722 {
723 result.cancelled = true;
724 result.cancelled_by = Some(name.clone());
725 result.errors.push((name.clone(), e.to_string()));
726 return result;
727 }
728 }
729 result
730 }
731
732 pub fn emit_session_before_tree_event(
734 &self,
735 event: &SessionBeforeTreeEvent,
736 ) -> SessionBeforeEmitResult {
737 let mut result = SessionBeforeEmitResult::default();
738 for name in &self.order {
739 if self.state(name) != ExtensionState::Active {
740 continue;
741 }
742 if let Some(ext) = self.registry.get(name)
743 && let Err(e) = ext.session_before_tree(event)
744 {
745 result.cancelled = true;
746 result.cancelled_by = Some(name.clone());
747 result.errors.push((name.clone(), e.to_string()));
748 return result;
749 }
750 }
751 result
752 }
753
754 pub fn emit_session_shutdown_event(&self, event: &SessionShutdownEvent) -> bool {
756 if !self.has_enabled_extensions() {
757 return false;
758 }
759 self.registry.emit_session_shutdown(event);
760 true
761 }
762
763 pub fn emit_event(&self, event: &AgentEvent) {
765 self.registry.emit_event(event);
766 }
767
768 pub fn registry(&self) -> &ExtensionRegistry {
770 &self.registry
771 }
772 pub fn registry_mut(&mut self) -> &mut ExtensionRegistry {
774 &mut self.registry
775 }
776 pub fn get(&self, name: &str) -> Option<Arc<dyn Extension>> {
778 self.registry.get(name)
779 }
780 pub fn names(&self) -> impl Iterator<Item = &str> {
782 self.order.iter().map(|s| s.as_str())
783 }
784 pub fn len(&self) -> usize {
786 self.order.len()
787 }
788 pub fn is_empty(&self) -> bool {
790 self.order.is_empty()
791 }
792 pub fn errors(&self) -> Vec<ExtensionErrorRecord> {
794 self.registry.errors()
795 }
796 pub fn clear_errors(&self) {
798 self.registry.clear_errors();
799 }
800}
801
802impl fmt::Debug for ExtensionRunner {
803 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
804 f.debug_struct("ExtensionRunner")
805 .field("cwd", &self.cwd)
806 .field("extensions", &self.order)
807 .finish()
808 }
809}
810
811pub struct ExtensionErrorHandle {
813 listener: Option<Arc<ExtensionErrorListener>>,
814}
815impl ExtensionErrorHandle {
816 pub fn unregister(&mut self) -> Option<Arc<ExtensionErrorListener>> {
818 self.listener.take()
819 }
820}
821impl Drop for ExtensionErrorHandle {
822 fn drop(&mut self) {}
823}
824
825struct RunnerState {
826 errors: Arc<RwLock<Vec<ExtensionErrorRecord>>>,
827 error_listeners: Vec<Arc<ExtensionErrorListener>>,
828}
829struct WrappedTool {
830 inner: ToolArc,
831 runner_state: Arc<RwLock<RunnerState>>,
832}
833
834impl oxi_agent::AgentTool for WrappedTool {
835 fn name(&self) -> &str {
836 self.inner.name()
837 }
838 fn label(&self) -> &str {
839 self.inner.label()
840 }
841 fn description(&self) -> &str {
842 self.inner.description()
843 }
844 fn parameters_schema(&self) -> Value {
845 self.inner.parameters_schema()
846 }
847 fn execute<'a>(
848 &'a self,
849 tool_call_id: &'a str,
850 params: Value,
851 signal: Option<tokio::sync::oneshot::Receiver<()>>,
852 ctx: &'a oxi_agent::ToolContext,
853 ) -> Pin<Box<dyn Future<Output = Result<AgentToolResult, oxi_agent::ToolError>> + Send + 'a>>
854 {
855 Box::pin(async move { self.inner.execute(tool_call_id, params, signal, ctx).await })
856 }
857}