1use anyhow::Result;
9use std::path::Path;
10
11#[derive(Debug, Clone, PartialEq)]
13#[allow(dead_code)]
14pub enum Role {
15 System,
17 User,
19 Assistant,
21 Tool,
23}
24
25impl Role {
26 pub fn as_str(&self) -> &'static str {
28 match self {
29 Self::System => "system",
30 Self::User => "user",
31 Self::Assistant => "assistant",
32 Self::Tool => "tool",
33 }
34 }
35}
36
37impl std::fmt::Display for Role {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 write!(f, "{}", self.as_str())
40 }
41}
42
43impl std::str::FromStr for Role {
44 type Err = String;
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 match s {
47 "system" => Ok(Self::System),
48 "user" => Ok(Self::User),
49 "assistant" => Ok(Self::Assistant),
50 "tool" => Ok(Self::Tool),
51 other => Err(format!("unknown role: {other}")),
52 }
53 }
54}
55
56#[derive(Debug, Clone)]
58#[allow(dead_code)]
59pub struct Message {
60 pub id: i64,
62 pub session_id: String,
64 pub role: Role,
66 pub content: Option<String>,
68 pub tool_calls: Option<String>,
70 pub tool_call_id: Option<String>,
72 pub prompt_tokens: Option<i64>,
74 pub completion_tokens: Option<i64>,
76 pub cache_read_tokens: Option<i64>,
78 pub cache_creation_tokens: Option<i64>,
80 pub thinking_tokens: Option<i64>,
82}
83
84#[derive(Debug, Clone, Default)]
86pub struct SessionUsage {
87 pub prompt_tokens: i64,
89 pub completion_tokens: i64,
91 pub cache_read_tokens: i64,
93 pub cache_creation_tokens: i64,
95 pub thinking_tokens: i64,
97 pub api_calls: i64,
99}
100
101#[derive(Debug, Clone)]
103pub struct SessionInfo {
104 pub id: String,
106 pub agent_name: String,
108 pub created_at: String,
110 pub message_count: i64,
112 pub total_tokens: i64,
114}
115
116#[derive(Debug, Clone, Default)]
118pub struct CompactedStats {
119 pub message_count: i64,
121 pub session_count: i64,
123 pub size_bytes: i64,
125 pub oldest: Option<String>,
127}
128
129#[async_trait::async_trait]
131pub trait Persistence: Send + Sync {
132 async fn create_session(&self, agent_name: &str, project_root: &Path) -> Result<String>;
136 async fn list_sessions(&self, limit: i64, project_root: &Path) -> Result<Vec<SessionInfo>>;
138 async fn delete_session(&self, session_id: &str) -> Result<bool>;
140
141 async fn insert_message(
145 &self,
146 session_id: &str,
147 role: &Role,
148 content: Option<&str>,
149 tool_calls: Option<&str>,
150 tool_call_id: Option<&str>,
151 usage: Option<&crate::providers::TokenUsage>,
152 ) -> Result<i64>;
153
154 #[allow(clippy::too_many_arguments)]
156 async fn insert_message_with_agent(
157 &self,
158 session_id: &str,
159 role: &Role,
160 content: Option<&str>,
161 tool_calls: Option<&str>,
162 tool_call_id: Option<&str>,
163 usage: Option<&crate::providers::TokenUsage>,
164 agent_name: Option<&str>,
165 ) -> Result<i64>;
166
167 async fn load_context(&self, session_id: &str) -> Result<Vec<Message>>;
169 async fn load_all_messages(&self, session_id: &str) -> Result<Vec<Message>>;
171 async fn recent_user_messages(&self, limit: i64) -> Result<Vec<String>>;
173 async fn last_assistant_message(&self, session_id: &str) -> Result<String>;
175 async fn last_user_message(&self, session_id: &str) -> Result<String>;
177 async fn has_pending_tool_calls(&self, session_id: &str) -> Result<bool>;
179
180 async fn session_token_usage(&self, session_id: &str) -> Result<SessionUsage>;
184 async fn session_usage_by_agent(&self, session_id: &str)
186 -> Result<Vec<(String, SessionUsage)>>;
187
188 async fn compact_session(
192 &self,
193 session_id: &str,
194 summary: &str,
195 preserve_count: usize,
196 ) -> Result<usize>;
197
198 async fn compacted_stats(&self) -> Result<CompactedStats>;
202 async fn purge_compacted(&self, min_age_days: u32) -> Result<usize>;
205
206 async fn get_metadata(&self, session_id: &str, key: &str) -> Result<Option<String>>;
210 async fn set_metadata(&self, session_id: &str, key: &str, value: &str) -> Result<()>;
212 async fn get_todo(&self, session_id: &str) -> Result<Option<String>>;
214 async fn set_todo(&self, session_id: &str, content: &str) -> Result<()>;
216}