claude_agent/types/tool/
output.rs

1//! Tool execution input and output types.
2
3use serde::{Deserialize, Serialize};
4
5use super::error::ToolError;
6use crate::types::response::Usage;
7
8#[derive(Debug, Clone)]
9pub struct ToolInput {
10    pub id: String,
11    pub name: String,
12    pub input: serde_json::Value,
13}
14
15#[derive(Debug, Clone)]
16pub enum ToolOutput {
17    Success(String),
18    SuccessBlocks(Vec<ToolOutputBlock>),
19    Error(ToolError),
20    Empty,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(tag = "type", rename_all = "snake_case")]
25pub enum ToolOutputBlock {
26    Text {
27        text: String,
28    },
29    Image {
30        data: String,
31        media_type: String,
32    },
33    #[serde(rename = "search_result")]
34    SearchResult(crate::types::search::SearchResultBlock),
35}
36
37impl ToolOutput {
38    pub fn success(content: impl Into<String>) -> Self {
39        Self::Success(content.into())
40    }
41
42    pub fn error(message: impl Into<String>) -> Self {
43        Self::Error(ToolError::execution_failed(message))
44    }
45
46    pub fn tool_error(error: ToolError) -> Self {
47        Self::Error(error)
48    }
49
50    pub fn permission_denied(tool: impl Into<String>, permission: impl Into<String>) -> Self {
51        Self::Error(ToolError::permission_denied(tool, permission))
52    }
53
54    pub fn not_found(path: impl Into<String>) -> Self {
55        Self::Error(ToolError::not_found(path))
56    }
57
58    pub fn invalid_input(message: impl Into<String>) -> Self {
59        Self::Error(ToolError::invalid_input(message))
60    }
61
62    pub fn timeout(timeout_ms: u64) -> Self {
63        Self::Error(ToolError::timeout(timeout_ms))
64    }
65
66    pub fn security_error(message: impl Into<String>) -> Self {
67        Self::Error(ToolError::security_violation(message))
68    }
69
70    pub fn empty() -> Self {
71        Self::Empty
72    }
73
74    pub fn search_results(results: Vec<crate::types::search::SearchResultBlock>) -> Self {
75        Self::SuccessBlocks(
76            results
77                .into_iter()
78                .map(ToolOutputBlock::SearchResult)
79                .collect(),
80        )
81    }
82
83    pub fn is_error(&self) -> bool {
84        matches!(self, Self::Error(_))
85    }
86
87    pub fn as_error(&self) -> Option<&ToolError> {
88        match self {
89            Self::Error(e) => Some(e),
90            _ => None,
91        }
92    }
93
94    pub fn error_message(&self) -> String {
95        match self {
96            Self::Error(e) => e.to_string(),
97            _ => String::new(),
98        }
99    }
100
101    pub fn text(&self) -> String {
102        match self {
103            Self::Success(content) => content.clone(),
104            Self::SuccessBlocks(blocks) => blocks
105                .iter()
106                .filter_map(|b| match b {
107                    ToolOutputBlock::Text { text } => Some(text.as_str()),
108                    _ => None,
109                })
110                .collect::<Vec<_>>()
111                .join("\n"),
112            Self::Error(e) => e.to_string(),
113            Self::Empty => String::new(),
114        }
115    }
116}
117
118impl From<String> for ToolOutput {
119    fn from(s: String) -> Self {
120        Self::Success(s)
121    }
122}
123
124impl From<&str> for ToolOutput {
125    fn from(s: &str) -> Self {
126        Self::Success(s.to_string())
127    }
128}
129
130impl<T, E> From<Result<T, E>> for ToolOutput
131where
132    T: Into<String>,
133    E: std::fmt::Display,
134{
135    fn from(result: Result<T, E>) -> Self {
136        match result {
137            Ok(content) => Self::Success(content.into()),
138            Err(e) => Self::error(e.to_string()),
139        }
140    }
141}
142
143impl From<ToolError> for ToolOutput {
144    fn from(error: ToolError) -> Self {
145        Self::Error(error)
146    }
147}
148
149#[derive(Debug, Clone)]
150pub struct ToolResult {
151    pub output: ToolOutput,
152    pub inner_usage: Option<Usage>,
153    pub inner_model: Option<String>,
154}
155
156impl ToolResult {
157    pub fn success(content: impl Into<String>) -> Self {
158        Self {
159            output: ToolOutput::success(content),
160            inner_usage: None,
161            inner_model: None,
162        }
163    }
164
165    pub fn error(message: impl Into<String>) -> Self {
166        Self {
167            output: ToolOutput::error(message),
168            inner_usage: None,
169            inner_model: None,
170        }
171    }
172
173    pub fn empty() -> Self {
174        Self {
175            output: ToolOutput::Empty,
176            inner_usage: None,
177            inner_model: None,
178        }
179    }
180
181    pub fn with_usage(mut self, usage: Usage) -> Self {
182        self.inner_usage = Some(usage);
183        self
184    }
185
186    pub fn with_model(mut self, model: impl Into<String>) -> Self {
187        self.inner_model = Some(model.into());
188        self
189    }
190
191    pub fn with_inner_call(mut self, usage: Usage, model: impl Into<String>) -> Self {
192        self.inner_usage = Some(usage);
193        self.inner_model = Some(model.into());
194        self
195    }
196
197    pub fn is_error(&self) -> bool {
198        self.output.is_error()
199    }
200
201    pub fn text(&self) -> String {
202        self.output.text()
203    }
204
205    pub fn error_message(&self) -> String {
206        self.output.error_message()
207    }
208
209    pub fn as_error(&self) -> Option<&ToolError> {
210        self.output.as_error()
211    }
212}
213
214impl From<ToolOutput> for ToolResult {
215    fn from(output: ToolOutput) -> Self {
216        Self {
217            output,
218            inner_usage: None,
219            inner_model: None,
220        }
221    }
222}
223
224impl From<String> for ToolResult {
225    fn from(s: String) -> Self {
226        Self::success(s)
227    }
228}
229
230impl From<&str> for ToolResult {
231    fn from(s: &str) -> Self {
232        Self::success(s)
233    }
234}
235
236#[cfg(test)]
237mod tests {
238    use super::*;
239
240    #[test]
241    fn test_tool_output_from_result() {
242        let ok: Result<&str, &str> = Ok("success");
243        let output: ToolOutput = ok.into();
244        assert!(!output.is_error());
245
246        let err: Result<&str, &str> = Err("failed");
247        let output: ToolOutput = err.into();
248        assert!(output.is_error());
249    }
250}