Zum Inhalt springen

RPC-Protokollreferenz

Der RPC-Modus führt den Coding-Agenten als zeilengetrenntes JSON-Protokoll über stdio aus.

  • stdin: Befehle (RpcCommand) und Erweiterungs-UI-Antworten
  • stdout: Befehlsantworten (RpcResponse), Sitzungs-/Agenten-Ereignisse, Erweiterungs-UI-Anfragen

Primäre Implementierung:

  • 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-Fenster
xcsh --mode rpc [reguläre CLI-Optionen]

Hinweise zum Verhalten:

  • @file-CLI-Argumente werden im RPC-Modus abgelehnt.
  • Der RPC-Modus deaktiviert standardmäßig die automatische Generierung von Sitzungstiteln, um einen zusätzlichen Modellaufruf zu vermeiden.
  • Der RPC-Modus setzt workflow-verändernde todo.*-, task.*- und async.*-Einstellungen auf ihre eingebauten Standardwerte zurück, anstatt Benutzerüberschreibungen zu übernehmen.
  • Der Prozess liest stdin als JSONL (readJsonl(Bun.stdin.stream())).
  • Wenn stdin geschlossen wird, beendet sich der Prozess mit Exit-Code 0.
  • Antworten/Ereignisse werden als ein JSON-Objekt pro Zeile geschrieben.

Jeder Frame ist ein einzelnes JSON-Objekt gefolgt von \n.

Es gibt keinen Umschlag über die Objektstruktur hinaus.

  1. RpcResponse ({ type: "response", ... })
  2. AgentSessionEvent-Objekte (agent_start, message_update, etc.)
  3. RpcExtensionUIRequest ({ type: "extension_ui_request", ... })
  4. Erweiterungsfehler ({ type: "extension_error", extensionPath, event, error })
  1. RpcCommand
  2. RpcExtensionUIResponse ({ type: "extension_ui_response", ... })

Alle Befehle akzeptieren ein optionales id?: string.

  • Falls angegeben, geben normale Befehlsantworten dieselbe id zurück.
  • RpcClient nutzt dies zur Auflösung ausstehender Anfragen.

Wichtiges Randverhalten zur Laufzeit:

  • Antworten auf unbekannte Befehle werden mit id: undefined ausgegeben (auch wenn die Anfrage eine id hatte).
  • Parse-/Handler-Ausnahmen in der Eingabeschleife geben command: "parse" mit id: undefined aus.
  • prompt und abort_and_prompt geben sofortigen Erfolg zurück und können dann eine spätere Fehlerantwort mit derselben ID ausgeben, falls die asynchrone Prompt-Planung fehlschlägt.

RpcCommand ist in src/modes/rpc/rpc-types.ts definiert:

  • { 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" }

Alle Befehlsergebnisse verwenden RpcResponse:

  • Erfolg: { id?, type: "response", command: <command>, success: true, data?: ... }
  • Fehler: { id?, type: "response", command: string, success: false, error: string }

Daten-Payloads sind befehlsspezifisch und in rpc-types.ts definiert.

{
"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"
}
]
}
]
}

Ersetzt den In-Memory-Todo-Zustand für die aktuelle Sitzung und gibt die normalisierte Phasenliste zurück:

{
"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"
}
]
}
]
}

Dies ist nützlich für Hosts, die einen Plan vor dem ersten Prompt vorausfüllen möchten.

Ersetzt den aktuellen Satz von Host-eigenen Tools, die der RPC-Server über stdio zurückrufen kann:

{
"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
}
}
]
}

Der Antwort-Payload ist:

{
"toolNames": ["echo_host"]
}

Diese Tools werden der aktiven Sitzungs-Tool-Registry vor dem nächsten Modellaufruf hinzugefügt. Ein erneutes Senden von set_host_tools ersetzt den vorherigen Host-eigenen Satz.

Der RPC-Modus leitet AgentSessionEvent-Objekte von AgentSession.subscribe(...) weiter.

Häufige Ereignistypen:

  • agent_start, agent_end
  • turn_start, turn_end
  • message_start, message_update, message_end
  • tool_execution_start, tool_execution_update, tool_execution_end
  • auto_compaction_start, auto_compaction_end
  • auto_retry_start, auto_retry_end
  • ttsr_triggered
  • todo_reminder
  • todo_auto_clear

Fehler des Erweiterungs-Runners werden separat ausgegeben als:

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

message_update enthält Streaming-Deltas in assistantMessageEvent (Text-/Denk-/Toolcall-Deltas).

Prompt/Warteschlangen-Nebenläufigkeit und Reihenfolge

Abschnitt betitelt „Prompt/Warteschlangen-Nebenläufigkeit und Reihenfolge“

