WebSocket events
The WebSocket endpoint streams agent execution in real time: tokens as the model generates them, tool calls as they fire, results as they come back, and turn boundaries. The dashboard chat is essentially a thin shell over this stream.
Connecting
Section titled “Connecting”wss://app.vonz.io/v1/streamSec-WebSocket-Protocol: Bearer.<your-token>Or pass the token as ?token=rc_… query parameter when subprotocols aren’t an option (in-browser clients).
Auth is the same as the REST API: an rc_… token or a Better Auth session cookie.
Wire format
Section titled “Wire format”Messages are JSON, one event per frame. All messages have a type field. Most have a session_id (which workspace they belong to).
Client → Server messages
Section titled “Client → Server messages”task.submit
Section titled “task.submit”Same shape as POST /v1/tasks. Submit and start streaming back over this socket.
{ "type": "task.submit", "mode": "session", "profile_id": "prof_…", "session_id": "sess_…", "prompt": "What's the weather?"}task.cancel
Section titled “task.cancel”{ "type": "task.cancel", "task_id": "task_…" }session.start
Section titled “session.start”Create a new session (without submitting a task yet). Useful for surfaces that want to register a session id ahead of the user’s first message.
{ "type": "session.start", "profile_id": "prof_…" }Server replies with session.ready carrying the new session_id.
session.resume
Section titled “session.resume”Re-attach to an existing session and request a transcript replay.
{ "type": "session.resume", "session_id": "sess_…" }Server first emits session.replay_start, then a sequence of historical events, then session.replay_end. After that, live events flow.
session.turn
Section titled “session.turn”Send a new user message into an existing session. Same as task.submit with mode=session, but defaults the profile from the session.
{ "type": "session.turn", "session_id": "sess_…", "prompt": "Follow-up question" }task.answer
Section titled “task.answer”Reply to an AskUserQuestion event the agent emitted.
{ "type": "task.answer", "task_id": "task_…", "answer": "Option B" }Server → Client events
Section titled “Server → Client events”session.ready
Section titled “session.ready”A session was created (in response to session.start or task.submit with no session_id).
{ "type": "session.ready", "session_id": "sess_…", "container_id": "ctr_…", "container_name": "agent-abc123", "profile_id": "prof_…"}session.replay_start
Section titled “session.replay_start”Begins a transcript replay (response to session.resume).
{ "type": "session.replay_start", "session_id": "sess_…" }session.replay_end
Section titled “session.replay_end”End of replay; live events follow.
task:token
Section titled “task:token”A single chunk of model-generated text. Emitted as the agent streams its assistant response. Multiple task:token events make up one assistant message.
{ "type": "task:token", "session_id": "sess_…", "text": "Hello " }task:tool_use
Section titled “task:tool_use”The agent called a tool. input contains the tool’s arguments; the result comes later as task:tool_result.
{ "type": "task:tool_use", "session_id": "sess_…", "tool": "Bash", "input": { "command": "ls /workspace" }}For AskUserQuestion, the input contains a questions array — the dashboard renders inline buttons.
task:tool_result
Section titled “task:tool_result”{ "type": "task:tool_result", "session_id": "sess_…", "tool": "Bash", "output": "file1\nfile2\n"}task:ask_user
Section titled “task:ask_user”A flattened variant of an AskUserQuestion tool_use, surfaced specifically so chat surfaces (dashboard, Slack, Telegram) can render interactive choices uniformly.
{ "type": "task:ask_user", "session_id": "sess_…", "task_id": "task_…", "questions": [ { "question": "Pick one", "options": [{ "label": "Yes" }, { "label": "No" }] } ]}turn.continuing
Section titled “turn.continuing”Mid-chain marker: the orchestrator is auto-continuing into a new chain (multi-chain playbooks).
{ "type": "turn.continuing", "continuation": 2, "max_continuations": 20 }turn.done
Section titled “turn.done”End of a single agent turn. result_text is the server-polished version of the assistant’s final text — image URLs are signed _pvt links, markdown is normalized.
{ "type": "turn.done", "session_id": "sess_…", "result_text": "Here's the summary…", "input_tokens": 1234, "output_tokens": 567, "cost_usd": 0.0123}If you’ve been streaming tokens for this turn, replace the accumulated text with result_text — it has the signed URLs needed for in-browser image rendering.
task:done
Section titled “task:done”End of a task (a single task.submit lifecycle). For session-mode tasks, fires alongside turn.done.
{ "type": "task:done", "task_id": "task_…", "session_id": "sess_…", "status": "completed" }task:failed
Section titled “task:failed”{ "type": "task:failed", "task_id": "task_…", "error": "Container exited 1" }task:system_prompt
Section titled “task:system_prompt”(Debug-tier.) The full system prompt the agent received this turn. Surfaced for dashboard “view system prompt” debug affordances. Only emitted when the user has a privileged role.
Event ordering invariants
Section titled “Event ordering invariants”- Every
task:tokenfor a turn arrives before that turn’sturn.done. - Every
task:tool_useis followed by exactly one matchingtask:tool_result(ortask:failedif the tool errored). - A turn can interleave token events and tool calls. The dashboard’s chat layout uses turn-grouping to render them coherently under one agent header.
session.replay_*events frame any transcript playback. Live events come strictly aftersession.replay_end.
Closing
Section titled “Closing”Either side can close cleanly. The server preserves session state on disconnect — reconnect + session.resume brings the user back to the same conversation with full replay.
Errors
Section titled “Errors”Frames with type: "error" carry a code (see Errors) and a human-readable message.
{ "type": "error", "code": "UNAUTHORIZED", "message": "Token invalid" }A WebSocket close with code 4001 means “authentication failed; reconnect with a valid token.”