Interrupts and Resume
Updated 6 days ago • July 27, 2026
Interrupts let a node pause execution and wait for user input.
Node side
Use stable id values for interrupts in nodes that can replay or contain multiple interrupt calls.
Or use useReason({ interrupt: ... }) when you want model-generated interrupt requests constrained by schema. By default, useReason treats interrupt config as required: the model must produce an interrupt request, the runtime pauses, and the hook continues after resume. Set interrupt.mode to "optional" when the model should return either decision: "continue" for a single-call result or decision: "interrupt" with an interrupt request.
Good to know: Use required interrupts for approvals and safety gates. Optional interrupts are best for flows where the model can answer immediately but may ask for user input when the request is ambiguous.
Stream side
During interrupt, runtime/orchestrator emits:
Resume payload
@kortyx/agent resume metadata shape (from parseResumeMeta):
Accepted selected shapes:
- string
- string[]
{ choice: { id } }{ choices: [{ id }, ...] }
Good to know: On resume, node code starts again from the top.
useReasoncontinues from its internal checkpoint, but code beforeuseReasoncan run again unless you guard it. Prefer puttinguseReasonfirst in the node and useuseNodeStatefor pre-events that should emit once.
Replay-Safe Side Effects
Code before an interrupt or resumable reasoning call can run more than once. Make side effects safe to repeat.
Replay-safe patterns:
- Put external writes after the interrupt when possible.
- Store "already did this" flags with
useNodeState(...)oruseWorkflowState(...). - Use idempotency keys when calling app services.
- Keep random ids and timestamps stable if they affect external writes.
Use the app database for product records, users, tickets, documents, conversation history, and anything that must outlive runtime execution state.
Persistence requirements
Resume only works if the framework adapter persists pending requests + checkpoints.
- in-memory adapter: good for local dev, not restart-safe
- redis adapter: recommended for production resume
- hook state (
useNodeState/useWorkflowState) follows the same checkpoint lifetime and limits
Expiry and late responses
Pending interrupt state expires after 15 minutes by default. Configure the TTL
for the application with KORTYX_FRAMEWORK_TTL_MS, or pass ttlMs to the
framework adapter:
The runtime includes the resulting expiresAt timestamp in
interrupt.created. Clients should stop offering the original resume action
after that time.
Once the checkpoint expires, its resume token cannot continue the original run. If the same message is still sent, Kortyx ignores the expired resume metadata and lets the application handle it as normal input. An application fallback may therefore start a new run, but it did not resume the expired run. Kortyx Studio preserves that distinction.
Static choices and dynamic pickers
An interrupt can obtain choices in two ways:
- a static choice embeds its options in the interrupt request;
- a dynamic picker sends a
schemaIdand lets the client resolve options from its own data source.
A dynamic picker can therefore have optionCount: 0 in telemetry even when the
client shows valid choices. The count describes options embedded by the server,
not the number rendered by the client.