Skip to content

Start a chat and stream the answer

Two ways to talk to OpenAgents from code:

WayCredentialStreamsKept
The model API: POST /v1/responses or POST /v1/chat/completionsAn oak_ API key (or no key, paid per request)Yes, server-sent eventsNothing between requests: send the whole conversation each time
An OpenAgents chat: POST /v1/threads on openagents.comA login key (oa_sk_...)No: read it until it's doneA chat on the account, also shown on the website and phone

With an API key: stream a model answer

Step 1: send the request with "stream": true

curl -N https://api.openagents.com/v1/responses \
  -H "Authorization: Bearer $OPENAGENTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "openagents/chat", "input": "Write a haiku about Lightning.", "stream": true}'

Step 2: read the events

Each event is an event: line and one data: line of JSON. The stream ends with data: [DONE].

event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_...","status":"in_progress",...}}

event: response.output_text.delta
data: {"type":"response.output_text.delta","item_id":"msg_...","output_index":0,"content_index":0,"delta":"Sats ","sequence_number":4}

event: response.completed
data: {"type":"response.completed","sequence_number":21,"response":{"id":"resp_...","status":"completed","usage":{...}}}

data: [DONE]
EventWhat to do
response.output_text.deltaAppend delta to the answer
response.output_text.doneThe full text of one part
response.function_call_arguments.deltaAppend to a tool call's arguments
response.completedDone; response.usage has the token counts
response.incompleteStopped early, for example at max_output_tokens
response.failed, errorFailed after it started; read error.code and error.message

Add the header x-openagents-events: 1 to also get our own events: openagents:route ({"model", "upstream"}: which model and provider answered) and openagents:cost ({"cost"}).

The answer's headers name the model and provider: x-openagents-model and x-openagents-upstream, with x-request-id for help.

The same with Chat Completions

curl -N https://api.openagents.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAGENTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "openagents/chat", "messages": [{"role": "user", "content": "Say hello."}], "stream": true, "stream_options": {"include_usage": true}}'

Each line is data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"..."},"finish_reason":null}],...}, then a last chunk with usage and no choices, then data: [DONE].

With the command

export OPENAGENTS_API_KEY=oak_...
openagents inference openagents/chat "Write a haiku about Lightning." --stream
openagents inference openagents/chat "Write a haiku about Lightning." --stream --format events

--format events prints each event as one JSON line.

With an OpenAI SDK

from openai import OpenAI

client = OpenAI(base_url="https://api.openagents.com/v1", api_key=OPENAGENTS_API_KEY)
with client.responses.stream(model="openagents/chat", input="Say hello.") as stream:
    for event in stream:
        if event.type == "response.output_text.delta":
            print(event.delta, end="")

With a login key: an OpenAgents chat

This starts a chat on the account, as starting one on the website does. It can run tools and Coder, and it shows on the website and phone.

Step 1: start the chat

curl -s https://api.openagents.com/v1/threads \
  -H "Authorization: Bearer $OPENAGENTS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"request_id\": \"$(uuidgen)\", \"text\": \"What changed in my repo this week?\"}"
{"id": "...", "answering": true}

request_id is a UUID you make. Sending the same one again returns the same chat (200) instead of a second one, so a retry is safe. Add "project": "prj_..." (or "name:Launch notes") to start the chat inside a project. Text is at most 4,000 characters.

Step 2: read it until the answer is done

curl -s https://api.openagents.com/v1/threads/THREAD_ID \
  -H "Authorization: Bearer $OPENAGENTS_TOKEN"
{"thread": {"id": "...", "working": true, ...}, "messages": [{"role": "user", "text": "..."}, {"role": "assistant", "text": "..."}], "earlier": false, "waiting": false}

Read it again about once a second while thread.working is true. The last assistant message grows as the answer is written.

Step 3: reply

curl -s https://api.openagents.com/v1/threads/THREAD_ID/messages \
  -H "Authorization: Bearer $OPENAGENTS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"request_id\": \"$(uuidgen)\", \"text\": \"Only the main branch, please.\"}"

The answer is 202; read the chat again for the reply.

StatuscodeWhy
400invalidrequest_id isn't a UUID, or the text is empty or too long
409busyThe chat is still answering
422secretThe text looks like a password or key; it wasn't sent

With the command

openagents chat send "What changed in my repo this week?" --project "Launch notes" --json

Under --json it prints one event per line while the answer is written ({"event":"partial","thread":"...","text":"...","delta":"..."}), then the result. Without --project, the chat is kept on this computer.

See also