Stop is served only when turn control is on for your environment. You can tell it is on in two ways: the conversation detail response carries the
turn key, or the conversation frame of a turn stream carries "turn_control": true. Until then the Stop and turn routes answer 404 not_found. Show Stop only after you have seen one of the two, and never call these routes before that.Terms
- A turn is one user message and the work the assistant does for it. A turn can span several requests.
- A segment is one request’s part of a turn: the stream you read until its
turn_endframe. - A turn is at rest when its status is
completed,stoppedorfailed. Nothing more happens to it. - A turn is stopping when Stop was pressed and the turn has not come to rest yet, for example because a write that already started is finishing. The platform does not store this status. It reads it from the stop request and the turn’s state.
Show Stop
Show one button. It replaces Send while the assistant works, in the same place and at the same size.- Show Stop from the moment you send a message until the turn is at rest.
- Keep showing it while the turn waits for a client tool result or for an approval. Stop works in every status that is not at rest.
- If the user presses Stop before you know the turn id, keep the press. Send Stop as soon as the
conversationframe gives youturn_id. - Show Send again once the turn is at rest.
Call Stop
POST /api/v1/conversation-instances/{instance_slug}/conversations/{conversation_id}/turns/{turn_id}/stop
Credential: an organization API key, or a scoped key with conversations:use. The body carries the same end_user as the turn.
- On a turn that was not at rest,
statusisstoppedwhen Stop ended it, orstoppingwhen a write that already started still has to finish. A turn already at rest is returned unchanged, whatever its status (completed,stoppedorfailed). - Stop is safe to repeat. On a turn at rest it changes nothing and returns the turn as it is.
- Stop works on an archived conversation.
- A turn that started before turn control was on has no record. Stop on it answers
404 turn_not_found.
While the turn is stopping
- Change the button to a disabled “Stopping” state. Do not show Send yet.
-
Keep reading the stream if you have one open. It ends with
turn_endandstop_reason: "stopped". -
Without an open stream, read the turn every two seconds until it is at rest:
GET /api/v1/conversation-instances/{instance_slug}/conversations/{conversation_id}/turns/{turn_id}?end_user=...It answers{"turn": {...}}in the same shape as Stop. The read changes nothing. -
If the turn reads
stoppingfor more than three seconds, call Stop again. A repeat ends the turn when nothing else holds it, for example after a lost signal. A write that is still running keeps the turn stopping until it finishes, so keep reading until the turn is at rest before you show Send.
Read a stopped turn
The turn object
The transcript
- Text the assistant streamed before the stop is kept as the reply’s text, when it passes the instance’s output checks. Show it with a short “Stopped” line under it.
- Every step that started gets a stored result. Show it as a stopped step. The result says what is known:
A server step that finished before the stop keeps its real result.
- The model sees the same stored results on the next message, so it can tell the user what is known about each stopped step.
After a reload
Conversation detail carries two keys while turn control is on:turnis the latest turn of the version the conversation serves, ornullwhen that turn has no record. Use it to decide whether to show Stop or Send.turnslists every turn with a message in the returned transcript window that did not end normally, oldest first:[{"id": "...", "status": "stopped", "stop_reason": "stopped"}]. It is an empty list when there is none. Each message carries itsturn_id, so mark the last message of each listed turn as stopped.
What Stop does not do
- It does not undo a step that ran.
- It never cuts a write. A write that already started finishes, and its result is kept.
- It cancels no run. A run the assistant submitted keeps going and its own status shows that. Runs your own tools started are yours to cancel. See Client tools.
Edit a message while a turn runs
Send the edit withstop_active_turn: true:
- The platform stops the running turn, then starts the reply to the edited message as a new version, in the same request.
- The old version keeps its stopped work. The user can switch back to it.
- Without
stop_active_turn, an edit while a turn runs answers409as it always has. - If the running turn does not come to rest within 10 seconds, the request answers
409 turn_in_progress. The stop stays recorded. Send the edit again once the turn is at rest. - Disable Save while the request is in flight. A repeat after a success is a new edit.
- A version switch while the latest turn is not at rest answers
409 turn_active. Disable the version switcher while the assistant works.
Late results
Your app may finish a step after the turn stopped. Post its result as usual, withtool_results on the turns route.
- The platform keeps it. The result replaces the step’s stored placeholder once. No model call follows.
- The answer is a short stream: a
conversationframe, thenturn_endwith the turn’sstop_reason. This is not an error. - A second post for the same step is ignored, with the same answer.
- Only a step that may have run takes a late result. A step stored as “It did not run” never does.
- The platform matches a late post against the conversation’s five most recent turns that did not end normally.
- If the post answers
409 turn_in_progress, a newer turn holds the conversation. Retry with backoff for up to 60 seconds, then keep the result and retry later.
Lost turns
The platform ends a turn nobody can finish, so a conversation never gets stuck:- A lost handoff: your app took client tool calls and posted no results within 10 minutes. The turn rests as
failedwithstop_reason: "handoff_lost". Its open steps get the “No result was recorded.” result. The next message is accepted. A result posted later is kept as a late result. - A lost segment: the segment running the turn died, for example in a deploy. The next request ends the turn as
failedwithstop_reason: "segment_lost", with the same result on its open steps.
Errors
Turns and streaming
Frames, turn states, and stop reasons.
Stop a turn (API reference)
The generated endpoint contract.