Messages and runs
Conversation activity, accepted runs and persisted messages have distinct identities. These rules apply across asynchronous sends, synchronous replies and state reads.
Required attachments
Omitting the resolution mode skips content it cannot resolve. Use FILE_RESOLUTION_FAILURE_MODE_FAIL_GENERATION when answering without the file would be misleading. If omission is acceptable, your application should still tell the user when required context is unavailable rather than presenting a complete analysis.
Conversation activity and submitted-run outcomes
Conversation activity answers whether a run is executing now. It does not answer whether a particular submitted question has finished. Keep those two states separate in the chat display:
| State read | Display and next action |
|---|---|
activeRunning is true | Show current activity. For one outstanding turn at a time, keep another send disabled until the retained run is resolved. |
activeRunning is absent | No run is currently active. Match the submitted run to its reply and terminal outcome before showing completion. |
This distinction matters after a queued send or a lost connection: the conversation can be idle without providing a correlated outcome for that request. Preserve the request as unresolved and follow send reconciliation before offering a retry.
Interrupt policy
Controls what happens when a user sends a new message while a generation run is already in progress. Use the full enum value in the wire format:
| Policy | Behavior |
|---|---|
INTERRUPT_POLICY_REJECT_NEW | The send fails immediately with an active-run error. The new message is not appended to history. |
INTERRUPT_POLICY_CANCEL_ONGOING | The active run is cancelled; the new run starts immediately. The cancelled run's response is marked interrupted: true. |
INTERRUPT_POLICY_QUEUE | The message goes into a pending queue (not yet history). When the active run completes, messages drain FIFO — each dequeued message is re-evaluated against the current policy at that moment. The queue has no depth cap. |
INTERRUPT_POLICY_IGNORE | The message is accepted but not persisted to history. The active run is unaffected and never sees it. |
Run outcomes
status | Meaning and next step |
|---|---|
AGENT_STATUS_COMPLETED | The run finished. Read the returned messages; check the assistant's finishReason to understand why the model stopped. |
AGENT_STATUS_FAILED, AGENT_STATUS_CANCELLED, AGENT_STATUS_TIMED_OUT | The run ended unsuccessfully. Do not turn absent messages into a successful empty reply. |
AGENT_STATUS_QUEUED | The message was queued behind an in-flight run; this response does not contain its completed reply. Reconcile using the asynchronous polling recipe; the current queued-operation correlation is incomplete, so idle alone does not establish this request's outcome. |
AGENT_STATUS_AWAITING_CLIENT_TOOLS | Execute pendingClientTools and echo clientToolCursor when submitting results, following the client-tool loop. |
AGENT_STATUS_ACTIVE | The bounded wait ended while the run was still going. Do not start another run. Reconcile the same run through get-conversation-state, preserving unknown state when correlation is unavailable; see also the tool recovery guidance. |
| absent | No status key at all. Treat the outcome as unknown and reconcile the same run. Do not assign an unrelated lastRunStatus to it. |
COMPLETED, FAILED, CANCELLED, and
TIMED_OUT are recognized terminal outcomes, each with the AGENT_STATUS_ prefix.
Agent run status has no SUCCESS alias; the legacy alias belongs only to tool execution status.
An absent or unrecognized value is an unknown outcome. Reconcile it with a bounded
wait; it is not proof of success, failure or continued activity. See
Run status and model finish reason.
status can be missing entirelyThe field is omitted rather than sent as an empty string, so read it with a
default — body.status ?? "" — not a presence check that throws. The reachable
case is submit-client-tool-results-sync for a run that had already finished
before your results arrived: the response carries runId and
clientToolCursor and nothing else. This response does not establish success or failure. The run ended before this submission; consult a correlated outcome, and retain uncertainty if the most recent state now belongs to another run.
Failed responses and diagnostics
Empty messages can be omitted. Do not require an inline error or
failureReason to recognize this failure: an explanation is not guaranteed in
this response. Other failures propagate as HTTP errors with an error body, so
handle both non-success HTTP responses and unsuccessful run statuses. Immediate
model validation failures are described in Model selection failures.
Conversation, run and message identities
| Field or identity | Meaning |
|---|---|
| Conversation key | The thread to read; it is not an access token |
Accepted runId | The generation operation returned by the send |
activeRunId | The run currently recorded as active on the conversation |
Message sequence | The persisted message's order within the conversation |
| Conversation activity sequence | An activity update sequence, separate from message ordering |
| Tool-call ID | The complete call whose approval or result is being submitted |
Message sequence values are JSON strings containing 64-bit integers. Keep them as strings for transport and use a 64-bit integer or big-integer type for numeric comparison; converting large values to floating point can change their order. An assistant message need not have the user message's sequence plus one: tool rounds and other messages can appear between them.
State reconciliation
An absent or false activeRunning means the conversation has no recorded active run; false is normally omitted. lastRunStatus reports its latest recorded outcome, which can belong to a newer run. It does not provide a complete history of outcomes for concurrent or queued sends. Refresh state after disconnects and retain an unknown outcome when correlation is unavailable.
Persisted message reads
Use returned persisted messages to refresh the display. While activeRunning is true, compare activeRunId with the accepted run. Once activity ends, lastRunStatus describes the latest run recorded on the conversation. It is not a receipt for every earlier send: a newer or concurrent run can replace it. Keep an unresolved outcome visible when you cannot correlate it.