Skip to main content

Persistence

Trait Persistence 

Source
pub trait Persistence: Send + Sync {
Show 29 methods // Required methods fn create_session<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, agent_name: &'life1 str, project_root: &'life2 Path, ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn list_sessions<'life0, 'life1, 'async_trait>( &'life0 self, limit: i64, project_root: &'life1 Path, ) -> Pin<Box<dyn Future<Output = Result<Vec<SessionInfo>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn delete_session<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn set_session_title<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, title: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn set_session_mode<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, mode: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn get_session_mode<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_session_idle_secs<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<i64>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn insert_message<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>( &'life0 self, session_id: &'life1 str, role: &'life2 Role, content: Option<&'life3 str>, tool_calls: Option<&'life4 str>, tool_call_id: Option<&'life5 str>, usage: Option<&'life6 TokenUsage>, ) -> Pin<Box<dyn Future<Output = Result<i64>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait; fn insert_message_with_agent<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'life7, 'async_trait>( &'life0 self, session_id: &'life1 str, role: &'life2 Role, content: Option<&'life3 str>, tool_calls: Option<&'life4 str>, tool_call_id: Option<&'life5 str>, usage: Option<&'life6 TokenUsage>, agent_name: Option<&'life7 str>, ) -> Pin<Box<dyn Future<Output = Result<i64>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait, 'life7: 'async_trait; fn insert_tool_message_with_full<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, session_id: &'life1 str, content: &'life2 str, tool_call_id: &'life3 str, full_content: &'life4 str, ) -> Pin<Box<dyn Future<Output = Result<i64>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait; fn load_context<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<Message>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn load_all_messages<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<Message>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn recent_user_messages<'life0, 'async_trait>( &'life0 self, limit: i64, ) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn last_assistant_message<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn last_user_message<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn has_pending_tool_calls<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn mark_message_complete<'life0, 'async_trait>( &'life0 self, message_id: i64, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn copy_messages_into_session<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, dst_session: &'life1 str, messages: &'life2 [Message], ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn update_message_thinking_content<'life0, 'life1, 'async_trait>( &'life0 self, message_id: i64, content: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn session_token_usage<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<SessionUsage>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn session_usage_by_agent<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<(String, SessionUsage)>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn compact_session<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, summary: &'life2 str, preserve_count: usize, ) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn clear_message_content<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, message_ids: &'life1 [i64], stub: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn compacted_stats<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<CompactedStats>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn purge_compacted<'life0, 'async_trait>( &'life0 self, min_age_days: u32, ) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn get_metadata<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, key: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn set_metadata<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, session_id: &'life1 str, key: &'life2 str, value: &'life3 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait; fn get_todo<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn set_todo<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, content: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait;
}
Expand description

Core storage contract for sessions, messages, and metadata.

Required Methods§

Source

fn create_session<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, agent_name: &'life1 str, project_root: &'life2 Path, ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Create a new session, returning its unique ID.

Source

fn list_sessions<'life0, 'life1, 'async_trait>( &'life0 self, limit: i64, project_root: &'life1 Path, ) -> Pin<Box<dyn Future<Output = Result<Vec<SessionInfo>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

List recent sessions for the given project root.

Source

fn delete_session<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Delete a session by ID. Returns true if it existed.

Source

fn set_session_title<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, title: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Set the auto-generated title for a session.

Source

fn set_session_mode<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, mode: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Persist the current approval mode for a session (restored on resume).

Source

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

Get the stored approval mode for a session.

Source

fn get_session_idle_secs<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<i64>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Seconds elapsed since the session was last accessed (last_accessed_at). Returns None if the column is NULL (session never had a context load).

Source

