Gateway Durable Runs
Gateway agents journal every turn so an interrupted turn can be resumed by run id β recorded tool results replay instead of re-firing side effects
Gateway agents journal every turn by default, so an interrupted turn can be resumed by run id without re-firing side-effecting tools or re-billing LLM calls. The gateway does not auto-resume on restart β you resume a turn yourself with ExecutionConfig(durable=True, resume_run_id=..., journal_path=...), the same journal, and the recorded task (see Resuming an interrupted turn). No flag needed for journalling β it auto-enables whenever your session store is durable (the shipped default). Two explicit opt-outs are supported for the zero-overhead path.
Quick Start
- Zero-config default (every turn is journalled)
Sessions persist by default, so durable runs are already on β no
gateway:block required:yaml # gateway.yaml agents: order_processor: instructions: "Charge the card and ship the order." tools: [charge_card, ship_order, notify_customer]Restart the gateway mid-run; the interrupted turn is left
runningin theRunJournal. To finish it without re-charging the card or re-billing the model, resume it by run id β see Resuming an interrupted turn. - Opt out (zero-overhead path)
Two explicit escape hatches turn durable runs off:
yaml # gateway.yaml β either one opts out gateway: durable_runs: false # explicit off # reliability: "off" # immediate-teardown posture also forces offIn-memory sessions disable it too β with
session.persist: falsethere is no durable store to journal against, so durable runs silently stay off. - Override per agent
A per-agent
durableflag wins in both directions β opt one agent out even when the gateway default is on, or opt one in even when it’s off:yaml gateway: durable_runs: false # gateway-wide off agents: order_processor: instructions: "Charge the card and ship the order." durable: true # this one agent is durable chit_chat: instructions: "Small talk only." # inherits the gateway default (non-durable) - Toggle the default off from the environment
gateway.durable_runsaccepts an${ENV_VAR}-substituted string. Because${DURABLE}renders as a string, the value is coerced explicitly β"false"/"0"/"no"/"off"/""disable, and"true"/"1"/"yes"/"on"enable:yaml # ${DURABLE} β "false" from the environment gateway: durable_runs: ${DURABLE} # "false"/"0"/"no"/"off"/"" disable; "true"/"1"/"yes"/"on" enable
How It Works
Each gateway agent journals its turn to the core RunJournal whenever durable runs are on β decided from config plus the effective session store. Resuming is a separate, manual step: a turn resumed by run id replays journalled steps and runs only the un-journalled ones.
| Role | Responsibility |
|---|---|
| Gateway | Consults gateway.durable_runs when explicitly set; otherwise auto-enables when the effective session store is durable (self._session_store is not None) |
| Agent | Journals every model and tool boundary to the core journal |
| RunJournal | Records results so a turn resumed by run id replays instead of re-executing |
Per-agent durable | Overrides the gateway default for a single agent |
Choosing whether durable runs run
Precedence ladder: per-agent durable > explicit gateway.durable_runs > gateway.reliability: "off" (forces off) > effective session store (auto-on when durable, off when in-memory).
Resuming an interrupted turn
Nothing resumes interrupted turns automatically. List them from the journal and resume each with its recorded task:
from praisonaiagents import Agent, ExecutionConfig
from praisonaiagents.runtime import RunJournal
journal = RunJournal() # default ~/.praisonai/runs/journal.db β pass the gateway's journal_path if set
for run_id in journal.interrupted_runs():
meta = journal.run_meta(run_id)
agent = Agent(
name=meta.agent,
instructions="Charge the card and ship the order.",
execution=ExecutionConfig(durable=True, resume_run_id=run_id),
)
agent.chat(meta.task) # must be the recorded taskHow to opt out
There are three ways to end up with durable_runs=false, plus one silent fallback:
- Explicit off β set
gateway.durable_runs: false. - Reliability off β set
gateway.reliability: "off"(the immediate-teardown posture forces durable runs off for the zero-overhead path). - No durable store β set
session.persist: false; with no store to journal against, durable runs auto-default to off. - Silent fallback β
session.persist: truebut the persistent store failed to initialise (e.g. absent or read-only~). The gateway logs the fallback and stays non-durable β worth checking, because operators otherwise assume their intent is honoured.
Configuration Options
| Config path | Type | Default | Effect |
|---|---|---|---|
gateway.durable_runs | bool (accepts env-substituted string forms) | true when a durable session store is present (the shipped default); false otherwise or when reliability: "off" | When truthy, every gateway agent is constructed with execution=ExecutionConfig(durable=True) so each turn is journalled to the core RunJournal. |
gateway.reliability | str | unset | "off" forces durable_runs off (immediate-teardown, zero-overhead posture). See Gateway Reliability. |
session.persist | bool | true | false removes the durable store, so the auto-default disables durable runs. See Gateway Session Persistence. |
agents.<id>.durable | bool (accepts string forms) | inherits gateway.durable_runs | Per-agent override β opts a single agent in (or out) regardless of the gateway-wide default. |
The underlying agent primitive is ExecutionConfig(durable=True) β see that page for journal_path, resume_run_id, and the resume contract.
Common Patterns
Fleet-wide durability with a chit-chat escape hatch β durable runs are already on by default, so opt out only the agents that make small talk:
# no gateway.durable_runs needed β on by default
agents:
order_processor:
instructions: "Charge the card and ship the order."
tools: [charge_card, ship_order]
chit_chat:
instructions: "Small talk only."
durable: false # no journalling for stateless banterToggle by environment β durable in production, off in ephemeral CI:
gateway:
durable_runs: ${DURABLE} # export DURABLE=true in prod, DURABLE=false in CIBest Practices
Point journal_path at a persistent volume in containers
The default ~/.praisonai/runs/journal.db is lost when a container is recreated. Configure a mounted volume so the journal survives restarts β see Durable Tool Runs.
Verify the store actually initialised
Durable runs only auto-enable when the session store instantiates. On an absent or read-only home directory the store degrades to in-memory and durable runs silently stay off β check the gateway log for the fallback if you expected crash-safe journalling.
Per-agent durable is your escape hatch
Small-talk agents don’t need journalling. Set durable: false on them, keeping the hot path clean for stateless turns even while the gateway default is on.
Compose with session persistence
Durable gateway runs and session persistence are different layers β one journals the in-flight turn so it can be resumed, the other restores conversation history. Both survive a restart and work together.