コンテンツにスキップ

RPCプロトコルリファレンス

RPCモードは、stdio上の改行区切りJSONプロトコルとしてコーディングエージェントを実行します。

  • stdin: コマンド(RpcCommand)および拡張UIレスポンス
  • stdout: コマンドレスポンス(RpcResponse)、セッション/エージェントイベント、拡張UIリクエスト

主要な実装:

  • src/modes/rpc/rpc-mode.ts
  • src/modes/rpc/rpc-types.ts
  • src/session/agent-session.ts
  • packages/agent/src/agent.ts
  • packages/agent/src/agent-loop.ts
Terminal window
xcsh --mode rpc [regular CLI options]

動作に関する注意事項:

  • @file CLI引数はRPCモードでは拒否されます。
  • RPCモードでは、余分なモデル呼び出しを避けるため、デフォルトで自動セッションタイトル生成が無効になっています。
  • RPCモードでは、ワークフローに影響する todo.*task.*、および async.* の設定を、ユーザーのオーバーライドを継承する代わりに組み込みのデフォルト値にリセットします。
  • プロセスはstdinをJSONLとして読み取ります(readJsonl(Bun.stdin.stream()))。
  • stdinが閉じられると、プロセスは終了コード 0 で終了します。
  • レスポンス/イベントは1行に1つのJSONオブジェクトとして書き込まれます。

トランスポートとフレーミング

Section titled “トランスポートとフレーミング”

各フレームは、\n が後続する単一のJSONオブジェクトです。

オブジェクトの形状自体以外にエンベロープはありません。

送信フレームカテゴリ(stdout)

