Skip to main content
The WebSocket at /v1/responses runs one episode per socket. It reaches the same models and the same sessions as chat completions. The API checks your key and payment once, at the handshake.

Connect

The model in session.open must equal the model query parameter. The API refuses a handshake with an HTTP status and the usual JSON error body:

Messages

You send text messages as JSON, and frames as binary messages. session.open also takes handoff, as in Handoff. observation also takes action_horizon and num_inference_steps, as on chat completions. A text message is at most 65,536 characters. observation_id is optional: use 1 to 128 characters from A-Z a-z 0-9 . _ : -. The API generates one if omitted and returns it on that observation’s actions or error message. Use a fresh id per logical observation, and reuse it with identical frames and controls when retrying. Supply expected_step, starting at zero, to reject out-of-order observations. A repeated completed id returns its original answer with no new execution or charge; different content conflicts. Concurrent duplicates share the outstanding observation’s answer. Generated ids cannot protect retries after a lost reply. Replay records have no expiry and survive gateway and engine restarts. Keep the same public session_id and opening message when retrieving an answer on a new connection. A stored answer does not restore the model’s lost episode. If an answer was never saved, observation_outcome_unknown refuses re-execution; do not switch to a new id to bypass it. Each connection admits at most 1,024 observation ids and buffers at most 16 MiB of frames; a retained answer must fit 4 MiB. See HTTP retries.

session.opened

The server states the model’s contract. Build every later message from this reply.

Frames

A frame message is binary. Its first byte is the camera index: 0 for the first camera in cameras, 1 for the second, 2 for the third. The remaining bytes are one JPEG, at most 262,144 bytes.
  • Before the first observation, send frames_per_camera_first frames per camera.
  • Before every later observation, send frames_per_camera_next frames per camera.
  • Within one camera, send frames oldest first.

actions

The answer to an observation carries the same action chunk as a chat completion, plus type, id and usage:
The example shows one action row and example numbers. A real answer holds action_horizon rows. An abstract/dreamzero-astra:yam answer also carries cache and context, as on chat completions. You can wait for each reply, or pipeline up to eight outstanding observations. Send all frames for A, then observation A, then all frames for B, then observation B. Give each observation its own id so you can match replies. The engine executes observations sequentially in arrival order; pipelining does not run them concurrently. Each observation has its own credit reservation and usage settlement. Socket ingress holds at most 16 MiB and 128 messages while earlier messages are processed; exceeding either limit closes the socket with message_too_large. Acknowledged observation ids remain protected by durable replay records, so a long episode does not need to restart after 1,024 observations. For stateful models, a failed observation does not advance the step. Later queued observations are validated against the step that actually exists, so a failure on the first observation can also make a queued continuation’s frame count invalid. Waiting for each reply is simplest when recovering from errors. Your robot controller must decide which returned actions remain applicable to its current state.

session.closed

{"type":"session.closed","session_id":"...","steps":3}. steps counts the chunks the session produced. The server then closes the socket with code 1000.

Errors

An error arrives as a text message:
Frame and session-control errors have no observation_id and are not terminal answers to other outstanding observations. Already queued observations can still return results. On a close, unanswered observations settle at zero; previously completed ones retain their usage. The close code tells you whose fault it was: Errors and limits lists every code.

Lifetime

  • One socket is one episode. Open a new socket for a new episode.
  • After the first observation, a session that sends no observation for 60 seconds expires. The next observation gets session_expired with closing: true.
  • Closing the socket mid-chunk cancels the model call and ends the episode.
  • Each observation is metered like one chat completion. See Usage and billing units.

Example

socket_episode.py
Install the client with pip install websockets, then run it with ABSTRACT_API_KEY="$(abstract token)" python socket_episode.py.