RPC Modus
Der RPC-Modus ermöglicht den kopflosen Betrieb des Codierungsagenten über ein JSON-Protokoll über stdin/stdout. Dies ist nützlich, um den Agenten in andere Anwendungen, IDEs oder benutzerdefinierte UIs einzubetten.
Hinweis für Node.js/TypeScript-Benutzer: Wenn Sie eine Node.js-Anwendung erstellen, sollten Sie erwägen, AgentSession direkt aus @earendil-works/pi-coding-agent zu verwenden, anstatt einen Unterprozess zu erzeugen. Siehe src/core/agent-session.ts für API. Informationen zu einem unterprozessbasierten TypeScript-Client finden Sie unter src/modes/rpc/rpc-client.ts.
Starten des RPC-Modus
pi --mode rpc [options]Häufige Optionen:
--provider <name>: Legen Sie den LLM-Anbieter fest (anthropic, openai, google usw.)--model <pattern>: Modellmuster oder ID (unterstütztprovider/idund optional:<thinking>)--name <name>/-n <name>: Legen Sie den Anzeigenamen der Sitzung beim Start fest--no-session: Sitzungspersistenz deaktivieren--session-dir <path>: Benutzerdefiniertes Sitzungsspeicherverzeichnis
Protokollübersicht
- Befehle: JSON Objekte werden an stdin gesendet, eines pro Zeile
- Antworten: JSON Objekte mit
type: "response", die den Erfolg/Fehler des Befehls anzeigen - Ereignisse: Agentenereignisse werden als JSON-Zeilen an stdout gestreamt
Alle Befehle unterstützen ein optionales id-Feld für die Anforderungs-/Antwortkorrelation. Sofern angegeben, enthält die entsprechende Antwort dasselbe id. bash_execution_update-Ereignisse umfassen auch die id ihres ursprünglichen bash-Befehls.
Rahmen
Der RPC-Modus verwendet die strikte JSONL-Semantik mit LF (\n) als einzigem Datensatztrennzeichen.
Das ist für Kunden wichtig:
- Datensätze nur am
\nteilen - Akzeptieren Sie die optionale
\r\n-Eingabe, indem Sie ein nachgestelltes\rentfernen. - Verwenden Sie keine generischen Zeilenleser, die Unicode-Trennzeichen als Zeilenumbrüche behandeln
Insbesondere ist Knoten readline nicht protokollkonform für den RPC-Modus, da er auch auf U+2028 und U+2029 aufteilt, die innerhalb von JSON-Strings gültig sind.
Befehle
Aufforderung
prompt
Senden Sie eine Benutzeraufforderung an den Agenten. Die Befehlsantwort wird ausgegeben, nachdem die Eingabeaufforderung akzeptiert, in die Warteschlange gestellt oder verarbeitet wurde. Ereignisse werden nach der Annahme weiterhin asynchron gestreamt.
{"id": "req-1", "type": "prompt", "message": "Hello, world!"}Mit Bildern:
{"type": "prompt", "message": "What's in this image?", "images": [{"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}]}Während des Streamings: Wenn der Agent bereits streamt, müssen Sie streamingBehavior angeben, um die Nachricht in die Warteschlange zu stellen:
{"type": "prompt", "message": "New instruction", "streamingBehavior": "steer"}"steer": Die Nachricht in die Warteschlange stellen, während der Agent ausgeführt wird. Es wird geliefert, nachdem der aktuelle Assistentenzug die Ausführung seiner Werkzeugaufrufe abgeschlossen hat, und zwar vor dem nächsten LLM-Aufruf."followUp": Warten Sie, bis der Agent fertig ist. Die Nachricht wird nur zugestellt, wenn der Agent stoppt.
Wenn der Agent streamt und kein streamingBehavior angegeben ist, gibt der Befehl einen Fehler zurück.
Erweiterungsbefehle: Wenn es sich bei der Nachricht um einen Erweiterungsbefehl handelt (z. B. /mycommand), wird dieser auch während des Streamings sofort ausgeführt. Erweiterungsbefehle verwalten ihre eigene LLM-Interaktion über pi.sendMessage().
Eingabeerweiterung: Skill-Befehle (/skill:name) und prompt templates (/template) werden vor dem Senden/in die Warteschlange erweitert.
Antwort:
{"id": "req-1", "type": "response", "command": "prompt", "success": true}success: true bedeutet, dass die Eingabeaufforderung angenommen, in die Warteschlange gestellt oder sofort bearbeitet wurde. success: false bedeutet, dass die Eingabeaufforderung vor der Annahme abgelehnt wurde. Fehler nach der Annahme werden über den normalen Ereignis- und Nachrichtenstrom gemeldet, nicht als zweites response für dieselbe Anforderungs-ID.
Das Feld images ist optional. Jedes Bild verwendet das ImageContent-Format: {"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}.
steuern
Stellen Sie eine Lenkungsnachricht in die Warteschlange, während der Agent ausgeführt wird. Es wird geliefert, nachdem der aktuelle Assistentenzug die Ausführung seiner Werkzeugaufrufe abgeschlossen hat, und zwar vor dem nächsten LLM-Aufruf. Fertigkeitsbefehle und prompt templates werden erweitert. Erweiterungsbefehle sind nicht zulässig (verwenden Sie stattdessen prompt).
{"type": "steer", "message": "Stop and do this instead"}Mit Bildern:
{"type": "steer", "message": "Look at this instead", "images": [{"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}]}Das Feld images ist optional. Jedes Bild verwendet das Format ImageContent (dasselbe wie prompt).
Antwort:
{"type": "response", "command": "steer", "success": true}Siehe set_steering_mode zur Steuerung der Verarbeitung von Lenkungsnachrichten.
nachverfolgen
Stellen Sie eine Folgenachricht in die Warteschlange, die verarbeitet werden soll, nachdem der Agent fertig ist. Wird nur zugestellt, wenn der Agent keine Tool-Anrufe oder Steuerungsnachrichten mehr hat. Fertigkeitsbefehle und prompt templates werden erweitert. Erweiterungsbefehle sind nicht zulässig (verwenden Sie stattdessen prompt).
{"type": "follow_up", "message": "After you're done, also do this"}Mit Bildern:
{"type": "follow_up", "message": "Also check this image", "images": [{"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}]}Das Feld images ist optional. Jedes Bild verwendet das Format ImageContent (dasselbe wie prompt).
Antwort:
{"type": "response", "command": "follow_up", "success": true}Siehe set_follow_up_mode für die Steuerung, wie Folgenachrichten verarbeitet werden.
abbrechen
Brechen Sie den aktuellen Agentenvorgang ab.
{"type": "abort"}Antwort:
{"type": "response", "command": "abort", "success": true}neue_Sitzung
Starten Sie eine neue Sitzung. Kann durch einen session_before_switch-Erweiterungsereignishandler abgebrochen werden.
{"type": "new_session"}Mit optionaler übergeordneter Sitzungsverfolgung:
{"type": "new_session", "parentSession": "/path/to/parent-session.jsonl"}Antwort:
{"type": "response", "command": "new_session", "success": true, "data": {"cancelled": false}}Wenn eine Verlängerung storniert wird:
{"type": "response", "command": "new_session", "success": true, "data": {"cancelled": true}}Zustand
get_state
Aktuellen Sitzungsstatus abrufen.
{"type": "get_state"}Antwort:
{
"type": "response",
"command": "get_state",
"success": true,
"data": {
"model": {...},
"thinkingLevel": "medium",
"isStreaming": false,
"isCompacting": false,
"steeringMode": "all",
"followUpMode": "one-at-a-time",
"sessionFile": "/path/to/session.jsonl",
"sessionId": "abc123",
"sessionName": "my-feature-work",
"autoCompactionEnabled": true,
"messageCount": 5,
"pendingMessageCount": 0
}
}Das Feld model ist ein vollständiges Model-Objekt oder null. Das Feld sessionName ist der über set_session_name festgelegte Anzeigename oder wird weggelassen, wenn es nicht festgelegt ist.
get_messages
Erhalten Sie alle Nachrichten in der Konversation.
{"type": "get_messages"}Antwort:
{
"type": "response",
"command": "get_messages",
"success": true,
"data": {"messages": [...]}
}Nachrichten sind AgentMessage Objekte (siehe Message Types).
Modell
set_model
Wechseln Sie zu einem bestimmten Modell.
{"type": "set_model", "provider": "anthropic", "modelId": "claude-sonnet-4-20250514"}Die Antwort enthält das vollständige Model-Objekt:
{
"type": "response",
"command": "set_model",
"success": true,
"data": {...}
}zyklusmodell
Wechseln Sie zum nächsten verfügbaren Modell. Gibt null Daten zurück, wenn nur ein Modell verfügbar ist.
{"type": "cycle_model"}Antwort:
{
"type": "response",
"command": "cycle_model",
"success": true,
"data": {
"model": {...},
"thinkingLevel": "medium",
"isScoped": false
}
}Das Feld model ist ein vollständiges Model-Objekt.
get_available_models
Listen Sie alle konfigurierten Modelle auf.
{"type": "get_available_models"}Die Antwort enthält ein Array vollständiger Model-Objekte:
{
"type": "response",
"command": "get_available_models",
"success": true,
"data": {
"models": [...]
}
}Denken
set_thinking_level
Legen Sie die Argumentations-/Denkebene für Modelle fest, die dies unterstützen.
{"type": "set_thinking_level", "level": "high"}Stufen: "off", "minimal", "low", "medium", "high", "xhigh", "max"
"xhigh" und "max" werden nur angezeigt, wenn sie vom ausgewählten Modell unterstützt werden. Einige Modelle, darunter GPT-5.6, stellen beides zur Verfügung.
Antwort:
{"type": "response", "command": "set_thinking_level", "success": true}Cycle_thinking_level
Durchlaufen Sie die verfügbaren Denkebenen. Gibt null Daten zurück, wenn das Modell das Denken nicht unterstützt.
{"type": "cycle_thinking_level"}Antwort:
{
"type": "response",
"command": "cycle_thinking_level",
"success": true,
"data": {"level": "high"}
}get_available_thinking_levels
Listen Sie die vom aktuellen Modell unterstützten Denkebenen auf. Gibt ["off"] für ein Modell ohne Begründungsunterstützung zurück.
{"type": "get_available_thinking_levels"}Antwort:
{
"type": "response",
"command": "get_available_thinking_levels",
"success": true,
"data": {
"levels": ["off", "minimal", "low", "medium", "high"]
}
}Warteschlangenmodi
set_steering_mode
Steuern Sie, wie Leitnachrichten (ab steer) übermittelt werden.
{"type": "set_steering_mode", "mode": "one-at-a-time"}Modi:
"all": Übermitteln Sie alle Lenknachrichten, nachdem der aktuelle Assistentenzug die Ausführung seiner Werkzeugaufrufe abgeschlossen hat"one-at-a-time": Übermittlung einer Lenkungsnachricht pro abgeschlossener Assistentendrehung (Standard)
Antwort:
{"type": "response", "command": "set_steering_mode", "success": true}set_follow_up_mode
Steuern Sie, wie Folgenachrichten (ab follow_up) zugestellt werden.
{"type": "set_follow_up_mode", "mode": "one-at-a-time"}Modi:
"all": Alle Folgenachrichten zustellen, wenn der Agent fertig ist"one-at-a-time": Eine Folgenachricht pro Agent-Abschluss senden (Standard)
Antwort:
{"type": "response", "command": "set_follow_up_mode", "success": true}Verdichtung
kompakt
Konversationskontext manuell komprimieren, um die Token-Nutzung zu reduzieren.
{"type": "compact"}Mit individueller Anleitung:
{"type": "compact", "customInstructions": "Focus on code changes"}Antwort:
{
"type": "response",
"command": "compact",
"success": true,
"data": {
"summary": "Summary of conversation...",
"firstKeptEntryId": "abc123",
"tokensBefore": 150000,
"estimatedTokensAfter": 32000,
"usage": {
"input": 32000,
"output": 1200,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 33200,
"cost": {"input": 0.01, "output": 0.02, "cacheRead": 0, "cacheWrite": 0, "total": 0.03}
},
"details": {}
}
}estimatedTokensAfter ist eine heuristische Schätzung des neu erstellten Nachrichtenkontexts unmittelbar nach der Komprimierung, keine anbietergenaue Tokenanzahl. usage meldet den oder die LLM-Aufrufe, die die Zusammenfassung generiert haben, und kann von benutzerdefinierten Komprimierungshandlern weggelassen werden.
set_auto_compaction
Aktivieren oder deaktivieren Sie die automatische Komprimierung, wenn der Kontext fast voll ist.
{"type": "set_auto_compaction", "enabled": true}Antwort:
{"type": "response", "command": "set_auto_compaction", "success": true}Wiederholen
set_auto_retry
Aktivieren oder deaktivieren Sie die automatische Wiederholung bei vorübergehenden Fehlern (Überlastung, Ratenbegrenzung, 5xx).
{"type": "set_auto_retry", "enabled": true}Antwort:
{"type": "response", "command": "set_auto_retry", "success": true}abort_retry
Einen laufenden Wiederholungsversuch abbrechen (die Verzögerung aufheben und den Wiederholungsversuch beenden).
{"type": "abort_retry"}Antwort:
{"type": "response", "command": "abort_retry", "success": true}Bash
bash
Führen Sie einen Shell-Befehl aus und fügen Sie die Ausgabe zum Konversationskontext hinzu. Geben Sie Streams als bash_execution_update-Ereignisse aus, während der Befehl ausgeführt wird. Die Antwort enthält das Endergebnis.
{"id": "req-1", "type": "bash", "command": "ls -la"}Fügen Sie eine id ein, um gestreamte bash_execution_update-Ereignisse mit diesem Befehl zu verknüpfen.
Antwort:
{
"id": "req-1",
"type": "response",
"command": "bash",
"success": true,
"data": {
"output": "total 48\ndrwxr-xr-x ...",
"exitCode": 0,
"cancelled": false,
"truncated": false
}
}Wenn die Ausgabe abgeschnitten wurde, enthält sie fullOutputPath:
{
"type": "response",
"command": "bash",
"success": true,
"data": {
"output": "truncated output...",
"exitCode": 0,
"cancelled": false,
"truncated": true,
"fullOutputPath": "/tmp/pi-bash-abc123.log"
}
}Wie bash Ergebnisse das LLM erreichen:
Der Befehl bash wird sofort ausgeführt und gibt eine BashResult zurück. Intern wird ein BashExecutionMessage erstellt und im Nachrichtenstatus des Agenten gespeichert.
Wenn der nächste prompt-Befehl gesendet wird, werden alle Nachrichten (einschließlich BashExecutionMessage) umgewandelt, bevor sie an das LLM gesendet werden. Die BashExecutionMessage wird mit diesem Format in eine UserMessage umgewandelt:
Ran `ls -la`
```
insgesamt 48
drwxr-xr-x...
```Das heisst:
- Die Bash-Ausgabe wird nicht sofort, sondern erst bei der nächsten Eingabeaufforderung in den LLM-Kontext eingebunden
- Vor einer Eingabeaufforderung können mehrere bash-Befehle ausgeführt werden; Alle Ausgaben werden einbezogen
abort_bash
Brechen Sie einen laufenden bash-Befehl ab.
{"type": "abort_bash"}Antwort:
{"type": "response", "command": "abort_bash", "success": true}Sitzung
get_session_stats
Erhalten Sie die Token-Nutzung, Kostenstatistiken und die aktuelle Kontextfensternutzung.
{"type": "get_session_stats"}Antwort:
{
"type": "response",
"command": "get_session_stats",
"success": true,
"data": {
"sessionFile": "/path/to/session.jsonl",
"sessionId": "abc123",
"userMessages": 5,
"assistantMessages": 5,
"toolCalls": 12,
"toolResults": 12,
"totalMessages": 22,
"tokens": {
"input": 50000,
"output": 10000,
"cacheRead": 40000,
"cacheWrite": 5000,
"total": 105000
},
"cost": 0.45,
"contextUsage": {
"tokens": 60000,
"contextWindow": 200000,
"percent": 30
}
}
}tokens und cost umfassen Assistentenmeldungen, von Tools gemeldete Nutzung und die Erstellung von Komprimierungs-/Zweigzusammenfassungen über die gesamte Sitzung hinweg. contextUsage enthält die tatsächliche aktuelle Kontextfensterschätzung, die für die Komprimierung und Fußzeilenanzeige verwendet wird.
contextUsage wird weggelassen, wenn kein Modell- oder Kontextfenster verfügbar ist. contextUsage.tokens und contextUsage.percent sind null unmittelbar nach der Verdichtung, bis eine neue Antwort des Assistenten nach der Verdichtung gültige Nutzungsdaten liefert.
export_html
Sitzung in eine HTML-Datei exportieren.
{"type": "export_html"}Mit benutzerdefiniertem Pfad:
{"type": "export_html", "outputPath": "/tmp/session.html"}Antwort:
{
"type": "response",
"command": "export_html",
"success": true,
"data": {"path": "/tmp/session.html"}
}switch_session
Laden Sie eine andere Sitzungsdatei. Kann durch einen session_before_switch-Erweiterungsereignishandler abgebrochen werden.
{"type": "switch_session", "sessionPath": "/path/to/session.jsonl"}Antwort:
{"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": false}}Wenn eine Erweiterung den Wechsel abgebrochen hat:
{"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": true}}Gabel
Erstellen Sie einen neuen Fork aus einer vorherigen Benutzernachricht im aktiven Zweig. Kann durch einen session_before_fork-Erweiterungsereignishandler abgebrochen werden. Gibt den Text der Nachricht zurück, aus der geforkt wird.
{"type": "fork", "entryId": "abc123"}Antwort:
{
"type": "response",
"command": "fork",
"success": true,
"data": {"text": "The original prompt text...", "cancelled": false}
}Wenn eine Erweiterung den Fork abgebrochen hat:
{
"type": "response",
"command": "fork",
"success": true,
"data": {"text": "The original prompt text...", "cancelled": true}
}Klon
Duplizieren Sie den aktuell aktiven Zweig in eine neue Sitzung an der aktuellen Position. Kann durch einen session_before_fork-Erweiterungsereignishandler abgebrochen werden.
{"type": "clone"}Antwort:
{
"type": "response",
"command": "clone",
"success": true,
"data": {"cancelled": false}
}Wenn eine Erweiterung den Klon abgebrochen hat:
{
"type": "response",
"command": "clone",
"success": true,
"data": {"cancelled": true}
}get_fork_messages
Erhalten Sie Benutzernachrichten, die zum Forken verfügbar sind.
{"type": "get_fork_messages"}Antwort:
{
"type": "response",
"command": "get_fork_messages",
"success": true,
"data": {
"messages": [
{"entryId": "abc123", "text": "First prompt..."},
{"entryId": "def456", "text": "Second prompt..."}
]
}
}get_entries
Ruft alle Sitzungseinträge in der Anhängereihenfolge ab (mit Ausnahme des Sitzungsheaders). Bei der Sitzung handelt es sich um einen Nur-Anhänge-Baum von Einträgen mit stabilen IDs, sodass eine Eintrags-ID als dauerhafter Cursor fungiert: Übergeben Sie die letzte Eintrags-ID, die Sie gesehen haben, als since, um nur Einträge direkt danach zu erhalten, auch über Client-Neustarts hinweg. Im Gegensatz zu get_messages umfasst dies auch den Verlauf vor der Verdichtung und verlassene Äste.
{"type": "get_entries"}Mit einem Cursor:
{"type": "get_entries", "since": "abc123"}Antwort:
{
"type": "response",
"command": "get_entries",
"success": true,
"data": {
"entries": [
{"type": "message", "id": "def456", "parentId": "abc123", "timestamp": "...", "message": {"role": "user", "...": "..."}}
],
"leafId": "def456"
}
}leafId ist die ID des aktuellen Blatteintrags (null für eine leere Sitzung), sodass ein Client in einem Roundtrip erkennen kann, ob der aktive Zweig verschoben wurde. Wenn since mit keiner Eintrags-ID übereinstimmt, lautet die Antwort success: false.
get_tree
Rufen Sie die Sitzung als Baumstruktur mit Einträgen ab. Jeder Knoten ist {entry, children, label?, labelTimestamp?}. Eine wohlgeformte Sitzung hat einen einzigen Stamm; verwaiste Einträge (unterbrochene übergeordnete Kette) erscheinen ebenfalls als Wurzeln.
{"type": "get_tree"}Antwort:
{
"type": "response",
"command": "get_tree",
"success": true,
"data": {
"tree": [
{
"entry": {"type": "message", "id": "abc123", "parentId": null, "...": "..."},
"children": [
{"entry": {"type": "message", "id": "def456", "parentId": "abc123", "...": "..."}, "children": []}
]
}
],
"leafId": "def456"
}
}get_last_assistant_text
Rufen Sie den Textinhalt der letzten Assistentennachricht ab.
{"type": "get_last_assistant_text"}Antwort:
{
"type": "response",
"command": "get_last_assistant_text",
"success": true,
"data": {"text": "The assistant's response..."}
}Gibt {"text": null} zurück, wenn keine Assistentenmeldungen vorhanden sind.
set_session_name
Legen Sie einen Anzeigenamen für die aktuelle Sitzung fest. Der Name erscheint in Sitzungslisten und hilft bei der Identifizierung von Sitzungen.
{"type": "set_session_name", "name": "my-feature-work"}Antwort:
{
"type": "response",
"command": "set_session_name",
"success": true
}Der aktuelle Sitzungsname ist über get_state im Feld sessionName verfügbar. Um den Anfangsnamen beim Starten des RPC-Modus festzulegen, übergeben Sie --name <name> oder -n <name> an den pi --mode rpc-Prozess.
Befehle
get_commands
Erhalten Sie verfügbare Befehle (Erweiterungsbefehle, prompt templates und Fähigkeiten). Diese können über den Befehl prompt mit dem Präfix / aufgerufen werden.
{"type": "get_commands"}Antwort:
{
"type": "response",
"command": "get_commands",
"success": true,
"data": {
"commands": [
{"name": "session-name", "description": "Set or clear session name", "source": "extension", "path": "/home/user/.pi/agent/extensions/session.ts"},
{"name": "fix-tests", "description": "Fix failing tests", "source": "prompt", "location": "project", "path": "/home/user/myproject/.pi/agent/prompts/fix-tests.md"},
{"name": "skill:brave-search", "description": "Web search via Brave API", "source": "skill", "location": "user", "path": "/home/user/.pi/agent/skills/brave-search/SKILL.md"}
]
}
}Jeder Befehl hat:
name: Befehlsname (Aufruf mit/name)description: Für Menschen lesbare Beschreibung (optional für Erweiterungsbefehle)source: Was für ein Befehl:"extension": Registriert überpi.registerCommand()in einer Nebenstelle"prompt": Wird aus einer Eingabeaufforderungsvorlagendatei.mdgeladen"skill": Aus einem Skill-Verzeichnis geladen (Name wird mitskill:vorangestellt)
location: Woher es geladen wurde (optional, bei Erweiterungen nicht vorhanden):"user": Benutzerebene (~/.pi/agent/)"project": Projektebene (./.pi/agent/)"path": Expliziter Pfad über CLI oder Einstellungen
path: Absoluter Dateipfad zur Befehlsquelle (optional)
Hinweis: Integrierte TUI-Befehle (/settings, /hotkeys usw.) sind nicht enthalten. Sie werden nur im interaktiven Modus verarbeitet und würden nicht ausgeführt, wenn sie über prompt gesendet würden.
Veranstaltungen
Ereignisse werden während des Agentenbetriebs als JSON-Leitungen an stdout gestreamt. Ereignisse enthalten im Allgemeinen kein id-Feld; bash_execution_update enthält die id des ursprünglichen bash-Befehls, wenn einer bereitgestellt wurde.
Ereignistypen
| Ereignis | Beschreibung |
|---|---|
agent_start |
Der Agent beginnt mit der Verarbeitung |
agent_end |
Eine Agentenausführung auf niedriger Ebene wird abgeschlossen (es können noch Wiederholungsversuche, eine Komprimierung oder Fortsetzungen in der Warteschlange folgen). |
agent_settled |
Der Agentenlauf ist vollständig abgewickelt; Es bleibt kein automatischer Wiederholungsversuch, kein Komprimierungswiederholungsversuch oder keine Fortsetzung in der Warteschlange übrig |
turn_start |
Eine neue Runde beginnt |
turn_end |
Drehung abgeschlossen (einschließlich Assistentenmeldung und Werkzeugergebnisse) |
message_start |
Die Nachricht beginnt |
message_update |
Streaming-Update (Text-/Denk-/Toolcall-Deltas) |
message_end |
Nachricht abgeschlossen |
bash_execution_update |
Direkter RPC bash Befehlsausgabeblock |
tool_execution_start |
Das Tool beginnt mit der Ausführung |
tool_execution_update |
Fortschritt der Tool-Ausführung (Streaming-Ausgabe) |
tool_execution_end |
Das Werkzeug ist fertig |
queue_update |
Ausstehende Lenkungs-/Folgewarteschlange geändert |
compaction_start |
Die Verdichtung beginnt |
compaction_end |
Die Verdichtung ist abgeschlossen |
auto_retry_start |
Automatischer Wiederholungsversuch beginnt (nach vorübergehendem Fehler) |
auto_retry_end |
Automatischer Wiederholungsversuch abgeschlossen (Erfolg oder endgültiger Fehler) |
summarization_retry_scheduled |
Ein Wiederholungsversuch ist für einen vorübergehenden Komprimierungs- oder Branch-Summary-Zusammenfassungsfehler geplant |
summarization_retry_attempt_start |
Die wiederholte Zusammenfassungsanforderung wird gestartet |
summarization_retry_finished |
Die Wiederholungsschleife für die Zusammenfassung ist abgeschlossen |
extension_error |
Die Erweiterung hat einen Fehler ausgegeben |
agent_start
Wird ausgegeben, wenn der Agent mit der Verarbeitung einer Eingabeaufforderung beginnt.
{"type": "agent_start"}agent_end
Wird ausgegeben, wenn die Ausführung eines Low-Level-Agents abgeschlossen ist. Enthält alle während dieses Laufs generierten Nachrichten. Wenn willRetry wahr ist, folgt ein automatischer Wiederholungsversuch.
{
"type": "agent_end",
"messages": [...],
"willRetry": false
}agent_settled
Wird ausgegeben, nachdem der vollständige Lauf auf Sitzungsebene abgeschlossen ist. Zu diesem Zeitpunkt wird Pi nicht automatisch durch Wiederholungsversuche, Komprimierungswiederholungsversuche oder in der Warteschlange befindliche Folgenachrichten fortgesetzt.
{"type": "agent_settled"}turn_start / turn_end
Eine Runde besteht aus einer Assistentenantwort sowie allen daraus resultierenden Werkzeugaufrufen und Ergebnissen.
{"type": "turn_start"}{
"type": "turn_end",
"message": {...},
"toolResults": [...]
}message_start / message_end
Wird ausgegeben, wenn eine Nachricht beginnt und endet. Das Feld message enthält eine AgentMessage.
{"type": "message_start", "message": {...}}
{"type": "message_end", "message": {...}}message_update (Streaming)
Wird während des Streamings von Assistentennachrichten ausgegeben. Enthält ein Delta-Ereignis ohne kumulativen Nachrichten-Snapshot.
{
"type": "message_update",
"assistantMessageEvent": {
"type": "text_delta",
"contentIndex": 0,
"delta": "Hello "
}
}Das Feld assistantMessageEvent enthält einen dieser Deltatypen:
| Typ | Beschreibung |
|---|---|
text_start |
Textinhaltsblock gestartet |
text_delta |
Textinhaltsblock |
text_end |
Textinhaltsblock beendet |
thinking_start |
Denkblockade begann |
thinking_delta |
Denkender Inhaltsblock |
thinking_end |
Denkblockade beendet |
toolcall_start |
Werkzeugaufruf gestartet |
toolcall_delta |
Block mit Toolaufrufargumenten |
toolcall_end |
Werkzeugaufruf beendet (einschließlich vollständigem toolCall-Objekt) |
Beispiel für das Streamen einer Textantwort:
{"type":"message_update","assistantMessageEvent":{"type":"text_start","contentIndex":0}}
{"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
{"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":" world"}}
{"type":"message_update","assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello world"}}message_update lässt das frühere kumulative message-Feld absichtlich weg und
assistantMessageEvent.partial. Clients, die eine Live-Teilnachricht benötigen, müssen diese zusammenstellen
ab message_start und Folgeereignisse mit contentIndex. Behandeln Sie message_end.message
als maßgeblich. Für Werkzeugaufrufe Puffer toolcall_delta.delta; toolcall_end.toolCall
enthält den abgeschlossenen Anruf.
bash_execution_update
Wird einmal für jeden Ausgabeblock eines direkten bash-Befehls ausgegeben. id stimmt mit id des Befehls überein, sodass Clients die Ausgabe dem richtigen Befehl zuordnen können.
Ereignisse streamen die gesamte Ausgabe, während der Befehl ausgeführt wird, auch wenn die endgültige bash-Antwort output abgeschnitten ist.
{
"type": "bash_execution_update",
"id": "req-1",
"delta": "total 48\n"
}tool_execution_start / tool_execution_update / tool_execution_end
Wird ausgegeben, wenn ein Tool startet, den Fortschritt streamt und die Ausführung abschließt.
{
"type": "tool_execution_start",
"toolCallId": "call_abc123",
"toolName": "bash",
"args": {"command": "ls -la"}
}Während der Ausführung strömen tool_execution_update Ereignisse Teilergebnisse (z. B. bash Ausgabe, sobald sie eintreffen):
{
"type": "tool_execution_update",
"toolCallId": "call_abc123",
"toolName": "bash",
"args": {"command": "ls -la"},
"partialResult": {
"content": [{"type": "text", "text": "partial output so far..."}],
"details": {"truncation": null, "fullOutputPath": null}
}
}Wenn es fertig ist:
{
"type": "tool_execution_end",
"toolCallId": "call_abc123",
"toolName": "bash",
"result": {
"content": [{"type": "text", "text": "total 48\n..."}],
"details": {...}
},
"isError": false
}Verwenden Sie toolCallId, um Ereignisse zu korrelieren. Die partialResult in tool_execution_update enthält die bisher akkumulierte Ausgabe (nicht nur das Delta), sodass Clients ihre Anzeige bei jedem Update einfach ersetzen können.
queue_update
Wird immer dann ausgegeben, wenn sich die ausstehende Steuerungs- oder Folgewarteschlange ändert.
{
"type": "queue_update",
"steering": ["Focus on error handling"],
"followUp": ["After that, summarize the result"]
}Verdichtungsstart / Verdichtungsende
Wird ausgegeben, wenn die Verdichtung ausgeführt wird, egal ob manuell oder automatisch.
{"type": "compaction_start", "reason": "threshold"}Das Feld reason ist "manual", "threshold" oder "overflow".
{
"type": "compaction_end",
"reason": "threshold",
"result": {
"summary": "Summary of conversation...",
"firstKeptEntryId": "abc123",
"tokensBefore": 150000,
"estimatedTokensAfter": 32000,
"usage": {
"input": 32000,
"output": 1200,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 33200,
"cost": {"input": 0.01, "output": 0.02, "cacheRead": 0, "cacheWrite": 0, "total": 0.03}
},
"details": {}
},
"aborted": false,
"willRetry": false
}Wenn reason "overflow" war und die Komprimierung erfolgreich war, ist willRetry true und der Agent wird die Eingabeaufforderung automatisch wiederholen.
Wenn die Komprimierung abgebrochen wurde, ist result null und aborted ist true.
Wenn die Komprimierung fehlgeschlagen ist (z. B. API Kontingent überschritten), ist result null, aborted ist false und errorMessage enthält die Fehlerbeschreibung.
auto_retry_start / auto_retry_end
Wird ausgegeben, wenn nach einem vorübergehenden Fehler (Überlastung, Ratenbegrenzung, 5xx) ein automatischer Wiederholungsversuch ausgelöst wird.
{
"type": "auto_retry_start",
"attempt": 1,
"maxAttempts": 3,
"delayMs": 2000,
"errorMessage": "529 {\"type\":\"error\",\"error\":{\"type\":\"overloaded_error\",\"message\":\"Overloaded\"}}"
}{
"type": "auto_retry_end",
"success": true,
"attempt": 2
}Bei endgültigem Fehlschlag (maximale Wiederholungsversuche überschritten):
{
"type": "auto_retry_end",
"success": false,
"attempt": 3,
"finalError": "529 overloaded_error: Overloaded"
}summarization_retry_scheduled / summarization_retry_attempt_start / summarization_retry_finished
Wird ausgegeben, wenn die Komprimierung oder Verzweigungszusammenfassung nach einem vorübergehenden Anbieterfehler erneut versucht wird. Für diese Ereignisse werden dieselben Wiederholungseinstellungen wie für automatische Wiederholungsversuche beim Assistenten verwendet.
{
"type": "summarization_retry_scheduled",
"attempt": 1,
"maxAttempts": 3,
"delayMs": 2000,
"errorMessage": "terminated"
}{
"type": "summarization_retry_attempt_start",
"source": "compaction",
"reason": "threshold"
}Für Zweigzusammenfassungen ist source gleich "branchSummary" und es ist kein reason vorhanden.
{
"type": "summarization_retry_finished"
}extension_error
Wird ausgegeben, wenn eine Erweiterung einen Fehler auslöst.
{
"type": "extension_error",
"extensionPath": "/path/to/extension.ts",
"event": "tool_call",
"error": "Error message..."
}Erweiterungs-UI-Protokoll
Extensions kann Benutzerinteraktion über ctx.ui.select(), ctx.ui.confirm() usw. anfordern. Im RPC-Modus werden diese in ein Anforderungs-/Antwort-Unterprotokoll über dem Basisbefehls-/Ereignisfluss übersetzt.
Es gibt zwei Kategorien von Erweiterungs-UI-Methoden:
- Dialogmethoden (
select,confirm,input,editor): Geben Sie einextension_ui_requestauf stdout aus und blockieren Sie, bis der Client einextension_ui_responseauf stdin mit dem passendenidzurücksendet. - Fire-and-Forget-Methoden (
notify,setStatus,setWidget,setTitle,set_editor_text): Geben Sie bei stdout eineextension_ui_requestaus, erwarten Sie jedoch keine Antwort. Der Client kann die Informationen anzeigen oder ignorieren.
Wenn eine Dialogmethode ein timeout-Feld enthält, führt die Agentenseite nach Ablauf des Timeouts automatisch eine Lösung mit einem Standardwert durch. Der Client muss keine Zeitüberschreitungen verfolgen.
Einige ExtensionUIContext-Methoden werden im RPC-Modus nicht unterstützt oder sind eingeschränkt, da sie direkten TUI-Zugriff erfordern:
custom()gibtundefinedzurücksetWorkingMessage(),setWorkingIndicator(),setFooter(),setHeader(),setEditorComponent(),setToolsExpanded()sind No-OpsgetEditorText()gibt""zurückgetToolsExpanded()gibtfalsezurückpasteToEditor()delegiert ansetEditorText()(keine Einfüge-/Reduzierungsbehandlung)getAllThemes()gibt[]zurückgetTheme()gibtundefinedzurücksetTheme()gibt{ success: false, error: "..." }zurück
Hinweis: ctx.mode ist "rpc" und ctx.hasUI ist true im RPC-Modus, da die Dialog- und Fire-and-Forget-Methoden über das Erweiterungs-UI-Unterprotokoll funktionieren. Verwenden Sie ctx.mode === "tui", um TUI-spezifische Funktionen wie custom() zu schützen, die ein echtes Terminal erfordern.
Erweiterungs-UI-Anfragen (stdout)
Alle Anfragen haben type: "extension_ui_request", ein eindeutiges id und ein method-Feld.
wählen
Fordern Sie den Benutzer auf, aus einer Liste auszuwählen. Dialogmethoden mit einem timeout-Feld enthalten den Timeout in Millisekunden; Der Agent führt automatisch eine Lösung mit undefined aus, wenn der Client nicht rechtzeitig antwortet.
{
"type": "extension_ui_request",
"id": "uuid-1",
"method": "select",
"title": "Allow dangerous command?",
"options": ["Allow", "Block"],
"timeout": 10000
}Erwartete Antwort: extension_ui_response mit value (der ausgewählten Optionszeichenfolge) oder cancelled: true.
bestätigen
Fordern Sie den Benutzer zur Ja/Nein-Bestätigung auf.
{
"type": "extension_ui_request",
"id": "uuid-2",
"method": "confirm",
"title": "Clear session?",
"message": "All messages will be lost.",
"timeout": 5000
}Erwartete Antwort: extension_ui_response mit confirmed: true/false oder cancelled: true.
Eingang
Fordern Sie den Benutzer auf, Freitext einzugeben.
{
"type": "extension_ui_request",
"id": "uuid-3",
"method": "input",
"title": "Enter a value",
"placeholder": "type something..."
}Erwartete Antwort: extension_ui_response mit value (der eingegebene Text) oder cancelled: true.
Editor
Öffnen Sie einen mehrzeiligen Texteditor mit optionalem vorab ausgefülltem Inhalt.
{
"type": "extension_ui_request",
"id": "uuid-4",
"method": "editor",
"title": "Edit some text",
"prefill": "Line 1\nLine 2\nLine 3"
}Erwartete Antwort: extension_ui_response mit value (der bearbeitete Text) oder cancelled: true.
benachrichtigen
Eine Benachrichtigung anzeigen. Feuer und Vergessen, keine Antwort erwartet.
{
"type": "extension_ui_request",
"id": "uuid-5",
"method": "notify",
"message": "Command blocked by user",
"notifyType": "warning"
}Das Feld notifyType ist "info", "warning" oder "error". Der Standardwert ist "info", wenn er weggelassen wird.
setStatus
Setzen oder löschen Sie einen Statuseintrag in der Fußzeile/Statusleiste. Feuer-und-vergessen.
{
"type": "extension_ui_request",
"id": "uuid-6",
"method": "setStatus",
"statusKey": "my-ext",
"statusText": "Turn 3 running..."
}Senden Sie statusText: undefined (oder lassen Sie es weg), um den Statuseintrag für diese Taste zu löschen.
setWidget
Legen Sie ein Widget (Textzeilenblock) fest oder löschen Sie es, das über oder unter dem Editor angezeigt wird. Feuer-und-vergessen.
{
"type": "extension_ui_request",
"id": "uuid-7",
"method": "setWidget",
"widgetKey": "my-ext",
"widgetLines": ["--- My Widget ---", "Line 1", "Line 2"],
"widgetPlacement": "aboveEditor"
}Senden Sie widgetLines: undefined (oder lassen Sie es weg), um das Widget zu löschen. Das Feld widgetPlacement ist "aboveEditor" (Standard) oder "belowEditor". Im RPC-Modus werden nur String-Arrays unterstützt; Komponentenfabriken werden ignoriert.
setTitle
Legen Sie den Titel des Terminalfensters/der Registerkarte fest. Feuer-und-vergessen.
{
"type": "extension_ui_request",
"id": "uuid-8",
"method": "setTitle",
"title": "pi - my project"
}set_editor_text
Legen Sie den Text im Eingabeeditor fest. Feuer-und-vergessen.
{
"type": "extension_ui_request",
"id": "uuid-9",
"method": "set_editor_text",
"text": "prefilled text for the user"
}Antworten auf die Erweiterungs-UI (stdin)
Antworten werden nur für Dialogmethoden gesendet (select, confirm, input, editor). Die id muss mit der Anfrage übereinstimmen.
Wertantwort (auswählen, eingeben, bearbeiten)
{"type": "extension_ui_response", "id": "uuid-1", "value": "Allow"}Bestätigungsantwort (Bestätigen)
{"type": "extension_ui_response", "id": "uuid-2", "confirmed": true}Stornierungsantwort (beliebiger Dialog)
Verwerfen Sie alle Dialogmethoden. Die Erweiterung erhält undefined (zum Auswählen/Eingeben/Bearbeiten) oder false (zum Bestätigen).
{"type": "extension_ui_response", "id": "uuid-3", "cancelled": true}Fehlerbehandlung
Fehlgeschlagene Befehle geben eine Antwort mit success: false zurück:
{
"type": "response",
"command": "set_model",
"success": false,
"error": "Model not found: invalid/model"
}Analysefehler:
{
"type": "response",
"command": "parse",
"success": false,
"error": "Failed to parse command: Unexpected token..."
}Typen
Quelldateien:
packages/ai/src/types.ts-Model,UserMessage,AssistantMessage,ToolResultMessagepackages/agent/src/types.ts-AgentMessage,AgentEventsrc/core/messages.ts-BashExecutionMessagesrc/modes/json-event.ts-JsonAgentSessionEventsrc/modes/rpc/rpc-types.ts– RPC Befehls-/Antworttypen, Erweiterungs-UI-Anforderungs-/Antworttypen
Modell
{
"id": "claude-sonnet-4-20250514",
"name": "Claude Sonnet 4",
"api": "anthropic-messages",
"provider": "anthropic",
"baseUrl": "https://api.anthropic.com",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 16384,
"cost": {
"input": 3.0,
"output": 15.0,
"cacheRead": 0.3,
"cacheWrite": 3.75
}
}Benutzernachricht
{
"role": "user",
"content": "Hello!",
"timestamp": 1733234567890,
"attachments": []
}Das Feld content kann eine Zeichenfolge oder ein Array aus TextContent/ImageContent Blöcken sein.
AssistantMessage
{
"role": "assistant",
"content": [
{"type": "text", "text": "Hello! How can I help?"},
{"type": "thinking", "thinking": "User is greeting me..."},
{"type": "toolCall", "id": "call_123", "name": "bash", "arguments": {"command": "ls"}}
],
"api": "anthropic-messages",
"provider": "anthropic",
"model": "claude-sonnet-4-20250514",
"usage": {
"input": 100,
"output": 50,
"cacheRead": 0,
"cacheWrite": 0,
"cost": {"input": 0.0003, "output": 0.00075, "cacheRead": 0, "cacheWrite": 0, "total": 0.00105}
},
"stopReason": "stop",
"timestamp": 1733234567890
}Stoppgründe: "stop", "length", "toolUse", "error", "aborted"
ToolResultMessage
{
"role": "toolResult",
"toolCallId": "call_123",
"toolName": "bash",
"content": [{"type": "text", "text": "total 48\ndrwxr-xr-x ..."}],
"usage": {
"input": 100,
"output": 50,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 150,
"cost": {"input": 0.0003, "output": 0.00075, "cacheRead": 0, "cacheWrite": 0, "total": 0.00105}
},
"isError": false,
"timestamp": 1733234567890
}usage ist optional und meldet verschachtelte LLM-Arbeiten, die vom Tool ausgeführt werden. Wenn es vorhanden ist, trägt es zum Sitzungs-Token und den Gesamtkosten bei.
BashExecutionMessage
Erstellt durch den Befehl bash RPC (nicht durch LLM-Tool-Aufrufe):
{
"role": "bashExecution",
"command": "ls -la",
"output": "total 48\ndrwxr-xr-x ...",
"exitCode": 0,
"cancelled": false,
"truncated": false,
"fullOutputPath": null,
"timestamp": 1733234567890
}Anhang
{
"id": "img1",
"type": "image",
"fileName": "photo.jpg",
"mimeType": "image/jpeg",
"size": 102400,
"content": "base64-encoded-data...",
"extractedText": null,
"preview": null
}Beispiel: Basic Client (Python)
import subprocess
import json
proc = subprocess.Popen(
["pi", "--mode", "rpc", "--no-session"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True
)
def send(cmd):
proc.stdin.write(json.dumps(cmd) + "\n")
proc.stdin.flush()
def read_events():
for line in proc.stdout:
yield json.loads(line)
# Send prompt
send({"type": "prompt", "message": "Hello!"})
# Process events
for event in read_events():
if event.get("type") == "message_update":
delta = event.get("assistantMessageEvent", {})
if delta.get("type") == "text_delta":
print(delta["delta"], end="", flush=True)
if event.get("type") == "agent_end":
print()
breakBeispiel: Interaktiver Client (Node.js)
Siehe test/rpc-example.ts für ein vollständiges interaktives Beispiel oder src/modes/rpc/rpc-client.ts für eine typisierte Client-Implementierung.
Ein vollständiges Beispiel für die Handhabung des Erweiterungs-UI-Protokolls finden Sie unter examples/rpc-extension-ui.ts, das mit der Erweiterung examples/extensions/rpc-demo.ts gepaart ist.
const { spawn } = require("child_process");
const { StringDecoder } = require("string_decoder");
const agent = spawn("pi", ["--mode", "rpc", "--no-session"]);
function attachJsonlReader(stream, onLine) {
const decoder = new StringDecoder("utf8");
let buffer = "";
stream.on("data", (chunk) => {
buffer += typeof chunk === "string" ? chunk : decoder.write(chunk);
while (true) {
const newlineIndex = buffer.indexOf("\n");
if (newlineIndex === -1) break;
let line = buffer.slice(0, newlineIndex);
buffer = buffer.slice(newlineIndex + 1);
if (line.endsWith("\r")) line = line.slice(0, -1);
onLine(line);
}
});
stream.on("end", () => {
buffer += decoder.end();
if (buffer.length > 0) {
onLine(buffer.endsWith("\r") ? buffer.slice(0, -1) : buffer);
}
});
}
attachJsonlReader(agent.stdout, (line) => {
const event = JSON.parse(line);
if (event.type === "message_update") {
const { assistantMessageEvent } = event;
if (assistantMessageEvent.type === "text_delta") {
process.stdout.write(assistantMessageEvent.delta);
}
}
});
// Send prompt
agent.stdin.write(JSON.stringify({ type: "prompt", message: "Hello" }) + "\n");
// Abort on Ctrl+C
process.on("SIGINT", () => {
agent.stdin.write(JSON.stringify({ type: "abort" }) + "\n");
});