Skip to main content

kowalski_core/conversation/
mod.rs

1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4/// Conversation: The AI's memory of what it's been talking about.
5/// "Conversations are like dreams - they make sense at the time but are hard to explain later."
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Conversation {
8    pub id: String,
9    pub model: String,
10    pub messages: Vec<Message>,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Message {
15    pub role: String,
16    pub content: String,
17    /// Structured calls emitted by an assistant turn (native provider tool calling).
18    #[serde(default, skip_serializing_if = "Option::is_none")]
19    pub tool_calls: Option<Vec<ToolCall>>,
20    /// For `role = "tool"` messages: the id of the [`ToolCall`] this result answers.
21    #[serde(default, skip_serializing_if = "Option::is_none")]
22    pub tool_call_id: Option<String>,
23}
24
25impl Message {
26    pub fn text(role: &str, content: &str) -> Self {
27        Self {
28            role: role.to_string(),
29            content: content.to_string(),
30            tool_calls: None,
31            tool_call_id: None,
32        }
33    }
34
35    /// Assistant turn that requested tool calls (content may be empty).
36    pub fn assistant_tool_calls(content: &str, calls: Vec<ToolCall>) -> Self {
37        Self {
38            role: "assistant".to_string(),
39            content: content.to_string(),
40            tool_calls: Some(calls),
41            tool_call_id: None,
42        }
43    }
44
45    /// Tool result answering the call with the given id, sent back as `role = "tool"`.
46    pub fn tool_result(tool_call_id: &str, content: &str) -> Self {
47        Self {
48            role: "tool".to_string(),
49            content: content.to_string(),
50            tool_calls: None,
51            tool_call_id: Some(tool_call_id.to_string()),
52        }
53    }
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct ToolCall {
58    pub id: String,
59    pub function: FunctionCall,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct FunctionCall {
64    pub name: String,
65    pub arguments: serde_json::Value,
66}
67
68impl Conversation {
69    pub fn new(model: &str) -> Self {
70        Self {
71            id: Uuid::new_v4().to_string(),
72            model: model.to_string(),
73            messages: Vec::new(),
74        }
75    }
76
77    pub fn with_id(model: &str, id: &str) -> Self {
78        Self {
79            id: id.to_string(),
80            model: model.to_string(),
81            messages: Vec::new(),
82        }
83    }
84
85    pub fn add_message(&mut self, role: &str, content: &str) {
86        self.messages.push(Message::text(role, content));
87    }
88
89    pub fn get_messages(&self) -> &[Message] {
90        &self.messages
91    }
92
93    pub fn clear(&mut self) {
94        self.messages.clear();
95    }
96}