RPC Modus
Mode RPC memungkinkan pengoperasian agen pengkode tanpa kepala melalui protokol JSON melalui stdin/stdout. Ini berguna untuk menyematkan agen di aplikasi lain, IDE, atau UI kustom.
Catatan untuk pengguna Node.js/TypeScript: Jika Anda membuat aplikasi Node.js, pertimbangkan untuk menggunakan AgentSession langsung dari @earendil-works/pi-coding-agent daripada membuat subproses. Lihat src/core/agent-session.ts untuk API. Untuk klien TypeScript berbasis subproses, lihat src/modes/rpc/rpc-client.ts.
Memulai Mode RPC
pi --mode rpc [options]Opsi umum:
--provider <name>: Tetapkan penyedia LLM (anthropic, openai, google, dll.)--model <pattern>: Pola atau ID model (mendukungprovider/iddan opsional:<thinking>)--name <name>/-n <name>: Mengatur nama tampilan sesi saat startup--no-session: Nonaktifkan persistensi sesi--session-dir <path>: Direktori penyimpanan sesi khusus
Ikhtisar Protokol
- Perintah: JSON objek dikirim ke stdin, satu per baris
- Respon: JSON objek dengan
type: "response"yang menunjukkan keberhasilan/kegagalan perintah - Acara: Acara agen dialirkan ke stdout sebagai baris JSON
Semua perintah mendukung bidang opsional id untuk korelasi permintaan/respons. Jika disediakan, respons terkait akan mencakup id yang sama. Peristiwa bash_execution_update juga menyertakan id dari perintah bash asalnya.
Pembingkaian
Mode RPC menggunakan semantik JSONL yang ketat dengan LF (\n) sebagai satu-satunya pembatas rekaman.
Ini penting bagi klien:
- Pisahkan catatan hanya pada
\n - Terima masukan opsional
\r\ndengan menghilangkan tanda\r - Jangan gunakan pembaca baris umum yang memperlakukan pemisah Unicode sebagai baris baru
Secara khusus, Node readline tidak sesuai protokol untuk mode RPC karena ia juga terbagi menjadi U+2028 dan U+2029, yang valid di dalam string JSON.
Perintah
Dorongan
mengingatkan
Kirimkan perintah pengguna ke agen. Respons perintah dikeluarkan setelah prompt diterima, dimasukkan dalam antrean, atau ditangani. Acara terus mengalir secara asinkron setelah penerimaan.
{"id": "req-1", "type": "prompt", "message": "Hello, world!"}Dengan gambar:
{"type": "prompt", "message": "What's in this image?", "images": [{"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}]}Selama streaming: Jika agen sudah melakukan streaming, Anda harus menentukan streamingBehavior untuk mengantri pesan:
{"type": "prompt", "message": "New instruction", "streamingBehavior": "steer"}"steer": Mengantri pesan saat agen sedang berjalan. Ini dikirimkan setelah giliran asisten saat ini selesai menjalankan panggilan alatnya, sebelum panggilan LLM berikutnya."followUp": Tunggu hingga agen selesai. Pesan dikirimkan hanya ketika agen berhenti.
Jika agen sedang streaming dan tidak ada streamingBehavior yang ditentukan, perintah akan mengembalikan kesalahan.
Perintah ekstensi: Jika pesannya berupa perintah ekstensi (misalnya /mycommand), pesan akan langsung dijalankan bahkan selama streaming. Perintah ekstensi mengelola interaksi LLM mereka sendiri melalui pi.sendMessage().
Perluasan input: Perintah keterampilan (/skill:name) dan prompt templates (/template) diperluas sebelum dikirim/antrian.
Tanggapan:
{"id": "req-1", "type": "response", "command": "prompt", "success": true}success: true berarti perintah diterima, dimasukkan dalam antrean, atau ditangani dengan segera. success: false berarti perintah ditolak sebelum diterima. Kegagalan setelah penerimaan dilaporkan melalui peristiwa normal dan aliran pesan, bukan sebagai response kedua untuk id permintaan yang sama.
Bidang images bersifat opsional. Setiap gambar menggunakan format ImageContent: {"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}.
mengarahkan
Antri pesan kemudi saat agen sedang berjalan. Ini dikirimkan setelah giliran asisten saat ini selesai menjalankan panggilan alatnya, sebelum panggilan LLM berikutnya. Perintah keterampilan dan prompt templates diperluas. Perintah ekstensi tidak diperbolehkan (sebagai gantinya gunakan prompt).
{"type": "steer", "message": "Stop and do this instead"}Dengan gambar:
{"type": "steer", "message": "Look at this instead", "images": [{"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}]}Bidang images bersifat opsional. Setiap gambar menggunakan format ImageContent (sama seperti prompt).
Tanggapan:
{"type": "response", "command": "steer", "success": true}Lihat set_steering_mode untuk mengontrol bagaimana pesan pengarah diproses.
menindaklanjuti
Antrian pesan tindak lanjut untuk diproses setelah agen selesai. Dikirim hanya ketika agen tidak lagi memiliki panggilan alat atau pesan pengarah. Perintah keterampilan dan prompt templates diperluas. Perintah ekstensi tidak diperbolehkan (sebagai gantinya gunakan prompt).
{"type": "follow_up", "message": "After you're done, also do this"}Dengan gambar:
{"type": "follow_up", "message": "Also check this image", "images": [{"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}]}Bidang images bersifat opsional. Setiap gambar menggunakan format ImageContent (sama seperti prompt).
Tanggapan:
{"type": "response", "command": "follow_up", "success": true}Lihat set_follow_up_mode untuk mengontrol bagaimana pesan tindak lanjut diproses.
menggugurkan
Batalkan operasi agen saat ini.
{"type": "abort"}Tanggapan:
{"type": "response", "command": "abort", "success": true}sesi_baru
Mulailah sesi baru. Dapat dibatalkan oleh pengendali acara ekstensi session_before_switch.
{"type": "new_session"}Dengan pelacakan sesi orang tua opsional:
{"type": "new_session", "parentSession": "/path/to/parent-session.jsonl"}Tanggapan:
{"type": "response", "command": "new_session", "success": true, "data": {"cancelled": false}}Jika perpanjangan dibatalkan:
{"type": "response", "command": "new_session", "success": true, "data": {"cancelled": true}}Negara
dapatkan_status
Dapatkan status sesi saat ini.
{"type": "get_state"}Tanggapan:
{
"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
}
}Bidang model adalah objek Model penuh atau null. Bidang sessionName adalah nama tampilan yang diatur melalui set_session_name, atau dihilangkan jika tidak diatur.
dapatkan_pesan
Dapatkan semua pesan dalam percakapan.
{"type": "get_messages"}Tanggapan:
{
"type": "response",
"command": "get_messages",
"success": true,
"data": {"messages": [...]}
}Pesan adalah AgentMessage objek (lihat Message Types).
Model
set_model
Beralih ke model tertentu.
{"type": "set_model", "provider": "anthropic", "modelId": "claude-sonnet-4-20250514"}Respons berisi objek Model lengkap:
{
"type": "response",
"command": "set_model",
"success": true,
"data": {...}
}siklus_model
Beralih ke model berikutnya yang tersedia. Mengembalikan null data jika hanya satu model yang tersedia.
{"type": "cycle_model"}Tanggapan:
{
"type": "response",
"command": "cycle_model",
"success": true,
"data": {
"model": {...},
"thinkingLevel": "medium",
"isScoped": false
}
}Bidang model adalah objek Model penuh.
dapatkan_tersedia_model
Daftar semua model yang dikonfigurasi.
{"type": "get_available_models"}Respons berisi serangkaian objek Model penuh:
{
"type": "response",
"command": "get_available_models",
"success": true,
"data": {
"models": [...]
}
}Pemikiran
set_thinking_level
Tetapkan tingkat penalaran/berpikir untuk model yang mendukungnya.
{"type": "set_thinking_level", "level": "high"}Tingkat: "off", "minimal", "low", "medium", "high", "xhigh", "max"
"xhigh" dan "max" hanya terekspos bila didukung oleh model yang dipilih. Beberapa model, termasuk GPT-5.6, menampilkan keduanya.
Tanggapan:
{"type": "response", "command": "set_thinking_level", "success": true}tingkat_pemikiran_siklus
Telusuri tingkat berpikir yang tersedia. Mengembalikan null data jika model tidak mendukung pemikiran.
{"type": "cycle_thinking_level"}Tanggapan:
{
"type": "response",
"command": "cycle_thinking_level",
"success": true,
"data": {"level": "high"}
}dapatkan_tersedia_tingkat_pemikiran
Buat daftar tingkat berpikir yang didukung oleh model saat ini. Mengembalikan ["off"] untuk model tanpa dukungan alasan.
{"type": "get_available_thinking_levels"}Tanggapan:
{
"type": "response",
"command": "get_available_thinking_levels",
"success": true,
"data": {
"levels": ["off", "minimal", "low", "medium", "high"]
}
}Mode Antrian
set_steering_mode
Kontrol bagaimana pesan pengarah (dari steer) dikirimkan.
{"type": "set_steering_mode", "mode": "one-at-a-time"}Mode:
"all": Mengirimkan semua pesan kemudi setelah giliran asisten saat ini selesai menjalankan panggilan alatnya"one-at-a-time": Mengirimkan satu pesan kemudi per giliran asisten yang selesai (default)
Tanggapan:
{"type": "response", "command": "set_steering_mode", "success": true}set_follow_up_mode
Kontrol bagaimana pesan tindak lanjut (dari follow_up) dikirimkan.
{"type": "set_follow_up_mode", "mode": "one-at-a-time"}Mode:
"all": Kirimkan semua pesan tindak lanjut setelah agen selesai"one-at-a-time": Mengirimkan satu pesan tindak lanjut per penyelesaian agen (default)
Tanggapan:
{"type": "response", "command": "set_follow_up_mode", "success": true}Pemadatan
kompak
Ringkas konteks percakapan secara manual untuk mengurangi penggunaan token.
{"type": "compact"}Dengan instruksi khusus:
{"type": "compact", "customInstructions": "Focus on code changes"}Tanggapan:
{
"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 adalah perkiraan heuristik atas konteks pesan yang dibangun kembali segera setelah pemadatan, bukan jumlah token persis penyedia. usage melaporkan panggilan LLM atau panggilan yang menghasilkan ringkasan dan dapat dihilangkan oleh penangan pemadatan khusus.
set_auto_compaction
Mengaktifkan atau menonaktifkan pemadatan otomatis ketika konteks hampir penuh.
{"type": "set_auto_compaction", "enabled": true}Tanggapan:
{"type": "response", "command": "set_auto_compaction", "success": true}Mencoba kembali
set_auto_coba lagi
Mengaktifkan atau menonaktifkan percobaan ulang otomatis pada kesalahan sementara (kelebihan beban, batas kecepatan, 5xx).
{"type": "set_auto_retry", "enabled": true}Tanggapan:
{"type": "response", "command": "set_auto_retry", "success": true}batalkan_coba lagi
Batalkan percobaan ulang yang sedang berlangsung (batalkan penundaan dan hentikan percobaan ulang).
{"type": "abort_retry"}Tanggapan:
{"type": "response", "command": "abort_retry", "success": true}Pesta
bash
Jalankan perintah shell dan tambahkan output ke konteks percakapan. Aliran keluaran sebagai bash_execution_update peristiwa saat perintah dijalankan; tanggapannya berisi hasil akhir.
{"id": "req-1", "type": "bash", "command": "ls -la"}Sertakan id untuk mengaitkan acara bash_execution_update yang dialirkan dengan perintah ini.
Tanggapan:
{
"id": "req-1",
"type": "response",
"command": "bash",
"success": true,
"data": {
"output": "total 48\ndrwxr-xr-x ...",
"exitCode": 0,
"cancelled": false,
"truncated": false
}
}Jika keluaran terpotong, termasuk fullOutputPath:
{
"type": "response",
"command": "bash",
"success": true,
"data": {
"output": "truncated output...",
"exitCode": 0,
"cancelled": false,
"truncated": true,
"fullOutputPath": "/tmp/pi-bash-abc123.log"
}
}Bagaimana hasil bash mencapai LLM:
Perintah bash segera dijalankan dan mengembalikan BashResult. Secara internal, BashExecutionMessage dibuat dan disimpan dalam status pesan agen.
Ketika perintah prompt berikutnya dikirim, semua pesan (termasuk BashExecutionMessage) diubah sebelum dikirim ke LLM. BashExecutionMessage diubah menjadi UserMessage dengan format ini:
Ran `ls -la`
```
jumlah 48
drwxr-xr-x...
```Artinya:
- Output Bash disertakan dalam konteks LLM pada prompt berikutnya, tidak langsung
- Beberapa perintah bash dapat dijalankan sebelum prompt; semua output akan disertakan
batalkan_bash
Batalkan perintah bash yang sedang berjalan.
{"type": "abort_bash"}Tanggapan:
{"type": "response", "command": "abort_bash", "success": true}Sidang
dapatkan_session_stats
Dapatkan penggunaan token, statistik biaya, dan penggunaan jendela konteks saat ini.
{"type": "get_session_stats"}Tanggapan:
{
"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 dan cost mencakup pesan asisten, laporan penggunaan alat, dan pembuatan ringkasan/ringkasan cabang di seluruh sesi. contextUsage berisi perkiraan jendela konteks terkini yang digunakan untuk pemadatan dan tampilan footer.
contextUsage dihilangkan jika tidak ada model atau jendela konteks yang tersedia. contextUsage.tokens dan contextUsage.percent adalah null segera setelah pemadatan hingga respons asisten pasca pemadatan yang baru memberikan data penggunaan yang valid.
ekspor_html
Ekspor sesi ke file HTML.
{"type": "export_html"}Dengan jalur khusus:
{"type": "export_html", "outputPath": "/tmp/session.html"}Tanggapan:
{
"type": "response",
"command": "export_html",
"success": true,
"data": {"path": "/tmp/session.html"}
}saklar_sesi
Muat file sesi yang berbeda. Dapat dibatalkan oleh pengendali acara ekstensi session_before_switch.
{"type": "switch_session", "sessionPath": "/path/to/session.jsonl"}Tanggapan:
{"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": false}}Jika ekstensi membatalkan peralihan:
{"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": true}}garpu
Buat fork baru dari pesan pengguna sebelumnya di cabang aktif. Dapat dibatalkan oleh pengendali acara ekstensi session_before_fork. Mengembalikan teks pesan yang dicabangkan.
{"type": "fork", "entryId": "abc123"}Tanggapan:
{
"type": "response",
"command": "fork",
"success": true,
"data": {"text": "The original prompt text...", "cancelled": false}
}Jika ekstensi membatalkan percabangan:
{
"type": "response",
"command": "fork",
"success": true,
"data": {"text": "The original prompt text...", "cancelled": true}
}klon
Gandakan cabang aktif saat ini ke dalam sesi baru di posisi saat ini. Dapat dibatalkan oleh pengendali acara ekstensi session_before_fork.
{"type": "clone"}Tanggapan:
{
"type": "response",
"command": "clone",
"success": true,
"data": {"cancelled": false}
}Jika ekstensi membatalkan kloning:
{
"type": "response",
"command": "clone",
"success": true,
"data": {"cancelled": true}
}dapatkan_fork_messages
Dapatkan pesan pengguna tersedia untuk forking.
{"type": "get_fork_messages"}Tanggapan:
{
"type": "response",
"command": "get_fork_messages",
"success": true,
"data": {
"messages": [
{"entryId": "abc123", "text": "First prompt..."},
{"entryId": "def456", "text": "Second prompt..."}
]
}
}dapatkan_entries
Dapatkan semua entri sesi dalam urutan penambahan (tidak termasuk header sesi). Sesi ini adalah pohon entri tambahan saja dengan id stabil, sehingga id entri berfungsi sebagai kursor yang tahan lama: teruskan id entri terakhir yang Anda lihat sebagai since untuk hanya mendapatkan entri setelahnya, bahkan saat klien dimulai ulang. Berbeda dengan get_messages, ini mencakup riwayat sebelum pemadatan dan cabang yang ditinggalkan.
{"type": "get_entries"}Dengan kursor:
{"type": "get_entries", "since": "abc123"}Tanggapan:
{
"type": "response",
"command": "get_entries",
"success": true,
"data": {
"entries": [
{"type": "message", "id": "def456", "parentId": "abc123", "timestamp": "...", "message": {"role": "user", "...": "..."}}
],
"leafId": "def456"
}
}leafId adalah id entri daun saat ini (null untuk sesi kosong), sehingga klien dapat mengetahui dalam satu perjalanan apakah cabang aktif telah berpindah. Jika since tidak cocok dengan id entri mana pun, responsnya adalah success: false.
dapatkan_pohon
Dapatkan sesi sebagai pohon entri. Setiap node adalah {entry, children, label?, labelTimestamp?}. Sesi yang terbentuk dengan baik memiliki satu root; entri yatim piatu (rantai induk yang rusak) juga muncul sebagai akar.
{"type": "get_tree"}Tanggapan:
{
"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"
}
}dapatkan_last_assistant_text
Dapatkan konten teks dari pesan asisten terakhir.
{"type": "get_last_assistant_text"}Tanggapan:
{
"type": "response",
"command": "get_last_assistant_text",
"success": true,
"data": {"text": "The assistant's response..."}
}Mengembalikan {"text": null} jika tidak ada pesan asisten.
set_sesi_nama
Tetapkan nama tampilan untuk sesi saat ini. Nama tersebut muncul dalam daftar sesi dan membantu mengidentifikasi sesi.
{"type": "set_session_name", "name": "my-feature-work"}Tanggapan:
{
"type": "response",
"command": "set_session_name",
"success": true
}Nama sesi saat ini tersedia melalui get_state di kolom sessionName. Untuk mengatur nama awal saat memulai mode RPC, teruskan --name <name> atau -n <name> ke proses pi --mode rpc.
Perintah
dapatkan_perintah
Dapatkan perintah yang tersedia (perintah ekstensi, prompt templates, dan keterampilan). Ini dapat dipanggil melalui perintah prompt dengan mengawali dengan /.
{"type": "get_commands"}Tanggapan:
{
"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"}
]
}
}Setiap perintah memiliki:
name: Nama perintah (dipanggil dengan/name)description: Deskripsi yang dapat dibaca manusia (opsional untuk perintah ekstensi)source: Perintah seperti apa:"extension": Terdaftar melaluipi.registerCommand()di ekstensi"prompt": Dimuat dari file templat cepat.md"skill": Dimuat dari direktori keterampilan (nama diawali denganskill:)
location: Dari mana file tersebut dimuat (opsional, tidak ada untuk ekstensi):"user": Tingkat pengguna (~/.pi/agent/)"project": Tingkat proyek (./.pi/agent/)"path": Jalur eksplisit melalui CLI atau pengaturan
path: Jalur file absolut ke sumber perintah (opsional)
Catatan: Perintah TUI bawaan (/settings, /hotkeys, dll.) tidak disertakan. Mereka hanya ditangani dalam mode interaktif dan tidak akan dijalankan jika dikirim melalui prompt.
Acara
Acara dialirkan ke baris stdout sebagai JSON selama operasi agen. Peristiwa umumnya tidak menyertakan kolom id; bash_execution_update termasuk id dari perintah asal bash ketika diberikan.
Jenis Acara
| Peristiwa | Keterangan |
|---|---|
agent_start |
Agen mulai memproses |
agent_end |
Satu proses agen tingkat rendah selesai (mungkin masih diikuti dengan percobaan ulang, pemadatan, atau kelanjutan antrean) |
agent_settled |
Pengoperasian agen telah diselesaikan sepenuhnya; tidak ada percobaan ulang otomatis, percobaan pemadatan, atau kelanjutan antrean yang tersisa |
turn_start |
Giliran baru dimulai |
turn_end |
Putaran selesai (termasuk pesan asisten dan hasil alat) |
message_start |
Pesan dimulai |
message_update |
Pembaruan streaming (teks/pemikiran/delta panggilan alat) |
message_end |
Pesan selesai |
bash_execution_update |
Potongan keluaran perintah langsung RPC bash |
tool_execution_start |
Alat memulai eksekusi |
tool_execution_update |
Kemajuan eksekusi alat (output streaming) |
tool_execution_end |
Alat selesai |
queue_update |
Antrean kemudi/tindak lanjut yang tertunda diubah |
compaction_start |
Pemadatan dimulai |
compaction_end |
Pemadatan selesai |
auto_retry_start |
Coba ulang otomatis dimulai (setelah kesalahan sementara) |
auto_retry_end |
Coba ulang otomatis selesai (berhasil atau gagal akhir) |
summarization_retry_scheduled |
Percobaan ulang dijadwalkan untuk kesalahan pemadatan sementara atau peringkasan ringkasan cabang |
summarization_retry_attempt_start |
Permintaan peringkasan ulang dimulai |
summarization_retry_finished |
Perulangan percobaan ulang peringkasan selesai |
extension_error |
Ekstensi menimbulkan kesalahan |
agen_mulai
Dipancarkan saat agen mulai memproses perintah.
{"type": "agent_start"}agen_akhir
Dipancarkan ketika satu agen tingkat rendah dijalankan selesai. Berisi semua pesan yang dihasilkan selama proses ini. Jika willRetry benar, percobaan ulang otomatis akan dilakukan.
{
"type": "agent_end",
"messages": [...],
"willRetry": false
}agen_menyelesaikan
Dipancarkan setelah proses tingkat sesi penuh diselesaikan. Pada titik ini Pi tidak akan dilanjutkan secara otomatis melalui percobaan ulang, percobaan pemadatan, atau pesan tindak lanjut dalam antrean.
{"type": "agent_settled"}turn_start / turn_end
Satu giliran terdiri dari satu respons asisten ditambah panggilan alat dan hasil apa pun yang dihasilkan.
{"type": "turn_start"}{
"type": "turn_end",
"message": {...},
"toolResults": [...]
}pesan_mulai / pesan_akhir
Dipancarkan saat pesan dimulai dan selesai. Bidang message berisi AgentMessage.
{"type": "message_start", "message": {...}}
{"type": "message_end", "message": {...}}pesan_perbarui (Streaming)
Dipancarkan selama streaming pesan asisten. Berisi peristiwa delta tanpa snapshot pesan kumulatif.
{
"type": "message_update",
"assistantMessageEvent": {
"type": "text_delta",
"contentIndex": 0,
"delta": "Hello "
}
}Bidang assistantMessageEvent berisi salah satu tipe delta berikut:
| Jenis | Keterangan |
|---|---|
text_start |
Blok konten teks dimulai |
text_delta |
Potongan konten teks |
text_end |
Blok konten teks berakhir |
thinking_start |
Blok berpikir dimulai |
thinking_delta |
Memikirkan potongan konten |
thinking_end |
Blok berpikir berakhir |
toolcall_start |
Panggilan alat dimulai |
toolcall_delta |
Potongan argumen pemanggilan alat |
toolcall_end |
Panggilan alat berakhir (termasuk objek toolCall penuh) |
Contoh streaming respons teks:
{"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 sengaja menghilangkan bidang kumulatif message sebelumnya dan
assistantMessageEvent.partial. Klien yang memerlukan pesan parsial langsung harus merakitnya
dari message_start dan kejadian selanjutnya menggunakan contentIndex. Perlakukan message_end.message
sebagai berwibawa. Untuk pemanggilan alat, buffer toolcall_delta.delta; toolcall_end.toolCall
berisi panggilan yang telah selesai.
bash_execution_update
Dipancarkan satu kali untuk setiap potongan keluaran dari perintah langsung bash. id cocok dengan id perintah, memungkinkan klien mengaitkan output dengan perintah yang benar.
Peristiwa mengalirkan semua output saat perintah dijalankan, meskipun respons bash akhir output terpotong.
{
"type": "bash_execution_update",
"id": "req-1",
"delta": "total 48\n"
}tool_execution_start / tool_execution_update / tool_execution_end
Dipancarkan saat alat dimulai, mengalirkan kemajuan, dan menyelesaikan eksekusi.
{
"type": "tool_execution_start",
"toolCallId": "call_abc123",
"toolName": "bash",
"args": {"command": "ls -la"}
}Selama eksekusi, tool_execution_update peristiwa mengalirkan sebagian hasil (misalnya, bash keluaran saat tiba):
{
"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}
}
}Ketika selesai:
{
"type": "tool_execution_end",
"toolCallId": "call_abc123",
"toolName": "bash",
"result": {
"content": [{"type": "text", "text": "total 48\n..."}],
"details": {...}
},
"isError": false
}Gunakan toolCallId untuk menghubungkan peristiwa. partialResult di tool_execution_update berisi akumulasi keluaran sejauh ini (bukan hanya delta), memungkinkan klien untuk dengan mudah mengganti tampilan mereka pada setiap pembaruan.
antrian_perbarui
Dipancarkan setiap kali kemudi yang tertunda atau antrian tindak lanjut berubah.
{
"type": "queue_update",
"steering": ["Focus on error handling"],
"followUp": ["After that, summarize the result"]
}pemadatan_mulai / pemadatan_akhir
Dikeluarkan saat pemadatan berjalan, baik manual maupun otomatis.
{"type": "compaction_start", "reason": "threshold"}Bidang reason adalah "manual", "threshold", atau "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
}Jika reason adalah "overflow" dan pemadatan berhasil, willRetry adalah true dan agen akan secara otomatis mencoba kembali perintah tersebut.
Jika pemadatan dibatalkan, result adalah null dan aborted adalah true.
Jika pemadatan gagal (misalnya, API melebihi kuota), result adalah null, aborted adalah false, dan errorMessage berisi deskripsi kesalahan.
auto_retry_start / auto_retry_end
Dipancarkan ketika percobaan ulang otomatis dipicu setelah kesalahan sementara (kelebihan beban, batas kecepatan, 5xx).
{
"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
}Pada kegagalan terakhir (percobaan ulang maksimal terlampaui):
{
"type": "auto_retry_end",
"success": false,
"attempt": 3,
"finalError": "529 overloaded_error: Overloaded"
}ringkasan_retry_scheduled / ringkasan_retry_attempt_start / ringkasan_retry_finished
Dipancarkan saat pemadatan atau peringkasan ringkasan cabang dicoba lagi setelah kesalahan penyedia sementara. Peristiwa ini menggunakan pengaturan percobaan ulang yang sama seperti percobaan ulang asisten otomatis.
{
"type": "summarization_retry_scheduled",
"attempt": 1,
"maxAttempts": 3,
"delayMs": 2000,
"errorMessage": "terminated"
}{
"type": "summarization_retry_attempt_start",
"source": "compaction",
"reason": "threshold"
}Untuk ringkasan cabang, source adalah "branchSummary" dan tidak ada reason.
{
"type": "summarization_retry_finished"
}ekstensi_kesalahan
Dipancarkan saat ekstensi menimbulkan kesalahan.
{
"type": "extension_error",
"extensionPath": "/path/to/extension.ts",
"event": "tool_call",
"error": "Error message..."
}Protokol UI Ekstensi
Extensions dapat meminta interaksi pengguna melalui ctx.ui.select(), ctx.ui.confirm(), dll. Dalam mode RPC, ini diterjemahkan ke dalam sub-protokol permintaan/respons di atas aliran perintah/peristiwa dasar.
Ada dua kategori metode UI ekstensi:
- Metode dialog (
select,confirm,input,editor): memancarkanextension_ui_requestpada stdout dan memblokir hingga klien mengirimkan kembaliextension_ui_responsepada stdin denganidyang cocok. - Metode api-dan-lupakan (
notify,setStatus,setWidget,setTitle,set_editor_text): pancarkanextension_ui_requestpada stdout tetapi jangan mengharapkan respons. Klien dapat menampilkan informasi atau mengabaikannya.
Jika metode dialog menyertakan kolom timeout, sisi agen akan menyelesaikan secara otomatis dengan nilai default ketika batas waktu habis. Klien tidak perlu melacak batas waktu.
Beberapa metode ExtensionUIContext tidak didukung atau terdegradasi dalam mode RPC karena memerlukan akses langsung TUI:
custom()mengembalikanundefinedsetWorkingMessage(),setWorkingIndicator(),setFooter(),setHeader(),setEditorComponent(),setToolsExpanded()tidak boleh dijalankangetEditorText()mengembalikan""getToolsExpanded()mengembalikanfalsepasteToEditor()delegasi kesetEditorText()(tidak ada penanganan tempel/ciutkan)getAllThemes()mengembalikan[]getTheme()mengembalikanundefinedsetTheme()mengembalikan{ success: false, error: "..." }
Catatan: ctx.mode adalah "rpc" dan ctx.hasUI adalah true dalam mode RPC karena metode dialog dan api-dan-lupa berfungsi melalui sub-protokol UI ekstensi. Gunakan ctx.mode === "tui" untuk menjaga TUI fitur khusus seperti custom() yang memerlukan terminal nyata.
Permintaan Ekstensi UI (stdout)
Semua permintaan memiliki bidang type: "extension_ui_request", bidang unik id, dan method.
memilih
Minta pengguna untuk memilih dari daftar. Metode dialog dengan kolom timeout menyertakan batas waktu dalam milidetik; agen menyelesaikan secara otomatis dengan undefined jika klien tidak merespons tepat waktu.
{
"type": "extension_ui_request",
"id": "uuid-1",
"method": "select",
"title": "Allow dangerous command?",
"options": ["Allow", "Block"],
"timeout": 10000
}Respons yang diharapkan: extension_ui_response dengan value (string opsi yang dipilih) atau cancelled: true.
mengonfirmasi
Meminta pengguna untuk konfirmasi ya/tidak.
{
"type": "extension_ui_request",
"id": "uuid-2",
"method": "confirm",
"title": "Clear session?",
"message": "All messages will be lost.",
"timeout": 5000
}Respons yang diharapkan: extension_ui_response dengan confirmed: true/false atau cancelled: true.
masukan
Meminta pengguna untuk teks bentuk bebas.
{
"type": "extension_ui_request",
"id": "uuid-3",
"method": "input",
"title": "Enter a value",
"placeholder": "type something..."
}Respons yang diharapkan: extension_ui_response dengan value (teks yang dimasukkan) atau cancelled: true.
editor
Buka editor teks multi-baris dengan konten opsional yang telah diisi sebelumnya.
{
"type": "extension_ui_request",
"id": "uuid-4",
"method": "editor",
"title": "Edit some text",
"prefill": "Line 1\nLine 2\nLine 3"
}Respons yang diharapkan: extension_ui_response dengan value (teks yang diedit) atau cancelled: true.
memberitahu
Tampilkan pemberitahuan. Api-dan-lupakan, tidak ada respons yang diharapkan.
{
"type": "extension_ui_request",
"id": "uuid-5",
"method": "notify",
"message": "Command blocked by user",
"notifyType": "warning"
}Bidang notifyType adalah "info", "warning", atau "error". Defaultnya adalah "info" jika dihilangkan.
setStatus
Mengatur atau menghapus entri status di footer/bilah status. Api-dan-lupakan.
{
"type": "extension_ui_request",
"id": "uuid-6",
"method": "setStatus",
"statusKey": "my-ext",
"statusText": "Turn 3 running..."
}Kirim statusText: undefined (atau hilangkan) untuk menghapus entri status untuk kunci tersebut.
setWidget
Mengatur atau menghapus widget (blok baris teks) yang ditampilkan di atas atau di bawah editor. Api-dan-lupakan.
{
"type": "extension_ui_request",
"id": "uuid-7",
"method": "setWidget",
"widgetKey": "my-ext",
"widgetLines": ["--- My Widget ---", "Line 1", "Line 2"],
"widgetPlacement": "aboveEditor"
}Kirim widgetLines: undefined (atau hilangkan) untuk menghapus widget. Bidang widgetPlacement adalah "aboveEditor" (default) atau "belowEditor". Hanya array string yang didukung dalam mode RPC; pabrik komponen diabaikan.
setJudul
Atur judul jendela/tab terminal. Api-dan-lupakan.
{
"type": "extension_ui_request",
"id": "uuid-8",
"method": "setTitle",
"title": "pi - my project"
}set_editor_teks
Atur teks di editor input. Api-dan-lupakan.
{
"type": "extension_ui_request",
"id": "uuid-9",
"method": "set_editor_text",
"text": "prefilled text for the user"
}Respons UI Ekstensi (stdin)
Respons dikirim hanya untuk metode dialog (select, confirm, input, editor). id harus sesuai dengan permintaan.
Respon nilai (pilih, masukan, editor)
{"type": "extension_ui_response", "id": "uuid-1", "value": "Allow"}Tanggapan konfirmasi (konfirmasi)
{"type": "extension_ui_response", "id": "uuid-2", "confirmed": true}Respons pembatalan (dialog apa pun)
Tutup metode dialog apa pun. Ekstensi menerima undefined (untuk pilih/input/editor) atau false (untuk konfirmasi).
{"type": "extension_ui_response", "id": "uuid-3", "cancelled": true}Penanganan Kesalahan
Perintah yang gagal mengembalikan respons dengan success: false:
{
"type": "response",
"command": "set_model",
"success": false,
"error": "Model not found: invalid/model"
}Kesalahan penguraian:
{
"type": "response",
"command": "parse",
"success": false,
"error": "Failed to parse command: Unexpected token..."
}Jenis
File sumber:
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 tipe perintah/respons, tipe permintaan/respons UI ekstensi
Model
{
"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
}
}Pesan Pengguna
{
"role": "user",
"content": "Hello!",
"timestamp": 1733234567890,
"attachments": []
}Bidang content dapat berupa string atau larik blok TextContent/ImageContent.
Pesan Asisten
{
"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
}Alasan berhenti: "stop", "length", "toolUse", "error", "aborted"
AlatHasilPesan
{
"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 bersifat opsional dan melaporkan pekerjaan LLM bertingkat yang dilakukan oleh alat tersebut. Saat ini, ini berkontribusi pada token sesi dan total biaya.
Pesan Eksekusi Bash
Dibuat dengan perintah bash RPC (bukan dengan panggilan alat LLM):
{
"role": "bashExecution",
"command": "ls -la",
"output": "total 48\ndrwxr-xr-x ...",
"exitCode": 0,
"cancelled": false,
"truncated": false,
"fullOutputPath": null,
"timestamp": 1733234567890
}Lampiran
{
"id": "img1",
"type": "image",
"fileName": "photo.jpg",
"mimeType": "image/jpeg",
"size": 102400,
"content": "base64-encoded-data...",
"extractedText": null,
"preview": null
}Contoh: Klien Dasar (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()
breakContoh: Klien Interaktif (Node.js)
Lihat test/rpc-example.ts untuk contoh interaktif lengkap, atau src/modes/rpc/rpc-client.ts untuk implementasi klien yang diketik.
Untuk contoh lengkap penanganan protokol UI ekstensi, lihat examples/rpc-extension-ui.ts yang berpasangan dengan ekstensi examples/extensions/rpc-demo.ts.
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");
});