Section titled “送信フレームカテゴリ(stdout)”
  1. RpcResponse{ type: "response", ... }
  2. AgentSessionEvent オブジェクト(agent_startmessage_update など)
  3. RpcExtensionUIRequest{ type: "extension_ui_request", ... }
  4. 拡張エラー({ type: "extension_error", extensionPath, event, error }
  1. RpcCommand
  2. RpcExtensionUIResponse{ type: "extension_ui_response", ... }

すべてのコマンドはオプションの id?: string を受け付けます。

  • 指定された場合、通常のコマンドレスポンスは同じ id をエコーバックします。
  • RpcClient はこれを利用して保留中のリクエストを解決します。

ランタイムにおける重要なエッジケースの動作:

  • 不明なコマンドのレスポンスは id: undefined で送信されます(リクエストに id があった場合でも)。
  • 入力ループでのパース/ハンドラー例外は command: "parse"id: undefined として送信されます。
  • promptabort_and_prompt は即座に成功を返しますが、非同期プロンプトのスケジューリングが失敗した場合、同じ idで後続のエラーレスポンスを送信する場合があります。

RpcCommandsrc/modes/rpc/rpc-types.ts で定義されています:

  • { id?, type: "prompt", message: string, images?: ImageContent[], streamingBehavior?: "steer" | "followUp" }
  • { id?, type: "steer", message: string, images?: ImageContent[] }
  • { id?, type: "follow_up", message: string, images?: ImageContent[] }
  • { id?, type: "abort" }
  • { id?, type: "abort_and_prompt", message: string, images?: ImageContent[] }
  • { id?, type: "new_session", parentSession?: string }
  • { id?, type: "get_state" }
  • { id?, type: "set_todos", phases: TodoPhase[] }
  • { id?, type: "set_host_tools", tools: RpcHostToolDefinition[] }
  • { id?, type: "set_model", provider: string, modelId: string }
  • { id?, type: "cycle_model" }
  • { id?, type: "get_available_models" }
  • { id?, type: "set_thinking_level", level: ThinkingLevel }
  • { id?, type: "cycle_thinking_level" }
  • { id?, type: "set_steering_mode", mode: "all" | "one-at-a-time" }
  • { id?, type: "set_follow_up_mode", mode: "all" | "one-at-a-time" }
  • { id?, type: "set_interrupt_mode", mode: "immediate" | "wait" }
  • { id?, type: "compact", customInstructions?: string }
  • { id?, type: "set_auto_compaction", enabled: boolean }
  • { id?, type: "set_auto_retry", enabled: boolean }
  • { id?, type: "abort_retry" }
  • { id?, type: "bash", command: string }
  • { id?, type: "abort_bash" }
  • { id?, type: "get_session_stats" }
  • { id?, type: "export_html", outputPath?: string }
  • { id?, type: "switch_session", sessionPath: string }
  • { id?, type: "branch", entryId: string }
  • { id?, type: "get_branch_messages" }
  • { id?, type: "get_last_assistant_text" }
  • { id?, type: "set_session_name", name: string }
  • { id?, type: "get_messages" }

すべてのコマンド結果は RpcResponse を使用します:

  • 成功: { id?, type: "response", command: <command>, success: true, data?: ... }
  • 失敗: { id?, type: "response", command: string, success: false, error: string }

データペイロードはコマンド固有であり、rpc-types.ts で定義されています。

{
"model": { "provider": "...", "id": "..." },
"thinkingLevel": "off|minimal|low|medium|high|xhigh",
"isStreaming": false,
"isCompacting": false,
"steeringMode": "all|one-at-a-time",
"followUpMode": "all|one-at-a-time",
"interruptMode": "immediate|wait",
"sessionFile": "...",
"sessionId": "...",
"sessionName": "...",
"autoCompactionEnabled": true,
"messageCount": 0,
"queuedMessageCount": 0,
"todoPhases": [
{
"id": "phase-1",
"name": "Todos",
"tasks": [
{
"id": "task-1",
"content": "Map the tool surface",
"status": "in_progress"
}
]
}
]
}

現在のセッションのインメモリTodo状態を置き換え、正規化されたフェーズリストを返します:

{
"id": "req_2",
"type": "set_todos",
"phases": [
{
"id": "phase-1",
"name": "Evaluation",
"tasks": [
{
"id": "task-1",
"content": "Map the read tool surface",
"status": "in_progress"
},
{
"id": "task-2",
"content": "Exercise edit operations",
"status": "pending"
}
]
}
]
}

これは、最初のプロンプトの前にプランを事前設定したいホストに便利です。

RPCサーバーがstdio経由でコールバックできるホスト所有ツールの現在のセットを置き換えます:

{
"id": "req_3",
"type": "set_host_tools",
"tools": [
{
"name": "echo_host",
"label": "Echo Host",
"description": "Echo a value from the embedding host",
"parameters": {
"type": "object",
"properties": {
"message": { "type": "string" }
},
"required": ["message"],
"additionalProperties": false
}
}
]
}

レスポンスペイロードは以下の通りです:

{
"toolNames": ["echo_host"]
}

これらのツールは、次のモデル呼び出しの前にアクティブセッションのツールレジストリに追加されます。set_host_tools を再送信すると、以前のホスト所有セットが置き換えられます。

RPCモードは、AgentSession.subscribe(...) から AgentSessionEvent オブジェクトを転送します。

一般的なイベントタイプ:

  • agent_startagent_end
  • turn_startturn_end
  • message_startmessage_updatemessage_end
  • tool_execution_starttool_execution_updatetool_execution_end
  • auto_compaction_startauto_compaction_end
  • auto_retry_startauto_retry_end
  • ttsr_triggered
  • todo_reminder
  • todo_auto_clear

拡張ランナーのエラーは以下のように個別に送信されます:

{ "type": "extension_error", "extensionPath": "...", "event": "...", "error": "..." }

message_update には assistantMessageEvent にストリーミングデルタ(テキスト/思考/ツールコールのデルタ)が含まれます。

プロンプト/キューの並行性と順序

Section titled “プロンプト/キューの並行性と順序”

これは最も重要な運用上の動作です。

promptabort_and_prompt即座に確認応答されます:

{ "id": "req_1", "type": "response", "command": "prompt", "success": true }

これは以下を意味します:

  • コマンドの受け入れ != 実行の完了
  • 最終的な完了は agent_end を通じて観察されます

AgentSession.prompt() はアクティブなストリーミング中に streamingBehavior を必要とします:

  • "steer" => キューに入れられたステアリングメッセージ(割り込みパス)
  • "followUp" => キューに入れられたフォローアップメッセージ(ターン後パス)

ストリーミング中に省略すると、プロンプトは失敗します。

コーディングエージェント設定スキーマ(packages/coding-agent/src/config/settings-schema.ts)より:

  • steeringMode: "one-at-a-time"
  • followUpMode: "one-at-a-time"
  • interruptMode: "wait"
  • set_steering_mode / set_follow_up_mode
    • "one-at-a-time": ターンごとにキューから1つのメッセージをデキュー
    • "all": キュー全体を一度にデキュー
  • set_interrupt_mode
    • "immediate": ツール実行がツールコール間でステアリングをチェックし、保留中のステアリングがターン内の残りのツールコールを中止できます
    • "wait": ターン完了までステアリングを遅延

RPCモードの拡張機能は、リクエスト/レスポンスUIフレームを使用します。

RpcExtensionUIRequesttype: "extension_ui_request")メソッド:

  • selectconfirminputeditor
  • notifysetStatussetWidgetsetTitleset_editor_text