Dies ist das wichtigste operative Verhalten.

prompt und abort_and_prompt werden sofort bestätigt:

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

Das bedeutet:

  • Befehlsannahme != Ausführungsabschluss
  • Der endgültige Abschluss wird über agent_end beobachtet

AgentSession.prompt() erfordert streamingBehavior während des aktiven Streamings:

  • "steer" => eingereihte Steuerungsnachricht (Unterbrechungspfad)
  • "followUp" => eingereihte Folgenachricht (Nach-Runde-Pfad)

Falls während des Streamings weggelassen, schlägt der Prompt fehl.

Aus dem Coding-Agent-Einstellungsschema (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": eine eingereihte Nachricht pro Runde abarbeiten
    • "all": gesamte Warteschlange auf einmal abarbeiten
  • set_interrupt_mode
    • "immediate": Tool-Ausführung prüft die Steuerung zwischen Tool-Aufrufen; ausstehende Steuerung kann verbleibende Tool-Aufrufe in der Runde abbrechen
    • "wait": Steuerung bis zum Rundenabschluss aufschieben

Erweiterungen im RPC-Modus verwenden Anfrage/Antwort-UI-Frames.

RpcExtensionUIRequest (type: "extension_ui_request") Methoden:

  • select, confirm, input, editor
  • notify, setStatus, setWidget, setTitle, set_editor_text

Laufzeithinweis:

  • Die automatische Sitzungstitel-Generierung ist im RPC-Modus deaktiviert, und setTitle-UI-Anfragen werden standardmäßig ebenfalls unterdrückt, da die meisten Hosts keine sinnvolle Terminal-Titel-Oberfläche haben. Setzen Sie PI_RPC_EMIT_TITLE=1, um das UI-Ereignis wieder zu aktivieren.

Beispiel:

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

RpcExtensionUIResponse (type: "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 }

Falls ein Dialog ein Timeout hat, löst der RPC-Modus auf einen Standardwert auf, wenn das Timeout/Abbruch ausgelöst wird.

RPC-Hosts können dem Agenten benutzerdefinierte Tools bereitstellen, indem sie set_host_tools senden und dann Ausführungsanfragen über denselben Transport bedienen.

Wenn der Agent möchte, dass der Host eines dieser Tools ausführt, gibt der RPC-Modus Folgendes aus:

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

Falls die Tool-Ausführung später abgebrochen wird, gibt der RPC-Modus Folgendes aus:

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

Hosts können optional den Fortschritt streamen:

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

Der Abschluss verwendet:

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

Setzen Sie isError: true bei host_tool_result, um den zurückgegebenen Inhalt als Tool-Fehler darzustellen.

Fehler haben success: false mit einem String error.

{ "id": "req_2", "type": "response", "command": "set_model", "success": false, "error": "Model not found: provider/model" }
  • Die meisten Befehlsfehler sind wiederherstellbar; der Prozess bleibt aktiv.
  • Fehlerhaftes JSONL / Parse-Loop-Ausnahmen geben eine parse-Fehlerantwort aus und lesen nachfolgende Zeilen weiter.
  • Ein leerer set_session_name wird abgelehnt (Session name cannot be empty).
  • Erweiterungs-UI-Antworten mit unbekannter id werden ignoriert.
  • Prozessbeendigungsbedingungen sind das Schließen von stdin oder ein expliziter durch eine Erweiterung ausgelöster Shutdown.

stdin:

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

stdout-Sequenz (typisch):

{ "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) Prompt während des Streamings mit expliziter Warteschlangen-Richtlinie

Abschnitt betitelt „2) Prompt während des Streamings mit expliziter Warteschlangen-Richtlinie“

stdin:

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

3) Warteschlangenverhalten inspizieren und anpassen

Abschnitt betitelt „3) Warteschlangenverhalten inspizieren und anpassen“

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" }

src/modes/rpc/rpc-client.ts ist ein Komfort-Wrapper, nicht die Protokolldefinition.

Aktuelle Helfer-Eigenschaften:

  • Startet bun <cliPath> --mode rpc
  • Korreliert Antworten über generierte req_<n>-IDs
  • Leitet nur erkannte AgentEvent-Typen an Listener weiter
  • Unterstützt Host-eigene benutzerdefinierte Tools über setCustomTools() und automatische Behandlung von host_tool_call / host_tool_cancel
  • Stellt nicht für jeden Protokollbefehl Hilfsmethoden bereit (zum Beispiel sind set_interrupt_mode und set_session_name in den Protokolltypen vorhanden, aber nicht als dedizierte Methoden gewrapped)

Verwenden Sie rohe Protokoll-Frames, wenn Sie vollständige Oberflächenabdeckung benötigen.