1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3
4use crate::{BoxFuture, ChatMessage};
5
6#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
7pub struct SessionPreferences {
8 #[serde(default, skip_serializing_if = "Option::is_none")]
9 pub model: Option<String>,
10}
11
12#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
13pub struct Session {
14 pub schema_version: u32,
15 pub id: String,
16 pub created_at_ms: i64,
17 pub updated_at_ms: i64,
18 pub workspace_root: String,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 pub origin_workspace_root: Option<String>,
21 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub title: Option<String>,
23 #[serde(default)]
24 pub preferences: SessionPreferences,
25 #[serde(default)]
26 pub history: Vec<ChatMessage>,
27}
28
29#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
30pub struct SessionSummary {
31 pub id: String,
32 pub workspace_root: Option<String>,
33 pub origin_workspace_root: Option<String>,
34 pub title: Option<String>,
35 pub preview: Option<String>,
36 pub created_at_ms: i64,
37 pub updated_at_ms: i64,
38 pub history_len: usize,
39 pub has_managed_children: bool,
40}
41
42#[derive(Clone, Debug, Eq, PartialEq)]
43pub enum SessionTarget {
44 Last,
45 Id(String),
46}
47
48#[derive(Debug, Error)]
49pub enum SessionStoreError {
50 #[error("session `{0}` was not found")]
51 NotFound(String),
52 #[error("invalid session id `{0}`")]
53 InvalidId(String),
54 #[error("session is corrupt: {0}")]
55 Corrupt(String),
56 #[error("session schema is unsupported: {0}")]
57 UnsupportedSchema(u32),
58 #[error("session store is unavailable: {0}")]
59 Unavailable(String),
60}
61
62pub trait SessionStore: Send + Sync {
65 fn load<'a>(
66 &'a self,
67 target: SessionTarget,
68 workspace_root: &'a str,
69 ) -> BoxFuture<'a, Result<Session, SessionStoreError>>;
70
71 fn save<'a>(&'a self, session: &'a Session) -> BoxFuture<'a, Result<(), SessionStoreError>>;
72
73 fn list<'a>(
74 &'a self,
75 workspace_root: Option<&'a str>,
76 limit: usize,
77 ) -> BoxFuture<'a, Result<Vec<SessionSummary>, SessionStoreError>>;
78}