fn insert_message<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>( &'life0 self, session_id: &'life1 str, role: &'life2 Role, content: Option<&'life3 str>, tool_calls: Option<&'life4 str>, tool_call_id: Option<&'life5 str>, usage: Option<&'life6 TokenUsage>, ) -> Pin<Box<dyn Future<Output = Result<i64>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait,

Insert a message into a session.

Source

fn insert_message_with_agent<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'life7, 'async_trait>( &'life0 self, session_id: &'life1 str, role: &'life2 Role, content: Option<&'life3 str>, tool_calls: Option<&'life4 str>, tool_call_id: Option<&'life5 str>, usage: Option<&'life6 TokenUsage>, agent_name: Option<&'life7 str>, ) -> Pin<Box<dyn Future<Output = Result<i64>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait, 'life7: 'async_trait,

Insert a message with an explicit agent name (for sub-agent tracking).

Source

fn insert_tool_message_with_full<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, session_id: &'life1 str, content: &'life2 str, tool_call_id: &'life3 str, full_content: &'life4 str, ) -> Pin<Box<dyn Future<Output = Result<i64>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait,

Insert a tool message with full (untruncated) output stored separately.

content holds the model-facing summary; full_content holds the complete output for later retrieval via RecallContext.

Source

fn load_context<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<Message>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Load active (non-compacted) conversation context for a session.

Source

fn load_all_messages<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<Message>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Load all messages in a session (no token limit).

Source

fn recent_user_messages<'life0, 'async_trait>( &'life0 self, limit: i64, ) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Recent user messages across all sessions (for startup hints).

Source

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

Last assistant message in a session.

Source

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

Last user message in a session.

Source

fn has_pending_tool_calls<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Check if the session has unresolved tool calls.

Source

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

Mark an assistant message as fully delivered.

Sets completed_at = CURRENT_TIMESTAMP. Only called after a legitimate StreamChunk::Done — not after user cancellation or a network error. A NULL completed_at means the message is in-progress or was interrupted.

Source

fn copy_messages_into_session<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, dst_session: &'life1 str, messages: &'life2 [Message], ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Atomically copy a slice of pre-loaded messages into a session.

Used by fork sub-agent dispatch (#1022 B20). Pre-fix, the fork path looped over Persistence::insert_message row-by-row — each iteration was 2 queries (INSERT + UPDATE last_accessed_at) plus, for assistant rows, a separate mark_message_complete (1 more query). For an N-message parent history that’s ~3N round-trips to SQLite, each its own commit, on the synchronous fork hot path.

This method:

  • Wraps every INSERT in a single transaction (one fsync at COMMIT instead of N).
  • Sets completed_at = datetime('now') inline at INSERT time for Role::Assistant rows, eliminating the separate mark_message_complete round-trip per row.
  • Updates last_accessed_at on the destination session exactly once at the end (not per-row).

Token usage stats are intentionally not copied: fork creates a new conversation perspective and cost-attributing parent tokens to the child would double-count session usage. Same policy as the pre-fix loop, which passed usage = None for every copied row.

Source

fn update_message_thinking_content<'life0, 'life1, 'async_trait>( &'life0 self, message_id: i64, content: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Persist thinking/reasoning text for an assistant message.

Called only for Claude with extended thinking enabled. All other providers leave thinking_content NULL.

Source

fn session_token_usage<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<SessionUsage>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Token usage totals for a session.

Source

fn session_usage_by_agent<'life0, 'life1, 'async_trait>( &'life0 self, session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<(String, SessionUsage)>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Token usage broken down by agent name.

Source

fn compact_session<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, summary: &'life2 str, preserve_count: usize, ) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Compact old messages into a summary, preserving the last N messages.

Source

fn clear_message_content<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, message_ids: &'life1 [i64], stub: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Replace message content for the given IDs with a stub string. Used by microcompact to clear old tool results without full compaction.

Source

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

Stats about compacted (archived) messages across all sessions.

Source

fn purge_compacted<'life0, 'async_trait>( &'life0 self, min_age_days: u32, ) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Permanently delete compacted messages older than min_age_days. Returns the number of messages deleted.

Source

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

Get a session metadata value by key.

Source

fn set_metadata<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, session_id: &'life1 str, key: &'life2 str, value: &'life3 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Set a session metadata value.

Source

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

Get the TODO list for a session.

Source

fn set_todo<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session_id: &'life1 str, content: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Set the TODO list for a session.

Implementors§