Skip to main content

starweaver_session/
store.rs

1//! Session store trait, executor adapter, and built-in implementations.
2
3mod contract;
4mod memory;
5
6use std::sync::Arc;
7
8use async_trait::async_trait;
9use starweaver_context::{
10    AgentCheckpoint, AgentExecutionDecision, AgentExecutor, AgentExecutorError,
11};
12use starweaver_core::SessionId;
13
14use crate::RunAdmissionLease;
15
16pub use contract::{
17    InteractionPage, InteractionPageKey, InteractionPageQuery, MAX_STABLE_PAGE_SIZE, SessionFilter,
18    SessionPage, SessionPageKey, SessionPageQuery, SessionStore,
19};
20pub use memory::InMemorySessionStore;
21
22/// Executor adapter that persists runtime checkpoints into a session store.
23#[derive(Clone)]
24pub struct SessionStoreExecutor {
25    store: Arc<dyn SessionStore>,
26    session_id: SessionId,
27    admission_lease: Option<RunAdmissionLease>,
28}
29
30impl SessionStoreExecutor {
31    /// Create a checkpoint executor for one session.
32    #[must_use]
33    pub fn new(store: Arc<dyn SessionStore>, session_id: SessionId) -> Self {
34        Self {
35            store,
36            session_id,
37            admission_lease: None,
38        }
39    }
40
41    /// Create a checkpoint executor fenced to one active run admission.
42    #[must_use]
43    pub fn new_fenced(
44        store: Arc<dyn SessionStore>,
45        session_id: SessionId,
46        admission_lease: RunAdmissionLease,
47    ) -> Self {
48        Self {
49            store,
50            session_id,
51            admission_lease: Some(admission_lease),
52        }
53    }
54
55    /// Return the session id associated with this executor.
56    #[must_use]
57    pub const fn session_id(&self) -> &SessionId {
58        &self.session_id
59    }
60}
61
62#[async_trait]
63impl AgentExecutor for SessionStoreExecutor {
64    fn requires_durable_hitl_preparation(&self) -> bool {
65        true
66    }
67
68    async fn checkpoint(
69        &self,
70        checkpoint: AgentCheckpoint,
71    ) -> Result<AgentExecutionDecision, AgentExecutorError> {
72        if let Some(lease) = self.admission_lease.as_ref() {
73            self.store
74                .commit_checkpoint_fenced(lease, checkpoint)
75                .await?;
76        } else {
77            self.store
78                .commit_checkpoint(&self.session_id, checkpoint)
79                .await?;
80        }
81        Ok(AgentExecutionDecision::Continue)
82    }
83}