1use 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#[derive(Clone, Debug)]
29pub struct LocalSessionStore {
30 store: SqliteSessionStore,
31}
32
33impl LocalSessionStore {
34 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}