Skip to main content

AcpSessionStore

Struct AcpSessionStore 

pub struct AcpSessionStore { /* private fields */ }

Implementations§

Source§

impl AcpSessionStore

Source

pub fn new(workspace_dir: &Path) -> Result<Self>

Source

pub fn create_session( &self, session_uuid: &str, agent_alias: &str, workspace_dir: &str, principal_id: Option<&str>, ) -> Result<i64>

Record a new session stamped with its owning principal (RFC 7141 session isolation). principal_id is the caller’s scope, or None for an unscoped/admin connection (NULL owner => visible only to unscoped connections). Returns the integer id assigned by SQLite.

Source

pub fn create_session_with_interaction_surface( &self, session_uuid: &str, agent_alias: &str, workspace_dir: &str, interaction_surface: Option<&str>, principal_id: Option<&str>, ) -> Result<i64>

Record a session with an optional host-validated interaction surface, stamped with its owning principal (RFC 7141).

Source

pub fn delete_session_owned( &self, session_uuid: &str, owner_principal_id: &str, ) -> Result<bool>

Delete a session ONLY if owner_principal_id matches the stored owner, in one predicated statement (RFC 7141 atomic ownership). Child-row cleanup follows the same cascade as Self::delete_session.

Source

pub fn session_principal( &self, session_uuid: &str, ) -> Result<Option<Option<String>>>

The owning principal of a session, for authorization on mutation paths (RFC 7141 F2) without hydrating its full message history. Returns Ok(None) when the session does not exist, Ok(Some(None)) for a NULL-owner (unscoped/legacy) row, and Ok(Some(Some(id))) when owned.

Source

pub fn session_owner_and_surface( &self, session_uuid: &str, ) -> Result<Option<(Option<String>, Option<String>)>>

Read the owner and interaction surface needed before checkpoint recovery without hydrating a potentially large transcript.

Source

pub fn bind_interaction_surface_if_unset( &self, session_uuid: &str, interaction_surface: &str, ) -> Result<String>

Bind an unlabelled legacy session to a validated surface exactly once. Returns the durable value after the update so the caller can reject a concurrent or pre-existing mismatch.

Source

pub fn load_session(&self, session_uuid: &str) -> Result<Option<AcpSessionData>>

Load session metadata and full message history for restore. Returns None if the session_uuid is not found.

Source

pub fn load_message_page( &self, session_uuid: &str, limit: usize, cursor: Option<&str>, ) -> Result<AcpSessionPage>

Load one bounded page of the projected ACP transcript. Cursor reads hydrate only the durable groups needed for this page; the cursor’s message bound makes later appends invisible to an established walk.

Source

pub fn load_session_for_agent( &self, session_uuid: &str, agent_alias: &str, ) -> Result<Option<AcpSessionData>>

Load a durable ACP transcript only when both its UUID and owning agent match. Keeping the alias predicate in SQL makes an unknown UUID and a UUID owned by another agent indistinguishable to callers. Killed sessions remain readable as history; killing prevents runtime rehydration, not access to retained transcripts by their owner.

Source

pub fn classify_session_for_agent( &self, session_uuid: &str, agent_alias: &str, ) -> Result<AcpSessionAccess>

Classify an exact ACP session key without exposing the foreign owner. Callers use Foreign and Missing to make the same fail-closed response while still avoiding an unsafe fallback to another session backend.

Source

pub fn is_live_session_for_agent( &self, session_uuid: &str, agent_alias: &str, ) -> Result<bool>

Whether session_uuid is a live ACP session owned by agent_alias.

Source

pub fn list_session_ids(&self) -> Result<Vec<String>>

Every durable ACP session key, used only to fail closed when a Chat key collides with the separate ACP namespace.

Source

pub fn load_session_for_restore( &self, session_uuid: &str, ) -> Result<AcpSessionRestore>

Load only durable ACP rows that are allowed to become live sessions. Killed rows keep their transcript for history/export but are terminal for runtime restore paths.

Source

pub fn list_sessions(&self) -> Result<Vec<AcpSessionSummary>>

List restorable sessions as lightweight summaries, ordered by most recent activity first. This is the picker-facing read: it avoids the full message-history hydration that load_session performs. Killed rows keep history/export data but are terminal and must not be offered for restore. Stale projected counts are rescored from the rows first, so the listing never reports a cache another writer left behind.

Source

pub fn list_live_sessions_by_agent( &self, agent_alias: &str, ) -> Result<Vec<AcpSessionSummary>>

List live ACP sessions owned by agent_alias, ordered by most recent activity. Killed rows are omitted from live discovery, but their retained transcripts remain readable through load_session_for_agent and they remain available to export through list_sessions_by_agent.

