1mod default_tools;
2
3pub use default_tools::{register_default_tools, register_skill_tools, register_spawn_agent};
4
5use super::sandbox::Sandbox;
6use crate::messages::MessageChannel;
7use crate::shared::{ToolDefinition, UserInteraction};
8use crate::tasks::TaskManager;
9use schemars::{JsonSchema, schema_for};
10use serde::de::DeserializeOwned;
11use serde_json::Value;
12use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc};
13
14#[derive(Clone, Default)]
20pub struct ToolCtx {
21 pub messages: MessageChannel,
23 pub session_id: String,
25 pub tasks: TaskManager,
27}
28
29type BoxFuture = Pin<Box<dyn Future<Output = Result<ToolOutcome, String>> + Send>>;
30type BoxedCall = Arc<dyn Fn(Arc<dyn Sandbox>, Value, ToolCtx) -> BoxFuture + Send + Sync>;
31
32#[derive(Debug, Clone)]
33pub enum ToolOutcome {
34 Completed(Value),
35 NeedsUserInteraction(UserInteraction),
36}
37
38impl From<Value> for ToolOutcome {
39 fn from(value: Value) -> Self {
40 Self::Completed(value)
41 }
42}
43
44#[derive(Clone)]
45pub struct ToolEntry {
46 pub name: String,
47 pub description: String,
48 pub schema: Value,
49 pub read_only: bool,
52 call: BoxedCall,
53}
54
55#[derive(Clone)]
56pub struct ToolRegistry {
57 tools: HashMap<String, ToolEntry>,
58}
59
60impl ToolRegistry {
61 pub fn new() -> Self {
62 Self {
63 tools: HashMap::new(),
64 }
65 }
66
67 pub fn register<A, F, Fut>(
71 &mut self,
72 name: &str,
73 description: &str,
74 read_only: bool,
75 handler: F,
76 ) where
77 A: DeserializeOwned + JsonSchema + Send + 'static,
78 F: Fn(Arc<dyn Sandbox>, A) -> Fut + Send + Sync + 'static,
79 Fut: Future<Output = Result<ToolOutcome, String>> + Send + 'static,
80 {
81 let schema = serde_json::to_value(schema_for!(A)).unwrap();
82 let handler = Arc::new(handler);
83 let call: BoxedCall =
84 Arc::new(move |sandbox: Arc<dyn Sandbox>, v: Value, _ctx: ToolCtx| {
85 let handler = handler.clone();
86 Box::pin(async move {
87 let args: A =
88 serde_json::from_value(v).map_err(|e| format!("参数不合法: {e}"))?;
89 handler(sandbox, args).await
90 })
91 });
92 self.tools.insert(
93 name.into(),
94 ToolEntry {
95 name: name.into(),
96 description: description.into(),
97 schema,
98 read_only,
99 call,
100 },
101 );
102 }
103
104 pub fn register_with_ctx<A, F, Fut>(
108 &mut self,
109 name: &str,
110 description: &str,
111 read_only: bool,
112 handler: F,
113 ) where
114 A: DeserializeOwned + JsonSchema + Send + 'static,
115 F: Fn(Arc<dyn Sandbox>, A, ToolCtx) -> Fut + Send + Sync + 'static,
116 Fut: Future<Output = Result<ToolOutcome, String>> + Send + 'static,
117 {
118 let schema = serde_json::to_value(schema_for!(A)).unwrap();
119 let handler = Arc::new(handler);
120 let call: BoxedCall = Arc::new(move |sandbox: Arc<dyn Sandbox>, v: Value, ctx: ToolCtx| {
121 let handler = handler.clone();
122 Box::pin(async move {
123 let args: A = serde_json::from_value(v).map_err(|e| format!("参数不合法: {e}"))?;
124 handler(sandbox, args, ctx).await
125 })
126 });
127 self.tools.insert(
128 name.into(),
129 ToolEntry {
130 name: name.into(),
131 description: description.into(),
132 schema,
133 read_only,
134 call,
135 },
136 );
137 }
138
139 pub fn is_read_only(&self, name: &str) -> bool {
141 self.tools.get(name).is_some_and(|t| t.read_only)
142 }
143
144 pub async fn call(
146 &self,
147 name: &str,
148 args: Value,
149 sandbox: Arc<dyn Sandbox>,
150 ctx: ToolCtx,
151 ) -> Result<ToolOutcome, String> {
152 let tool = self
153 .tools
154 .get(name)
155 .ok_or_else(|| format!("工具不存在: {name}"))?;
156 (tool.call)(sandbox, args, ctx).await
157 }
158
159 pub fn definitions(&self) -> Vec<ToolDefinition> {
161 self.tools
162 .values()
163 .map(|t| ToolDefinition {
164 name: t.name.clone(),
165 desc: t.description.clone(),
166 arguments: t.schema.clone(),
167 })
168 .collect()
169 }
170}
171
172impl Default for ToolRegistry {
173 fn default() -> Self {
174 Self::new()
175 }
176}