llm_coding_tools_core/
output.rs

1//! Common output types for tool responses.
2
3use crate::operations::WebFetchOutput;
4use serde::Serialize;
5
6/// Wrapper for tool output with truncation metadata.
7#[derive(Debug, Clone, Serialize)]
8pub struct ToolOutput {
9    /// The main content returned by the tool.
10    pub content: String,
11    /// Whether the output was truncated due to size limits.
12    #[serde(skip_serializing_if = "std::ops::Not::not")]
13    pub truncated: bool,
14}
15
16impl ToolOutput {
17    /// Creates a new output with the given content.
18    #[inline]
19    pub fn new(content: impl Into<String>) -> Self {
20        Self {
21            content: content.into(),
22            truncated: false,
23        }
24    }
25
26    /// Creates a truncated output.
27    #[inline]
28    pub fn truncated(content: impl Into<String>) -> Self {
29        Self {
30            content: content.into(),
31            truncated: true,
32        }
33    }
34}
35
36impl From<String> for ToolOutput {
37    fn from(content: String) -> Self {
38        Self::new(content)
39    }
40}
41
42impl From<&str> for ToolOutput {
43    fn from(content: &str) -> Self {
44        Self::new(content)
45    }
46}
47
48impl From<WebFetchOutput> for ToolOutput {
49    fn from(output: WebFetchOutput) -> Self {
50        Self::new(format!(
51            "[{} - {} bytes]\n\n{}",
52            output.content_type, output.byte_length, output.content
53        ))
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn tool_output_new_creates_non_truncated() {
63        let output = ToolOutput::new("content");
64        assert_eq!(output.content, "content");
65        assert!(!output.truncated);
66    }
67
68    #[test]
69    fn tool_output_truncated_marks_truncated() {
70        let output = ToolOutput::truncated("partial");
71        assert!(output.truncated);
72    }
73
74    #[test]
75    fn tool_output_from_string() {
76        let output: ToolOutput = "hello".into();
77        assert_eq!(output.content, "hello");
78    }
79
80    #[test]
81    fn tool_output_serializes_without_truncated_when_false() {
82        let output = ToolOutput::new("content");
83        let json = serde_json::to_string(&output).unwrap();
84        assert!(!json.contains("truncated"));
85    }
86
87    #[test]
88    fn tool_output_serializes_with_truncated_when_true() {
89        let output = ToolOutput::truncated("content");
90        let json = serde_json::to_string(&output).unwrap();
91        assert!(json.contains("truncated"));
92    }
93
94    #[test]
95    fn tool_output_from_webfetch_output() {
96        let webfetch = WebFetchOutput {
97            content: "Hello, world!".to_string(),
98            content_type: "text/plain".to_string(),
99            byte_length: 13,
100        };
101        let output: ToolOutput = webfetch.into();
102        assert_eq!(output.content, "[text/plain - 13 bytes]\n\nHello, world!");
103        assert!(!output.truncated);
104    }
105}