Skip to main content

SessionStore

Struct SessionStore 

pub struct SessionStore {
    pub session_queue: Arc<SessionActorQueue>,
    /* private fields */
}

Fields§

§session_queue: Arc<SessionActorQueue>

Implementations§

Source§

impl SessionStore

Source

pub fn new(max_sessions: usize, session_queue: Arc<SessionActorQueue>) -> Self

Source

pub async fn insert( &self, id: String, session: RpcSession, ) -> Result<u64, &'static str>

Source

pub async fn insert_admitted( &self, admission: &SessionGuard, id: String, session: RpcSession, ) -> Result<u64, &'static str>

Publish a session while the caller already owns the session’s admission permit. handle_session_new drives the whole incarnation — predecessor wait, transcript load, build, publish, history restore — under ONE permit acquisition: the transcript is only read after the predecessor turn has fully finalized, and no prompt can be admitted against the successor until the caller drops its guard after the history restore. Re-acquiring the permit internally (as SessionStore::insert does) would deadlock against the caller’s guard.

This REPLACES any live incarnation already present under id: rehydration legitimately swaps a same-ID successor for the published session while holding the permit, so absence is not required here. The session/new external boundary, which must never overwrite a concurrent incarnation, uses SessionStore::insert_admitted_if_absent instead.

The caller must hold admission for exactly id (debug-asserted) and must keep it alive until the published session is fully restored.

Source

pub async fn insert_admitted_if_absent( &self, admission: &SessionGuard, id: String, session: RpcSession, ) -> Result<u64, &'static str>

Absence-safe variant of SessionStore::insert_admitted for the session/new external boundary, combining the admission permit contract with SessionStore::insert_if_absent’s refusal to overwrite a live incarnation: under the caller’s permit the slot was cleared (or never occupied) before the rebuild began, so a live entry here means a concurrent resume won the race. Two concurrent resume requests therefore cannot silently replace one another.

The caller must hold admission for exactly id (debug-asserted) and must keep it alive until the published session is fully restored.

Source

pub async fn insert_if_absent( &self, id: String, session: RpcSession, ) -> Result<(), &'static str>

Publish a newly constructed session only when no live incarnation is already present. session/new uses this at the external boundary so two concurrent resume requests cannot replace one another, and so a session/new can never replace (and thereby hijack) an existing session’s agent, whoever owns it.

Source

pub async fn insert_for_prompt( &self, id: String, session: RpcSession, cancel_generation: u64, ) -> Result<(), &'static str>

Publish a rehydrated session and bind the admitted prompt’s cancel token to the new incarnation before the session becomes observable.

Source

pub async fn get_agent(&self, id: &str) -> Option<Arc<Mutex<Agent>>>

Source

pub async fn get_generation(&self, id: &str) -> Option<u64>

Return the current generation for the session with id, or None if the session is absent. Provider-refresh callers capture this value before building a provider box and thread it through apply_model_provider so stale work targeting a replaced session becomes a no-op.

Source

pub async fn generation_and_mode(&self, id: &str) -> Option<(u64, ChatMode)>

Snapshot the live session identity under one map lock.

Source

pub async fn owner_generation_and_mode( &self, id: &str, ) -> Option<(Option<String>, u64, ChatMode)>

The owning principal and generation of the LIVE incarnation under id, read together under the store lock. Ownership is a property of one incarnation: an operation that authorized against generation g must find this exact pair again at its admission boundary, or the record it authorized is not the record it is about to act on.

Source

pub async fn matches_generation_and_mode( &self, id: &str, expected: &(u64, ChatMode), ) -> bool

Return whether id still names the captured live incarnation.

Source

pub async fn touch(&self, id: &str)

Source

pub async fn set_overrides( &self, id: &str, patch: SessionOverrides, ) -> Option<SessionOverrides>

Source

pub async fn set_overrides_gated( &self, id: &str, generation: u64, patch: SessionOverrides, ) -> Option<SessionOverrides>

Like set_overrides, but validates generation before mutating the session entry or its agent. Returns None if the session is absent or if it was replaced under the same ID — both cases mean the caller captured a stale generation and the work must be discarded.

Source

pub async fn preview_overrides( &self, id: &str, patch: &SessionOverrides, ) -> Option<SessionOverrides>

Source

pub async fn migrate_model_provider_override( &self, id: &str, generation: u64, new_ref: String, ) -> bool

