1use crate::{CallbackContext, EventActions, MemoryEntry, Result};
2use async_trait::async_trait;
3use serde_json::Value;
4use std::sync::Arc;
5
6#[async_trait]
7pub trait Tool: Send + Sync {
8 fn name(&self) -> &str;
9 fn description(&self) -> &str;
10
11 fn enhanced_description(&self) -> String {
16 self.description().to_string()
17 }
18
19 fn is_long_running(&self) -> bool {
23 false
24 }
25 fn parameters_schema(&self) -> Option<Value> {
26 None
27 }
28 fn response_schema(&self) -> Option<Value> {
29 None
30 }
31 async fn execute(&self, ctx: Arc<dyn ToolContext>, args: Value) -> Result<Value>;
32}
33
34#[async_trait]
35pub trait ToolContext: CallbackContext {
36 fn function_call_id(&self) -> &str;
37 fn actions(&self) -> &EventActions;
38 async fn search_memory(&self, query: &str) -> Result<Vec<MemoryEntry>>;
39}
40
41#[async_trait]
42pub trait Toolset: Send + Sync {
43 fn name(&self) -> &str;
44 async fn tools(&self, ctx: Arc<dyn crate::ReadonlyContext>) -> Result<Vec<Arc<dyn Tool>>>;
45}
46
47pub type ToolPredicate = Box<dyn Fn(&dyn Tool) -> bool + Send + Sync>;
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::{Content, EventActions, ReadonlyContext, RunConfig};
53
54 struct TestTool {
55 name: String,
56 }
57
58 #[allow(dead_code)]
59 struct TestContext {
60 content: Content,
61 config: RunConfig,
62 actions: EventActions,
63 }
64
65 impl TestContext {
66 fn new() -> Self {
67 Self {
68 content: Content::new("user"),
69 config: RunConfig::default(),
70 actions: EventActions::default(),
71 }
72 }
73 }
74
75 #[async_trait]
76 impl ReadonlyContext for TestContext {
77 fn invocation_id(&self) -> &str {
78 "test"
79 }
80 fn agent_name(&self) -> &str {
81 "test"
82 }
83 fn user_id(&self) -> &str {
84 "user"
85 }
86 fn app_name(&self) -> &str {
87 "app"
88 }
89 fn session_id(&self) -> &str {
90 "session"
91 }
92 fn branch(&self) -> &str {
93 ""
94 }
95 fn user_content(&self) -> &Content {
96 &self.content
97 }
98 }
99
100 #[async_trait]
101 impl CallbackContext for TestContext {
102 fn artifacts(&self) -> Option<Arc<dyn crate::Artifacts>> {
103 None
104 }
105 }
106
107 #[async_trait]
108 impl ToolContext for TestContext {
109 fn function_call_id(&self) -> &str {
110 "call-123"
111 }
112 fn actions(&self) -> &EventActions {
113 &self.actions
114 }
115 async fn search_memory(&self, _query: &str) -> Result<Vec<crate::MemoryEntry>> {
116 Ok(vec![])
117 }
118 }
119
120 #[async_trait]
121 impl Tool for TestTool {
122 fn name(&self) -> &str {
123 &self.name
124 }
125
126 fn description(&self) -> &str {
127 "test tool"
128 }
129
130 async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
131 Ok(Value::String("result".to_string()))
132 }
133 }
134
135 #[test]
136 fn test_tool_trait() {
137 let tool = TestTool { name: "test".to_string() };
138 assert_eq!(tool.name(), "test");
139 assert_eq!(tool.description(), "test tool");
140 assert!(!tool.is_long_running());
141 }
142
143 #[tokio::test]
144 async fn test_tool_execute() {
145 let tool = TestTool { name: "test".to_string() };
146 let ctx = Arc::new(TestContext::new()) as Arc<dyn ToolContext>;
147 let result = tool.execute(ctx, Value::Null).await.unwrap();
148 assert_eq!(result, Value::String("result".to_string()));
149 }
150}