1#[doc(hidden)]
12pub use llm_tool::__private;
13pub use llm_tool::{
14 EmptyParams, Json, JsonSchema, RustTool, ToolContext, ToolDefinition, ToolError, ToolOutput,
15 ToolRegistry, definition_of,
16};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
22#[serde(rename_all = "snake_case")]
23pub enum ToolSource {
24 Builtin,
27 Custom,
29 Mcp,
31}
32
33impl std::fmt::Display for ToolSource {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 Self::Builtin => f.write_str("builtin"),
37 Self::Custom => f.write_str("custom"),
38 Self::Mcp => f.write_str("mcp"),
39 }
40 }
41}
42
43#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
49pub struct AvailableTool {
50 pub name: String,
52 pub description: String,
54 pub parameter_schema: serde_json::Value,
56 pub source: ToolSource,
58}
59
60impl std::fmt::Display for AvailableTool {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 write!(f, "{} [{}]", self.name, self.source)
63 }
64}
65
66#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
75 fn tool_source_display() {
76 assert_eq!(ToolSource::Builtin.to_string(), "builtin");
77 assert_eq!(ToolSource::Custom.to_string(), "custom");
78 assert_eq!(ToolSource::Mcp.to_string(), "mcp");
79 }
80
81 #[test]
82 fn tool_source_serde_roundtrip() {
83 for source in [ToolSource::Builtin, ToolSource::Custom, ToolSource::Mcp] {
84 let json = serde_json::to_string(&source).unwrap();
85 let parsed: ToolSource = serde_json::from_str(&json).unwrap();
86 assert_eq!(parsed, source);
87 }
88 }
89
90 #[test]
91 fn tool_source_serializes_as_snake_case() {
92 assert_eq!(
93 serde_json::to_string(&ToolSource::Builtin).unwrap(),
94 "\"builtin\""
95 );
96 assert_eq!(
97 serde_json::to_string(&ToolSource::Custom).unwrap(),
98 "\"custom\""
99 );
100 assert_eq!(serde_json::to_string(&ToolSource::Mcp).unwrap(), "\"mcp\"");
101 }
102
103 #[test]
106 fn available_tool_display() {
107 let tool = AvailableTool {
108 name: "get_weather".to_owned(),
109 description: "Gets weather.".to_owned(),
110 parameter_schema: serde_json::Value::Null,
111 source: ToolSource::Mcp,
112 };
113 assert_eq!(tool.to_string(), "get_weather [mcp]");
114 }
115
116 #[test]
117 fn available_tool_serde_roundtrip() {
118 let tool = AvailableTool {
119 name: "view_file".to_owned(),
120 description: "Read file contents.".to_owned(),
121 parameter_schema: serde_json::json!({"type": "object"}),
122 source: ToolSource::Builtin,
123 };
124 let json = serde_json::to_string(&tool).unwrap();
125 let parsed: AvailableTool = serde_json::from_str(&json).unwrap();
126 assert_eq!(parsed.name, "view_file");
127 assert_eq!(parsed.source, ToolSource::Builtin);
128 assert!(!parsed.description.is_empty());
129 }
130}