1use serde::{Deserialize, Serialize};
4
5use super::feedback::ExecutionFeedback;
6use super::task::Task;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct ChatMessage {
11 pub role: String,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub content: Option<String>,
14 #[serde(skip_serializing_if = "Option::is_none")]
15 pub tool_calls: Option<Vec<ToolCall>>,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub tool_call_id: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub name: Option<String>,
20}
21
22impl ChatMessage {
23 pub fn system(content: &str) -> Self {
24 Self {
25 role: "system".to_string(),
26 content: Some(content.to_string()),
27 tool_calls: None,
28 tool_call_id: None,
29 name: None,
30 }
31 }
32
33 pub fn user(content: &str) -> Self {
34 Self {
35 role: "user".to_string(),
36 content: Some(content.to_string()),
37 tool_calls: None,
38 tool_call_id: None,
39 name: None,
40 }
41 }
42
43 pub fn assistant(content: &str) -> Self {
44 Self {
45 role: "assistant".to_string(),
46 content: Some(content.to_string()),
47 tool_calls: None,
48 tool_call_id: None,
49 name: None,
50 }
51 }
52
53 pub fn assistant_with_tool_calls(content: Option<&str>, tool_calls: Vec<ToolCall>) -> Self {
54 Self {
55 role: "assistant".to_string(),
56 content: content.map(|s| s.to_string()),
57 tool_calls: Some(tool_calls),
58 tool_call_id: None,
59 name: None,
60 }
61 }
62
63 pub fn tool_result(tool_call_id: &str, content: &str) -> Self {
64 Self {
65 role: "tool".to_string(),
66 content: Some(content.to_string()),
67 tool_calls: None,
68 tool_call_id: Some(tool_call_id.to_string()),
69 name: None,
70 }
71 }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct ToolCall {
77 pub id: String,
78 #[serde(rename = "type")]
79 pub call_type: String,
80 pub function: FunctionCall,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct FunctionCall {
86 pub name: String,
87 pub arguments: String,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq)]
93pub enum ToolFormat {
94 OpenAI,
96 Claude,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct ToolDefinition {
103 #[serde(rename = "type")]
104 pub tool_type: String,
105 pub function: FunctionDef,
106}
107
108impl ToolDefinition {
109 pub fn to_claude_format(&self) -> serde_json::Value {
112 serde_json::json!({
113 "name": self.function.name,
114 "description": self.function.description,
115 "input_schema": self.function.parameters
116 })
117 }
118
119 pub fn to_format(&self, format: &ToolFormat) -> serde_json::Value {
121 match format {
122 ToolFormat::OpenAI => serde_json::to_value(self).unwrap_or_default(),
123 ToolFormat::Claude => self.to_claude_format(),
124 }
125 }
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct FunctionDef {
131 pub name: String,
132 pub description: String,
133 pub parameters: serde_json::Value,
134}
135
136#[derive(Debug, Clone)]
138pub struct ToolResult {
139 pub tool_call_id: String,
140 pub tool_name: String,
141 pub content: String,
142 pub is_error: bool,
143 pub counts_as_failure: bool,
145}
146
147impl ToolResult {
148 pub fn to_claude_format(&self) -> serde_json::Value {
150 serde_json::json!({
151 "type": "tool_result",
152 "tool_use_id": self.tool_call_id,
153 "content": self.content,
154 "is_error": self.is_error
155 })
156 }
157
158 pub fn to_openai_format(&self) -> serde_json::Value {
160 serde_json::json!({
161 "role": "tool",
162 "tool_call_id": self.tool_call_id,
163 "content": self.content
164 })
165 }
166
167 pub fn to_format(&self, format: &ToolFormat) -> serde_json::Value {
169 match format {
170 ToolFormat::OpenAI => self.to_openai_format(),
171 ToolFormat::Claude => self.to_claude_format(),
172 }
173 }
174}
175
176pub fn parse_claude_tool_calls(content_blocks: &[serde_json::Value]) -> Vec<ToolCall> {
180 let mut calls = Vec::new();
181 for block in content_blocks {
182 if block.get("type").and_then(|v| v.as_str()) == Some("tool_use") {
183 let id = block
184 .get("id")
185 .and_then(|v| v.as_str())
186 .unwrap_or("")
187 .to_string();
188 let name = block
189 .get("name")
190 .and_then(|v| v.as_str())
191 .unwrap_or("")
192 .to_string();
193 let input = block.get("input").cloned().unwrap_or(serde_json::json!({}));
194 let arguments = serde_json::to_string(&input).unwrap_or_else(|_| "{}".to_string());
195
196 calls.push(ToolCall {
197 id,
198 call_type: "function".to_string(),
199 function: FunctionCall { name, arguments },
200 });
201 }
202 }
203 calls
204}
205
206#[derive(Debug)]
208pub struct AgentResult {
209 pub response: String,
210 #[allow(dead_code)]
211 pub messages: Vec<ChatMessage>,
212 #[allow(dead_code)]
213 pub tool_calls_count: usize,
214 #[allow(dead_code)]
215 pub iterations: usize,
216 pub task_plan: Vec<Task>,
218 pub feedback: ExecutionFeedback,
220}
221
222impl AgentResult {
223 pub fn to_node_result(
226 &self,
227 task_id: impl Into<String>,
228 ) -> skilllite_core::protocol::NodeResult {
229 skilllite_core::protocol::NodeResult {
230 task_id: task_id.into(),
231 response: self.response.clone(),
232 task_completed: self.feedback.task_completed,
233 tool_calls: self.feedback.total_tools,
234 new_skill: None, }
236 }
237}