Skip to main content

RPC extension UI protocol

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 or degraded in RPC mode because they require direct TUI access:
  • custom() returns undefined
  • setWorkingMessage(), setWorkingIndicator(), setFooter(), setHeader(), setEditorComponent() are no-ops
  • getEditorText() returns ""
  • setToolsExpanded() and getToolsExpanded() maintain context-local expansion state; getChatRenderSettings().toolOutputExpanded reports the same value. A same-value setToolsExpanded() call is a no-op and does not request a custom-UI render. This state is not sent through the client extension-UI protocol.
  • pasteToEditor() delegates to setEditorText() (no paste/collapse handling)
  • getAllThemes() returns []
  • getTheme() returns undefined
  • setTheme() returns { success: false, error: "..." }
Note: ctx.mode is "rpc" and ctx.hasUI is true in RPC mode because the dialog and fire-and-forget methods are functional via the extension UI sub-protocol. Use ctx.mode === "tui" to guard TUI-specific features like custom() that require a real terminal.

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.
Expected response: extension_ui_response with value (the selected option string) or cancelled: true.

confirm

Prompt the user for yes/no confirmation.
Expected response: extension_ui_response with confirmed: true/false or cancelled: true.

input

Prompt the user for free-form text.
Expected response: extension_ui_response with value (the entered text) or cancelled: true.

editor

Open a multi-line text editor with optional prefilled content.
Expected response: extension_ui_response with value (the edited text) or cancelled: true.

notify

Display a notification. Fire-and-forget, no response expected.
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.
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.
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.

set_editor_text

Set the text in the input editor. Fire-and-forget.

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)

Confirmation response (confirm)

Cancellation response (any dialog)

Dismiss any dialog method. The extension receives undefined (for select/input/editor) or false (for confirm).