Rewrite a session’s in-memory model_provider override to a new reference. SessionOverrides is transient session state rather than config, so a provider alias rename does not reach it through the config cascade. Without this migration the override would keep naming an alias that no longer exists, and the next resolution would fall back to compatibility values or fail while rebuilding the old reference. Called from the live-refresh publication step while that session’s model_provider_update guard is held.

generation must match the session’s current generation (same contract as apply_model_provider). A same-ID successor inserted by session/new or ACP rehydration while this refresh was in flight would have a different generation, and the migration must be rejected for it: the successor never requested an alias rename, and a stale refresh must not write its override. Returns true when the migration applied, false when the session was absent or its generation did not match.

Source

pub async fn get_overrides(&self, id: &str) -> Option<SessionOverrides>

Source

pub async fn with_session_uploads<R>( &self, session_id: &str, f: impl FnOnce(&mut HashMap<String, UploadEntry>) -> R, ) -> Option<R>

Run f on the upload index of the live session session_id, holding the session map for the whole call. None, without calling f, when no live session has that id.

f is synchronous, so the dedup lookup, the file write it guards, and the index insert happen with no session change in between.

Source

pub async fn with_incarnation_uploads<R>( &self, session_id: &str, generation: u64, owner: Option<&str>, f: impl FnOnce(&mut HashMap<String, UploadEntry>) -> R, ) -> Option<R>

Self::with_session_uploads for one exact incarnation: f runs only while session_id still names the live session of generation owned by owner. A session closed or deleted, recreated under the same id, or re-owned since the caller resolved it yields None and f is not called.

Source

pub async fn live_incarnation( &self, session_id: &str, ) -> Option<(u64, Option<String>, String)>

The live incarnation of session_id, read in one snapshot: its generation, owning principal, and agent alias. None if no live session has that id.

Source

pub async fn get_workspace_dir(&self, session_id: &str) -> Option<String>

Get the workspace directory for a session.

Source

pub async fn get_agent_alias(&self, session_id: &str) -> Option<String>

Get the agent alias bound to a session, if known. Used by the dispatcher to route uploads to the agent’s own workspace dir rather than to the user’s session cwd (which is often a git repo we shouldn’t be writing into).

Source

pub async fn seed_history(&self, id: &str, msgs: &[ChatMessage])

Source

pub async fn history_has_trim_breadcrumb(&self, id: &str) -> Option<bool>

Whether the session’s in-memory agent currently believes its history starts with the synthetic trim breadcrumb. None if the session is unknown. Callers persist this alongside the transcript so a later restore never has to infer provenance from message text.

Source

pub async fn set_history_has_trim_breadcrumb(&self, id: &str, present: bool)

Restore the session’s own canonical breadcrumb-provenance record onto its in-memory agent. No-op if the session is unknown.

Source

pub async fn seed_history_with_event( &self, id: &str, msgs: &[ChatMessage], ) -> Option<TurnEvent>

Source

pub async fn set_plan(&self, id: &str, entries: Vec<PlanEntry>)

Replace the session’s execution plan wholesale (TodoWrite whole-list semantics). No-op if the session is unknown.

Source

pub async fn get_plan(&self, id: &str) -> Option<Vec<PlanEntry>>

Current stored plan for a session. None if the session is unknown; Some(empty) if the session exists with no/cleared plan.

Source

pub async fn seed_conversation_history( &self, id: &str, msgs: Vec<ConversationMessage>, )

Source

pub async fn seed_conversation_history_with_event( &self, id: &str, msgs: Vec<ConversationMessage>, ) -> Option<TurnEvent>

Source

pub async fn chat_mode(&self, id: &str) -> Option<ChatMode>

Source

pub async fn history_len(&self, id: &str) -> Option<usize>

Source

pub async fn history_slice_from( &self, id: &str, from: usize, ) -> Option<Vec<ConversationMessage>>

Source

pub async fn remove(&self, id: &str) -> bool

Source

pub async fn remove_generation(&self, id: &str, generation: u64) -> bool

Remove the live incarnation under id only if it is still the one with generation. A successor installed under the same id after the caller authorized its predecessor is left untouched, and the caller learns the removal did not happen.

Source

pub async fn evict_same_mode_sibling( &self, tui_id: &str, chat_mode: &ChatMode, except_id: &str, ) -> Vec<(String, String)>

Source

pub async fn session_owner_tui_id( &self, session_id: &str, ) -> Option<Option<String>>

Read the owner_tui_id stamp from a session. Returns None if the session doesn’t exist, Some(None) if it exists but is unowned (e.g. created by an anonymous connection), Some(Some(id)) if owned by id.

Source

