distri_types/tool.rs
1use anyhow::Result;
2use std::{collections::HashMap, sync::Arc};
3use tokio::sync::mpsc;
4
5use crate::Part;
6use crate::{
7 ToolCall, ToolDefinition, auth::AuthMetadata, events::AgentEvent, stores::SessionStore,
8};
9
10/// Tool execution context - lighter weight than ExecutorContext
11#[derive(Debug, Clone)]
12pub struct ToolContext {
13 /// Agent ID executing the tool
14 pub agent_id: String,
15 /// Session ID for the current conversation
16 pub session_id: String,
17 /// Task ID for the current task
18 pub task_id: String,
19 /// Run ID for the current execution
20 pub run_id: String,
21 /// Thread ID for conversation grouping
22 pub thread_id: String,
23 /// User ID if available
24 pub user_id: String,
25 /// Session store for persistent state across tool calls
26 pub session_store: Arc<dyn SessionStore>,
27 /// Event sender for emitting events during tool execution
28 pub event_tx: Option<Arc<mpsc::Sender<AgentEvent>>>,
29
30 /// Additional metadata for the tool. Useful in direct inline agent invocation.
31 pub metadata: Option<HashMap<String, serde_json::Value>>,
32}
33
34/// Tool trait for implementing tools that can be called by agents
35#[async_trait::async_trait]
36pub trait Tool: Send + Sync + std::fmt::Debug + std::any::Any {
37 fn get_name(&self) -> String;
38
39 /// Get the tool definition for the LLM
40 fn get_tool_definition(&self) -> ToolDefinition {
41 ToolDefinition {
42 name: self.get_name(),
43 description: self.get_description(),
44 parameters: self.get_parameters(),
45 output_schema: None,
46 examples: self.get_tool_examples(),
47 prompt: self.prompt(),
48 }
49 }
50
51 fn get_parameters(&self) -> serde_json::Value;
52 fn get_description(&self) -> String;
53
54 fn get_tool_examples(&self) -> Option<String> {
55 None
56 }
57
58 /// Optional detailed prompt/instructions for this tool.
59 /// When provided, these instructions are injected into the system prompt
60 /// so the LLM knows HOW to use the tool (not just what parameters it takes).
61 /// This mirrors claude-code's per-tool `prompt()` pattern.
62 fn prompt(&self) -> Option<String> {
63 None
64 }
65
66 /// Check if this tool is external (handled by frontend)
67 fn is_external(&self) -> bool {
68 false // Default to false for built-in tools
69 }
70
71 /// Check if this tool is an MCP tool
72 fn is_mcp(&self) -> bool {
73 false // Default to false for built-in tools
74 }
75
76 fn is_sync(&self) -> bool {
77 false // Default to false for built-in tools
78 }
79
80 fn is_final(&self) -> bool {
81 false // Default to false for built-in tools
82 }
83
84 /// Whether this tool is safe to execute concurrently with other tool
85 /// calls emitted in the same LLM turn.
86 ///
87 /// When the model returns several tool calls at once they are grouped into
88 /// a single execution step and run in parallel. Tools that mutate shared
89 /// state (write a file, save content, edit a document) should override this
90 /// to `false` so the batch is serialized and writes cannot race. Read-only
91 /// tools (search, fetch, list) can keep the default and run in parallel.
92 fn concurrency_safe(&self) -> bool {
93 true // Default: most tools are read-only / independent
94 }
95
96 /// Check if this tool needs ExecutorContext instead of ToolContext
97 fn needs_executor_context(&self) -> bool {
98 false // Default to false - most tools use ToolContext
99 }
100
101 /// Get authentication metadata for this tool
102 fn get_auth_metadata(&self) -> Option<Box<dyn AuthMetadata>> {
103 None // Default to no authentication required
104 }
105
106 /// Get the plugin name this tool belongs to (nullable)
107 /// If this returns Some, the tool is part of a plugin
108 /// If None, the tool is standalone
109 fn get_plugin_name(&self) -> Option<String> {
110 None // Default to standalone tool
111 }
112
113 /// Execute the tool with given arguments, returning content parts
114 async fn execute(
115 &self,
116 tool_call: ToolCall,
117 context: Arc<ToolContext>,
118 ) -> Result<Vec<Part>, anyhow::Error>;
119
120 /// Synchronous execution of the tool, returning content parts (default unsupported)
121 fn execute_sync(
122 &self,
123 _tool_call: ToolCall,
124 _context: Arc<ToolContext>,
125 ) -> Result<Vec<Part>, anyhow::Error> {
126 Err(anyhow::anyhow!("Sync execution not supported"))
127 }
128}