POST /v1/omni-ai/threads/{thread_id}/messages now accepts a message while another response in the thread is queued or running. It returns 200 with a new response_id. The new response has status queued. The endpoint no longer returns 409 for an active response. It still returns 409 when the thread scope changed or an Idempotency-Key was used for a different request.
Omni reads the new message at the next safe point of the running response. The running response then ends with status steered if it showed text, or merged if it showed no text. The response for the newest message continues the work and answers all messages sent so far. Earlier queued responses that it answers also end merged. Some requests, such as research, do not steer. Their responses, and the responses for messages sent after them, start in order after the earlier responses end.
Message outcome has two new values:
steered: the assistant message is complete as written. The user sent another message before it finished.
merged: the assistant message has no content. A later answer covers its turn. Hide this message.
GET /v1/omni-ai/threads/{thread_id}/response now returns the running response. When no response is running, it returns the next queued response. It returns data: null when the thread is idle.
DELETE /v1/omni-ai/responses/{response_id} on a running response also cancels the queued responses in that thread. On a queued response, it cancels only that response. On a response that ended steered or merged, it stops the response that continues its work, as for a running response. Each canceled response has a canceled assistant message.
Omni can also start a response the user did not send. When background work finishes, such as a subagent Omni started to look into a question, Omni answers it in the thread without a new user message. That response omits user_message_id, which is now optional on the response returned by GET /v1/omni-ai/responses/{response_id} and GET /v1/omni-ai/threads/{thread_id}/response; its absence means the response presents a background result, such as a subagent’s report. Its assistant message appears in the thread with no preceding user message. Typed SDK callers that read user_message_id as always present must handle it being absent.
This updates the existing 2025-10-31 contract; no API version change is required. To migrate:
- Accept
steered and merged in response status and message outcome. Treat an unknown response status as terminal.
- When a response ends
steered or merged, poll GET /v1/omni-ai/threads/{thread_id}/response at once for the response that continues the work.
- To show every answer, including ones that start without a request, poll the thread response endpoint while the thread is open. Refresh messages when the response
id changes or data becomes null.
POST /v1/omni-ai/threads/{thread_id}/messages
GET /v1/omni-ai/threads/{thread_id}/messages
GET /v1/omni-ai/messages/{message_id}
GET /v1/omni-ai/threads/{thread_id}/response
GET /v1/omni-ai/responses/{response_id}
DELETE /v1/omni-ai/responses/{response_id}