202, not 200 — the agent has the work, not the answer.
Every refusal arrives in the shape described in errors.md, with the
code above in
error.code.
input.message
content takes a string, or an array of parts if you prefer the longer form:
Idempotency-Key. A retried send without one is a
second message.
Finding the turn your message produced
The reply carries noturn_id, because at the moment it is written there is no
turn yet — the agent starts one when it picks the message up, which is later
even when nothing was queued.
If you watch events or take a webhook, the turn id
arrives with them and there is nothing to do. If you poll, there is one trap
worth knowing:
input.context
Something the session should know, without being asked to reply. It lands in
the transcript and no turn runs.
The reply carries
delivered:
true— a running agent took it there and thenfalse— the sandbox was not up
false does not mean it was lost. The text is in the transcript either
way, and the next turn is built with it — so a room can hand an agent context
before that agent has ever spoken, which is the usual case when someone joins a
conversation already in progress.
It appears afterwards as an item of type context, and on the stream as
user.context. Deliberately not a message: nobody said it to this session,
and rendering it as one would show the agent a conversation that never
happened.
If a turn is already running, the context lands after it finishes. That turn’s
context is fixed, and inserting into it would make one turn’s behaviour depend
on when a message happened to arrive.
Without this, keeping several agents current means holding your own copy of the
conversation and resending it — which makes every prompt grow with the length
of the room. See agents that work together.
input.tool_result
The answer to a function the agent called. turn_id and call_id are copied
from the required action verbatim.
The reply’s
outcome is the thing to check:
accepted— the turn has it and continuesalready_resolved— this call was answered before; the second answer is discarded rather than appliednot_delivered— nothing was waiting for it
error. It goes to the model,
and a stack trace is an efficient way to put your database host into a prompt.
Send a fixed string; log the real one.
input.steer
Change course while a turn is running.
conflict — there is nothing to steer, and silently
turning it into a message would be a different thing than you asked for.
input.cancel
Stop the running turn.
cancelled — not failed, because you
asked for it, and a failure status would send you looking for a fault that is
not there.
Cancelling when nothing is running is accepted rather than refused: a caller
racing a finishing turn should not have to care which of them won.
Work already done stays. Items the turn produced remain readable, and anything
published to /workspace/outputs before the stop is still collected.
Next
- required-actions.md — the calls you answer with
input.tool_result - events.md — watching what the agent does with what you sent
- idempotency.md — retrying a send without sending twice