Skip to main content
Session stores persist chat history and metadata — swap the default JSON backend or use hierarchical forks without changing your agent code.
SqliteSessionStore (this page) and SqliteTranscriptStore (see SQLite Transcript Store) are two different types. SqliteSessionStore adds an FTS5 search index for scalable cross-session recall; SqliteTranscriptStore replaces persistence with WAL SQLite for gateway concurrency and is the default gateway backend as of PraisonAI PR #3409. Choose one — running both against the same DB file is not tested.
As of PraisonAI PR #3637, AgentTeam.save_session_state / restore_session_state also route through this store (via update_session_metadata / get_session), so team resume is now memory-independent.
As of PraisonAI PR #3648, DefaultSessionStore also accepts a mirror= sink implementing SessionMirrorProtocol — every persisted record is additionally replicated to the mirror on a background thread, local-first (a mirror outage never blocks the turn). Default mirror=None keeps the store byte-for-byte unchanged.
The user chats across restarts; the session store persists history under ~/.praisonai/sessions/.

How It Works

Where sessions are stored

The session directory is resolved live from PRAISONAI_HOME, so relocating the store root works even after PraisonAI is imported (PraisonAI PR #4125). Resolution order (highest priority first): Set PRAISONAI_HOME before the first turn to redirect storage — it is honoured live, even after praisonaiagents is imported:
get_default_session_store() tracks the resolved directory and rebuilds the process-wide singleton when that directory changes — so a multi-tenant host that switches PRAISONAI_HOME at runtime gets the correct per-tenant directory. A store you inject (praisonaiagents.session.store._default_store = my_store) is always honoured verbatim and never rebuilt.
This is a fix relative to older releases. Before PraisonAI PR #4125, PRAISONAI_HOME set after import was silently ignored and the store could read, write, and delete sessions in the wrong directory. Set PRAISONAI_HOME at process start for deterministic behaviour.
DEFAULT_SESSION_DIR remains a readable, assignable module attribute — but is now resolved at access time. Reading it returns the live directory; assigning it (store_module.DEFAULT_SESSION_DIR = "/some/path") pins the root process-wide.

Quick Start

1

Persist with session_id

Default files live at ~/.praisonai/sessions/{session_id}.json.
2

Use the store directly

Sub-agent transcripts live inside the parent session’s record (PraisonAI PR #4126). Transcripts from session.Agent(name, role=...) are persisted under metadata["agent_histories"][agent_key] on the parent session — not as separate top-level sessions. You don’t need to do anything: they round-trip automatically with the parent.Restore reads, in order:
  1. The parent record’s agent_histories map (always wins on key collisions).
  2. Tagged legacy per-agent records (parent_session_id + agent_key) — migrated forward into the parent’s agent_histories on the next save. Migration scans every stored session, not just recent ones, so a tagged record is always picked up no matter how many newer sessions sit above it (PraisonAI PR #4162 — before this, records outside the default 50-session recency window were silently skipped).
  3. Untagged pre-tag records — only when PRAISONAI_SESSION_LEGACY_AGENT_KEYS=1 is set (accepts 1 / true / yes / on, case-insensitive; default off). Otherwise they are ignored — a warning names the exact record — because their sanitised id "{parent}_{agent_key}" is indistinguishable from a real user session of that name.
Legacy records are never deleted. Concurrent saves under the same parent are safe (bounded read-verify-write, up to 5 retries). list_sessions() still surfaces agent_key / parent_session_id, now used for legacy-record discovery. The full-store scan runs at most once per Session instance — the result is memoised, keyed on PRAISONAI_SESSION_LEGACY_AGENT_KEYS, so restoring N sub-agents costs one scan, not N.
Set PRAISONAI_SESSION_LEGACY_AGENT_KEYS=1 only when you know which records on disk are legacy sub-agent transcripts. An untagged id like "chat_support_agent" may in fact be a real user session of that sanitised name.

Core Exports

DefaultSessionStore constructor

SqliteSessionStore

SqliteSessionStore is a drop-in subclass of DefaultSessionStore that keeps JSON transcripts as the durable record and maintains a stdlib sqlite3 index alongside them. It gives you two indexed hot paths instead of directory scans:
  • Cross-session search — FTS5 index of message content, used by search() (Issue #2927).
  • Gateway/agent routingsession_route index of gateway_session_id and agent_id, used by get_by_gateway_session() and list_sessions_by_gateway_agent() (Issue #2956).
Both stay independent of the number of stored sessions, so a long-lived gateway bot with thousands of sessions still routes an inbound message in a single indexed lookup.

Constructor

Behaviour

Fallback matrix

Sizing

  • Each row in session_fts holds the flattened concatenation of a session’s message content (newline-joined). Large transcripts increase index size roughly linearly.
  • Use ":memory:" for ephemeral tests; use the default disk path for gateway bots that need durability across restarts.
Bookends, automated demotion, and lineage dedup apply to results from both stores — see Cross-Session Recall.

Compaction Checkpoints

When context compaction runs during a conversation, the store can persist the summary so a later resume replays the compacted working history (summary + retained tail) instead of the full raw transcript. See Compacted Session Resume for the end-to-end agent flow.

Store Methods

SessionData additions

SessionData.last_compaction holds the latest CompactionCheckpoint (or None). Two helpers support cheap resume:
set_chat_history() and clear_session() both clear last_compaction — replacing or clearing the transcript invalidates the anchor.

Task-Local Context

Best Practices

Let Agent(memory={"session_id": "..."}) handle persistence — use the store directly only for admin, migration, or custom backends.
Switch to get_hierarchical_session_store() when you need branching conversations or revert — see Session Hierarchy.
Call set_session_context() at the start of each async task so downstream code reads the correct session without threading IDs through every call.

Session Persistence

Agent-centric session_id usage

Session Hierarchy

Forking and snapshots

Cross-Session Recall

Search past sessions — anchored, demoted, deduped results