Skip to main content

starweaver_cli/local_store/
session_store.rs

1//! CLI adapter over the shared `SQLite` session store.
2
3use async_trait::async_trait;
4use chrono::{DateTime, Utc};
5use starweaver_context::ResumableState;
6use starweaver_core::{RunId, SessionId, SubagentAttemptId};
7use starweaver_runtime::{AgentCheckpoint, AgentStreamRecord};
8use starweaver_session::{
9    AcquireBackgroundSubagentContinuation, AcquireRunAdmission, AdmitRunControl, ApprovalRecord,
10    BackgroundSubagentArtifact, BackgroundSubagentContinuationReceipt, BackgroundSubagentRecord,
11    BackgroundSubagentTerminalCommit, CompactRunTrace, CompactSessionTrace, DeferredToolRecord,
12    DurableBackgroundSubagentDeliveryClaim, DurableBackgroundSubagentDeliveryRelease,
13    DurableControlReceipt, DurableHostEventClass, DurableHostEventPage, DurableHostEventQuery,
14    DurableHostEventRecord, DurableHostEventScope, DurableRunControlIntent,
15    DurableRunControlStatus, EnvironmentStateRef, HitlResumeAbortOutcome, HitlResumeClaim,
16    ManagedRunTarget, PendingHostEventPublication, PendingStreamPublication, RunAdmissionLease,
17    RunAdmissionReceipt, RunEvidenceCommit, RunRecord, RunStatus, RunTerminalProjection,
18    SessionContinuationFence, SessionFilter, SessionPage, SessionPageQuery, SessionRecord,
19    SessionResumeSnapshot, SessionStatus, SessionStore, SessionStoreResult, StreamCursorRef,
20    StreamPublicationTarget, UpdateManagedSession,
21};
22use starweaver_storage::SqliteSessionStore;
23use starweaver_stream::ReplayEvent;
24
25use crate::config::CliConfig;
26
27/// Session store bound to a resolved CLI database path.
28#[derive(Clone, Debug)]
29pub struct LocalSessionStore {
30    store: SqliteSessionStore,
31}
32
33impl LocalSessionStore {
34    /// Open a CLI session-store adapter before it is used by async runtime code.
35    pub fn new(config: CliConfig) -> SessionStoreResult<Self> {
36        crate::config::ensure_config_dirs(&config)
37            .map_err(|error| starweaver_session::SessionStoreError::Failed(error.to_string()))?;
38        let database_path = config.database_path;
39        Ok(Self {
40            store: SqliteSessionStore::open(&database_path)?,
41        })
42    }
43}
44
45#[async_trait]
46impl SessionStore for LocalSessionStore {
47    async fn commit_run_evidence(
48        &self,
49        commit: RunEvidenceCommit,
50    ) -> SessionStoreResult<RunRecord> {
51        self.store.commit_run_evidence(commit).await
52    }
53
54    async fn commit_checkpoint(
55        &self,
56        session_id: &SessionId,
57        checkpoint: AgentCheckpoint,
58    ) -> SessionStoreResult<()> {
59        self.store.commit_checkpoint(session_id, checkpoint).await
60    }
61
62    async fn claim_hitl_resume(&self, claim: HitlResumeClaim) -> SessionStoreResult<()> {
63        self.store.claim_hitl_resume(claim).await
64    }
65
66    async fn start_hitl_resume_effect(
67        &self,
68        lease: &RunAdmissionLease,
69        source_run_id: &RunId,
70        claim_id: &str,
71    ) -> SessionStoreResult<()> {
72        self.store
73            .start_hitl_resume_effect(lease, source_run_id, claim_id)
74            .await
75    }
76
77    async fn abort_admitted_hitl_resume(
78        &self,
79        lease: &RunAdmissionLease,
80        source_run_id: &RunId,
81        claim_id: &str,
82        output_preview: &str,
83    ) -> SessionStoreResult<HitlResumeAbortOutcome> {
84        self.store
85            .abort_admitted_hitl_resume(lease, source_run_id, claim_id, output_preview)
86            .await
87    }
88
89    async fn mark_hitl_resume_started(
90        &self,
91        session_id: &SessionId,
92        run_id: &RunId,
93        claim_id: &str,
94    ) -> SessionStoreResult<()> {
95        self.store
96            .mark_hitl_resume_started(session_id, run_id, claim_id)
97            .await
98    }
99
100    async fn release_hitl_resume_claim(
101        &self,
102        session_id: &SessionId,
103        run_id: &RunId,
104        claim_id: &str,
105    ) -> SessionStoreResult<()> {
106        self.store
107            .release_hitl_resume_claim(session_id, run_id, claim_id)
108            .await
109    }
110
111    async fn pending_stream_publications(
112        &self,
113        session_id: &SessionId,
114    ) -> SessionStoreResult<Vec<PendingStreamPublication>> {
115        self.store.pending_stream_publications(session_id).await
116    }
117
118    async fn acknowledge_stream_publication(
119        &self,
120        publication_id: &str,
121        target: StreamPublicationTarget,
122    ) -> SessionStoreResult<()> {
123        self.store
124            .acknowledge_stream_publication(publication_id, target)
125            .await
126    }
127
128    async fn create_session_idempotent(
129        &self,
130        session: SessionRecord,
131        idempotency_key: &str,
132        command_fingerprint: &str,
133    ) -> SessionStoreResult<SessionRecord> {
134        self.store
135            .create_session_idempotent(session, idempotency_key, command_fingerprint)
136            .await
137    }
138
139    async fn update_managed_session(
140        &self,
141        command: UpdateManagedSession,
142        command_fingerprint: &str,
143    ) -> SessionStoreResult<SessionRecord> {
144        self.store
145            .update_managed_session(command, command_fingerprint)
146            .await
147    }
148
149    async fn acquire_session_deletion_fence(
150        &self,
151        session_id: &SessionId,
152        expected_revision: u64,
153        fence_id: &str,
154        requested_by: &str,
155        idempotency_key: &str,
156        command_fingerprint: &str,
157    ) -> SessionStoreResult<SessionRecord> {
158        self.store
159            .acquire_session_deletion_fence(
160                session_id,
161                expected_revision,
162                fence_id,
163                requested_by,
164                idempotency_key,
165                command_fingerprint,
166            )
167            .await
168    }
169
170    async fn tombstone_session(
171        &self,
172        session_id: &SessionId,
173        fence_id: &str,
174    ) -> SessionStoreResult<SessionRecord> {
175        self.store.tombstone_session(session_id, fence_id).await
176    }
177
178    async fn session_continuation_fence(
179        &self,
180        namespace_id: &str,
181        session_id: &SessionId,
182    ) -> SessionStoreResult<SessionContinuationFence> {
183        self.store
184            .session_continuation_fence(namespace_id, session_id)
185            .await
186    }
187
188    async fn acquire_run_admission(
189        &self,
190        request: AcquireRunAdmission,
191    ) -> SessionStoreResult<RunAdmissionReceipt> {
192        self.store.acquire_run_admission(request).await
193    }
194
195    async fn heartbeat_run_admission(
196        &self,
197        lease: &RunAdmissionLease,
198        lease_expires_at: chrono::DateTime<chrono::Utc>,
199    ) -> SessionStoreResult<RunAdmissionLease> {
200        self.store
201            .heartbeat_run_admission(lease, lease_expires_at)
202            .await
203    }
204
205    async fn release_run_admission(&self, lease: &RunAdmissionLease) -> SessionStoreResult<()> {
206        self.store.release_run_admission(lease).await
207    }
208
209    async fn load_run_admission(
210        &self,
211        target: &ManagedRunTarget,
212    ) -> SessionStoreResult<Option<RunAdmissionLease>> {
213        self.store.load_run_admission(target).await
214    }
215
216    async fn reconcile_expired_run_admissions(
217        &self,
218        namespace_id: &str,
219        now: chrono::DateTime<chrono::Utc>,
220    ) -> SessionStoreResult<Vec<ManagedRunTarget>> {
221        self.store
222            .reconcile_expired_run_admissions(namespace_id, now)
223            .await
224    }
225
226    async fn load_control_receipt(
227        &self,
228        target: &ManagedRunTarget,
229        idempotency_key: &str,
230    ) -> SessionStoreResult<Option<DurableControlReceipt>> {
231        self.store
232            .load_control_receipt(target, idempotency_key)
233            .await
234    }
235
236    async fn reserve_control_receipt(
237        &self,
238        receipt: DurableControlReceipt,
239    ) -> SessionStoreResult<DurableControlReceipt> {
240        self.store.reserve_control_receipt(receipt).await
241    }
242
243    async fn update_control_receipt_state(
244        &self,
245        receipt_id: &str,
246        state: &str,
247    ) -> SessionStoreResult<DurableControlReceipt> {
248        self.store
249            .update_control_receipt_state(receipt_id, state)
250            .await
251    }
252
253    async fn drain_background_subagent_operations(&self) -> SessionStoreResult<()> {
254        self.store.drain_background_subagent_operations().await
255    }
256
257    async fn save_session(&self, session: SessionRecord) -> SessionStoreResult<()> {
258        self.store.save_session(session).await
259    }
260
261    async fn load_session(&self, session_id: &SessionId) -> SessionStoreResult<SessionRecord> {
262        self.store.load_session(session_id).await
263    }
264
265    async fn list_sessions(&self, filter: SessionFilter) -> SessionStoreResult<Vec<SessionRecord>> {
266        self.store.list_sessions(filter).await
267    }
268
269    async fn list_session_page(&self, query: SessionPageQuery) -> SessionStoreResult<SessionPage> {
270        self.store.list_session_page(query).await
271    }
272
273    async fn update_session_status(
274        &self,
275        session_id: &SessionId,
276        status: SessionStatus,
277    ) -> SessionStoreResult<()> {
278        self.store.update_session_status(session_id, status).await
279    }
280
281    async fn save_context_state(
282        &self,
283        session_id: &SessionId,
284        state: ResumableState,
285    ) -> SessionStoreResult<()> {
286        self.store.save_context_state(session_id, state).await
287    }
288
289    async fn save_environment_state(
290        &self,
291        session_id: &SessionId,
292        environment_state: EnvironmentStateRef,
293    ) -> SessionStoreResult<()> {
294        self.store
295            .save_environment_state(session_id, environment_state)
296            .await
297    }
298
299    async fn append_run(&self, run: RunRecord) -> SessionStoreResult<()> {
300        self.store.append_run(run).await
301    }
302
303    async fn load_run(
304        &self,
305        session_id: &SessionId,
306        run_id: &RunId,
307    ) -> SessionStoreResult<RunRecord> {
308        self.store.load_run(session_id, run_id).await
309    }
310
311    async fn list_runs(&self, session_id: &SessionId) -> SessionStoreResult<Vec<RunRecord>> {
312        self.store.list_runs(session_id).await
313    }
314
315    async fn update_run_status(
316        &self,
317        session_id: &SessionId,
318        run_id: &RunId,
319        status: RunStatus,
320        output_preview: Option<String>,
321    ) -> SessionStoreResult<()> {
322        self.store
323            .update_run_status(session_id, run_id, status, output_preview)
324            .await
325    }
326
327    async fn append_checkpoint(
328        &self,
329        session_id: &SessionId,
330        checkpoint: AgentCheckpoint,
331    ) -> SessionStoreResult<()> {
332        self.store.append_checkpoint(session_id, checkpoint).await
333    }
334
335    async fn load_checkpoints(
336        &self,
337        session_id: &SessionId,
338        run_id: &RunId,
339    ) -> SessionStoreResult<Vec<AgentCheckpoint>> {
340        self.store.load_checkpoints(session_id, run_id).await
341    }
342
343    async fn append_stream_records(
344        &self,
345        session_id: &SessionId,
346        run_id: &RunId,
347        records: Vec<AgentStreamRecord>,
348    ) -> SessionStoreResult<()> {
349        self.store
350            .append_stream_records(session_id, run_id, records)
351            .await
352    }
353
354    async fn replay_stream_records(
355        &self,
356        session_id: &SessionId,
357        run_id: &RunId,
358    ) -> SessionStoreResult<Vec<AgentStreamRecord>> {
359        self.store.replay_stream_records(session_id, run_id).await
360    }
361
362    async fn replay_stream_records_after(
363        &self,
364        session_id: &SessionId,
365        run_id: &RunId,
366        after_sequence: Option<usize>,
367    ) -> SessionStoreResult<Vec<AgentStreamRecord>> {
368        self.store
369            .replay_stream_records_after(session_id, run_id, after_sequence)
370            .await
371    }
372
373    async fn save_stream_cursor(
374        &self,
375        session_id: &SessionId,
376        run_id: &RunId,
377        cursor: StreamCursorRef,
378    ) -> SessionStoreResult<()> {
379        self.store
380            .save_stream_cursor(session_id, run_id, cursor)
381            .await
382    }
383
384    async fn append_approval(&self, approval: ApprovalRecord) -> SessionStoreResult<()> {
385        self.store.append_approval(approval).await
386    }
387
388    async fn load_approvals(
389        &self,
390        session_id: &SessionId,
391        run_id: &RunId,
392    ) -> SessionStoreResult<Vec<ApprovalRecord>> {
393        self.store.load_approvals(session_id, run_id).await
394    }
395
396    async fn append_deferred_tool(&self, record: DeferredToolRecord) -> SessionStoreResult<()> {
397        self.store.append_deferred_tool(record).await
398    }
399
400    async fn load_deferred_tools(
401        &self,
402        session_id: &SessionId,
403        run_id: &RunId,
404    ) -> SessionStoreResult<Vec<DeferredToolRecord>> {
405        self.store.load_deferred_tools(session_id, run_id).await
406    }
407
408    async fn compact_run_trace(
409        &self,
410        session_id: &SessionId,
411        run_id: &RunId,
412    ) -> SessionStoreResult<CompactRunTrace> {
413        self.store.compact_run_trace(session_id, run_id).await
414    }
415
416    async fn compact_session_trace(
417        &self,
418        session_id: &SessionId,
419    ) -> SessionStoreResult<CompactSessionTrace> {
420        self.store.compact_session_trace(session_id).await
421    }
422
423    async fn commit_run_evidence_fenced(
424        &self,
425        lease: &RunAdmissionLease,
426        commit: RunEvidenceCommit,
427    ) -> SessionStoreResult<RunRecord> {
428        self.store.commit_run_evidence_fenced(lease, commit).await
429    }
430
431    async fn append_replay_events_fenced(
432        &self,
433        lease: &RunAdmissionLease,
434        events: Vec<ReplayEvent>,
435    ) -> SessionStoreResult<()> {
436        self.store.append_replay_events_fenced(lease, events).await
437    }
438
439    async fn commit_checkpoint_fenced(
440        &self,
441        lease: &RunAdmissionLease,
442        checkpoint: AgentCheckpoint,
443    ) -> SessionStoreResult<()> {
444        self.store.commit_checkpoint_fenced(lease, checkpoint).await
445    }
446
447    async fn enqueue_host_event_publications(
448        &self,
449        publications: Vec<PendingHostEventPublication>,
450    ) -> SessionStoreResult<()> {
451        self.store
452            .enqueue_host_event_publications(publications)
453            .await
454    }
455
456    async fn pending_host_event_publications(
457        &self,
458        limit: usize,
459    ) -> SessionStoreResult<Vec<PendingHostEventPublication>> {
460        self.store.pending_host_event_publications(limit).await
461    }
462
463    async fn materialize_host_event_publications(
464        &self,
465        limit: usize,
466    ) -> SessionStoreResult<Vec<DurableHostEventRecord>> {
467        self.store.materialize_host_event_publications(limit).await
468    }
469
470    async fn replay_host_events(
471        &self,
472        query: DurableHostEventQuery,
473    ) -> SessionStoreResult<DurableHostEventPage> {
474        self.store.replay_host_events(query).await
475    }
476
477    async fn host_event_fence(
478        &self,
479        scope: &DurableHostEventScope,
480        event_classes: &[DurableHostEventClass],
481    ) -> SessionStoreResult<Option<u64>> {
482        self.store.host_event_fence(scope, event_classes).await
483    }
484
485    async fn create_session_idempotent_with_host_events(
486        &self,
487        session: SessionRecord,
488        idempotency_key: &str,
489        command_fingerprint: &str,
490        publications: Vec<PendingHostEventPublication>,
491    ) -> SessionStoreResult<SessionRecord> {
492        self.store
493            .create_session_idempotent_with_host_events(
494                session,
495                idempotency_key,
496                command_fingerprint,
497                publications,
498            )
499            .await
500    }
501
502    async fn load_session_mutation_receipt(
503        &self,
504        namespace_id: &str,
505        idempotency_key: &str,
506        command_fingerprint: &str,
507    ) -> SessionStoreResult<Option<SessionRecord>> {
508        self.store
509            .load_session_mutation_receipt(namespace_id, idempotency_key, command_fingerprint)
510            .await
511    }
512
513    async fn update_managed_session_with_host_events(
514        &self,
515        command: UpdateManagedSession,
516        command_fingerprint: &str,
517        publications: Vec<PendingHostEventPublication>,
518    ) -> SessionStoreResult<SessionRecord> {
519        self.store
520            .update_managed_session_with_host_events(command, command_fingerprint, publications)
521            .await
522    }
523
524    async fn tombstone_session_idempotent_with_host_events(
525        &self,
526        session_id: &SessionId,
527        fence_id: &str,
528        idempotency_key: &str,
529        command_fingerprint: &str,
530        publications: Vec<PendingHostEventPublication>,
531    ) -> SessionStoreResult<SessionRecord> {
532        self.store
533            .tombstone_session_idempotent_with_host_events(
534                session_id,
535                fence_id,
536                idempotency_key,
537                command_fingerprint,
538                publications,
539            )
540            .await
541    }
542
543    async fn load_run_admission_receipt(
544        &self,
545        namespace_id: &str,
546        idempotency_key: &str,
547        command_fingerprint: &str,
548    ) -> SessionStoreResult<Option<RunAdmissionReceipt>> {
549        self.store
550            .load_run_admission_receipt(namespace_id, idempotency_key, command_fingerprint)
551            .await
552    }
553
554    async fn update_run_status_fenced(
555        &self,
556        lease: &RunAdmissionLease,
557        status: RunStatus,
558        output_preview: Option<String>,
559    ) -> SessionStoreResult<RunRecord> {
560        self.store
561            .update_run_status_fenced(lease, status, output_preview)
562            .await
563    }
564
565    async fn finalize_run_admission(
566        &self,
567        lease: &RunAdmissionLease,
568        terminal: RunTerminalProjection,
569    ) -> SessionStoreResult<RunRecord> {
570        self.store.finalize_run_admission(lease, terminal).await
571    }
572
573    async fn admit_run_control(
574        &self,
575        request: AdmitRunControl,
576    ) -> SessionStoreResult<DurableRunControlIntent> {
577        self.store.admit_run_control(request).await
578    }
579
580    async fn load_run_control_intent(
581        &self,
582        target: &ManagedRunTarget,
583        operation_id: &str,
584    ) -> SessionStoreResult<Option<DurableRunControlIntent>> {
585        self.store
586            .load_run_control_intent(target, operation_id)
587            .await
588    }
589
590    async fn list_run_control_intents(
591        &self,
592        target: &ManagedRunTarget,
593        statuses: &[DurableRunControlStatus],
594        limit: usize,
595    ) -> SessionStoreResult<Vec<DurableRunControlIntent>> {
596        self.store
597            .list_run_control_intents(target, statuses, limit)
598            .await
599    }
600
601    async fn advance_run_control_intent(
602        &self,
603        lease: &RunAdmissionLease,
604        operation_id: &str,
605        expected: DurableRunControlStatus,
606        next: DurableRunControlStatus,
607        occurred_at: DateTime<Utc>,
608    ) -> SessionStoreResult<DurableRunControlIntent> {
609        self.store
610            .advance_run_control_intent(lease, operation_id, expected, next, occurred_at)
611            .await
612    }
613
614    async fn reconcile_run_control_intent(
615        &self,
616        target: &ManagedRunTarget,
617        operation_id: &str,
618        occurred_at: DateTime<Utc>,
619    ) -> SessionStoreResult<DurableRunControlIntent> {
620        self.store
621            .reconcile_run_control_intent(target, operation_id, occurred_at)
622            .await
623    }
624
625    async fn record_background_subagent_acceptance(
626        &self,
627        record: BackgroundSubagentRecord,
628    ) -> SessionStoreResult<BackgroundSubagentRecord> {
629        self.store
630            .record_background_subagent_acceptance(record)
631            .await
632    }
633
634    async fn update_background_subagent_execution(
635        &self,
636        record: BackgroundSubagentRecord,
637    ) -> SessionStoreResult<BackgroundSubagentRecord> {
638        self.store
639            .update_background_subagent_execution(record)
640            .await
641    }
642
643    async fn heartbeat_background_subagent(
644        &self,
645        attempt_id: &SubagentAttemptId,
646        host_instance_id: &str,
647        fencing_generation: u64,
648        lease_expires_at: chrono::DateTime<chrono::Utc>,
649    ) -> SessionStoreResult<BackgroundSubagentRecord> {
650        self.store
651            .heartbeat_background_subagent(
652                attempt_id,
653                host_instance_id,
654                fencing_generation,
655                lease_expires_at,
656            )
657            .await
658    }
659
660    async fn commit_background_subagent_terminal(
661        &self,
662        commit: BackgroundSubagentTerminalCommit,
663    ) -> SessionStoreResult<BackgroundSubagentRecord> {
664        self.store.commit_background_subagent_terminal(commit).await
665    }
666
667    async fn load_background_subagent_artifact(
668        &self,
669        artifact_ref: &str,
670    ) -> SessionStoreResult<BackgroundSubagentArtifact> {
671        self.store
672            .load_background_subagent_artifact(artifact_ref)
673            .await
674    }
675
676    async fn expire_background_subagent_retention(
677        &self,
678        namespace_id: &str,
679        now: chrono::DateTime<chrono::Utc>,
680        limit: usize,
681    ) -> SessionStoreResult<Vec<BackgroundSubagentRecord>> {
682        self.store
683            .expire_background_subagent_retention(namespace_id, now, limit)
684            .await
685    }
686
687    async fn record_background_subagent_terminal(
688        &self,
689        record: BackgroundSubagentRecord,
690    ) -> SessionStoreResult<BackgroundSubagentRecord> {
691        self.store.record_background_subagent_terminal(record).await
692    }
693
694    async fn load_background_subagent(
695        &self,
696        attempt_id: &SubagentAttemptId,
697    ) -> SessionStoreResult<BackgroundSubagentRecord> {
698        self.store.load_background_subagent(attempt_id).await
699    }
700
701    async fn list_background_subagents(
702        &self,
703        namespace_id: &str,
704        session_id: Option<&SessionId>,
705        limit: usize,
706    ) -> SessionStoreResult<Vec<BackgroundSubagentRecord>> {
707        self.store
708            .list_background_subagents(namespace_id, session_id, limit)
709            .await
710    }
711
712    async fn list_pending_background_subagents(
713        &self,
714        namespace_id: &str,
715        session_id: Option<&SessionId>,
716        limit: usize,
717    ) -> SessionStoreResult<Vec<BackgroundSubagentRecord>> {
718        self.store
719            .list_pending_background_subagents(namespace_id, session_id, limit)
720            .await
721    }
722
723    async fn claim_background_subagent_delivery(
724        &self,
725        attempt_id: &SubagentAttemptId,
726        claim: DurableBackgroundSubagentDeliveryClaim,
727    ) -> SessionStoreResult<BackgroundSubagentRecord> {
728        self.store
729            .claim_background_subagent_delivery(attempt_id, claim)
730            .await
731    }
732
733    async fn acknowledge_background_subagent_delivery(
734        &self,
735        attempt_id: &SubagentAttemptId,
736        claim_id: &str,
737    ) -> SessionStoreResult<BackgroundSubagentRecord> {
738        self.store
739            .acknowledge_background_subagent_delivery(attempt_id, claim_id)
740            .await
741    }
742
743    async fn release_background_subagent_delivery(
744        &self,
745        attempt_id: &SubagentAttemptId,
746        claim_id: &str,
747        release: DurableBackgroundSubagentDeliveryRelease,
748    ) -> SessionStoreResult<BackgroundSubagentRecord> {
749        self.store
750            .release_background_subagent_delivery(attempt_id, claim_id, release)
751            .await
752    }
753
754    async fn acquire_background_subagent_continuation(
755        &self,
756        request: AcquireBackgroundSubagentContinuation,
757    ) -> SessionStoreResult<BackgroundSubagentContinuationReceipt> {
758        self.store
759            .acquire_background_subagent_continuation(request)
760            .await
761    }
762
763    async fn reconcile_background_subagents(
764        &self,
765        namespace_id: &str,
766        now: chrono::DateTime<chrono::Utc>,
767    ) -> SessionStoreResult<Vec<BackgroundSubagentRecord>> {
768        self.store
769            .reconcile_background_subagents(namespace_id, now)
770            .await
771    }
772
773    async fn latest_checkpoint(
774        &self,
775        session_id: &SessionId,
776        run_id: &RunId,
777    ) -> SessionStoreResult<Option<AgentCheckpoint>> {
778        self.store.latest_checkpoint(session_id, run_id).await
779    }
780
781    async fn resume_snapshot(
782        &self,
783        session_id: &SessionId,
784        run_id: &RunId,
785    ) -> SessionStoreResult<SessionResumeSnapshot> {
786        self.store.resume_snapshot(session_id, run_id).await
787    }
788}