Skip to main content

haki_core/
message.rs

1//! Core message types for the agent loop.
2//!
3//! haki-llm owns the wire types (Message, Role). This module adds the richer
4//! in-memory types needed by the agent loop: tool calls, tool results, and
5//! multi-block content.
6
7use serde::{Deserialize, Serialize};
8
9// Re-export the LLM wire types so callers only import from haki-core.
10pub use haki_llm::{Message, Role};
11
12// ─── Tool types ───────────────────────────────────────────────────────────────
13
14#[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// ─── Rich content for multi-block messages ────────────────────────────────────
29
30#[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// ─── Tests ────────────────────────────────────────────────────────────────────
39
40#[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}