mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 13:03:42 +00:00
docs(coding-agent): document extension UI protocol in RPC docs, add examples (#1144)
This commit is contained in:
parent
4ca7bbe450
commit
7feae0d5c2
5 changed files with 951 additions and 1 deletions
|
|
@ -903,6 +903,191 @@ Emitted when an extension throws an error.
|
|||
}
|
||||
```
|
||||
|
||||
## Extension UI Protocol
|
||||
|
||||
Extensions can request user interaction via `ctx.ui.select()`, `ctx.ui.confirm()`, etc. In RPC mode, these are translated into a request/response sub-protocol on top of the base command/event flow.
|
||||
|
||||
There are two categories of extension UI methods:
|
||||
|
||||
- **Dialog methods** (`select`, `confirm`, `input`, `editor`): emit an `extension_ui_request` on stdout and block until the client sends back an `extension_ui_response` on stdin with the matching `id`.
|
||||
- **Fire-and-forget methods** (`notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text`): emit an `extension_ui_request` on stdout but do not expect a response. The client can display the information or ignore it.
|
||||
|
||||
If a dialog method includes a `timeout` field, the agent-side will auto-resolve with a default value when the timeout expires. The client does not need to track timeouts.
|
||||
|
||||
Some `ExtensionUIContext` methods are not supported in RPC mode because they require direct TUI access:
|
||||
- `custom()` returns `undefined`
|
||||
- `setWorkingMessage()`, `setFooter()`, `setHeader()`, `setEditorComponent()` are no-ops
|
||||
- `getEditorText()` returns `""`
|
||||
|
||||
### Extension UI Requests (stdout)
|
||||
|
||||
All requests have `type: "extension_ui_request"`, a unique `id`, and a `method` field.
|
||||
|
||||
#### select
|
||||
|
||||
Prompt the user to choose from a list. Dialog methods with a `timeout` field include the timeout in milliseconds; the agent auto-resolves with `undefined` if the client doesn't respond in time.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-1",
|
||||
"method": "select",
|
||||
"title": "Allow dangerous command?",
|
||||
"options": ["Allow", "Block"],
|
||||
"timeout": 10000
|
||||
}
|
||||
```
|
||||
|
||||
Expected response: `extension_ui_response` with `value` (the selected option string) or `cancelled: true`.
|
||||
|
||||
#### confirm
|
||||
|
||||
Prompt the user for yes/no confirmation.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-2",
|
||||
"method": "confirm",
|
||||
"title": "Clear session?",
|
||||
"message": "All messages will be lost.",
|
||||
"timeout": 5000
|
||||
}
|
||||
```
|
||||
|
||||
Expected response: `extension_ui_response` with `confirmed: true/false` or `cancelled: true`.
|
||||
|
||||
#### input
|
||||
|
||||
Prompt the user for free-form text.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-3",
|
||||
"method": "input",
|
||||
"title": "Enter a value",
|
||||
"placeholder": "type something..."
|
||||
}
|
||||
```
|
||||
|
||||
Expected response: `extension_ui_response` with `value` (the entered text) or `cancelled: true`.
|
||||
|
||||
#### editor
|
||||
|
||||
Open a multi-line text editor with optional prefilled content.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-4",
|
||||
"method": "editor",
|
||||
"title": "Edit some text",
|
||||
"prefill": "Line 1\nLine 2\nLine 3"
|
||||
}
|
||||
```
|
||||
|
||||
Expected response: `extension_ui_response` with `value` (the edited text) or `cancelled: true`.
|
||||
|
||||
#### notify
|
||||
|
||||
Display a notification. Fire-and-forget, no response expected.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-5",
|
||||
"method": "notify",
|
||||
"message": "Command blocked by user",
|
||||
"notifyType": "warning"
|
||||
}
|
||||
```
|
||||
|
||||
The `notifyType` field is `"info"`, `"warning"`, or `"error"`. Defaults to `"info"` if omitted.
|
||||
|
||||
#### setStatus
|
||||
|
||||
Set or clear a status entry in the footer/status bar. Fire-and-forget.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-6",
|
||||
"method": "setStatus",
|
||||
"statusKey": "my-ext",
|
||||
"statusText": "Turn 3 running..."
|
||||
}
|
||||
```
|
||||
|
||||
Send `statusText: undefined` (or omit it) to clear the status entry for that key.
|
||||
|
||||
#### setWidget
|
||||
|
||||
Set or clear a widget (block of text lines) displayed above or below the editor. Fire-and-forget.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-7",
|
||||
"method": "setWidget",
|
||||
"widgetKey": "my-ext",
|
||||
"widgetLines": ["--- My Widget ---", "Line 1", "Line 2"],
|
||||
"widgetPlacement": "aboveEditor"
|
||||
}
|
||||
```
|
||||
|
||||
Send `widgetLines: undefined` (or omit it) to clear the widget. The `widgetPlacement` field is `"aboveEditor"` (default) or `"belowEditor"`. Only string arrays are supported in RPC mode; component factories are ignored.
|
||||
|
||||
#### setTitle
|
||||
|
||||
Set the terminal window/tab title. Fire-and-forget.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-8",
|
||||
"method": "setTitle",
|
||||
"title": "pi - my project"
|
||||
}
|
||||
```
|
||||
|
||||
#### set_editor_text
|
||||
|
||||
Set the text in the input editor. Fire-and-forget.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "extension_ui_request",
|
||||
"id": "uuid-9",
|
||||
"method": "set_editor_text",
|
||||
"text": "prefilled text for the user"
|
||||
}
|
||||
```
|
||||
|
||||
### Extension UI Responses (stdin)
|
||||
|
||||
Responses are sent for dialog methods only (`select`, `confirm`, `input`, `editor`). The `id` must match the request.
|
||||
|
||||
#### Value response (select, input, editor)
|
||||
|
||||
```json
|
||||
{"type": "extension_ui_response", "id": "uuid-1", "value": "Allow"}
|
||||
```
|
||||
|
||||
#### Confirmation response (confirm)
|
||||
|
||||
```json
|
||||
{"type": "extension_ui_response", "id": "uuid-2", "confirmed": true}
|
||||
```
|
||||
|
||||
#### Cancellation response (any dialog)
|
||||
|
||||
Dismiss any dialog method. The extension receives `undefined` (for select/input/editor) or `false` (for confirm).
|
||||
|
||||
```json
|
||||
{"type": "extension_ui_response", "id": "uuid-3", "cancelled": true}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Failed commands return a response with `success: false`:
|
||||
|
|
@ -933,7 +1118,7 @@ Source files:
|
|||
- [`packages/ai/src/types.ts`](../../ai/src/types.ts) - `Model`, `UserMessage`, `AssistantMessage`, `ToolResultMessage`
|
||||
- [`packages/agent/src/types.ts`](../../agent/src/types.ts) - `AgentMessage`, `AgentEvent`
|
||||
- [`src/core/messages.ts`](../src/core/messages.ts) - `BashExecutionMessage`
|
||||
- [`src/modes/rpc/rpc-types.ts`](../src/modes/rpc/rpc-types.ts) - RPC command/response types
|
||||
- [`src/modes/rpc/rpc-types.ts`](../src/modes/rpc/rpc-types.ts) - RPC command/response types, extension UI request/response types
|
||||
|
||||
### Model
|
||||
|
||||
|
|
@ -1082,6 +1267,8 @@ for event in read_events():
|
|||
|
||||
See [`test/rpc-example.ts`](../test/rpc-example.ts) for a complete interactive example, or [`src/modes/rpc/rpc-client.ts`](../src/modes/rpc/rpc-client.ts) for a typed client implementation.
|
||||
|
||||
For a complete example of handling the extension UI protocol, see [`examples/rpc-extension-ui.ts`](../examples/rpc-extension-ui.ts) which pairs with the [`examples/extensions/rpc-demo.ts`](../examples/extensions/rpc-demo.ts) extension.
|
||||
|
||||
```javascript
|
||||
const { spawn } = require("child_process");
|
||||
const readline = require("readline");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue