1use serde::{Deserialize, Serialize};
8
9pub use haki_llm::{Message, Role};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ToolCall {
16 pub id: String,
17 pub name: String,
18 pub input: serde_json::Value,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ToolResult {
23 pub tool_call_id: String,
24 pub content: String,
25 pub is_error: bool,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(tag = "type", rename_all = "snake_case")]
32pub enum ContentBlock {
33 Text { text: String },
34 ToolUse(ToolCall),
35 ToolResult(ToolResult),
36}
37
38#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn tool_call_roundtrip() {
46 let tc = ToolCall {
47 id: "call_1".into(),
48 name: "bash".into(),
49 input: serde_json::json!({ "command": "ls" }),
50 };
51 let json = serde_json::to_string(&tc).unwrap();
52 let back: ToolCall = serde_json::from_str(&json).unwrap();
53 assert_eq!(back.name, "bash");
54 }
55
56 #[test]
57 fn tool_result_error_flag() {
58 let tr = ToolResult {
59 tool_call_id: "call_1".into(),
60 content: "permission denied".into(),
61 is_error: true,
62 };
63 assert!(tr.is_error);
64 }
65
66 #[test]
67 fn content_block_text_tag() {
68 let block = ContentBlock::Text { text: "hello".into() };
69 let json = serde_json::to_value(&block).unwrap();
70 assert_eq!(json["type"], "text");
71 }
72}