Skip to main content

fxrs_core/
session.rs

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
62/// Durable session port. Implementations must commit atomically and preserve
63/// the previous readable state when a write fails.
64pub 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}