nandi/oripublic Fork 0
7895c1d1c9bb1048807dc04f7246dc456c47e025
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

websocket-protocol.md · 103 lines · 4.3 KBmarkdown
Blame HistoryOpen raw

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.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
# 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](https://agentclientprotocol.com).

## 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>" }`. |

```json
{ "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.

```json
{ "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_request`s. Not recorded: `hello` (regenerated per connection) and `error` events emitted outside a turn failure.