Skip to main content

kiss_agent/
tool.rs

1//! The tool contract used by the agent runtime.
2
3use 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    /// Text or image content returned to the model.
18    pub content: Vec<ContentBlock>,
19    /// Structured details for logs / UI rendering (never sent to the model).
20    pub details: Value,
21    /// A tool can report a failure while retaining structured details and images.
22    pub is_error: bool,
23    /// Usage from nested LLM work performed by the tool, if any.
24    pub usage: Option<Usage>,
25    /// Hint that the agent should stop after the current tool batch.
26    pub terminate: bool,
27}
28
29impl ToolResult {
30    pub fn text(text: impl Into<String>) -> Self {
31        ToolResult {
32            content: vec![ContentBlock::text(text)],
33            ..Default::default()
34        }
35    }
36
37    pub fn output_text(&self) -> String {
38        self.content
39            .iter()
40            .filter_map(|c| match c {
41                ContentBlock::Text { text, .. } => Some(text.as_str()),
42                _ => None,
43            })
44            .collect::<Vec<_>>()
45            .join("\n")
46    }
47}
48
49/// Sink for streaming partial tool results (e.g. live bash output).
50pub type ToolUpdateSink = Arc<dyn Fn(ToolResult) + Send + Sync>;
51
52#[async_trait::async_trait]
53pub trait AgentTool: Send + Sync {
54    fn name(&self) -> &str;
55    fn label(&self) -> &str {
56        self.name()
57    }
58    fn description(&self) -> String;
59    /// JSON schema object describing the arguments.
60    fn parameters(&self) -> Value;
61    fn execution_mode(&self) -> ExecutionMode {
62        ExecutionMode::Parallel
63    }
64    /// Normalize raw arguments before schema validation (compat shims).
65    fn prepare_arguments(&self, args: Value) -> Value {
66        args
67    }
68    /// Execute. Return Err on failure. The loop converts it into an error
69    /// tool result visible to the model.
70    async fn execute(
71        &self,
72        tool_call_id: &str,
73        args: Value,
74        cancel: CancellationToken,
75        on_update: Option<ToolUpdateSink>,
76    ) -> anyhow::Result<ToolResult>;
77
78    fn to_def(&self) -> ToolDef {
79        ToolDef {
80            name: self.name().to_string(),
81            description: self.description(),
82            parameters: self.parameters(),
83        }
84    }
85}
86
87pub type DynTool = Arc<dyn AgentTool>;