lc_core/tools/
tool_definition.rs1use schemars::{schema_for, JsonSchema};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ToolDefinition {
13 #[serde(rename = "type")]
15 pub tool_type: String,
16
17 pub function: FunctionDefinition,
19}
20
21impl ToolDefinition {
22 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
24 Self {
25 tool_type: "function".to_string(),
26 function: FunctionDefinition {
27 name: name.into(),
28 description: Some(description.into()),
29 parameters: None,
30 strict: None,
31 },
32 }
33 }
34
35 pub fn with_parameters(mut self, parameters: serde_json::Value) -> Self {
37 self.function.parameters = Some(parameters);
38 self
39 }
40
41 pub fn from_type<T: JsonSchema>(
43 name: impl Into<String>,
44 description: impl Into<String>,
45 ) -> Self {
46 let schema = schema_for!(T);
47 let parameters = serde_json::to_value(schema).unwrap_or(serde_json::Value::Null);
48 Self::new(name, description).with_parameters(parameters)
49 }
50
51 pub fn with_strict(mut self, strict: bool) -> Self {
53 self.function.strict = Some(strict);
54 self
55 }
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct FunctionDefinition {
61 pub name: String,
63
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub description: Option<String>,
67
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub parameters: Option<serde_json::Value>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub strict: Option<bool>,
75}
76
77impl FunctionDefinition {
78 pub fn new(name: impl Into<String>) -> Self {
80 Self {
81 name: name.into(),
82 description: None,
83 parameters: None,
84 strict: None,
85 }
86 }
87
88 pub fn with_description(mut self, description: impl Into<String>) -> Self {
90 self.description = Some(description.into());
91 self
92 }
93
94 pub fn with_parameters(mut self, parameters: serde_json::Value) -> Self {
96 self.parameters = Some(parameters);
97 self
98 }
99}
100
101pub use lc_shared::tools::{FunctionCall, ToolCall, ToolCallBuilder, ToolCallResult};
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use serde_json::json;
108
109 #[test]
110 fn test_tool_definition() {
111 let tool = ToolDefinition::new("calculator", "Calculate mathematical expressions")
112 .with_parameters(json!({
113 "type": "object",
114 "properties": {
115 "expression": {
116 "type": "string",
117 "description": "Mathematical expression to calculate"
118 }
119 },
120 "required": ["expression"]
121 }));
122
123 assert_eq!(tool.tool_type, "function");
124 assert_eq!(tool.function.name, "calculator");
125 assert!(tool.function.parameters.is_some());
126 }
127}
128
129#[cfg(test)]
130mod tool_call_tests {
131 use super::*;
132 use serde_json::json;
133 use std::collections::HashMap;
134
135 #[test]
136 fn test_tool_call() {
137 let call = ToolCall::builder("call_123")
138 .name("calculator")
139 .arguments(json!({"expression": "2 + 3"}).to_string())
140 .build();
141
142 assert_eq!(call.id, "call_123");
143 assert_eq!(call.name(), "calculator");
144
145 let args: HashMap<String, String> = call.parse_arguments().unwrap();
146 assert_eq!(args.get("expression").unwrap(), "2 + 3");
147 }
148
149 #[test]
150 fn test_tool_call_result() {
151 let result = ToolCallResult::new("call_123", "5");
152
153 assert_eq!(result.tool_call_id, "call_123");
154 assert_eq!(result.role, "tool");
155 assert_eq!(result.content, "5");
156 }
157}