Reference: WebSocket protocol
Neutral, exhaustive description of the messages exchanged between the browser and the ori backend on GET /ws. One JSON object per text frame. ACP payloads are relayed verbatim; their shapes are specified by the Agent Client Protocol.
Connection sequence
On every connection the server sends hello, then replays the recorded session history (up to 4096 events), then any permission request still awaiting an answer, then live events as they happen.
Browser → server messages
prompt
Starts a turn.
| Field |
Type |
Required |
Description |
type |
string |
yes |
"prompt" |
text |
string |
yes |
The user's message. |
attachments |
array |
no |
Files mentioned with @ in the text: { "path": "<absolute or root-relative path>", "name": "<label>" }. |
{ "type": "prompt", "text": "Explain @src/main.go", "attachments": [ { "path": "/work/src/main.go", "name": "src/main.go" } ] }
The server sends the ACP prompt as a text content block followed by one resource_link block per attachment (uri: "file://<absolute path>", name as given, defaulting to the path). Relative paths are joined to the server's --cwd; attachments with an empty path are dropped. The @name mention stays in the text.
cancel
Interrupts the running turn.
| Field |
Type |
Required |
Description |
type |
string |
yes |
"cancel" |
permission_response
Answers a permission_request.
| Field |
Type |
Required |
Description |
type |
string |
yes |
"permission_response" |
requestId |
string |
yes |
The id from the permission_request event. |
optionId |
string |
one of the two |
The chosen ACP permission option. |
cancelled |
boolean |
one of the two |
true dismisses the request without choosing. |
Server → browser messages
hello
| Field |
Type |
Description |
sessionId |
string |
The ACP session id, empty if no agent is attached. |
turnActive |
boolean |
true if a turn is currently running. |
user_message
Echo of the prompt that started a turn; also present in replays.
| Field |
Type |
Description |
text |
string |
The user's message. |
attachments |
array |
The attachments of the prompt, verbatim (absent when there were none). |
turn_started / turn_ended
| Field |
Type |
Description |
stopReason |
string |
turn_ended only: the ACP stop reason (end_turn, cancelled, refusal, max_tokens, max_turn_requests). |
session_update
| Field |
Type |
Description |
update |
object |
One raw ACP SessionUpdate, discriminated by its sessionUpdate field (agent_message_chunk, agent_thought_chunk, tool_call, tool_call_update, plan, available_commands_update, …). |
The SPA renders message and thought chunks, tool calls and the plan, and keeps the availableCommands of the last available_commands_update for the composer's / selector (the mock agent sends one at session start; the Claude Code adapter sends Claude Code's slash commands). Other kinds are ignored.
{ "type": "session_update", "update": { "sessionUpdate": "agent_message_chunk", "content": { "type": "text", "text": "Hello" } } }
permission_request
| Field |
Type |
Description |
requestId |
string |
Correlates with permission_response and permission_resolved. |
request |
object |
The raw ACP RequestPermissionRequest (toolCall, options). |
permission_resolved
| Field |
Type |
Description |
requestId |
string |
The request that was answered (by any connected client, or cancelled by the agent). |
error
| Field |
Type |
Description |
message |
string |
Human-readable error ("a turn is already running", "no agent session", "prompt failed: …", "cancel failed: …", "malformed message: …", "unknown message type …"). |
Recorded vs transient events
Events replayed to late-joining clients: user_message, turn_started, turn_ended, session_update, permission_resolved, plus pending permission_requests. Not recorded: hello (regenerated per connection) and error events emitted outside a turn failure.