1use kiss_ai::{ContentBlock, ToolDef, Usage};
4use serde_json::Value;
5use std::sync::Arc;
6use tokio_util::sync::CancellationToken;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9pub enum ExecutionMode {
10 Sequential,
11 #[default]
12 Parallel,
13}
14
15#[derive(Debug, Clone, Default)]
16pub struct ToolResult {
17 pub content: Vec<ContentBlock>,
19 pub details: Value,
21 pub usage: Option<Usage>,
23 pub terminate: bool,
25}
26
27impl ToolResult {
28 pub fn text(text: impl Into<String>) -> Self {
29 ToolResult {
30 content: vec![ContentBlock::text(text)],
31 ..Default::default()
32 }
33 }
34
35 pub fn output_text(&self) -> String {
36 self.content
37 .iter()
38 .filter_map(|c| match c {
39 ContentBlock::Text { text, .. } => Some(text.as_str()),
40 _ => None,
41 })
42 .collect::<Vec<_>>()
43 .join("\n")
44 }
45}
46
47pub type ToolUpdateSink = Arc<dyn Fn(ToolResult) + Send + Sync>;
49
50#[async_trait::async_trait]
51pub trait AgentTool: Send + Sync {
52 fn name(&self) -> &str;
53 fn label(&self) -> &str {
54 self.name()
55 }
56 fn description(&self) -> String;
57 fn parameters(&self) -> Value;
59 fn execution_mode(&self) -> ExecutionMode {
60 ExecutionMode::Parallel
61 }
62 fn prepare_arguments(&self, args: Value) -> Value {
64 args
65 }
66 async fn execute(
69 &self,
70 tool_call_id: &str,
71 args: Value,
72 cancel: CancellationToken,
73 on_update: Option<ToolUpdateSink>,
74 ) -> anyhow::Result<ToolResult>;
75
76 fn to_def(&self) -> ToolDef {
77 ToolDef {
78 name: self.name().to_string(),
79 description: self.description(),
80 parameters: self.parameters(),
81 }
82 }
83}
84
85pub type DynTool = Arc<dyn AgentTool>;