Channel-originated sessions (Slack/Discord/Telegram) get this server-initiated notice. Direct-client sessions keep resuming via the client’s own reconnect +
since cursor — see Session Continuity.Quick Start
1
Start with an agent
2
Enable session persistence (the only opt-in)
3
What a channel user sees
After a restart interrupts their request, the originating channel receives:
4
What operators see
The boot scan logs a one-line summary:
How It Works
On boot — before serving new traffic — the gateway scans persisted sessions, notifies the originating channel of any interrupted turn, and re-drives it when the agent is still registered. The whole scan is wrapped in atry / except at the start() site — a failure in the resume loop never blocks the gateway from serving new traffic.
What Triggers a Resume
A persisted session is resumed when all of these hold:is_executing == Trueorpending_inboxis non-empty (a turn was in flight).channel_targetis set on the persisted snapshot — channel-originated only; direct-client sessions resume via reconnect.- A durable session store is configured (the scan is a no-op without one).
The Notice Contract
The originating channel receives one verbatim message per interruption:Exactly-once. The notice is delivered through the durable delivery router with an idempotency key
restart:<session_id>:<run_epoch>, where run_epoch is the event_cursor at persist time. The router’s idempotency store survives restart, so a crash loop (boot → notice → crash → boot) notifies the originating channel at most once per interruption. This is why the router path is used instead of a bare bot.send_message().WebSocketGateway.delivery_router is None, the notice falls back to bot.send_message(target, text) via get_channel_bot(channel) — best-effort, no idempotency. If you disable the delivery router, you also opt out of exactly-once: an ill-configured deployment can double-notify on a crash loop.
channel_target on Persisted Sessions
channel_target is a "channel:target" string (for example "telegram:12345") recording where to notify a channel user after a restart.- Set by the channel adapter at inbound time via
session.set_channel_target("telegram:12345"). - Round-trips through
to_dict/from_dict; backward-compatible —Nonefor sessions created before the field existed and for direct-client sessions. - Fallback: when the explicit target is absent, it derives from
client_idiffclient_iditself encodes achannel:targetorigin (contains a:). This makes the field a live consumer of existing state — it matters for operators upgrading with in-flight sessions the setter never touched.
None):
Best-Effort Re-drive
Whether the turn actually resumes depends on the agent still being registered on the fresh process.- Agent still registered (same
agent_idin the config) → the session is rehydrated and_run_session_queuerestarts, so a real reply follows the notice. - Agent no longer registered (removed from the config) → the notice above still fires, and its wording already asks the user to resend. No exception, no crash-loop.
Configuration Options
No new user-facing config flags. The feature is enabled transitively by the presence of:
No operator action is required to opt in beyond enabling session persistence — the feature is on by default when persistence is on.
Operator Observability
Search a log stream for these lines to find this behaviour:
The boot scan calls
list_sessions() with an explicit large limit, so interrupted turns beyond the store’s default 50-session pagination window are not silently skipped.
Common Patterns
Two deployment scenarios where restart continuation changes behaviour. Rolling restarts. Restart continuation makes rolling deploys safer for channel users, provided session persistence is on and the delivery router is shared across instances. Deliberate maintenance drop. To swallow all in-flight work on a restart (for example, a schema migration invalidates the persisted format), turn offgateway.session.persist for that boot — the scan is a no-op without a store.
Best Practices
Enable session persistence if you have channel users
Enable session persistence if you have channel users
The feature is a no-op without a durable store. Set
gateway.session.persist: true.Keep the delivery router on if you use channels
Keep the delivery router on if you use channels
The fallback path is best-effort, not exactly-once. A crash loop can double-notify when the router is disabled.
Watch the boot scan log line
Watch the boot scan log line
A non-zero
Resumed N count on every boot signals that something upstream is crashing regularly.Don't rely on re-drive alone
Don't rely on re-drive alone
If the agent was removed from the config, the turn can’t re-drive. The notice already asks users to resend — treat re-drive as a nice-to-have.
Size the session store paginator
Size the session store paginator
The scan uses an explicit large limit so the default 50-session window doesn’t hide interrupted sessions, but very large stores still benefit from ordering by recency.
Related
Session Continuity
Client-initiated reconnect resume — the sibling capability
Session Persistence
The persistence layer this feature rides on
Undelivered Notice
Peer user-facing message when something went wrong
Approval Durability
The durable rehydrate-on-boot pattern this feature mirrors

