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, RunPage, RunPageQuery, RunRecord, RunStatus,
18    RunTerminalProjection, SessionContinuationFence, SessionFilter, SessionPage, SessionPageQuery,
19    SessionRecord, SessionResumeSnapshot, SessionStatus, SessionStore, SessionStoreResult,
20    StreamCursorRef, 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 list_recent_runs(
316        &self,
317        session_id: &SessionId,
318        limit: usize,
319    ) -> SessionStoreResult<Vec<RunRecord>> {
320        self.store.list_recent_runs(session_id, limit).await
321    }
322
323    async fn list_run_page(
324        &self,
325        session_id: &SessionId,
326        query: RunPageQuery,
327    ) -> SessionStoreResult<RunPage> {
328        self.store.list_run_page(session_id, query).await
329    }
330
331    async fn update_run_status(
332        &self,
333        session_id: &SessionId,
334        run_id: &RunId,
335        status: RunStatus,
336        output_preview: Option<String>,
337    ) -> SessionStoreResult<()> {
338        self.store
339            .update_run_status(session_id, run_id, status, output_preview)
340            .await
341    }
342
343    async fn append_checkpoint(
344        &self,
345        session_id: &SessionId,
346        checkpoint: AgentCheckpoint,
347    ) -> SessionStoreResult<()> {
348        self.store.append_checkpoint(session_id, checkpoint).await
349    }
350
351    async fn load_checkpoints(
352        &self,
353        session_id: &SessionId,
354        run_id: &RunId,
355    ) -> SessionStoreResult<Vec<AgentCheckpoint>> {
356        self.store.load_checkpoints(session_id, run_id).await
357    }
358
359    async fn append_stream_records(
360        &self,
361        session_id: &SessionId,
362        run_id: &RunId,
363        records: Vec<AgentStreamRecord>,
364    ) -> SessionStoreResult<()> {
365        self.store
366            .append_stream_records(session_id, run_id, records)
367            .await
368    }
369
370    async fn replay_stream_records(
371        &self,
372        session_id: &SessionId,
373        run_id: &RunId,
374    ) -> SessionStoreResult<Vec<AgentStreamRecord>> {
375        self.store.replay_stream_records(session_id, run_id).await
376    }
377
378    async fn replay_stream_records_after(
379        &self,
380        session_id: &SessionId,
381        run_id: &RunId,
382        after_sequence: Option<usize>,
383    ) -> SessionStoreResult<Vec<AgentStreamRecord>> {
384        self.store
385            .replay_stream_records_after(session_id, run_id, after_sequence)
386            .await
387    }
388
389    async fn save_stream_cursor(
390        &self,
391        session_id: &SessionId,
392        run_id: &RunId,
393        cursor: StreamCursorRef,
394    ) -> SessionStoreResult<()> {
395        self.store
396            .save_stream_cursor(session_id, run_id, cursor)
397            .await
398    }
399
400    async fn append_approval(&self, approval: ApprovalRecord) -> SessionStoreResult<()> {
401        self.store.append_approval(approval).await
402    }
403
404    async fn load_approvals(
405        &self,
406        session_id: &SessionId,
407        run_id: &RunId,
408    ) -> SessionStoreResult<Vec<ApprovalRecord>> {
409        self.store.load_approvals(session_id, run_id).await
410    }
411
412    async fn append_deferred_tool(&self, record: DeferredToolRecord) -> SessionStoreResult<()> {
413        self.store.append_deferred_tool(record).await
414    }
415
416    async fn load_deferred_tools(
417        &self,
418        session_id: &SessionId,
419        run_id: &RunId,
420    ) -> SessionStoreResult<Vec<DeferredToolRecord>> {
421        self.store.load_deferred_tools(session_id, run_id).await
422    }
423
424    async fn compact_run_trace(
425        &self,
426        session_id: &SessionId,
427        run_id: &RunId,
428    ) -> SessionStoreResult<CompactRunTrace> {
429        self.store.compact_run_trace(session_id, run_id).await
430    }
431
432    async fn compact_session_trace(
433        &self,
434        session_id: &SessionId,
435    ) -> SessionStoreResult<CompactSessionTrace> {
436        self.store.compact_session_trace(session_id).await
437    }
438
439    async fn commit_run_evidence_fenced(
440        &self,
441        lease: &RunAdmissionLease,
442        commit: RunEvidenceCommit,
443    ) -> SessionStoreResult<RunRecord> {
444        self.store.commit_run_evidence_fenced(lease, commit).await
445    }
446
447    async fn append_replay_events_fenced(
448        &self,
449        lease: &RunAdmissionLease,
450        events: Vec<ReplayEvent>,
451    ) -> SessionStoreResult<()> {
452        self.store.append_replay_events_fenced(lease, events).await
453    }
454
455    async fn commit_checkpoint_fenced(
456        &self,
457        lease: &RunAdmissionLease,
458        checkpoint: AgentCheckpoint,
459    ) -> SessionStoreResult<()> {
460        self.store.commit_checkpoint_fenced(lease, checkpoint).await
461    }
462
463    async fn enqueue_host_event_publications(
464        &self,
465        publications: Vec<PendingHostEventPublication>,
466    ) -> SessionStoreResult<()> {
467        self.store
468            .enqueue_host_event_publications(publications)
469            .await
470    }
471
472    async fn pending_host_event_publications(
473        &self,
474        limit: usize,
475    ) -> SessionStoreResult<Vec<PendingHostEventPublication>> {
476        self.store.pending_host_event_publications(limit).await
477    }
478
479    async fn materialize_host_event_publications(
480        &self,
481        limit: usize,
482    ) -> SessionStoreResult<Vec<DurableHostEventRecord>> {
483        self.store.materialize_host_event_publications(limit).await
484    }
485
486    async fn replay_host_events(
487        &self,
488        query: DurableHostEventQuery,
489    ) -> SessionStoreResult<DurableHostEventPage> {
490        self.store.replay_host_events(query).await
491    }
492
493    async fn host_event_fence(
494        &self,
495        scope: &DurableHostEventScope,
496        event_classes: &[DurableHostEventClass],
497    ) -> SessionStoreResult<Option<u64>> {
498        self.store.host_event_fence(scope, event_classes).await
499    }
500
501    async fn create_session_idempotent_with_host_events(
502        &self,
503        session: SessionRecord,
504        idempotency_key: &str,
505        command_fingerprint: &str,
506        publications: Vec<PendingHostEventPublication>,
507    ) -> SessionStoreResult<SessionRecord> {
508        self.store
509            .create_session_idempotent_with_host_events(
510                session,
511                idempotency_key,
512                command_fingerprint,
513                publications,
514            )
515            .await
516    }
517
518    async fn load_session_mutation_receipt(
519        &self,
520        namespace_id: &str,
521        idempotency_key: &str,
522        command_fingerprint: &str,
523    ) -> SessionStoreResult<Option<SessionRecord>> {
524        self.store
525            .load_session_mutation_receipt(namespace_id, idempotency_key, command_fingerprint)
526            .await
527    }
528
529    async fn update_managed_session_with_host_events(
530        &self,
531        command: UpdateManagedSession,
532        command_fingerprint: &str,
533        publications: Vec<PendingHostEventPublication>,
534    ) -> SessionStoreResult<SessionRecord> {
535        self.store
536            .update_managed_session_with_host_events(command, command_fingerprint, publications)
537            .await
538    }
539
540    async fn tombstone_session_idempotent_with_host_events(
541        &self,
542        session_id: &SessionId,
543        fence_id: &str,
544        idempotency_key: &str,
545        command_fingerprint: &str,
546        publications: Vec<PendingHostEventPublication>,
547    ) -> SessionStoreResult<SessionRecord> {
548        self.store
549            .tombstone_session_idempotent_with_host_events(
550                session_id,
551                fence_id,
552                idempotency_key,
553                command_fingerprint,
554                publications,
555            )
556            .await
557    }
558
559    async fn load_run_admission_receipt(
560        &self,
561        namespace_id: &str,
562        idempotency_key: &str,
563        command_fingerprint: &str,
564    ) -> SessionStoreResult<Option<RunAdmissionReceipt>> {
565        self.store
566            .load_run_admission_receipt(namespace_id, idempotency_key, command_fingerprint)
567            .await
568    }
569
570    async fn update_run_status_fenced(
571        &self,
572        lease: &RunAdmissionLease,
573        status: RunStatus,
574        output_preview: Option<String>,
575    ) -> SessionStoreResult<RunRecord> {
576        self.store
577            .update_run_status_fenced(lease, status, output_preview)
578            .await
579    }
580
581    async fn finalize_run_admission(
582        &self,
583        lease: &RunAdmissionLease,
584        terminal: RunTerminalProjection,
585    ) -> SessionStoreResult<RunRecord> {
586        self.store.finalize_run_admission(lease, terminal).await
587    }
588
589    async fn admit_run_control(
590        &self,
591        request: AdmitRunControl,
592    ) -> SessionStoreResult<DurableRunControlIntent> {
593        self.store.admit_run_control(request).await
594    }
595
596    async fn load_run_control_intent(
597        &self,
598        target: &ManagedRunTarget,
599        operation_id: &str,
600    ) -> SessionStoreResult<Option<DurableRunControlIntent>> {
601        self.store
602            .load_run_control_intent(target, operation_id)
603            .await
604    }
605
606    async fn list_run_control_intents(
607        &self,
608        target: &ManagedRunTarget,
609        statuses: &[DurableRunControlStatus],
610        limit: usize,
611    ) -> SessionStoreResult<Vec<DurableRunControlIntent>> {
612        self.store
613            .list_run_control_intents(target, statuses, limit)
614            .await
615    }
616
617    async fn advance_run_control_intent(
618        &self,
619        lease: &RunAdmissionLease,
620        operation_id: &str,
621        expected: DurableRunControlStatus,
622        next: DurableRunControlStatus,
623        occurred_at: DateTime<Utc>,
624    ) -> SessionStoreResult<DurableRunControlIntent> {
625        self.store
626            .advance_run_control_intent(lease, operation_id, expected, next, occurred_at)
627            .await
628    }
629
630    async fn reconcile_run_control_intent(
631        &self,
632        target: &ManagedRunTarget,
633        operation_id: &str,
634        occurred_at: DateTime<Utc>,
635    ) -> SessionStoreResult<DurableRunControlIntent> {
636        self.store
637            .reconcile_run_control_intent(target, operation_id, occurred_at)
638            .await
639    }
640
641    async fn record_background_subagent_acceptance(
642        &self,
643        record: BackgroundSubagentRecord,
644    ) -> SessionStoreResult<BackgroundSubagentRecord> {
645        self.store
646            .record_background_subagent_acceptance(record)
647            .await
648    }
649
650    async fn update_background_subagent_execution(
651        &self,
652        record: BackgroundSubagentRecord,
653    ) -> SessionStoreResult<BackgroundSubagentRecord> {
654        self.store
655            .update_background_subagent_execution(record)
656            .await
657    }
658
659    async fn heartbeat_background_subagent(
660        &self,
661        attempt_id: &SubagentAttemptId,
662        host_instance_id: &str,
663        fencing_generation: u64,
664        lease_expires_at: chrono::DateTime<chrono::Utc>,
665    ) -> SessionStoreResult<BackgroundSubagentRecord> {
666        self.store
667            .heartbeat_background_subagent(
668                attempt_id,
669                host_instance_id,
670                fencing_generation,
671                lease_expires_at,
672            )
673            .await
674    }
675
676    async fn commit_background_subagent_terminal(
677        &self,
678        commit: BackgroundSubagentTerminalCommit,
679    ) -> SessionStoreResult<BackgroundSubagentRecord> {
680        self.store.commit_background_subagent_terminal(commit).await
681    }
682
683    async fn load_background_subagent_artifact(
684        &self,
685        artifact_ref: &str,
686    ) -> SessionStoreResult<BackgroundSubagentArtifact> {
687        self.store
688            .load_background_subagent_artifact(artifact_ref)
689            .await
690    }
691
692    async fn expire_background_subagent_retention(
693        &self,
694        namespace_id: &str,
695        now: chrono::DateTime<chrono::Utc>,
696        limit: usize,
697    ) -> SessionStoreResult<Vec<BackgroundSubagentRecord>> {
698        self.store
699            .expire_background_subagent_retention(namespace_id, now, limit)
700            .await
701    }
702
703    async fn record_background_subagent_terminal(
704        &self,
705        record: BackgroundSubagentRecord,
706    ) -> SessionStoreResult<BackgroundSubagentRecord> {
707        self.store.record_background_subagent_terminal(record).await
708    }
709
710    async fn load_background_subagent(
711        &self,
712        attempt_id: &SubagentAttemptId,
713    ) -> SessionStoreResult<BackgroundSubagentRecord> {
714        self.store.load_background_subagent(attempt_id).await
715    }
716
717    async fn list_background_subagents(
718        &self,
719        namespace_id: &str,
720        session_id: Option<&SessionId>,
721        limit: usize,
722    ) -> SessionStoreResult<Vec<BackgroundSubagentRecord>> {
723        self.store
724            .list_background_subagents(namespace_id, session_id, limit)
725            .await
726    }
727
728    async fn list_pending_background_subagents(
729        &self,
730        namespace_id: &str,
731        session_id: Option<&SessionId>,
732        limit: usize,
733    ) -> SessionStoreResult<Vec<BackgroundSubagentRecord>> {
734        self.store
735            .list_pending_background_subagents(namespace_id, session_id, limit)
736            .await
737    }
738
739    async fn claim_background_subagent_delivery(
740        &self,
741        attempt_id: &SubagentAttemptId,
742        claim: DurableBackgroundSubagentDeliveryClaim,
743    ) -> SessionStoreResult<BackgroundSubagentRecord> {
744        self.store
745            .claim_background_subagent_delivery(attempt_id, claim)
746            .await
747    }
748
749    async fn acknowledge_background_subagent_delivery(
750        &self,
751        attempt_id: &SubagentAttemptId,
752        claim_id: &str,
753    ) -> SessionStoreResult<BackgroundSubagentRecord> {
754        self.store
755            .acknowledge_background_subagent_delivery(attempt_id, claim_id)
756            .await
757    }
758
759    async fn release_background_subagent_delivery(
760        &self,
761        attempt_id: &SubagentAttemptId,
762        claim_id: &str,
763        release: DurableBackgroundSubagentDeliveryRelease,
764    ) -> SessionStoreResult<BackgroundSubagentRecord> {
765        self.store
766            .release_background_subagent_delivery(attempt_id, claim_id, release)
767            .await
768    }
769
770    async fn acquire_background_subagent_continuation(
771        &self,
772        request: AcquireBackgroundSubagentContinuation,
773    ) -> SessionStoreResult<BackgroundSubagentContinuationReceipt> {
774        self.store
775            .acquire_background_subagent_continuation(request)
776            .await
777    }
778
779    async fn reconcile_background_subagents(
780        &self,
781        namespace_id: &str,
782        now: chrono::DateTime<chrono::Utc>,
783    ) -> SessionStoreResult<Vec<BackgroundSubagentRecord>> {
784        self.store
785            .reconcile_background_subagents(namespace_id, now)
786            .await
787    }
788
789    async fn latest_checkpoint(
790        &self,
791        session_id: &SessionId,
792        run_id: &RunId,
793    ) -> SessionStoreResult<Option<AgentCheckpoint>> {
794        self.store.latest_checkpoint(session_id, run_id).await
795    }
796
797    async fn resume_snapshot(
798        &self,
799        session_id: &SessionId,
800        run_id: &RunId,
801    ) -> SessionStoreResult<SessionResumeSnapshot> {
802        self.store.resume_snapshot(session_id, run_id).await
803    }
804}