Konfigurasi, kustomisasi, pengaturan platform, dan referensi API untuk Pi.

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 (mendukung provider/id dan 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\n dengan 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:

  1. Output Bash disertakan dalam konteks LLM pada prompt berikutnya, tidak langsung
  2. 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 melalui pi.registerCommand() di ekstensi
    • "prompt": Dimuat dari file templat cepat .md
    • "skill": Dimuat dari direktori keterampilan (nama diawali dengan skill:)
  • 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): memancarkan extension_ui_request pada stdout dan memblokir hingga klien mengirimkan kembali extension_ui_response pada stdin dengan id yang cocok.
  • Metode api-dan-lupakan (notify, setStatus, setWidget, setTitle, set_editor_text): pancarkan extension_ui_request pada 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() mengembalikan undefined
  • setWorkingMessage(), setWorkingIndicator(), setFooter(), setHeader(), setEditorComponent(), setToolsExpanded() tidak boleh dijalankan
  • getEditorText() mengembalikan ""
  • getToolsExpanded() mengembalikan false
  • pasteToEditor() delegasi ke setEditorText() (tidak ada penanganan tempel/ciutkan)
  • getAllThemes() mengembalikan []
  • getTheme() mengembalikan undefined
  • setTheme() 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:

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()
        break

Contoh: 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");
});