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.

python
from praisonaiagents import Agent

agent = Agent(name="assistant", instructions="Be helpful")
# Persistence is on by default — this agent's session survives gateway restarts

The user returns later; persisted session state reloads so the agent remembers prior turns.

Diagram

Active session

Disconnect

Persisted store

Reconnect + since cursor

Rehydrate + replay

Quick Start

  1. Persistence is on by default

    No session: block is required — persistence engages automatically:

    yaml
    gateway:
      host: "127.0.0.1"
      port: 8765
    bash
    praisonai gateway start --config gateway.yaml

    Default storage: ~/.praisonai/sessions/sessions.db

    Opt out for ephemeral, in-memory sessions:

    yaml
    # Ephemeral sessions (explicit opt-out)
    gateway:
      session:
        persist: false
  2. 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))
  3. 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:

KeyTypePurpose
session_idstrStable identifier; used on resume
event_cursorintPosition in the event log for replay
sequenceintMonotonic outbound sequence (gap detection)
protocol_versionintProtocol version negotiated at the last handshake
capabilitiesList[str]Capability tokens advertised by the client (streaming, presence, ack, …)
eventsList[GatewayEvent]Last 100 events (for replay)
pending_inboxList[...]In-flight inbound queue snapshot
is_executingboolMid-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

Diagram
SessionStoreGatewayClientSessionStoreGatewayClientjoin (new session)joined + cursor eventsleave / disconnectpersist session + TTLjoin (session_id, since)load sessionjoined (resumed=true)replay events
RoleResponsibility
ClientTrack highest cursor; send since on reconnect
GatewayRehydrate sessions; emit replay frames
SessionStorePersist state to disk
TTL cleanupHourly purge of expired sessions

Reconnect protocol

Client join (resume):

json
{ "type": "join", "agent_id": "assistant", "session_id": "abc-123", "since": 42 }

Server joined:

json
{ "type": "joined", "session_id": "abc-123", "agent_id": "assistant", "resumed": true, "cursor": 57 }

Replay frames:

json
{ "type": "replay", "event": { "...": "..." } }

Configuration options

OptionTypeDefaultDescription
persistbooltruePersist 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_pathstr~/.praisonai/sessions/Storage directory
storestr"sqlite"Transcript backend — "sqlite" (SQLite Transcript Store) or "file" (legacy JSON)
resume_windowint86400Seconds a detached session stays resumable (24 h)
timeoutint3600Active session expiry in seconds
max_messagesint1000History cap per session
max_inboxint256Bounded per-session queue size; 0 = unlimited
mirror_runtime_stateboolfalseOpt-in runtime-state mirroring for native transcript replay

Common patterns

Python override:

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

Diagram

No

Yes

Yes

Need ephemeral sessions?

Default: persist: true

persist: false

Frequent reconnects?

Tune resume_window

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