Skip to main content
A research session rarely ends after the first answer. Users follow up, refine their question, or branch into a new line of inquiry. Both the Research Agent and Workflows support multi-turn continuation, but the surfaces differ slightly and involve four related identifiers that are easy to confuse. This guide disambiguates them, shows how persistence interacts with continuity, and provides worked examples for the common multi-turn and branching patterns.

The four identifiers

In practice:
  • A vanilla follow-up turn uses chat_id (or execution_id) alone to identify the conversation.
  • A branching turn additionally uses from_checkpoint_id to specify where in the conversation to resume.
  • The checkpoint_id you store today is what becomes a from_checkpoint_id tomorrow.

persistence_mode

The Research Agent request accepts persistence_mode with two values. Both allow multi-turn follow-ups; they differ in how long the conversation survives.
  • disabled (default) — creates an ephemeral conversation thread. Follow-up turns against the same chat_id work for approximately one hour. After that, the underlying checkpoint is evicted and a resume attempt returns HTTP 404 with the detail "Cannot follow up: chat expired".
  • enabled — creates a persistent conversation thread. The chat_id and checkpoint_id returned in COMPLETE can be used to continue or branch the conversation indefinitely.
The mode is immutable for the life of a conversation. It is fixed when the conversation is created on turn 1; every resume request must pass the same value. A mismatch returns HTTP 400 on the Research Agent (with detail "persistence_mode mismatch") and HTTP 409 on Workflows. Choosing a mode: leave the default disabled for one-off questions and short sessions that wrap up within an hour. Set enabled on turn 1 when the conversation needs to survive longer — branching workflows, research threads spanning a working session, anything you want a user to resume the next day. Workflows expose persistence_mode on the synchronous execute endpoint with the same semantics (default disabled, immutable, mismatch returns 409). Asynchronous workflows always persist because the events blob is the client’s only way to read execution state after the SSE connection closes; they do not expose persistence_mode.

The "INITIAL" sentinel

Passing from_checkpoint_id: "INITIAL" is a special instruction that truncates the entire conversation and starts over with the new message. Use it when the user explicitly says “let’s start over” or when you detect a context-poisoning mistake (a typo in a name, a wrong company id, a stale assumption) that you want to clear cleanly while keeping the same chat_id.
"INITIAL" deletes all prior interactions for that chat_id. There is no undo.

Worked example: multi-turn conversation

The pattern below persists chat_id and checkpoint_id between turns, letting the user ask follow-up questions on top of the agent’s previous answers.
The chat_id returned by each event identifies the conversation thread; the checkpoint_id returned in COMPLETE is your cursor for the next turn. Persist both server-side or in client storage if you need conversations to survive across sessions.

Branching a conversation

To “rewind” a conversation — for example, when the user edits an earlier message or wants to explore a different follow-up question from a known good state — pass the checkpoint_id from the turn you want to resume from, with the same chat_id. Any interactions after that checkpoint are discarded, and the new message takes their place.
After this call, the conversation’s history consists of: the system prompt, the first user message, the first answer, and the new branched turn. The follow-ups that originally came after ckpt_after_turn_1 no longer exist on the server.

Workflows: resuming by execution_id

Workflows do not expose checkpoints. Instead, each execution has an execution_id that the streaming response carries on every event. Pass that id back in a later request to continue the same conversation.
Resuming a workflow by execution_id continues the conversation but does not re-run the original template’s research plan from scratch; the agent treats the new input (or follow-up message) as a continuation, with prior interactions in context.

Common pitfalls

  • Treating the default disabled mode as suitable for long sessions. Ephemeral threads expire after about an hour; a follow-up that arrives later returns HTTP 404 with detail "Cannot follow up: chat expired". Set persistence_mode: "enabled" on turn 1 if the conversation needs to survive longer than that.
  • Switching modes mid-conversation. The mode is immutable once a conversation is created. Resume requests must pass the same value used on turn 1 or the server returns HTTP 400 (Research Agent) / 409 (Workflows).
  • Storing chat_id but not checkpoint_id. A chat_id alone is enough for the simple “continue the latest turn” case, but if you want stable replay or branching, you also need the checkpoint_id returned in COMPLETE.
  • Mixing chat_id between users. The chat_id is a server-side conversation identifier; do not share it across users or sessions you want isolated.
  • Treating checkpoint_id as introspectable. It is an opaque string; do not parse, compare, or derive meaning from its contents.
  • Calling from_checkpoint_id: "INITIAL" accidentally. It deletes the entire thread. Guard this code path behind an explicit user action.

Next steps

Streaming responses

Reference for every message type, including how checkpoint_id arrives in COMPLETE.

Error handling

Handle 404s from invalid checkpoint IDs and other continuity failures.