pub trait RuntimeSessionPersistence: Send + Sync {
// Required method
fn save_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
// Provided methods
fn seed_runtime_activation<'life0, 'life1, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn record_permission_posture_activation<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
_expected_audit_revision: Option<u64>,
_seed: &'life2 PermissionAuditSeed,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn save_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn load_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn update_task_list_control_plane<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
task_list: &'life2 TaskList,
version: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait { ... }
fn checkpoint_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn load_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn clear_legacy_pending_messages<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
expected: &'life2 [Value],
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn append_token_usage_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
json_line: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
}Expand description
Port for runtime (non-authoritative) session persistence.
Implementors must:
- Serialize concurrent saves per session ID.
- Merge on-disk authoritative metadata (
title,pinned,title_version,metadata_version) before writing, so UI edits are never clobbered.
Required Methods§
Sourcefn save_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn save_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Persist the session, merging any newer authoritative metadata from disk.
Provided Methods§
Sourcefn seed_runtime_activation<'life0, 'life1, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn seed_runtime_activation<'life0, 'life1, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Authoritatively seed one validated actor activation.
Unlike an ordinary runtime save, the incoming RunSpec posture and its complete audit record must replace any posture left by a previous warm activation. Implementations must still preserve durable SessionInbox admission/transcript proof and serialize the operation per session.
There is no safe generic implementation through
Self::save_runtime_session: that primitive is explicitly allowed to
adopt a newer disk posture, which would make warm workers sticky across
runs. Custom persisters therefore fail closed until they implement this
authority boundary deliberately.
Sourcefn record_permission_posture_activation<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
_expected_audit_revision: Option<u64>,
_seed: &'life2 PermissionAuditSeed,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn record_permission_posture_activation<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
_expected_audit_revision: Option<u64>,
_seed: &'life2 PermissionAuditSeed,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Atomically persist a worker-declared executor mapping for the current host-authoritative permission posture.
The caller supplies the audit revision it observed before dispatch. Implementations must load and compare that revision while holding the per-session lock, reject a concurrent posture update, and allocate a new host revision/timestamp themselves. Remote audit clocks are never an authority at this boundary.
Sourcefn save_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn save_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Persist only the runtime control-plane for a session.
Task lists and other runtime metadata belong to the control-plane and do not require rewriting the potentially large message transcript. Built-in persistence implementations with a runtime sidecar should override this operation with their sidecar-only path. Custom/legacy implementations remain source-compatible and safely fall back to the full runtime save.
Callers must not rely on this operation to persist message changes.
Sourcefn load_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn load_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Load the representation paired with
save_runtime_control_plane.
Sidecar-capable implementations should return their message-free control-plane snapshot. The default deliberately returns the full runtime session: when the paired save also falls back to a full save, retaining the transcript makes that fallback safe rather than replacing durable messages with an empty sidecar-shaped snapshot.
Sourcefn update_task_list_control_plane<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
task_list: &'life2 TaskList,
version: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
fn update_task_list_control_plane<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
task_list: &'life2 TaskList,
version: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
Atomically update only the shared Task list and its version.
The default is safe for custom/legacy persistence: it loads the full
runtime session, changes only Task-owned fields, then uses the paired
control-plane save (which itself defaults to a full save). Returning
false means the implementation could not load the target; callers that
also hold a Storage may retain legacy
behavior with an explicit full-load/full-save fallback.
Implementations with per-session transactions should override this so the load, narrow mutation and save share one critical section.
Sourcefn checkpoint_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn checkpoint_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Append-safe checkpoint used at the shared engine execute boundary.
Unlike save_runtime_session, this must
preserve messages that were appended durably by a concurrent writer
after the runner loaded its snapshot. Implementations that can provide
a per-session transaction should override this method and perform the
load/merge/save under one lock. The default still reconciles against a
latest snapshot for lightweight/custom SDK persisters; the built-in
storage implementation supplies the atomic variant.
Sourcefn load_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn load_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Load the latest runtime-visible session snapshot when the persistence implementation can coordinate reads. Tools may update a repository-owned clone while an agent loop holds its own live Session; the loop uses this hook to merge narrowly-scoped tool side effects before its next save.
Sourcefn clear_legacy_pending_messages<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
expected: &'life2 [Value],
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn clear_legacy_pending_messages<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
expected: &'life2 [Value],
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Clear the bounded compatibility queue iff it still equals the entries that were durably copied into SessionInbox. Implementations with a per-session transaction should override this method.
Sourcefn append_token_usage_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
json_line: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn append_token_usage_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
json_line: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Append one JSON-line analysis record to the session’s append-only
token-usage log (see Storage::append_token_usage_record). Defaults to
a no-op so non-file-backed persisters are unaffected.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl RuntimeSessionPersistence for LockedSessionStore
Infrastructure implementation of the domain runtime-persistence port.
Server should assemble this as Arc<dyn RuntimeSessionPersistence> and must
not define a separate adapter layer for the same behavior.
impl RuntimeSessionPersistence for LockedSessionStore
Infrastructure implementation of the domain runtime-persistence port.
Server should assemble this as Arc<dyn RuntimeSessionPersistence> and must
not define a separate adapter layer for the same behavior.
fn save_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
LockedSessionStore: 'async_trait,
fn seed_runtime_activation<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
LockedSessionStore: 'async_trait,
fn record_permission_posture_activation<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
expected_audit_revision: Option<u64>,
seed: &'life2 PermissionAuditSeed,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
LockedSessionStore: 'async_trait,
fn save_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
LockedSessionStore: 'async_trait,
fn load_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
LockedSessionStore: 'async_trait,
fn update_task_list_control_plane<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
task_list: &'life2 TaskList,
version: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
LockedSessionStore: 'async_trait,
fn checkpoint_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
LockedSessionStore: 'async_trait,
fn load_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
LockedSessionStore: 'async_trait,
fn clear_legacy_pending_messages<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
expected: &'life2 [Value],
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
LockedSessionStore: 'async_trait,
Source§impl<T> RuntimeSessionPersistence for Arc<T>where
T: RuntimeSessionPersistence + ?Sized,
impl<T> RuntimeSessionPersistence for Arc<T>where
T: RuntimeSessionPersistence + ?Sized,
fn save_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Arc<T>: 'async_trait,
fn seed_runtime_activation<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Arc<T>: 'async_trait,
fn record_permission_posture_activation<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
expected_audit_revision: Option<u64>,
seed: &'life2 PermissionAuditSeed,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Arc<T>: 'async_trait,
fn save_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Arc<T>: 'async_trait,
fn load_runtime_control_plane<'life0, 'life1, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Arc<T>: 'async_trait,
fn update_task_list_control_plane<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
task_list: &'life2 TaskList,
version: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Arc<T>: 'async_trait,
fn checkpoint_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Arc<T>: 'async_trait,
fn load_runtime_session<'life0, 'life1, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Session>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Arc<T>: 'async_trait,
fn clear_legacy_pending_messages<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
expected: &'life2 [Value],
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Arc<T>: 'async_trait,
fn append_token_usage_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session_id: &'life1 str,
json_line: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Arc<T>: 'async_trait,
Implementors§
impl RuntimeSessionPersistence for SessionRepository
SessionRepository is the canonical RuntimeSessionPersistence: the runtime
can persist a session through the same coordinator (merge-on-write + cache
refresh) instead of a bespoke adapter.