aa_core/storage/session_store.rs
1//! [`SessionStore`] — persistence for per-execution session records.
2
3use super::{AgentId, Result, SessionId};
4use async_trait::async_trait;
5
6/// A persisted record of a single agent execution session.
7///
8/// One record is created per execution run and ties together all governance
9/// events within that run. Backends key the record by its
10/// [`session_id`](SessionRecord::session_id).
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct SessionRecord {
13 /// Stable identifier for this execution run.
14 pub session_id: SessionId,
15 /// The agent that owns this session.
16 pub agent_id: AgentId,
17 /// Wall-clock start time of the session, in nanoseconds since the Unix epoch.
18 pub started_at_ns: u64,
19}
20
21/// Persists, loads, and deletes [`SessionRecord`]s.
22///
23/// The runtime saves a record when a session starts, loads it to resume
24/// governance context, and deletes it when the session ends.
25///
26/// # Example
27///
28/// ```
29/// use aa_core::storage::{Result, SessionId, SessionRecord, SessionStore, StorageError};
30/// use async_trait::async_trait;
31///
32/// /// A store that holds no sessions.
33/// struct EmptySessionStore;
34///
35/// #[async_trait]
36/// impl SessionStore for EmptySessionStore {
37/// async fn save(&self, _session: SessionRecord) -> Result<()> {
38/// Ok(())
39/// }
40///
41/// async fn load(&self, session_id: &SessionId) -> Result<SessionRecord> {
42/// Err(StorageError::NotFound(format!("{:?}", session_id.as_bytes())))
43/// }
44///
45/// async fn delete(&self, _session_id: &SessionId) -> Result<()> {
46/// Ok(())
47/// }
48/// }
49/// ```
50#[async_trait]
51pub trait SessionStore: Send + Sync {
52 /// Persist `session`, overwriting any record with the same session id.
53 async fn save(&self, session: SessionRecord) -> Result<()>;
54
55 /// Load the record for `session_id`.
56 ///
57 /// Returns [`StorageError::NotFound`](super::StorageError::NotFound) when no
58 /// record exists for the id.
59 async fn load(&self, session_id: &SessionId) -> Result<SessionRecord>;
60
61 /// Delete the record for `session_id`.
62 ///
63 /// Idempotent: deleting an absent session succeeds.
64 async fn delete(&self, session_id: &SessionId) -> Result<()>;
65}