Source

pub fn contains_session(&self, session_uuid: &str) -> Result<bool>

Source

pub fn append_turn( &self, session_uuid: &str, messages: &[ConversationMessage], ) -> Result<()>

Append all ConversationMessages from one completed turn in one transaction.

Source

pub fn replace_messages( &self, session_uuid: &str, messages: &[ConversationMessage], ) -> Result<()>

Replace a session’s visible transcript while keeping message identity local to the transcript. Native retained provider context uses a separate projection and never calls this method for a trim.

Source

pub fn replace_messages_and_breadcrumb( &self, session_uuid: &str, messages: &[ConversationMessage], breadcrumb_present: bool, ) -> Result<()>

Source

pub fn begin_turn_checkpoint( &self, session_uuid: &str, turn_id: &str, messages: &[ConversationMessage], ) -> Result<()>

Source

pub fn append_turn_checkpoint( &self, session_uuid: &str, turn_id: &str, messages: &[ConversationMessage], ) -> Result<i64>

Source

pub fn persist_retained_context_at_frontier( &self, session_uuid: &str, turn_id: &str, retained_messages: &[ConversationMessage], breadcrumb: bool, frontier: i64, ) -> Result<()>

Persist an owner-observed checkpoint frontier. The frontier is supplied by the serial event consumer after its append transaction; it is never inferred by content comparison or by a delayed global MAX in this path.

Source

pub fn persist_retained_context_seed( &self, session_uuid: &str, retained_messages: &[ConversationMessage], breadcrumb: bool, ) -> Result<()>

Persist a seed-time trim projection. No turn checkpoint exists during restore, so this path verifies only the session identity and commits the owner-produced snapshot before its notification is forwarded.

Source

pub fn checkpoint_frontier( &self, session_uuid: &str, turn_id: &str, ) -> Result<i64>

Source

pub fn finalize_turn_checkpoint_with_context( &self, session_uuid: &str, turn_id: &str, terminal_messages: &[ConversationMessage], retained_messages: &[ConversationMessage], breadcrumb: bool, ) -> Result<()>

Finalize a turn while atomically preserving visible journal fragments, the final provider projection, breadcrumb provenance and checkpoint deletion. Existing transcript rows are never replaced or re-identified.

Source

pub fn finalize_turn_checkpoint_with_context_for_owner( &self, session_uuid: &str, turn_id: &str, terminal_messages: &[ConversationMessage], retained_messages: &[ConversationMessage], breadcrumb: bool, owner_principal_id: Option<&str>, ) -> Result<()>

Finalize only the durable row owned by the expected principal. The owner test and transcript, retained-context, and checkpoint changes occur in the same immediate transaction.

Source

pub fn discard_turn_checkpoint( &self, session_uuid: &str, turn_id: &str, ) -> Result<()>

Source

pub fn finalize_turn_checkpoint( &self, session_uuid: &str, turn_id: &str, messages: &[ConversationMessage], ) -> Result<()>

Source

pub fn recover_turn_checkpoint( &self, session_uuid: &str, interruption_marker: &str, ) -> Result<bool>

Source

pub fn recover_turn_checkpoint_for_owner( &self, session_uuid: &str, interruption_marker: &str, owner_principal_id: Option<&str>, ) -> Result<bool>

Recover an interrupted turn only while the durable row still belongs to owner_principal_id. The owner lookup and all checkpoint changes share one immediate transaction, so a same-ID replacement cannot be recovered under a stale principal authorization.

Source

pub fn bounded_transcript_messages( messages: &[ConversationMessage], ) -> Vec<ConversationMessage>

Apply the transcript’s existing display/storage bound to native tool results before they enter a checkpoint or canonical ACP history.

Source

pub fn bounded_tool_output(output: &str) -> String

Source

pub fn provider_safe_history( messages: &[ConversationMessage], ) -> Vec<ConversationMessage>

Produce provider-safe ACP history while preserving client-visible text. Only an immediately adjacent tool-call/result pair is retained, and one result is kept for each unambiguous call id. Duplicate call or result IDs within a batch are rejected; recovery markers stay transcript-only.

Source

pub fn set_token_count( &self, session_uuid: &str, token_count: u64, ) -> Result<()>

Source

pub fn clear_token_count(&self, session_uuid: &str) -> Result<()>

Clear the durable token snapshot back to the schema’s unknown representation (0). Used when an accepted turn attempt serves a route without token usage: the prior snapshot must not survive, mirroring the client-side meter which clears on accepted usage-less events.

Source

pub fn persist_usage_snapshot( &self, session_uuid: &str, input_tokens: Option<u64>, accepted: bool, ) -> Result<()>

