crabtalk_runtime/conversation.rs
1//! Conversation — pure working-context container.
2
3use crate::ConversationHandle;
4use std::time::Instant;
5use wcore::{model::HistoryEntry, storage::ConversationMeta};
6
7/// A conversation tied to a specific agent.
8///
9/// Pure working-context container. Persistence is delegated to the
10/// Storage trait via the session handle.
11#[derive(Debug, Clone)]
12pub struct Conversation {
13 /// Unique conversation identifier (monotonic counter, runtime-only).
14 pub id: u64,
15 /// Conversation history (the working context for the LLM).
16 pub history: Vec<HistoryEntry>,
17 /// Conversation title (set by the `set_title` tool).
18 pub title: String,
19 /// Accumulated active time in seconds.
20 pub uptime_secs: u64,
21 /// When this conversation was loaded/created in this process.
22 pub created_at: Instant,
23 /// Persistent conversation identity, assigned by the storage layer.
24 /// `None` until the first persistence call — and remains `None` for
25 /// tmp chats that never enter a topic.
26 pub handle: Option<ConversationHandle>,
27 /// Topic this conversation belongs to, if any. `None` = tmp chat
28 /// (no storage, no resume). Set by `switch_topic`.
29 pub topic: Option<String>,
30}
31
32impl Conversation {
33 /// Create a new conversation with an empty history.
34 pub fn new(id: u64) -> Self {
35 Self {
36 id,
37 history: Vec::new(),
38 title: String::new(),
39 uptime_secs: 0,
40 created_at: Instant::now(),
41 handle: None,
42 topic: None,
43 }
44 }
45
46 /// Build a [`ConversationMeta`] snapshot from this conversation's
47 /// current state.
48 pub fn meta(&self, agent: &str, created_by: &str) -> ConversationMeta {
49 ConversationMeta {
50 agent: agent.to_owned(),
51 created_by: created_by.to_owned(),
52 created_at: chrono::Utc::now().to_rfc3339(),
53 title: self.title.clone(),
54 uptime_secs: self.uptime_secs,
55 topic: self.topic.clone(),
56 }
57 }
58}