use async_trait::async_trait;
use serde_json::Value;
use crate::error::Result;
#[async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn parameters(&self) -> Value;
async fn execute(&self, args: Value, ctx: &ToolContext) -> Result<String>;
}
#[derive(Debug, Clone, Default)]
pub struct ToolContext {
pub channel: Option<String>,
pub chat_id: Option<String>,
pub workspace: Option<String>,
}
impl ToolContext {
pub fn new() -> Self {
Self::default()
}
pub fn with_channel(mut self, channel: &str, chat_id: &str) -> Self {
self.channel = Some(channel.to_string());
self.chat_id = Some(chat_id.to_string());
self
}
pub fn with_workspace(mut self, workspace: &str) -> Self {
self.workspace = Some(workspace.to_string());
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tool_context_new() {
let ctx = ToolContext::new();
assert!(ctx.channel.is_none());
assert!(ctx.chat_id.is_none());
assert!(ctx.workspace.is_none());
}
#[test]
fn test_tool_context_default() {
let ctx = ToolContext::default();
assert!(ctx.channel.is_none());
assert!(ctx.chat_id.is_none());
assert!(ctx.workspace.is_none());
}
#[test]
fn test_tool_context_with_channel() {
let ctx = ToolContext::new().with_channel("telegram", "123456");
assert_eq!(ctx.channel.as_deref(), Some("telegram"));
assert_eq!(ctx.chat_id.as_deref(), Some("123456"));
assert!(ctx.workspace.is_none());
}
#[test]
fn test_tool_context_with_workspace() {
let ctx = ToolContext::new().with_workspace("/home/user/project");
assert!(ctx.channel.is_none());
assert!(ctx.chat_id.is_none());
assert_eq!(ctx.workspace.as_deref(), Some("/home/user/project"));
}
#[test]
fn test_tool_context_builder_chain() {
let ctx = ToolContext::new()
.with_channel("discord", "abc123")
.with_workspace("/tmp/workspace");
assert_eq!(ctx.channel.as_deref(), Some("discord"));
assert_eq!(ctx.chat_id.as_deref(), Some("abc123"));
assert_eq!(ctx.workspace.as_deref(), Some("/tmp/workspace"));
}
#[test]
fn test_tool_context_debug() {
let ctx = ToolContext::new().with_channel("cli", "test");
let debug_str = format!("{:?}", ctx);
assert!(debug_str.contains("ToolContext"));
assert!(debug_str.contains("cli"));
}
#[test]
fn test_tool_context_clone() {
let ctx1 = ToolContext::new()
.with_channel("telegram", "123")
.with_workspace("/test");
let ctx2 = ctx1.clone();
assert_eq!(ctx1.channel, ctx2.channel);
assert_eq!(ctx1.chat_id, ctx2.chat_id);
assert_eq!(ctx1.workspace, ctx2.workspace);
}
}