1use std::sync::Arc;
7
8use async_trait::async_trait;
9use lspkit::EngineApi;
10use serde_json::Value;
11
12use crate::tools::{ToolDescription, ToolRegistry};
13
14#[non_exhaustive]
16#[derive(Debug, Clone)]
17pub struct ToolInvocation {
18 pub name: String,
20 pub output: Value,
22}
23
24#[non_exhaustive]
26#[derive(Debug, thiserror::Error)]
27pub enum AdapterError {
28 #[error("tool not found: {0}")]
30 UnknownTool(String),
31 #[error("invalid input for {tool}: {message}")]
33 InvalidInput {
34 tool: String,
36 message: String,
38 },
39 #[error("engine error: {0}")]
41 Engine(String),
42}
43
44#[async_trait]
46pub trait ToolHandler<E: EngineApi>: Send + Sync + 'static {
47 async fn invoke(&self, engine: &E, input: Value) -> Result<Value, AdapterError>;
49}
50
51#[derive(Clone)]
53pub struct Adapter<E: EngineApi> {
54 engine: Arc<E>,
55 registry: ToolRegistry,
56 handlers: Vec<(String, Arc<dyn ToolHandler<E>>)>,
57}
58
59impl<E: EngineApi> Adapter<E> {
60 #[must_use]
62 pub fn new(engine: Arc<E>) -> Self {
63 Self {
64 engine,
65 registry: ToolRegistry::new(),
66 handlers: Vec::new(),
67 }
68 }
69
70 pub fn register(&mut self, description: ToolDescription, handler: Arc<dyn ToolHandler<E>>) {
72 let name = description.name.clone();
73 self.registry.register(description);
74 if let Some(slot) = self.handlers.iter_mut().find(|(n, _)| n == &name) {
75 slot.1 = handler;
76 } else {
77 self.handlers.push((name, handler));
78 }
79 }
80
81 #[must_use]
83 pub fn tools(&self) -> &[ToolDescription] {
84 self.registry.list()
85 }
86
87 pub async fn invoke(&self, name: &str, input: Value) -> Result<ToolInvocation, AdapterError> {
93 let handler = self
94 .handlers
95 .iter()
96 .find(|(n, _)| n == name)
97 .map(|(_, h)| h.clone())
98 .ok_or_else(|| AdapterError::UnknownTool(name.to_owned()))?;
99 let output = handler.invoke(self.engine.as_ref(), input).await?;
100 Ok(ToolInvocation {
101 name: name.to_owned(),
102 output,
103 })
104 }
105}
106
107impl<E: EngineApi> std::fmt::Debug for Adapter<E> {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 f.debug_struct("Adapter")
110 .field("tools", &self.registry.list().len())
111 .finish_non_exhaustive()
112 }
113}