1use std::collections::HashMap;
2use std::sync::Arc;
3
4use async_trait::async_trait;
5use serde_json::{Value, json};
6use tokio::sync::mpsc;
7
8use crate::engine::SessionStore;
9use crate::llm::StreamClient;
10use crate::types::{AgentError, AgentResult, SessionId, UserEvent};
11
12pub mod auto_continue;
13pub mod policy;
14pub mod subagent;
15pub mod update_plan;
16
17pub use auto_continue::AutoContinueTool;
18pub use subagent::{SubAgentSessionPolicy, SubAgentTool};
19pub use update_plan::UpdatePlanTool;
20
21pub use policy::ToolPolicy;
22
23#[derive(Clone, Debug, Default)]
24pub struct ToolOutput {
25 pub summary: String,
26 pub raw: Option<Value>,
27 pub control_flow: ToolControlFlow,
28 pub truncation: Option<TruncationInfo>,
29}
30
31#[derive(Clone, Debug)]
32pub struct TruncationInfo {
33 pub original_summary_len: usize,
34 pub original_raw_len: Option<usize>,
35 pub max_allowed_chars: usize,
36}
37
38#[derive(Clone, Debug, Default)]
39pub enum ToolControlFlow {
40 #[default]
41 Break,
42 Continue,
43}
44
45#[derive(Clone)]
46pub struct ToolContext {
47 pub session_id: SessionId,
48 pub user_event_tx: mpsc::UnboundedSender<UserEvent>,
51 pub llm_client: Option<Arc<dyn StreamClient>>,
52 pub session_store: Option<Arc<dyn SessionStore>>,
53 pub language: crate::types::Language,
56 pub cancel_token: tokio_util::sync::CancellationToken,
58}
59
60impl ToolContext {
61 pub fn emit_user_event(&self, event: UserEvent) {
63 let _ = self.user_event_tx.send(event);
64 }
65
66 pub fn emit_progress(&self, text: impl Into<String>) {
68 self.emit_user_event(UserEvent::Progress { text: text.into() });
69 }
70
71 pub fn emit_partial_result(
74 &self,
75 tool_call_id: &str,
76 content: impl Into<String>,
77 is_partial: bool,
78 ) {
79 self.emit_user_event(UserEvent::ToolPartialResult {
80 tool_call_id: tool_call_id.to_string(),
81 content: content.into(),
82 is_partial,
83 });
84 }
85}
86
87#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
91pub struct ToolMetadata {
92 pub name: String,
94 pub description: String,
96 pub origin: String,
100 pub version: String,
102 pub requirements: Vec<String>,
106}
107
108#[async_trait]
109pub trait Tool: Send + Sync {
110 fn name(&self) -> &'static str;
111 fn definition(&self) -> Value;
112 async fn call(&self, args: &Value, ctx: &ToolContext) -> AgentResult<ToolOutput>;
113
114 #[allow(private_interfaces)]
118 fn as_framework_tool(&self) -> Option<&dyn FrameworkTool> {
119 None
120 }
121
122 fn metadata(&self) -> ToolMetadata {
129 let name = self.name().to_string();
130 let description = self
131 .definition()
132 .get("function")
133 .and_then(|f| f.get("description"))
134 .and_then(|d| d.as_str())
135 .unwrap_or("")
136 .to_string();
137 ToolMetadata {
138 name,
139 description,
140 origin: "custom".to_string(),
141 version: "unknown".to_string(),
142 requirements: vec![],
143 }
144 }
145}
146
147pub(crate) trait FrameworkTool: Tool {
155 fn set_event_bus(&self, _event_bus: crate::engine::EventBus) {}
157}
158
159#[async_trait]
160pub trait TypedTool: Send + Sync {
161 type Args: serde::de::DeserializeOwned;
162 type Output: serde::Serialize;
163
164 fn name(&self) -> &'static str;
165 fn description(&self) -> &'static str;
166 fn parameters_schema(&self) -> Value;
167 async fn call_typed(&self, args: Self::Args, ctx: &ToolContext) -> AgentResult<Self::Output>;
168
169 fn control_flow() -> ToolControlFlow
170 where
171 Self: Sized,
172 {
173 ToolControlFlow::Break
174 }
175
176 fn format_output(&self, output: Self::Output) -> String {
177 serde_json::to_string(&output).unwrap_or_default()
178 }
179}
180
181#[async_trait]
182impl<T: TypedTool + Send + Sync + 'static> Tool for T {
183 fn name(&self) -> &'static str {
184 TypedTool::name(self)
185 }
186
187 fn definition(&self) -> Value {
188 json!({
189 "type": "function",
190 "function": {
191 "name": self.name(),
192 "description": self.description(),
193 "parameters": self.parameters_schema(),
194 }
195 })
196 }
197
198 async fn call(&self, args: &Value, ctx: &ToolContext) -> AgentResult<ToolOutput> {
199 let typed_args: T::Args =
200 serde_json::from_value(args.clone()).map_err(|_| AgentError::ToolArgsInvalid {
201 name: self.name().to_string(),
202 raw: args.to_string(),
203 })?;
204 let output = self.call_typed(typed_args, ctx).await?;
205 let output_json = serde_json::to_value(&output).ok();
206 let summary = self.format_output(output);
207 Ok(ToolOutput {
208 summary,
209 raw: output_json,
210 control_flow: T::control_flow(),
211 truncation: None,
212 })
213 }
214}
215
216pub(crate) type ToolRef = Arc<dyn Tool>;
217
218#[derive(Clone, Default)]
219pub struct ToolRegistry {
220 tools: HashMap<String, ToolRef>,
221}
222
223impl ToolRegistry {
224 pub fn register(&mut self, tool: impl Tool + 'static) {
225 self.tools.insert(tool.name().to_string(), Arc::new(tool));
226 }
227
228 pub fn register_arc(&mut self, tool: Arc<dyn Tool>) {
229 self.tools.insert(tool.name().to_string(), tool);
230 }
231
232 pub fn update(&mut self, tool: impl Tool + 'static) {
233 self.tools.insert(tool.name().to_string(), Arc::new(tool));
234 }
235
236 pub fn remove(&mut self, name: &str) {
238 self.tools.remove(name);
239 }
240
241 pub fn get(&self, name: &str) -> Option<ToolRef> {
242 self.tools.get(name).cloned()
243 }
244
245 pub fn definitions(&self) -> Vec<Value> {
246 self.tools.values().map(|tool| tool.definition()).collect()
247 }
248
249 pub fn len(&self) -> usize {
250 self.tools.len()
251 }
252
253 pub fn is_empty(&self) -> bool {
254 self.tools.is_empty()
255 }
256
257 pub fn metadatas(&self) -> Vec<ToolMetadata> {
263 let mut list: Vec<_> = self.tools.values().map(|tool| tool.metadata()).collect();
264 list.sort_by(|a, b| a.name.cmp(&b.name));
265 list
266 }
267
268 pub(crate) fn inject_event_bus(&self, event_bus: &crate::engine::EventBus) {
270 for tool in self.tools.values() {
271 if let Some(fw) = tool.as_framework_tool() {
272 fw.set_event_bus(event_bus.clone());
273 }
274 }
275 }
276}