Apply a TurnEvent::Usage to the durable token snapshot. Accepted events with usage overwrite it; accepted usage-less events clear it back to unknown (0) so a resumed session never replays a stale route’s count; rejected billing telemetry never touches the store. Both durable consumers (ACP server, RPC dispatch) route through here so the accepted-gate cannot drift between paths.

Source

pub fn set_trim_breadcrumb( &self, session_uuid: &str, present: bool, ) -> Result<()>

Record whether this session’s persisted transcript currently starts with the synthetic trim breadcrumb, as one canonical fact alongside the transcript. Silently no-ops for an unknown session (matching append_turn’s tolerance for a session removed mid-turn) rather than erroring like set_token_count, since this is best-effort bookkeeping that must never fail a turn.

Source

pub fn set_plan(&self, session_uuid: &str, entries: &[PlanEntry]) -> Result<()>

Persist the session’s latest TodoWrite plan as a JSON array of PlanEntry (whole-list replace). An empty slice stores an empty array (a cleared plan), distinct from SQL NULL (never had one).

Source

pub fn get_plan(&self, session_uuid: &str) -> Result<Vec<PlanEntry>>

Load the session’s stored plan. Returns an empty vec when the session has no plan (NULL or absent). Malformed JSON is treated as an empty plan rather than a hard error, so a corrupt plan column never blocks session restore.

Source

pub fn append_event( &self, session_uuid: &str, action: Action, outcome: EventOutcome, payload: Option<&str>, ) -> Result<()>

Record a session-lifecycle event. Caller passes typed enums; the SQLite layer is the only place strings appear. Same Action / EventOutcome values are used at the matching zeroclaw_log::record! call site.

Source

pub fn delete_session(&self, session_uuid: &str) -> Result<bool>

Delete a session and all its child rows (messages, tool calls, events cascade via FK). Returns true if the session existed.

Source

pub fn count_live_sessions_by_agent(&self, agent_alias: &str) -> Result<usize>

Count live ACP sessions for agent_alias — rows not yet killed (killed_at IS NULL). A non-zero count is a HARD blocker for deleting the agent: the operator must end the sessions first.

Source

pub fn list_sessions_by_agent( &self, agent_alias: &str, ) -> Result<Vec<AcpSessionSummary>>

Summaries of every ACP session (live or killed) attributed to agent_alias, for the export-then-delete archive.

Source

pub fn projected_message_count( &self, session_uuid: &str, ) -> Result<Option<usize>>

Persisted projected conversation-entry count for the session, the same number the session picker lists and turn_end reports. Reading it avoids hydrating the full message history that load_session performs just to re-derive the count; a cache another writer left stale is rescored from the session’s rows here first. None when the session UUID is unknown.

Source

pub fn delete_sessions_by_agent(&self, agent_alias: &str) -> Result<usize>

Delete every ACP session (live or killed) for agent_alias, returning the row count. Child tables (acp_messages/acp_tool_calls/acp_session_events) cascade via their ON DELETE CASCADE FKs (foreign_keys = ON).

Source

pub fn rename_sessions_by_agent(&self, from: &str, to: &str) -> Result<usize>

Re-point every ACP session (live or killed) from from to to, returning the row count. The agent-rename cascadekeeps the session and its transcript; only the owning alias moves. Unlike delete, a live session (killed_at IS NULL) is no obstacle to rename.

Source

pub fn mark_session_killed_atomic( &self, session_uuid: &str, ) -> Result<AcpSessionKillTransition>

Atomically persist that an admin intentionally killed this ACP session. The transcript and any checkpoint stay durable, but runtime rehydration must not revive it.

Source

pub fn mark_session_killed_atomic_for_owner( &self, session_uuid: &str, owner_principal_id: Option<&str>, ) -> Result<AcpSessionKillTransition>

Tombstone only the durable row still owned by this principal. The update predicate and transition inspection share one transaction.

Source

pub fn mark_session_killed(&self, session_uuid: &str) -> Result<bool>

Persist that an admin intentionally killed this ACP session. The transcript stays durable, but runtime rehydration must not revive it. This compatibility wrapper retains the original boolean contract for existing callers; use mark_session_killed_atomic when the distinction between marked, already-killed, and missing matters.

Source

pub fn is_session_killed(&self, session_uuid: &str) -> Result<bool>

Return whether this durable ACP session has been intentionally killed. Missing rows are not killed; callers can then use normal load handling to distinguish SESSION_NOT_FOUND from a terminal killed session.

Source

pub fn touch_session(&self, session_uuid: &str) -> Result<()>

Update last_activity without appending messages.

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
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
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> 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<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