1pub mod fs;
2
3use crate::capture::CaptureRecord;
4use async_trait::async_trait;
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9pub use fs::FsStore;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct SessionMeta {
13 pub session_id: String,
14 pub provider: String,
15 pub upstream: String,
16 pub proxy_port: u16,
17 pub api_port: u16,
18 pub started_at: DateTime<Utc>,
19 pub ended_at: Option<DateTime<Utc>>,
20 pub request_count: u64,
21 pub schema_version: u32,
22 #[serde(default)]
23 pub cwd: Option<String>,
24 #[serde(default)]
25 pub models: Vec<String>,
26}
27
28#[derive(Debug, Clone, Serialize)]
29pub struct RequestSummary {
30 pub seq: u64,
31 pub session_id: String,
32 pub request_id: Option<String>,
33 pub started_at: DateTime<Utc>,
34 pub duration_ms: Option<u64>,
35 pub model: Option<String>,
36 pub status: Option<u16>,
37 pub input_tokens: Option<u64>,
38 pub output_tokens: Option<u64>,
39 pub has_error: bool,
40}
41
42#[derive(Debug, Error)]
43pub enum StoreError {
44 #[error("io error: {0}")]
45 Io(#[from] std::io::Error),
46 #[error("serde: {0}")]
47 Json(#[from] serde_json::Error),
48 #[error("session not found: {0}")]
49 SessionNotFound(String),
50}
51
52#[async_trait]
53pub trait Store: Send + Sync + 'static {
54 fn as_any(&self) -> &dyn std::any::Any;
55 async fn init_session(&self, meta: SessionMeta) -> Result<(), StoreError>;
56 async fn finalize_session(&self, session_id: &str) -> Result<(), StoreError>;
57 async fn append(&self, rec: CaptureRecord) -> Result<(), StoreError>;
58 async fn list_sessions(&self) -> Result<Vec<SessionMeta>, StoreError>;
59 async fn list_requests(&self, session_id: &str) -> Result<Vec<RequestSummary>, StoreError>;
60 async fn get_request(
61 &self,
62 session_id: &str,
63 seq: u64,
64 ) -> Result<Option<CaptureRecord>, StoreError>;
65}