Gateway Session Persistence
Persistent gateway sessions that survive restarts, with reconnect and event replay
Persistent sessions keep conversation state alive across gateway restarts and let clients resume mid-conversation with event replay.
from praisonaiagents import Agent
agent = Agent(name="assistant", instructions="Be helpful")
# Persistence is on by default — this agent's session survives gateway restartsThe user returns later; persisted session state reloads so the agent remembers prior turns.
Quick Start
- Persistence is on by default
No
session:block is required — persistence engages automatically:yaml gateway: host: "127.0.0.1" port: 8765bash praisonai gateway start --config gateway.yamlDefault storage:
~/.praisonai/sessions/sessions.dbOpt out for ephemeral, in-memory sessions:
yaml # Ephemeral sessions (explicit opt-out) gateway: session: persist: false - Resume as a client
python import asyncio import json import websockets async def resume(session_id: str, since: int): async with websockets.connect("ws://127.0.0.1:8765") as ws: await ws.send(json.dumps({ "type": "join", "agent_id": "assistant", "session_id": session_id, "since": since, })) while True: msg = json.loads(await ws.recv()) if msg.get("type") == "joined" and msg.get("resumed"): print("Resumed at cursor", msg.get("cursor")) if msg.get("type") == "replay": print("Replay:", msg.get("event")) asyncio.run(resume("abc-123", 42)) - Full configuration
yaml gateway: session: persist: true # default — shown here for completeness persist_path: ~/.praisonai/sessions/ resume_window: 86400 timeout: 3600 max_messages: 1000 max_inbox: 256
What gets persisted
The on-disk record under persist_path is the JSON returned by GatewaySession.to_dict(). Key fields:
| Key | Type | Purpose | |
|---|---|---|---|
session_id | str | Stable identifier; used on resume | |
event_cursor | int | Position in the event log for replay | |
sequence | int | Monotonic outbound sequence (gap detection) | |
protocol_version | int | Protocol version negotiated at the last handshake | |
capabilities | List[str] | Capability tokens advertised by the client (streaming, presence, ack, …) | |
events | List[GatewayEvent] | Last 100 events (for replay) | |
pending_inbox | List[...] | In-flight inbound queue snapshot | |
is_executing | bool | Mid-turn flag for Session Continuity | |
channel_target | `str \ | None` | "channel:target" origin used by Restart Continuation to notify channel users; None for direct-client sessions |
How it works
| Role | Responsibility |
|---|---|
| Client | Track highest cursor; send since on reconnect |
| Gateway | Rehydrate sessions; emit replay frames |
| SessionStore | Persist state to disk |
| TTL cleanup | Hourly purge of expired sessions |
Reconnect protocol
Client join (resume):
{ "type": "join", "agent_id": "assistant", "session_id": "abc-123", "since": 42 }Server joined:
{ "type": "joined", "session_id": "abc-123", "agent_id": "assistant", "resumed": true, "cursor": 57 }Replay frames:
{ "type": "replay", "event": { "...": "..." } }Configuration options
| Option | Type | Default | Description |
|---|---|---|---|
persist | bool | true | Persist session state. Defaults to true — an out-of-the-box gateway remembers conversations across restarts via the SQLite transcript store. Set false to opt into ephemeral, in-memory sessions |
persist_path | str | ~/.praisonai/sessions/ | Storage directory |
store | str | "sqlite" | Transcript backend — "sqlite" (SQLite Transcript Store) or "file" (legacy JSON) |
resume_window | int | 86400 | Seconds a detached session stays resumable (24 h) |
timeout | int | 3600 | Active session expiry in seconds |
max_messages | int | 1000 | History cap per session |
max_inbox | int | 256 | Bounded per-session queue size; 0 = unlimited |
mirror_runtime_state | bool | false | Opt-in runtime-state mirroring for native transcript replay |
Common patterns
Python override:
from praisonai.gateway.server import WebSocketGateway
from praisonaiagents.session.store import DefaultSessionStore
gateway = WebSocketGateway(
port=8765,
session_store=DefaultSessionStore("./sessions"),
)An explicit session_store always wins over the YAML/default derivation.
CLI opt-out now honoured: session.persist: false in gateway.yaml is re-read on start_with_config, so the multi-bot CLI now actually runs ephemeral (previously the flag was silently ignored).
Choosing resume_window: minutes for ephemeral chat, 24 h for support bots, up to 7 days for long tasks.
Best Practices
Opt out only when you need to
The default is durable because most conversational bots want continuity. Only set persist: false for stateless, single-shot flows or ephemeral CI runs.
Confirm the on-disk store engaged
Expect the transcript DB at ~/.praisonai/sessions/sessions.db. If the doctor or logs report an in-memory fallback, $HOME is unwritable.
Always send since on reconnect
Without since, the client may miss events between disconnect and resume.
Match resume_window to user behaviour
Too short loses conversations; too long grows disk usage.
Back up persist_path
Session files should be included in normal backup rotation.
One gateway per persist_path
Do not share storage between two gateway processes — see Gateway Overview single-instance guidance.
Related
Gateway setup and configuration
SQLite Transcript StoreThe default persistence backend, engaged out-of-the-box
Gateway Session ContinuityPreserve pending inbox and mid-turn state across disconnects
Restart ContinuationNotify channel users after a gateway restart
Write-failure salvageSpill + re-ingest when a durable session write fails