Skip to main content
POST https://api.abstract.inc/v1/chat/completions takes one observation and returns one action chunk. The request uses the OpenAI chat-completion shape. The chunk comes back as a JSON string in the assistant message.

Request

string
required
A robot model id from Robot models.
array
required
The server reads the last user message only.
object
The robot’s state at the time of the latest frame. Required with image parts. Its shape depends on the model.
string
The episode id you choose. Required with image parts on a stateful model. Optional otherwise. At most 128 printable characters, no surrounding whitespace.
string
Unique logical observation id, 1–128 characters from A-Z a-z 0-9 . _ : -. Reuse only for an identical retry.
integer
Expected next session step, starting at zero. A mismatch returns 409 without inference.
boolean
true returns server-sent events. Default false.
integer
How many action rows to return, from 1 to the model’s rows per chunk. Default: all rows.
integer
From 1 to 4. Accepted for compatibility. No served model reads it.
boolean
true is refused today with handoff_unavailable. See Handoff. Default false.
The server ignores other fields.

Retrying an observation

Send observation_id and expected_step with each observation. Keep the id and body byte-for-byte identical when retrying a lost response. Idempotency-Key can replace observation_id; if both are supplied they must match. Reusing an id with different content returns 409 idempotency_conflict. A completed retry returns the original result and does not execute or bill another chunk. Keyed SSE is returned after the complete reply is retained; unkeyed streaming is unchanged. Replay records currently have no expiry and survive gateway and engine restarts. If execution is still pending, or the answer could not be saved (including the 4 MiB retained-response limit), another gateway may return observation_outcome_unknown. Retry only the same id. Changing the id may execute an observation twice. A replayed answer does not restore an expired model session. Requests without an id are not safe to retry automatically.

The last user message

  • Its text parts are the task instruction. The server joins them with spaces.
  • Its image parts are the camera frames, camera-major and oldest first within a camera.
  • Each image is a data:image/jpeg;base64, URL. Only JPEG is accepted.
  • Each image is at most 262,144 bytes before base64 encoding.
  • The whole request body is at most 8 MiB.
A request with images needs a text part. A session keeps one instruction from its first request to its last.

Frame order on a stateful model

abstract/dreamzero-astra:yam takes 1 frame per camera on the first request of a session, so 3 image parts. Every later request takes 4 frames per camera, so 12 image parts: Take the 4 frames per camera from the chunk the robot just executed. The last frame of each camera is the latest one.

Answer

The example shows one action row. A real answer holds action_horizon rows. Parse choices[0].message.content as JSON to get the action chunk:
string
The session this chunk belongs to. A request without session_id gets a generated id.
integer
The chunk’s zero-based index in the session.
number
Seconds between consecutive action rows.
integer
Values per action row.
string
joint_position or ee_6d_position. See Robot models.
number[][]
action_horizon rows of action_dim numbers.
integer
Frames per camera the next request of this session needs.
object
Server-side durations in milliseconds: decode, queue, prefill, denoise, encode.
object
Present when the model reports its denoiser step cache for this chunk.
object
Present when the model reports its attention context after this chunk.
usage is what the chunk is billed from. See Usage and billing units. The answer carries two headers:

Streaming

With "stream": true, the answer is text/event-stream:
  1. A : processing comment at once, then one every 250 ms until the chunk is ready.
  2. One data: event whose choices[0].delta.content holds the whole action chunk.
  3. One data: event with finish_reason "stop" and usage.
  4. data: [DONE].
Ignore lines that start with :. If the model fails after the stream starts, the HTTP status stays 200. The failure arrives as a data: event with an error object and finish_reason "error".
stream.py

Sessions

A session is one episode. You name it with session_id, for example a UUID.
  • A new session_id starts a new episode. There is no reset call.
  • Keep the instruction the same for the whole session. A change returns instruction_changed.
  • Send one request per session at a time. An overlapping request returns HTTP 409 session_busy.
  • A session expires after 60 seconds without a request.
  • On a stateful model, a request for an expired session returns HTTP 410 session_expired. Start a new session with a new session_id and 1 frame per camera.
  • When no capacity is free for a new session, the API returns HTTP 429 no_replica_free with a Retry-After header. Existing sessions keep running.
episode.py

A request without images

A request whose last user message has no image parts returns a short text description of the model’s inputs and outputs. Its usage is zero. Use it to check a model id and its expected shapes.