gglib_core/domain/
chat.rs

1//! Chat domain types.
2//!
3//! These types represent chat conversations and messages in the domain model,
4//! independent of any infrastructure concerns.
5
6use serde::{Deserialize, Serialize};
7
8/// A chat conversation.
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Conversation {
11    pub id: i64,
12    pub title: String,
13    pub model_id: Option<i64>,
14    pub system_prompt: Option<String>,
15    pub created_at: String,
16    pub updated_at: String,
17}
18
19/// A chat message within a conversation.
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct Message {
22    pub id: i64,
23    pub conversation_id: i64,
24    pub role: MessageRole,
25    pub content: String,
26    pub created_at: String,
27    /// Optional JSON metadata for deep research state, tool usage, etc.
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub metadata: Option<serde_json::Value>,
30}
31
32/// The role of a message sender.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(rename_all = "lowercase")]
35pub enum MessageRole {
36    System,
37    User,
38    Assistant,
39}
40
41impl MessageRole {
42    /// Parse a role from a string.
43    #[must_use]
44    pub fn parse(s: &str) -> Option<Self> {
45        match s {
46            "system" => Some(Self::System),
47            "user" => Some(Self::User),
48            "assistant" => Some(Self::Assistant),
49            _ => None,
50        }
51    }
52
53    /// Convert role to string representation.
54    #[must_use]
55    pub const fn as_str(&self) -> &'static str {
56        match self {
57            Self::System => "system",
58            Self::User => "user",
59            Self::Assistant => "assistant",
60        }
61    }
62}
63
64impl std::fmt::Display for MessageRole {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        write!(f, "{}", self.as_str())
67    }
68}
69
70/// Data for creating a new conversation.
71#[derive(Debug, Clone)]
72pub struct NewConversation {
73    pub title: String,
74    pub model_id: Option<i64>,
75    pub system_prompt: Option<String>,
76}
77
78/// Data for creating a new message.
79#[derive(Debug, Clone)]
80pub struct NewMessage {
81    pub conversation_id: i64,
82    pub role: MessageRole,
83    pub content: String,
84    /// Optional JSON metadata for deep research state, tool usage, etc.
85    pub metadata: Option<serde_json::Value>,
86}
87
88/// Data for updating an existing conversation.
89#[derive(Debug, Clone, Default)]
90pub struct ConversationUpdate {
91    pub title: Option<String>,
92    /// Use `Some(Some(prompt))` to set, `Some(None)` to clear, `None` to leave unchanged.
93    pub system_prompt: Option<Option<String>>,
94}