Skip to main content

AssistantSessionStore

Trait AssistantSessionStore 

Source
pub trait AssistantSessionStore:
    Send
    + Sync
    + 'static {
    // Required methods
    fn put_assistant_session<'life0, 'async_trait>(
        &'life0 self,
        record: AssistantSessionRecord,
    ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn get_assistant_session<'life0, 'life1, 'async_trait>(
        &'life0 self,
        session_id: &'life1 AssistantSessionId,
    ) -> Pin<Box<dyn Future<Output = Result<Option<AssistantSessionRecord>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn list_assistant_sessions<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<AssistantSessionListing, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn append_assistant_transcript_event<'life0, 'life1, 'async_trait>(
        &'life0 self,
        session_id: &'life1 AssistantSessionId,
        recorded_at: DateTime<Utc>,
        payload: Payload,
    ) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn assistant_transcript_head<'life0, 'life1, 'async_trait>(
        &'life0 self,
        session_id: &'life1 AssistantSessionId,
    ) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn assistant_transcript<'life0, 'life1, 'async_trait>(
        &'life0 self,
        session_id: &'life1 AssistantSessionId,
        after: Option<u64>,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<AssistantTranscriptEvent>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn put_assistant_default_harness<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        subject: &'life1 str,
        harness: &'life2 str,
    ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn assistant_default_harness<'life0, 'life1, 'async_trait>(
        &'life0 self,
        subject: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
}
Expand description

Durable assistant-session persistence contract.

Implemented by every backend and exercised by crate::conformance::run_assistant_session_suite against all of them, so the index-assignment and poisoned-row guarantees are properties of the CONTRACT rather than of whichever backend a deployment happens to run.

Required Methods§

Source

fn put_assistant_session<'life0, 'async_trait>( &'life0 self, record: AssistantSessionRecord, ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Create or replace a session’s record.

Source

fn get_assistant_session<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 AssistantSessionId, ) -> Pin<Box<dyn Future<Output = Result<Option<AssistantSessionRecord>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Look up one session by id.

Source

fn list_assistant_sessions<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<AssistantSessionListing, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List decodable sessions and report every undecodable row, ordered by created_at then session id.

Unfiltered: a store enumerates what it holds, and the per-caller narrowing is the server’s authorization decision, made where the caller identity is.

Source

fn append_assistant_transcript_event<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 AssistantSessionId, recorded_at: DateTime<Utc>, payload: Payload, ) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Append one event to a session’s transcript, returning the index the store assigned it.

The index is the store’s to give: it is the next index after the last stored one, committed under the backend’s optimistic-concurrency discipline so two appenders racing on one session get n and n+1 and never n twice. A caller cannot pass an index and so cannot mint a duplicate.

§Errors

StoreError::AssistantSessionNotFound when no record exists for session_id — an append never silently creates a session, because a transcript with no record is a conversation with no owner. Otherwise a backend or serialization error.

Source

fn assistant_transcript_head<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 AssistantSessionId, ) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

The next index the store would assign this session — equivalently, how many events its transcript holds.

An unwritten transcript reads 0. Cheap on every backend (it reads stream metadata, never the events), which is what lets a listing find each session’s last record without reading its whole conversation.

Source

fn assistant_transcript<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 AssistantSessionId, after: Option<u64>, ) -> Pin<Box<dyn Future<Output = Result<Vec<AssistantTranscriptEvent>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

A session’s transcript in index order, excluding every event at or below after.

None reads the whole transcript. An unknown session reads empty rather than refusing: a read of a session that is not there is an absence, and the refusal that matters is on the WRITE.

Source

fn put_assistant_default_harness<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, subject: &'life1 str, harness: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Remember the harness subject last opened a session on.

Written by createSession and by nothing else: the memory is a record of what the operator DID, not a preference they set, so there is no second door through which it could say something a session never said.

It lives in the store rather than in the process because it must survive a restart — an operator who picked Claude Code yesterday must not be asked again this morning — and CALLER-scoped because it is one person’s last choice, not a deployment default.

Source

fn assistant_default_harness<'life0, 'life1, 'async_trait>( &'life0 self, subject: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

The harness subject last opened a session on, or None before any.

None is a complete answer and never a fallback: a caller who has picked nothing has picked nothing, and a surface that invented a default here would be reporting a choice its operator never made.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§