ランタイムに関する注意:

  • RPCモードでは自動セッションタイトル生成が無効になっており、setTitle UIリクエストもデフォルトで抑制されます。これは、ほとんどのホストが意味のあるターミナルタイトルサーフェスを持っていないためです。UIイベントのみをオプトインするには PI_RPC_EMIT_TITLE=1 を設定してください。

例:

{ "type": "extension_ui_request", "id": "123", "method": "confirm", "title": "Confirm", "message": "Continue?", "timeout": 30000 }

RpcExtensionUIResponsetype: "extension_ui_response"):

  • { type: "extension_ui_response", id: string, value: string }
  • { type: "extension_ui_response", id: string, confirmed: boolean }
  • { type: "extension_ui_response", id: string, cancelled: true }

ダイアログにタイムアウトがある場合、RPCモードはタイムアウト/中止が発生するとデフォルト値に解決します。

RPCホストは set_host_tools を送信してエージェントにカスタムツールを公開し、同じトランスポート上で実行リクエストを処理できます。

エージェントがホストにこれらのツールの1つを実行してほしい場合、RPCモードは以下を送信します:

{
"type": "host_tool_call",
"id": "host_1",
"toolCallId": "toolu_123",
"toolName": "echo_host",
"arguments": { "message": "hello" }
}

ツール実行が後に中止された場合、RPCモードは以下を送信します:

{
"type": "host_tool_cancel",
"id": "host_cancel_1",
"targetId": "host_1"
}

ホストはオプションで進捗をストリーミングできます:

{
"type": "host_tool_update",
"id": "host_1",
"partialResult": {
"content": [{ "type": "text", "text": "working" }]
}
}

完了には以下を使用します:

{
"type": "host_tool_result",
"id": "host_1",
"result": {
"content": [{ "type": "text", "text": "done" }]
}
}

返されたコンテンツをツールエラーとして表示するには、host_tool_resultisError: true を設定してください。

エラーモデルとリカバリ可能性

Section titled “エラーモデルとリカバリ可能性”

失敗は success: false と文字列の error で表されます。

{ "id": "req_2", "type": "response", "command": "set_model", "success": false, "error": "Model not found: provider/model" }
  • ほとんどのコマンドの失敗はリカバリ可能であり、プロセスは存続します。
  • 不正なJSONL / パースループの例外は parse エラーレスポンスを送信し、後続の行の読み取りを続行します。
  • 空の set_session_name は拒否されます(Session name cannot be empty)。
  • 不明な id を持つ拡張UIレスポンスは無視されます。
  • プロセスの終了条件は、stdinの閉鎖または拡張機能によるシャットダウンのトリガーです。

stdin:

{ "id": "req_1", "type": "prompt", "message": "Summarize this repo" }

stdout シーケンス(典型的):

{ "id": "req_1", "type": "response", "command": "prompt", "success": true }
{ "type": "agent_start" }
{ "type": "message_update", "assistantMessageEvent": { "type": "text_delta", "delta": "..." }, "message": { "role": "assistant", "content": [] } }
{ "type": "agent_end", "messages": [] }

2) 明示的なキューポリシーによるストリーミング中のプロンプト

Section titled “2) 明示的なキューポリシーによるストリーミング中のプロンプト”

stdin:

{ "id": "req_2", "type": "prompt", "message": "Also include risks", "streamingBehavior": "followUp" }

stdin:

{ "id": "q1", "type": "get_state" }
{ "id": "q2", "type": "set_steering_mode", "mode": "all" }
{ "id": "q3", "type": "set_interrupt_mode", "mode": "wait" }

stdout:

{ "type": "extension_ui_request", "id": "ui_7", "method": "input", "title": "Branch name", "placeholder": "feature/..." }

stdin:

{ "type": "extension_ui_response", "id": "ui_7", "value": "feature/rpc-host" }

RpcClient ヘルパーに関する注意事項

Section titled “RpcClient ヘルパーに関する注意事項”

src/modes/rpc/rpc-client.ts は便利なラッパーであり、プロトコル定義ではありません。

現在のヘルパーの特性:

  • bun <cliPath> --mode rpc を起動します
  • 生成された req_<n> IDでレスポンスを相関させます
  • 認識された AgentEvent タイプのみをリスナーにディスパッチします
  • setCustomTools() およびホスト所有カスタムツールの host_tool_call / host_tool_cancel の自動処理をサポートします
  • すべてのプロトコルコマンドに対するヘルパーメソッドを公開していません(例えば、set_interrupt_modeset_session_name はプロトコル型にありますが、専用メソッドとしてラップされていません)

完全なサーフェスカバレッジが必要な場合は、生のプロトコルフレームを使用してください。