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 {
79 Self {
80 name: name.into(),
81 description: None,
82 parameters: None,
83 strict: None,
84 }
85 }
86
87 pub fn with_description(mut self, description: impl Into<String>) -> Self {
88 self.description = Some(description.into());
89 self
90 }
91
92 pub fn with_parameters(mut self, parameters: serde_json::Value) -> Self {
93 self.parameters = Some(parameters);
94 self
95 }
96}
97
98pub use lc_shared::tools::{FunctionCall, ToolCall, ToolCallResult};
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use serde_json::json;
105
106 #[test]
107 fn test_tool_definition() {
108 let tool = ToolDefinition::new("calculator", "Calculate mathematical expressions")
109 .with_parameters(json!({
110 "type": "object",
111 "properties": {
112 "expression": {
113 "type": "string",
114 "description": "Mathematical expression to calculate"
115 }
116 },
117 "required": ["expression"]
118 }));
119
120 assert_eq!(tool.tool_type, "function");
121 assert_eq!(tool.function.name, "calculator");
122 assert!(tool.function.parameters.is_some());
123 }
124}
125
126#[cfg(test)]
127mod tool_call_tests {
128 use super::*;
129 use serde_json::json;
130 use std::collections::HashMap;
131
132 #[test]
133 fn test_tool_call() {
134 let call = ToolCall::new(
135 "call_123",
136 "calculator",
137 json!({"expression": "2 + 3"}).to_string(),
138 );
139
140 assert_eq!(call.id, "call_123");
141 assert_eq!(call.name(), "calculator");
142
143 let args: HashMap<String, String> = call.parse_arguments().unwrap();
144 assert_eq!(args.get("expression").unwrap(), "2 + 3");
145 }
146
147 #[test]
148 fn test_tool_call_result() {
149 let result = ToolCallResult::new("call_123", "5");
150
151 assert_eq!(result.tool_call_id, "call_123");
152 assert_eq!(result.role, "tool");
153 assert_eq!(result.content, "5");
154 }
155}