claude_agent/types/tool/
output.rs1use 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}