pub async fn session_owner_principal( &self, session_id: &str, ) -> Option<Option<String>>

Read the owning-principal stamp from a LIVE session. Same tri-state contract as Self::session_owner_tui_id.

Source

pub async fn session_access_snapshot( &self, session_id: &str, ) -> Option<(u64, Option<String>)>

Capture the incarnation and owner checked by a session-scoped request. Callers that wait on another ordering boundary can compare this with a later snapshot so an authorized request cannot act on a same-ID successor.

Source

pub async fn list_ids(&self) -> Vec<String>

Source

pub async fn list_ids_for_owner(&self, owner_tui_id: &str) -> Vec<String>

Source

pub fn register_cancel_token(&self, id: &str, token: CancellationToken) -> u64

Source

pub fn remove_cancel_token(&self, id: &str, generation: u64)

Source

pub async fn cancel_all_inflight_and_wait(&self, cause: CancelCause)

Cancel every active turn and wait until each owner has removed its registration. Earlier cancellation causes remain authoritative.

Source

pub fn cancel_session(&self, id: &str) -> bool

Source

pub fn abort_session(&self, id: &str) -> bool

Interrupt the session’s running turn on an operator’s behalf. Unlike Self::cancel_session it is not tied to the owning client.

Source

pub fn abort_session_for_generation( &self, id: &str, session_generation: Option<u64>, ) -> bool

Self::abort_session bound to the live session incarnation the caller was authorized against: a turn belonging to any other incarnation under the same id (a same-id successor) is left running.

Source

pub async fn signal_cancellation_for_incarnation( &self, id: &str, expected_generation: Option<u64>, cause: CancelCause, ) -> Option<bool>

Signal only the session incarnation observed by the caller.

Holding the session map lock across the generation check and token signal prevents a same-ID replacement from receiving a stale request’s cancellation.

Source

pub fn signal_session_removal(&self, id: &str) -> bool

Signal an in-flight turn before a close/delete handler waits for the session admission permit. The handler removes the session only after the admitted prompt has finalized under its original incarnation.

Source

pub fn signal_session_removal_for_generation( &self, id: &str, session_generation: Option<u64>, ) -> bool

Signal removal only when the in-flight turn belongs to the captured live session incarnation. A stale close must not cancel a same-ID successor that registered its prompt before the close acquired admission.

Source

pub fn signal_session_kill_for_generation( &self, id: &str, session_generation: Option<u64>, ) -> bool

Signal an administrative kill only when the in-flight turn belongs to the captured live session incarnation.

Source

pub fn signal_session_kill(&self, id: &str) -> bool

Signal an in-flight turn before an administrative kill waits for the session admission permit.

Source

pub fn steer_session_for_generation( &self, id: &str, session_generation: Option<u64>, input: SteeringInput, ) -> SteerOutcome

Queue a steering message for the session’s running turn, but only if that turn belongs to the live session incarnation the caller was authorized against. The turn’s registration (which records the incarnation it runs in) and its steering sender are read and the message is queued in one critical section, so a same-id successor that replaced the authorized incarnation never receives it.

Source

pub fn has_inflight_turn(&self, id: &str) -> bool

Returns true if a cancel token is registered — i.e. a turn is in flight.

Source

pub fn inflight_turn_generation(&self, id: &str) -> Option<u64>

Generation of the runtime-owned turn currently executing for a session. This is the authoritative live-turn identity for RPC status; persisted session metadata is not updated on every RPC turn.

Source

pub async fn kill_session(&self, id: &str) -> bool

Source

pub async fn kill_session_generation(&self, id: &str, generation: u64) -> bool

Self::kill_session bound to one incarnation: kills only if the live record under id still carries generation.

Source

pub fn record_cancel_cause(&self, id: &str, cause: CancelCause)

Record the cause for an imminent cancel-token fire. Call immediately before firing so the verdict site can attribute the cancel.

Source

pub fn record_cancel_cause_if_absent(&self, id: &str, cause: CancelCause)

Record a fallback cause without overwriting a more specific cancel that won the race (for example an explicit client cancel immediately before the transport disconnects).

Source

pub fn take_cancel_cause(&self, id: &str) -> Option<CancelCause>

Drain the recorded cancel cause for a session. Returns None only when no cancel actually fired (clean completion); every firing path records before token.cancel(), so Some(_) after a fired token is the invariant the verdict audit relies on.

Source

pub async fn count(&self) -> usize

Source

pub async fn count_by_agent(&self) -> HashMap<String, usize>

Count active sessions grouped by agent alias.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more