@ryuu-reinzz/ryuu-cli 0.0.0-stage → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +592 -0
- package/LICENSE +21 -0
- package/README.md +1269 -2
- package/package.json +45 -4
- package/src/agent/agent.js +1194 -0
- package/src/agent/approvals.js +76 -0
- package/src/agent/context.js +106 -0
- package/src/agent/planner.js +237 -0
- package/src/agent/worklog.js +318 -0
- package/src/cli/app.js +471 -0
- package/src/cli/commands.js +1155 -0
- package/src/cli/input.js +287 -0
- package/src/cli/markdown.js +527 -0
- package/src/cli/prompts.js +255 -0
- package/src/cli/renderer.js +2155 -0
- package/src/cli/settings-editor.js +280 -0
- package/src/cli/settings-tui.js +669 -0
- package/src/cli/tui.js +1737 -0
- package/src/cli/width.js +48 -0
- package/src/config/load.js +137 -0
- package/src/config/scaffold.js +50 -0
- package/src/config/settings-registry.js +495 -0
- package/src/config/settings.js +304 -0
- package/src/config/validate.js +461 -0
- package/src/index.js +449 -0
- package/src/providers/catalog.js +407 -0
- package/src/providers/ids.js +24 -0
- package/src/providers/index.js +103 -0
- package/src/providers/nvidia.js +671 -0
- package/src/providers/registry.js +104 -0
- package/src/providers/river.js +198 -0
- package/src/providers/tokenharbor.js +38 -0
- package/src/providers/vendor-extras.js +82 -0
- package/src/services/clipboard.js +38 -0
- package/src/services/diff.js +153 -0
- package/src/services/doctor.js +126 -0
- package/src/services/logger.js +190 -0
- package/src/services/preferences.js +249 -0
- package/src/services/processes.js +345 -0
- package/src/services/provider-settings.js +226 -0
- package/src/services/sessions.js +279 -0
- package/src/services/undo.js +133 -0
- package/src/services/ushell.js +146 -0
- package/src/services/websearch/manager.js +616 -0
- package/src/services/websearch/mcp.js +233 -0
- package/src/services/websearch/normalize.js +284 -0
- package/src/services/websearch/providers.js +178 -0
- package/src/services/websearch/serper.js +263 -0
- package/src/services/workspace.js +589 -0
- package/src/tools/filesystem.js +304 -0
- package/src/tools/git.js +114 -0
- package/src/tools/index.js +48 -0
- package/src/tools/project.js +160 -0
- package/src/tools/registry.js +118 -0
- package/src/tools/search.js +210 -0
- package/src/tools/shell.js +279 -0
- package/src/tools/url.js +542 -0
- package/src/tools/web.js +67 -0
- package/src/utils/errors.js +160 -0
- package/src/utils/network.js +129 -0
- package/src/utils/redaction.js +73 -0
- package/src/utils/validation.js +370 -0
- package/src/utils/version.js +24 -0
package/README.md
CHANGED
|
@@ -1,3 +1,1270 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Ryuu Agent CLI
|
|
2
|
+
|
|
3
|
+
Agen coding AI otonom yang setiap aksi tulis/eksekusi harus disetujui dulu, untuk
|
|
4
|
+
terminal Anda. Ryuu memeriksa workspace, menyusun rencana, memanggil tool,
|
|
5
|
+
menunjukkan apa yang sedang dilakukannya, dan melaporkan apa yang berubah —
|
|
6
|
+
didukung oleh beberapa provider AI melalui antarmuka Chat Completions yang
|
|
7
|
+
kompatibel dengan OpenAI: NVIDIA Integrate API dan Token Harbor sudah tersedia,
|
|
8
|
+
dan provider lain bisa Anda daftarkan sendiri lewat konfigurasi.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
╭─ ◢ RYUU // AGENT OS ──────────────────────────────────────────── v0.3.1 ─╮
|
|
12
|
+
│ │
|
|
13
|
+
│ ██████╗ ██╗ ██╗██╗ ██╗██╗ ██╗ │
|
|
14
|
+
│ ██╔══██╗╚██╗ ██╔╝██║ ██╗██║ ██╗ │
|
|
15
|
+
│ ██████╔╝ ╚████╔╝ ██║ ██╗██║ ██╗ │
|
|
16
|
+
│ ██╔══██╗ ╚██╔╝ ██║ ██╝██║ ██╗ │
|
|
17
|
+
│ ██║ ██║ ██║ ╚██████╔╝╚██████╔╝ │
|
|
18
|
+
│ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ │
|
|
19
|
+
│ │
|
|
20
|
+
│ autonomous coding intelligence · NVIDIA │
|
|
21
|
+
│ │
|
|
22
|
+
├─ ◆ TELEMETRY ────────────────────────────────────────────────────────────┤
|
|
23
|
+
│ model minimaxai/minimax-m3.1-flash │
|
|
24
|
+
│ workspace /path/to/your/project │
|
|
25
|
+
│ runtime Node.js v25.x · linux │
|
|
26
|
+
│ access ask · shell is not a sandbox │
|
|
27
|
+
│ log /path/to/your/project/.ryuu/logs/agent.log │
|
|
28
|
+
╰──────────────────────────────────────────────────────────────────────────╯
|
|
29
|
+
click a block or /expand N !cmd shell ⌃C cancel /help commands /exit quit
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
## Fitur
|
|
35
|
+
|
|
36
|
+
- **Loop agent yang eksplisit** — model → tool call tervalidasi → persetujuan →
|
|
37
|
+
eksekusi nyata → hasil tool → model, sampai ada jawaban akhir, pembatalan, atau
|
|
38
|
+
batas durasi tugas. Jumlah langkah tidak dibatasi secara bawaan;
|
|
39
|
+
`agent.maxSteps` menambahkan batas opsional.
|
|
40
|
+
- **Tool workspace yang nyata** — list, tree, read, search, file info, diff,
|
|
41
|
+
create, edit, write, move, delete, inspeksi Git, dan ringkasan project.
|
|
42
|
+
- **Manajer proses** — menjalankan command dengan stdout/stderr asli, exit code,
|
|
43
|
+
sinyal, durasi, timeout, buffer terbatas, server background, dan penghentian
|
|
44
|
+
yang bersih.
|
|
45
|
+
- **Gerbang persetujuan (approval gate)** — setiap aksi tulis, eksekusi, dan
|
|
46
|
+
destruktif diperiksa sebelum dijalankan. Tool read-only tidak pernah meminta
|
|
47
|
+
konfirmasi. Aksi yang ditolak dilaporkan kembali ke model.
|
|
48
|
+
- **HUD kaya telemetri** — banner gradien `RYUU // AGENT OS`, panel telemetri,
|
|
49
|
+
feed aktivitas, panel reasoning live, kartu persetujuan, dan dasbor ringkasan
|
|
50
|
+
run. Baris aktivitas yang selalu menyala melaporkan fase, waktu berjalan per
|
|
51
|
+
fase, **total waktu run, nomor langkah, tool mana yang sedang berjalan dan
|
|
52
|
+
berapa lagi mengantre (`writing edit_file src/x.js (2/5)`), jumlah token
|
|
53
|
+
prompt/completion live, dan latensi token pertama**.
|
|
54
|
+
Setiap pemanggilan model mencetak barisnya sendiri `◇ model 9.4s · 21.3k↑ 388↓ tok · first token 1.8s`,
|
|
55
|
+
command yang berjalan mengalirkan stdout/stderr ke wilayah live, setiap command
|
|
56
|
+
yang selesai mencetak kotak output `$ argv` bernomor (pratinjau lima baris;
|
|
57
|
+
klik bloknya, atau jalankan `/expand <id>`, untuk log utuh yang disimpan beserta
|
|
58
|
+
scrolling internal, dan `/logs <id>` sesudahnya), dan setiap perubahan file
|
|
59
|
+
mencetak baris `-`/`+` yang benar-benar berubah. Blok reasoning dinomori dengan
|
|
60
|
+
cara yang sama dan tetap bisa dibuka ulang selama sesi ini. Tempel panjang
|
|
61
|
+
(1000+ karakter) diringkas menjadi placeholder `> [Pasted text #N X chars]` di
|
|
62
|
+
composer, sementara model tetap menerima teks lengkapnya.
|
|
63
|
+
- **Tanpa batas retry buatan** — koneksi provider yang putus atau giliran model
|
|
64
|
+
kosong akan dicoba ulang dengan heartbeat di layar dan backoff eksponensial
|
|
65
|
+
sampai model menjawab, tenggat tugas lewat, atau Anda membatalkan. Giliran
|
|
66
|
+
kosong tidak pernah mengakhiri tugas dengan galat; `agent.maxRecoveryAttempts`
|
|
67
|
+
tetap bisa memasang batas keras.
|
|
68
|
+
- **Composer tetap bisa dipakai saat run** — prompt digambar di bawah wilayah
|
|
69
|
+
aktivitas live dan dicetak ulang di setiap baris yang dialirkan, jadi slash
|
|
70
|
+
command bisa diketik dan dijalankan sementara agent sedang berpikir,
|
|
71
|
+
menjalankan tool, atau mengalirkan jawabannya (`/status`, `/expand 4`,
|
|
72
|
+
`/model 2`, `/cancel`, …). Prompt tugas baru ditolak sampai run selesai,
|
|
73
|
+
sehingga dua run tidak bisa tumpang tindih.
|
|
74
|
+
- **Session worklog** — fakta terverifikasi (file yang dibaca beserta rentang
|
|
75
|
+
barisnya, file yang diubah, command dan exit code, temuan, rencana) disimpan
|
|
76
|
+
sepanjang sesi dan diteruskan ke tugas berikutnya, sehingga tindak lanjut
|
|
77
|
+
melanjutkan pekerjaan alih-alih mengulang analisis. File yang sudah dibaca dan
|
|
78
|
+
tidak berubah di disk tidak dibaca lagi; agent diberi tahu bahwa isinya sudah
|
|
79
|
+
diketahui.
|
|
80
|
+
- **Jawaban Markdown-native** — heading, bold/italic, inline code, link, list,
|
|
81
|
+
kutipan, code fence dengan penyorotan sintaks, dan tabel yang mengecil,
|
|
82
|
+
membungkus, atau berpindah ke tata letak vertikal agar sesuai lebar terminal.
|
|
83
|
+
- **Perlindungan workspace** — penolakan escape path/symlink, pemblokiran file
|
|
84
|
+
rahasia, pengecualian direktori hasil-generate, batas ukuran, penulisan
|
|
85
|
+
atomik, dan deteksi penulisan basi.
|
|
86
|
+
- **Memori lokal** — memori percakapan lintas tugas dalam satu sesi (lihat dengan
|
|
87
|
+
`/memory`, pulihkan yang tersimpan dengan `/resume <id>`), ID sesi dan
|
|
88
|
+
riwayat, transkrip yang disunting (redacted), cache ringkasan project,
|
|
89
|
+
pemadatan konteks, dan undo stack yang terbatas pada sesi.
|
|
90
|
+
- **Mode gagal yang aman** — konfigurasi hilang, input tidak valid, galat
|
|
91
|
+
provider, batas laju, dan tool calling yang tidak didukung menghasilkan pesan
|
|
92
|
+
yang bisa ditindaklanjuti alih-alih stack trace (pakai `--debug` untuk stack).
|
|
93
|
+
- **Mode layar penuh (`--tui`)** — antarmuka opsional bertipe retained-mode yang
|
|
94
|
+
menggambar ulang seluruh percakapan dari sebuah model, alih-alih menambahkan
|
|
95
|
+
baris ke scrollback: setiap reasoning, output `run_command`, dan jawaban punya
|
|
96
|
+
keadaan terbuka/tertutupnya sendiri, sehingga beberapa blok bisa dibuka
|
|
97
|
+
sekaligus dan yang lama tetap bisa dibuka sepanjang sesi. Composer adalah bagian
|
|
98
|
+
dari frame yang sama, dan transkrip menggul di dalam aplikasi
|
|
99
|
+
(`PgUp`/`PgDn`, roda mouse, klik untuk melipat/membuka) alih-alih sejarah milik
|
|
100
|
+
terminal. Blok dipisahkan baris kosong dan diberi warna (prosa putih, Markdown
|
|
101
|
+
dan tabel biru langit, nama tool kuning, reasoning hijau, kegagalan merah),
|
|
102
|
+
layar pembuka memakai banner ASCII yang sama dengan antarmuka baris, prompt
|
|
103
|
+
berupa gradien pink → blue `ryuu > `, dan setiap baris membungkus sesuai lebar
|
|
104
|
+
terminal. Tanpa flag ini tidak ada yang berubah.
|
|
105
|
+
- **Shell Anda sendiri (`/bash`, `!cmd`)** — jalankan sendiri sebuah command di
|
|
106
|
+
workspace tanpa melibatkan model: output lengkap dicetak segera, dan command,
|
|
107
|
+
exit code, serta outputnya disimpan sebagai giliran pengguna di sesi, sehingga
|
|
108
|
+
tugas berikutnya tahu apa yang Anda jalankan dan apa yang terjadi.
|
|
109
|
+
- **Mode plain** — dipakai otomatis ketika stdout bukan TTY, atau dengan
|
|
110
|
+
`--plain`.
|
|
111
|
+
|
|
112
|
+
## Persyaratan
|
|
113
|
+
|
|
114
|
+
| Persyaratan | Detail |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| Node.js | **25.x dianjurkan dan terverifikasi.** Minimum yang didukung: 22.x (versi mayor lebih tua tidak diuji). |
|
|
117
|
+
| npm | 10+ (sudah menyertai Node 25). |
|
|
118
|
+
| OS | Linux, macOS, atau Windows. Perilaku pensinyalan proses berbeda di Windows; lihat [Perilaku proses](#perilaku-proses). |
|
|
119
|
+
| Jaringan | Dibutuhkan untuk panggilan model langsung. Git opsional dan hanya dipakai untuk `/diff` dan `inspect_git`. |
|
|
120
|
+
| Kunci provider | Dibutuhkan untuk panggilan langsung. Kunci disimpan di `config.json` di bawah `providers.<id>.apiKey` (`nvidia`, `tokenharbor`), diisi lewat `ryuu --settings`. |
|
|
121
|
+
|
|
122
|
+
Instal Node 25 dengan [nvm](https://github.com/nvm-sh/nvm):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
nvm install 25
|
|
126
|
+
nvm use 25
|
|
127
|
+
node --version # v25.x
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Di Windows, pakai nvm-windows atau installer resmi Node.js, lalu verifikasi dengan
|
|
131
|
+
`node --version` di PowerShell.
|
|
132
|
+
|
|
133
|
+
## Instalasi dan konfigurasi
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# paket npm, versi terbaru
|
|
137
|
+
npm install -g @ryuu-reinzz/ryuu-cli@latest
|
|
138
|
+
ryuu --version
|
|
139
|
+
|
|
140
|
+
# atau tanpa instalasi global
|
|
141
|
+
npx @ryuu-reinzz/ryuu-cli@latest --version
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Dari source (untuk pengembangan):
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npm install
|
|
148
|
+
node src/index.js --version
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Setelah terpasang, simpan kunci provider di `config.json` (owner-only, di luar
|
|
152
|
+
repo) — file itu dibuat otomatis pada run pertama:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
ryuu --settings
|
|
156
|
+
# lalu isi baris providers.nvidia.apiKey dengan kunci asli
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Tidak ada file `.env` dan tidak ada variabel environment: **semua konfigurasi
|
|
160
|
+
berasal dari `config.json`**. Saat pertama dijalankan tanpa file itu, Ryuu
|
|
161
|
+
membuatnya otomatis berisi semua kunci yang bisa diatur dengan nilai kosong —
|
|
162
|
+
nilai kosong berarti memakai bawaan katalog, jadi Anda hanya perlu mengisi kunci
|
|
163
|
+
provider. File dibuat mode `0600`, berada di luar repo, dan tidak pernah dicetak
|
|
164
|
+
balik oleh CLI (API key selalu `••••••••`).
|
|
165
|
+
|
|
166
|
+
Ambil kunci NVIDIA di <https://build.nvidia.com/> dan kunci Token Harbor di
|
|
167
|
+
<https://tokenharbor.ai/>. Jangan pernah meng-commit kunci asli, menempelkannya
|
|
168
|
+
ke issue, atau memasukkannya ke log. CLI tidak pernah mencetak kunci: `/config`
|
|
169
|
+
menampilkan `set (redacted)`, dan log/sesi sudah melewati proses penyingkatan
|
|
170
|
+
(redaction). Kunci satu provider tidak pernah dikirim ke provider lain.
|
|
171
|
+
|
|
172
|
+
Pilih provider aktif secara eksplisit (opsional):
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# permanen: ubah baris provider / providerModel.<id> dengan --settings
|
|
176
|
+
ryuu --settings
|
|
177
|
+
|
|
178
|
+
# atau per run
|
|
179
|
+
ryuu --provider tokenharbor --model deepseek-v4.1-flash:free "tugas"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Tanpa pilihan eksplisit, Ryuu memakai `nvidia` bila kuncinya ada; jika tidak,
|
|
183
|
+
provider pertama yang punya kunci. Provider yang dipilih dengan `/provider`
|
|
184
|
+
disimpan di `.ryuu/preferences.json` workspace itu dan menimpa `config.json`
|
|
185
|
+
untuk workspace tersebut.
|
|
186
|
+
|
|
187
|
+
### Verifikasi instalasi
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
ryuu --doctor # pemeriksaan offline, tanpa panggilan API
|
|
191
|
+
ryuu --doctor --live # satu permintaan nyata yang kecil (memakai kuota)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Hasil offline yang diharapkan dengan kunci valid: runtime, config, endpoint,
|
|
195
|
+
workspace, direktori state, dan Git lolos; konektivitas berupa `SKIP` sampai Anda
|
|
196
|
+
memakai `--live`.
|
|
197
|
+
|
|
198
|
+
## Menjalankan
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
ryuu # antarmuka terminal interaktif (instalasi npm)
|
|
202
|
+
npm start # dari source
|
|
203
|
+
node src/index.js # sama saja
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Binary `ryuu` bisa dipakai dari direktori mana pun setelah instalasi global:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
cd /path/to/another/project
|
|
210
|
+
ryuu
|
|
211
|
+
ryuu "Summarize this project"
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Saat dijalankan di luar project ini, `ryuu` tetap memakai folder saat ini sebagai
|
|
215
|
+
workspace dan membaca `config.json` milik pengguna, sehingga kunci dan batasan
|
|
216
|
+
tidak perlu diulang di setiap direktori.
|
|
217
|
+
|
|
218
|
+
Di prompt interaktif, ketik tugas lalu tekan Enter sekali untuk mengirimnya. Untuk
|
|
219
|
+
tugas beberapa baris, akhiri baris dengan `\` lalu teruskan; baris berikutnya tanpa
|
|
220
|
+
`\` menyelesaikannya. Slash command (`/help`, `/model`, `/exit`, …) berjalan
|
|
221
|
+
segera.
|
|
222
|
+
Selama tugas berjalan, composer tetap aktif: slash command (beserta argumennya)
|
|
223
|
+
dieksekusi segera, dan hanya prompt tugas baru yang ditolak dengan
|
|
224
|
+
`A task is already running...` sampai run selesai atau dihentikan `/cancel`.
|
|
225
|
+
Berpikir, reasoning, tool call, persetujuan, dan jawaban yang dialirkan tetap
|
|
226
|
+
berjalan sementara output command dicetak di atas prompt.
|
|
227
|
+
|
|
228
|
+
Menjalankan satu tugas tanpa REPL:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
ryuu "List the files in src and summarize the architecture"
|
|
232
|
+
ryuu "Fix the failing test in tests/util.test.js, then run npm test"
|
|
233
|
+
echo "Explain the error in build.log" | ryuu
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Sesi non-interaktif tidak punya prompt untuk persetujuan, jadi penulisan dan
|
|
237
|
+
command **ditolak secara bawaan**. `--yes` menyetujui otomatis penulisan file
|
|
238
|
+
(command tetap butuh persetujuan interaktif). Pakai `--auto-approve` untuk
|
|
239
|
+
menyetujui otomatis **semua** aksi — termasuk command shell — agar agent bisa
|
|
240
|
+
menyelesaikan pekerjaan tanpa pengawasan:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
ryuu --auto-approve "Fix the failing test, then run npm test"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Eksekusi shell tetap bukan sandbox; hanya pakai `--auto-approve` pada tugas yang
|
|
247
|
+
Anda percaya.
|
|
248
|
+
|
|
249
|
+
### Opsi CLI
|
|
250
|
+
|
|
251
|
+
| Opsi | Fungsi |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| `-h`, `--help` | Menampilkan penggunaan. |
|
|
254
|
+
| `-v`, `--version` | Menampilkan versi. |
|
|
255
|
+
| `--task "..."` | Tugas sekali jalan eksplisit (tugas posisional juga bisa). |
|
|
256
|
+
| `--workspace <path>` | Override workspace untuk run ini. |
|
|
257
|
+
| `--provider <id>` | Override provider untuk run ini, mis. `tokenharbor`. |
|
|
258
|
+
| `--model <id>` | Override model untuk run ini. |
|
|
259
|
+
| `--max-steps <n>` | Batas langkah agent opsional (`0` = tanpa batas, bawaan). |
|
|
260
|
+
| `-y`, `--yes` | Menyetujui otomatis penulisan file untuk sesi ini. |
|
|
261
|
+
| `--read-only` | Menolak setiap aksi tulis, eksekusi, dan destruksi. |
|
|
262
|
+
| `--doctor` | Diagnostik offline. |
|
|
263
|
+
| `--live` | Bersama `--doctor`: satu permintaan konektivitas nyata. |
|
|
264
|
+
| `--settings` | Editor pengaturan global baris bernomor (tanpa menjalankan agent). |
|
|
265
|
+
| `--settings --tui` | Editor pengaturan layar penuh (butuh TTY interaktif). |
|
|
266
|
+
| `--settings --list` | Mencetak pengaturan yang bisa diedit lalu keluar. |
|
|
267
|
+
| `--tui` | UI layar penuh retained-mode (butuh TTY interaktif; diabaikan dengan `--plain`). |
|
|
268
|
+
| `--plain` | Output plain, tanpa spinner atau gaya ANSI. |
|
|
269
|
+
| `--no-color` | Menonaktifkan warna. |
|
|
270
|
+
| `--debug` | Log debug dan stack trace. |
|
|
271
|
+
|
|
272
|
+
### Pengaturan global (`ryuu --settings`)
|
|
273
|
+
|
|
274
|
+
Semua pengaturan milik pengguna tinggal di satu file yang terbaca dari direktori
|
|
275
|
+
kerja mana pun — tidak ada `.env` dan tidak ada variabel environment:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
ryuu --settings # editor baris bernomor
|
|
279
|
+
ryuu --settings --tui # editor layar penuh (butuh TTY)
|
|
280
|
+
ryuu --settings --list # cetak daftar, tanpa masuk mode edit
|
|
281
|
+
ryuu --settings --help # bantuan khusus pengaturan
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Lokasi file mengikuti konvensi platform dan bisa dialihkan dengan
|
|
285
|
+
`RYUU_CONFIG_DIR` (berguna di mesin tanpa home tetap atau di test):
|
|
286
|
+
|
|
287
|
+
| Platform | Lokasi bawaan |
|
|
288
|
+
| --- | --- |
|
|
289
|
+
| Linux/BSD | `$XDG_CONFIG_HOME/ryuu/config.json` atau `~/.config/ryuu/config.json` |
|
|
290
|
+
| macOS | `~/Library/Application Support/ryuu/config.json` |
|
|
291
|
+
| Windows | `%APPDATA%\ryuu\config.json` |
|
|
292
|
+
|
|
293
|
+
**Editor baris.** Daftar bernomor menampilkan nilai saat ini, dengan API key
|
|
294
|
+
selalu disamarkan (`••••••••`). Perintahnya: `<nomor> <nilai baru>`, `/list`,
|
|
295
|
+
`/show <nomor>`, `/reset <nomor>` (meminta konfirmasi), `/help`, dan `/exit`.
|
|
296
|
+
Nilai boleh mengandung spasi; semuanya setelah nomor dipertahankan. Setiap
|
|
297
|
+
perubahan divalidasi lalu **langsung disimpan** (read-modify-write), jadi
|
|
298
|
+
terminal yang tertutup mendadak tidak menghilangkan perubahan yang sudah lolos.
|
|
299
|
+
Jika penulisan gagal, editor menyebut nilai itu `NOT saved` dan mempertahankan
|
|
300
|
+
nilai valid terakhir; satu kunci tidak pernah menghapus kunci lain atau properti
|
|
301
|
+
yang tidak dikenal. `/reset` adalah cara mengosongkan kunci rahasia — tidak
|
|
302
|
+
perlu memasukkan placeholder.
|
|
303
|
+
|
|
304
|
+
**Editor TUI.** `--settings --tui` membuka layar alternatif (bukan agent): daftar
|
|
305
|
+
di kiri/atas, panel deskripsi dan batasan di bawahnya, `↑↓`/`PgUp`/`PgDn` untuk
|
|
306
|
+
navigasi, `←/→` untuk memilih provider dan model katalog (mengetik tetap bisa
|
|
307
|
+
memasukkan id khusus), `Enter` membuka/menyimpan, `Esc` membatalkan edit (dan
|
|
308
|
+
`Esc` lagi keluar), `Ctrl+C` keluar. Raw mode, layar alternatif, dan listener
|
|
309
|
+
selalu dipulihkan saat keluar, termasuk setelah galat; tanpa TTY perintah gagal
|
|
310
|
+
dengan pesan jelas dan tidak pernah menjalankan agent.
|
|
311
|
+
|
|
312
|
+
**Presedensi** (terkuat lebih dulu): flag CLI (`--provider`, `--model`,
|
|
313
|
+
`--max-steps`) → `.ryuu/preferences.json` workspace → `config.json` → bawaan
|
|
314
|
+
katalog. Perubahan file berlaku pada run berikutnya. Satu-satunya variabel
|
|
315
|
+
environment yang masih dibaca adalah `RYUU_CONFIG_DIR`, yang menentukan letak
|
|
316
|
+
file ini.
|
|
317
|
+
|
|
318
|
+
**Dibuat otomatis.** Jika file belum ada, run pertama (termasuk `--doctor`)
|
|
319
|
+
langsung membuatnya berisi `version`, `provider`, `providers`,
|
|
320
|
+
`providerModel`, `extraProviders`, `agent`, dan `webSearch` dengan setiap kunci
|
|
321
|
+
bernilai kosong. Nilai kosong divalidasi sebagai bawaan, sehingga file yang baru
|
|
322
|
+
dibuat tidak mengubah perilaku apa pun; file yang sudah ada — termasuk yang JSON-
|
|
323
|
+
nya rusak — tidak pernah ditimpa.
|
|
324
|
+
|
|
325
|
+
**Provider dan model.** Baris kunci, base URL, dan model dibuat dari katalog
|
|
326
|
+
provider yang sama dengan runtime. Provider tambahan dari `extraProviders`
|
|
327
|
+
(lihat [Menambah provider sendiri](#menambah-provider-sendiri-extraproviders))
|
|
328
|
+
otomatis mendapat baris `providers.<id>.apiKey`, `providers.<id>.baseURL`, dan
|
|
329
|
+
`providerModel.<id>`.
|
|
330
|
+
|
|
331
|
+
**Keamanan, backup, dan pemulihan.** File ditulis atomik (file sementara di
|
|
332
|
+
direktori yang sama, fsync, lalu rename) dengan izin `0600` pada POSIX; path yang
|
|
333
|
+
berupa symlink ditolak. JSON yang rusak **tidak pernah ditimpa**: mode
|
|
334
|
+
`--settings` berhenti dengan pesan yang menyebut path-nya, sedangkan startup
|
|
335
|
+
normal hanya memberi peringatan lalu memakai bawaan. Untuk
|
|
336
|
+
memulihkan, perbaiki JSON-nya atau pindahkan file ke samping, lalu jalankan
|
|
337
|
+
`ryuu --settings` lagi. Hanya nilai yang Anda ubah yang ditulis; kunci yang
|
|
338
|
+
tidak ada memakai bawaan. Jangan meng-commit file ini — lokasinya di luar repo,
|
|
339
|
+
tetapi tetap berisi kredensial.
|
|
340
|
+
|
|
341
|
+
**Pemecahan masalah.** `Permission denied` berarti direktori tidak bisa ditulis:
|
|
342
|
+
arahkan `RYUU_CONFIG_DIR` ke lokasi yang bisa ditulis. Nilai yang ditolak
|
|
343
|
+
menyebut batasannya (mis. `agent.maxSteps must be between 0 and 100000`), dan
|
|
344
|
+
kesalahan format JSON menyebut path serta tidak mengubah file.
|
|
345
|
+
|
|
346
|
+
### UI layar penuh (`--tui`)
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
ryuu --tui
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+

|
|
353
|
+
|
|
354
|
+
Antarmuka bawaan menambahkan baris ke scrollback terminal dan melupakan setiap
|
|
355
|
+
barisnya. `--tui` justru menyimpan percakapan sebagai data: setiap item punya id
|
|
356
|
+
stabil, tanda terbuka/tertutup, dan teks lengkap di memori, dan setiap frame
|
|
357
|
+
digambar dari model tersebut. Di sinilah perilaku blok menjadi mungkin:
|
|
358
|
+
|
|
359
|
+
| Aksi | Hasil |
|
|
360
|
+
| --- | --- |
|
|
361
|
+
| Klik sebuah prompt (`▸ TASK … ⧉ copy`) | Menyalin prompt itu ke clipboard terminal. |
|
|
362
|
+
| Klik sebuah blok kode (header `js … ⧉ copy`) | Menyalin isi blok kode itu — hanya kodenya, tanpa penanda fence — ke clipboard terminal. Berlaku di UI baris maupun `--tui`. |
|
|
363
|
+
| Klik blok reasoning / `run_command` / shell | Menukar keadaan terbuka/tertutup di tempat; setiap blok menyimpan keadaan sendiri, sehingga beberapa bisa tetap terbuka. |
|
|
364
|
+
| `PgUp`, `PgDn`, roda mouse | Menggul transkrip di dalam aplikasi (scrollback terminal sendiri tidak dipakai). |
|
|
365
|
+
| `/expand <id>` | Membuka blok yang sudah tergulir keluar dari tampilan. `/expand` tanpa id mendaftarkannya. |
|
|
366
|
+
| `Esc` | Melipat setiap blok yang terbuka, atau melompat kembali ke bawah. |
|
|
367
|
+
| `Enter` | Mengirim baris; `↑`/`↓` memanggil riwayat, `←`/`→`, `Home`/`End` menyunting composer. |
|
|
368
|
+
| `Ctrl+Y` | Menyalin prompt yang terakhir Anda kirim. `/copy [n]` menyalin yang lebih lama (`n` = berapa prompt ke belakang). |
|
|
369
|
+
| `Ctrl+C` | Membatalkan tugas atau command shell yang berjalan; dua kali untuk keluar. |
|
|
370
|
+
|
|
371
|
+
#### Tampilan dan rasa
|
|
372
|
+
|
|
373
|
+
Setiap blok dibuka dengan header kecil (`▸ TASK`, `◆ response`, `⚙ Using tools`,
|
|
374
|
+
`◈ reasoning`, `◆ PLAN`, `▸ run_command`) dan blok dipisahkan baris kosong
|
|
375
|
+
serta garis pada gradien **pink → violet → biru langit**, sehingga perubahan jenis
|
|
376
|
+
terlihat sekilas. Tool call berurutan berbagi satu blok dan satu header
|
|
377
|
+
`⚙ Using tools` (dengan jumlah pemanggilan) tanpa pembatas di antaranya, karena
|
|
378
|
+
keduanya aktivitas sejenis. Warna membawa jenis baris:
|
|
379
|
+
|
|
380
|
+
| Baris | Warna |
|
|
381
|
+
| --- | --- |
|
|
382
|
+
| Header blok (`⚙ Using tools`, `◈ reasoning`, `◆ response`) | Gradien pink → blue (tool), putih tebal (response), glif hijau (reasoning) |
|
|
383
|
+
| Jawaban assistant dan prosa biasa | Putih |
|
|
384
|
+
| Heading, daftar, link, inline code, code fence, tabel Markdown | Biru langit |
|
|
385
|
+
| Header tugas, rencana, prompt persetujuan | Violet / amber |
|
|
386
|
+
| Isi reasoning (`◈ reasoning #N`) | Hijau, dengan baris status putih (`chars · live · partial`) |
|
|
387
|
+
| Nama tool (`✓ read_file`, `▸ run_command #N`) | Kuning |
|
|
388
|
+
| Nama tool yang gagal (`✕ run_command`) | Merah tebal, dengan outputnya merah-redup |
|
|
389
|
+
| Baris command `$` dan header shell | Biru langit |
|
|
390
|
+
| Galat runtime dan aksi yang ditolak | Merah / amber |
|
|
391
|
+
| Input composer | Kelabu, dengan `ryuu` pada gradien pink → blue dan ` > ` sesudahnya |
|
|
392
|
+
|
|
393
|
+
Pertanyaan (persetujuan, kelanjutan) dicetak di atas composer alih-alih
|
|
394
|
+
menggantikan prompt. Status bar mewarnai setiap segmen secara terpisah (fase,
|
|
395
|
+
langkah, tool, token, posisi gulir). Semuanya — telemetri banner, output command,
|
|
396
|
+
diff, pemberitahuan, dan composer — membungkus sesuai lebar terminal alih-alih
|
|
397
|
+
terpotong atau tergulir keluar dari tampilan. Palet naik ke truecolor ketika
|
|
398
|
+
terminal mendukungnya (`--no-color` tetap mematikannya).
|
|
399
|
+
|
|
400
|
+
Tombol salin (`⧉ copy` di setiap prompt dan blok kode, `Ctrl+Y`, atau `/copy [n]`) menulis teks
|
|
401
|
+
dengan **OSC 52**, sehingga terminal itulah yang memiliki clipboard: tanpa proses
|
|
402
|
+
anak `pbcopy`/`xclip`/`clip.exe`, dan bisa dipakai lewat SSH. Terminal yang tidak
|
|
403
|
+
menerapkan OSC 52 mengabaikan sekuensnya; status bar tetap melaporkan apa yang
|
|
404
|
+
dikirim beserta jumlah karakternya.
|
|
405
|
+
|
|
406
|
+
Versi yang tampil di banner, header TUI, dan `--version` dibaca dari
|
|
407
|
+
`package.json` saat runtime, sehingga sebuah rilis hanya perlu menaikkan file itu.
|
|
408
|
+
|
|
409
|
+
Ia butuh TTY sungguhan. Dengan `--plain`, output yang dipipe, atau sesi
|
|
410
|
+
non-interaktif, flag diabaikan dengan peringatan dan antarmuka baris normal
|
|
411
|
+
dipakai.
|
|
412
|
+
|
|
413
|
+
### Menjalankan shell Anda sendiri (`/bash`, `!cmd`)
|
|
414
|
+
|
|
415
|
+
Baris yang dimulai dengan `!` adalah command shell, bukan prompt:
|
|
416
|
+
|
|
417
|
+
```text
|
|
418
|
+
!git status
|
|
419
|
+
!npm test
|
|
420
|
+
/bash npm test # hal yang sama, ditulis panjang
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Command berjalan di workspace dengan izin Anda sendiri (tanpa prompt
|
|
424
|
+
persetujuan, tidak ada yang dikirim ke model), dan stdout/stderr yang tersimpan
|
|
425
|
+
dicetak lengkap — pratinjau `run_command` memang untuk tool call milik model,
|
|
426
|
+
bukan untuk shell Anda sendiri. Output yang sangat panjang menyimpan ekor
|
|
427
|
+
hasil tangkapan dan menyatakan bahwa ia terpotong.
|
|
428
|
+
|
|
429
|
+
Command, exit code, durasi, dan outputnya ditambahkan ke sesi sebagai giliran
|
|
430
|
+
pengguna, sehingga tugas berikutnya sudah tahu apa yang Anda jalankan, apa yang
|
|
431
|
+
dicataknya, dan apakah gagal. `/memory` menampilkan giliran itu; `/clear`
|
|
432
|
+
membuangnya.
|
|
433
|
+
|
|
434
|
+
`--read-only` menolak baris shell, dan `Ctrl+C` membatalkan command yang masih
|
|
435
|
+
berjalan (seluruh grup proses disinyalkan, sehingga `npm test` tidak selamat
|
|
436
|
+
darinya).
|
|
437
|
+
|
|
438
|
+
## Di dalam CLI
|
|
439
|
+
|
|
440
|
+
Apa pun yang tidak dimulai dengan `/` dikirim ke agent sebagai tugas; apa pun
|
|
441
|
+
yang dimulai dengan `!` dijalankan sebagai command shell Anda sendiri.
|
|
442
|
+
|
|
443
|
+
| Command | Keterangan | Catatan |
|
|
444
|
+
| --- | --- | --- |
|
|
445
|
+
| `/help [command]` | Mendaftarkan command atau menampilkan detail. | |
|
|
446
|
+
| `/exit` | Keluar dan menghentikan proses anak. | Juga `Ctrl+C` dua kali. |
|
|
447
|
+
| `/clear` | Melupakan memori percakapan agar tugas berikutnya mulai bersih. | Sesi tersimpan tidak disentuh. |
|
|
448
|
+
| `/memory [clear]` | Menampilkan apa yang diingat agent antar-tugas. | Dibatasi `agent.maxContextChars`. |
|
|
449
|
+
| `/worklog` | Menampilkan fakta terverifikasi (file dibaca/diubah, command, temuan) yang akan dipakai agent alih-alih membaca ulang. | Dihapus oleh `/clear`. |
|
|
450
|
+
| `/resume <session-id>` | Memulihkan memori percakapan sebuah sesi tersimpan. | Daftar id dengan `/history`. |
|
|
451
|
+
| `/status` | Provider, model, endpoint, status kunci, workspace, batas, jumlah proses/undo, tugas terakhir. | |
|
|
452
|
+
| `/provider [user <name> \| add <name> <url> [apiKey] \| del <name>]` | Mendaftarkan provider beserta status kunci, berpindah provider, atau menambah/menghapus provider sendiri. | Riwayat percakapan dan worklog tetap. Pilihan disimpan di `.ryuu/preferences.json`; `--provider` menimpa per run. Provider sendiri disimpan di `config.json`. |
|
|
453
|
+
| `/model [n]` | Mendaftarkan model milik provider aktif secara bernomor, atau berpindah model menurut nomor. | Disimpan per provider di `.ryuu/preferences.json`; tetap ada setelah restart. `--model` menimpa per run. |
|
|
454
|
+
| `/addmodel <provider> <model-id>` | Menambahkan id model ke daftar `/model` milik satu provider. | Provider sendiri menyimpannya di `config.json`; provider bawaan di `.ryuu/preferences.json`. Id tidak diperiksa ke server: id salah akan gagal saat dipakai, dan itu risiko pengguna. |
|
|
455
|
+
| `/delmodel <provider> <model-id>` | Membuang id yang ditambahkan lewat `/addmodel` dari satu provider. | Model bawaan katalog tidak bisa dibuang. Membuang model saat ini tetap menyimpannya untuk sesi ini. |
|
|
456
|
+
| `/cmodel <name>` | Mengeset id model apa pun langsung, tanpa menambahkannya ke daftar. | Alias: `/custommodel`. Aturan tanpa-pemeriksaan sama seperti `/addmodel`. |
|
|
457
|
+
| `/workspace` | Menampilkan satu workspace yang boleh disentuh sesi ini. | Berpindah di tengah sesi sengaja tidak didukung. |
|
|
458
|
+
| `/files [path]` | Mendaftarkan sebuah direktori. | File rahasia/direktori hasil-generate disembunyikan. |
|
|
459
|
+
| `/tree [path]` | Pohon direktori dengan batas. | |
|
|
460
|
+
| `/tools` | Tool terdaftar, risiko, kebutuhan persetujuan. | |
|
|
461
|
+
| `/copy [n]` | Menyalin prompt yang sudah Anda kirim ke clipboard terminal. | `n` menghitung mundur dari yang terbaru (bawaan: yang terakhir). Bekerja di kedua antarmuka; memakai OSC 52. |
|
|
462
|
+
| `/bash <command>` | Menjalankan sendiri command shell di workspace. | Output lengkap; command dan output masuk ke konteks sesi. Sama dengan baris yang dimulai `!`. |
|
|
463
|
+
| `/web [status\|providers\|test\|enable <id>\|disable <id>]` | Status pencarian web multi-provider, daftar kapabilitas, uji koneksi, dan aktif/nonaktif sesi. | `test` hanya memeriksa koneksi dan penemuan tool; tidak menjalankan kueri pencarian. |
|
|
464
|
+
| `/processes` | Proses yang berjalan dan terbaru. | |
|
|
465
|
+
| `/logs [id]` | Output proses, atau lokasi file log. | |
|
|
466
|
+
| `/expand [block-id]` | Mendaftarkan blok reasoning/`run_command`, atau membuka satu secara penuh. | Bisa juga dengan mengklik blok; `Esc` atau klik lain menutup panel. Blok tetap tersedia sepanjang sesi. |
|
|
467
|
+
| `/cancel [process-id]` | Membatalkan tugas aktif atau menghentikan proses. | Bekerja saat tugas berjalan; command tetap tersedia sepanjang waktu. |
|
|
468
|
+
| `/history` | Sesi tersimpan terbaru. | Disunting (redacted), lokal saja. |
|
|
469
|
+
| `/sessions [list\|show <id>\|delete <id>\|clear]` | Mengelola riwayat sesi. | `clear` meminta konfirmasi di mode interaktif. |
|
|
470
|
+
| `/diff` | Diff perubahan agent, atau `git diff` sebagai cadangan. | |
|
|
471
|
+
| `/undo [confirm]` | Mengembalikan perubahan file terakhir oleh agent. | Lihat [Undo](#undo). |
|
|
472
|
+
| `/config` | Konfigurasi efektif, kunci disunting. | |
|
|
473
|
+
| `/doctor [live]` | Diagnostik; `live` membuat satu permintaan API. | |
|
|
474
|
+
|
|
475
|
+
### Provider dan model (`/provider`, `/model`, `/addmodel`, `/delmodel`)
|
|
476
|
+
|
|
477
|
+
Provider adalah endpoint API beserta kuncinya; model adalah id yang dikirim ke
|
|
478
|
+
endpoint itu. Daftar keduanya dideklarasikan di katalog provider, bukan di loop
|
|
479
|
+
agent, sehingga menambah model atau provider tidak menyentuh agent core.
|
|
480
|
+
|
|
481
|
+
| Provider | Nama | Base URL | Kunci | Model bawaan | Kapabilitas yang diumumkan |
|
|
482
|
+
| --- | --- | --- | --- | --- | --- |
|
|
483
|
+
| `nvidia` | NVIDIA Integrate API | `https://integrate.api.nvidia.com/v1` | `providers.nvidia.apiKey` | `minimaxai/minimax-m3.1-flash` (ke-6 di `/model`) | streaming, tools, reasoning, multimodal |
|
|
484
|
+
| `tokenharbor` | Token Harbor | `https://tokenharbor.ai/v1` | `providers.tokenharbor.apiKey` | `deepseek-v4.1-flash:free` | streaming, tools, reasoning |
|
|
485
|
+
|
|
486
|
+
Memilih provider dan model:
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
ryuu --provider tokenharbor # default model provider itu
|
|
490
|
+
ryuu --provider tokenharbor --model deepseek-v4.1-flash:free
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Di dalam sesi:
|
|
494
|
+
|
|
495
|
+
```text
|
|
496
|
+
/provider # daftar provider, status kunci, model bawaan
|
|
497
|
+
/provider add river https://api.river.ai/v1 rv_… # tambah provider OpenAI-compatible
|
|
498
|
+
/addmodel river deepseek-ai/DeepSeek-V4.1-Flash-1017 # tambah model untuk provider itu
|
|
499
|
+
/provider user river # pindah provider; riwayat & worklog tetap
|
|
500
|
+
/provider del river # hapus provider yang Anda tambahkan
|
|
501
|
+
/model # daftar model provider aktif
|
|
502
|
+
/model 2 # pindah model menurut nomor
|
|
503
|
+
/addmodel nvidia model-baru # tambah id ke provider bawaan
|
|
504
|
+
/delmodel nvidia model-baru # buang id yang ditambahkan
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
- `/provider` hanya menampilkan `key set (redacted)` atau
|
|
508
|
+
`no key (providers.<id>.apiKey)`; nilai kunci tidak pernah dicetak. Provider
|
|
509
|
+
tanpa kunci tidak bisa dipilih dan pesannya menyebut baris `config.json` yang
|
|
510
|
+
harus diisi.
|
|
511
|
+
- Berpindah provider tidak menghapus memori percakapan atau worklog. Pilihan
|
|
512
|
+
provider dan model per provider disimpan di `.ryuu/preferences.json` milik
|
|
513
|
+
workspace saat ini; `--provider`/`--model` hanya berlaku untuk satu run dan
|
|
514
|
+
tidak menulis pilihan tersimpan.
|
|
515
|
+
- Hanya format id yang divalidasi (huruf, angka, `. _ : / -`, sampai 200 karakter,
|
|
516
|
+
maksimal 100 id tambahan **per provider**). Ketersediaan, kuota, ukuran
|
|
517
|
+
konteks, dan dukungan tool calling model **tidak** diperiksa. Daftar model
|
|
518
|
+
adalah id yang ditawarkan CLI, bukan jaminan model itu aktif di server.
|
|
519
|
+
- `/provider add <name> <url> [apiKey]` menyimpan provider ke `extraProviders`
|
|
520
|
+
di `config.json` dan kuncinya ke `providers.<name>.apiKey`. Argumen ketiga
|
|
521
|
+
opsional; tanpa itu, isi kuncinya lewat `ryuu --settings`. Memanggil `add`
|
|
522
|
+
lagi dengan nama yang sama dan kunci baru akan memperbarui kuncinya.
|
|
523
|
+
- `/provider del <name>` hanya menghapus provider yang Anda tambahkan, beserta
|
|
524
|
+
kunci dan model tersimpannya. Provider bawaan (`nvidia`, `tokenharbor`) dan
|
|
525
|
+
provider yang sedang aktif tidak bisa dihapus; pindah dulu dengan
|
|
526
|
+
`/provider user <name>`.
|
|
527
|
+
- Provider baru boleh belum punya model. Tambahkan lewat
|
|
528
|
+
`/addmodel <name> <model-id>`; model pertama menjadi default provider itu.
|
|
529
|
+
- Entri katalog bawaan tidak bisa dihapus, dan id yang sudah ada tidak
|
|
530
|
+
ditambahkan dua kali.
|
|
531
|
+
- `/cmodel <name>` memilih id apa pun untuk provider aktif tanpa menambahkannya
|
|
532
|
+
ke daftar; `/help addmodel` dan `/help delmodel` menampilkan tutorial yang sama
|
|
533
|
+
di dalam CLI.
|
|
534
|
+
|
|
535
|
+
#### Menambah provider sendiri (`extraProviders`)
|
|
536
|
+
|
|
537
|
+
Provider tambahan didaftarkan sebagai array JSON di `config.json`. Semua provider
|
|
538
|
+
memakai protokol Chat Completions yang kompatibel OpenAI:
|
|
539
|
+
|
|
540
|
+
```json
|
|
541
|
+
{
|
|
542
|
+
"extraProviders": [
|
|
543
|
+
{
|
|
544
|
+
"id": "myproxy",
|
|
545
|
+
"name": "My Proxy",
|
|
546
|
+
"baseURL": "https://proxy.example/v1",
|
|
547
|
+
"defaultModel": "model-b",
|
|
548
|
+
"models": ["model-a", { "id": "model-b", "name": "Model B" }],
|
|
549
|
+
"capabilities": { "tools": true, "streaming": true, "reasoning": false }
|
|
550
|
+
}
|
|
551
|
+
],
|
|
552
|
+
"providers": { "myproxy": { "apiKey": "…" } }
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
Cara termudah adalah dari dalam sesi — perintahnya menulis bentuk yang sama:
|
|
557
|
+
|
|
558
|
+
```text
|
|
559
|
+
/provider add myproxy https://proxy.example/v1 sk-…
|
|
560
|
+
/addmodel myproxy model-a
|
|
561
|
+
/provider user myproxy
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
Kuncinya disimpan seperti provider lain, yaitu `providers.myproxy.apiKey`, dan
|
|
565
|
+
bisa diisi lewat `ryuu --settings` setelah provider terdaftar.
|
|
566
|
+
|
|
567
|
+
- `id`, `name`, dan `baseURL` wajib. `models` boleh kosong saat baru dibuat dan
|
|
568
|
+
diisi lewat `/addmodel`; `id` tidak boleh menabrak provider bawaan (`nvidia`,
|
|
569
|
+
`tokenharbor`, `river`).
|
|
570
|
+
- `capabilities` menentukan apakah agent mengirim tools (`tools`), meminta
|
|
571
|
+
stream (`streaming`), dan menampilkan reasoning bila provider mengirimnya
|
|
572
|
+
(`reasoning`). Jangan menyalakan `tools` untuk endpoint yang tidak mendukung
|
|
573
|
+
`tool_calls`: agent akan menampilkan keterbatasan dan tetap bisa menjawab,
|
|
574
|
+
tetapi tidak bisa membaca atau mengubah file.
|
|
575
|
+
- Setelah ditambahkan, provider muncul di `/provider` dan bisa dipilih dengan
|
|
576
|
+
`/provider user myproxy` (alias lama `/provider myproxy`) atau
|
|
577
|
+
`--provider myproxy`.
|
|
578
|
+
- Tidak ada fallback otomatis antar-provider AI. Kegagalan provider aktif
|
|
579
|
+
dilaporkan apa adanya (dengan retry terbatas untuk kegagalan sesaat) agar
|
|
580
|
+
kunci dan data tidak berpindah ke provider lain tanpa keputusan Anda.
|
|
581
|
+
|
|
582
|
+
#### Provider bawaan dan modul klien per vendor (`src/providers/`)
|
|
583
|
+
|
|
584
|
+
Tiga provider dikenali tanpa entri `extraProviders`: `nvidia`, `tokenharbor`,
|
|
585
|
+
dan `river`. Masing-masing punya modul sendiri di `src/providers/`:
|
|
586
|
+
|
|
587
|
+
| Modul | Provider | Isi |
|
|
588
|
+
| --- | --- | --- |
|
|
589
|
+
| `nvidia.js` | `nvidia` | Klien Chat Completions bersama (dipakai semua provider OpenAI-compatible), retry, streaming, ekstraksi reasoning. |
|
|
590
|
+
| `tokenharbor.js` | `tokenharbor` | Default provider + pass-through `extraBody`/`requestParams`. |
|
|
591
|
+
| `river.js` | `river` | Menambahkan `reasoning_effort` (lihat di bawah) dan profil reasoning per model. |
|
|
592
|
+
| `vendor-extras.js` | — | Tabel field request per provider; klien bersama bertanya ke sini sebelum setiap request. |
|
|
593
|
+
|
|
594
|
+
Karena ketiganya bawaan, `extraProviders` **tidak boleh** memakai id yang sama.
|
|
595
|
+
Entri lama untuk `river` yang menunjuk base URL yang sama tetap diterima: entri
|
|
596
|
+
itu diabaikan dengan peringatan, bukan menggagalkan startup, dan descriptor
|
|
597
|
+
bawaan yang dipakai (daftar model, kapabilitas, field vendor). Provider kustom
|
|
598
|
+
lainnya tetap memakai template `nvidia.js` tanpa perubahan kode; field request
|
|
599
|
+
tambahan bisa diberikan lewat `extraBody`/`requestParams` di entrinya:
|
|
600
|
+
|
|
601
|
+
```json
|
|
602
|
+
{ "id": "myproxy", "baseURL": "https://proxy.example/v1",
|
|
603
|
+
"extraBody": { "top_k": 40 }, "requestParams": { "reasoning_effort": "high" } }
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
#### Reasoning DeepSeek di River AI
|
|
607
|
+
|
|
608
|
+
River mematikan thinking secara default untuk `DeepSeek-V4.1-Flash-1017` dan
|
|
609
|
+
`DeepSeek-V4.1-Flash`: tanpa `reasoning_effort` di body request, respons hanya
|
|
610
|
+
berisi `content`, dan tidak ada teks reasoning untuk ditampilkan. `river.js`
|
|
611
|
+
mengirim field itu otomatis (dokumentasi: <https://docs.river.ai/guides/inference-controls/>):
|
|
612
|
+
|
|
613
|
+
- Default: `high` untuk kedua model DeepSeek, sehingga reasoning langsung muncul
|
|
614
|
+
di UI dan di `.ryuu/logs/reasoning/`.
|
|
615
|
+
- Model River lain (`GLM-5.3`, `GLM-5.3-Flash`, `Qwen3.8-27B-FP8`,
|
|
616
|
+
`Nemotron-3.5-Super-VL-120B`) sudah reasoning secara default dan tidak dipaksa
|
|
617
|
+
— effort hanya dikirim bila Anda memintanya.
|
|
618
|
+
- Urutan prioritas: env `RYUU_RIVER_REASONING_EFFORT` → `reasoningEffort` di
|
|
619
|
+
`config.json` → env `RYUU_REASONING_EFFORT` → `capabilities.reasoningEffort`
|
|
620
|
+
di entri provider.
|
|
621
|
+
- Nilai yang diterima: `none|low|medium|high|xhigh|max` (plus `off`/`on`).
|
|
622
|
+
Level yang tidak didukung model akan diturunkan ke level aman model itu dan
|
|
623
|
+
dicatat di log, jadi request tidak gagal.
|
|
624
|
+
|
|
625
|
+
Contoh mematikan reasoning River lewat `config.json`:
|
|
626
|
+
|
|
627
|
+
```json
|
|
628
|
+
{ "provider": "river", "reasoningEffort": "none" }
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
`capabilities.reasoning` hanya label tampilan di `/provider`; reasoning tetap
|
|
632
|
+
ditampilkan selama provider benar-benar mengirim `reasoning_content`.
|
|
633
|
+
|
|
634
|
+
## Tool yang tersedia untuk model
|
|
635
|
+
|
|
636
|
+
Model hanya bisa memanggil tool yang terdaftar di allowlist lokal. Setiap
|
|
637
|
+
pemanggilan divalidasi skemanya sebelum dieksekusi.
|
|
638
|
+
|
|
639
|
+
| Tool | Risiko | Persetujuan | Tujuan |
|
|
640
|
+
| --- | --- | --- | --- |
|
|
641
|
+
| `list_files` | read | tidak | Daftar direktori terfilter dan berpaginasi. |
|
|
642
|
+
| `tree` | read | tidak | Pohon direktori dengan batas. |
|
|
643
|
+
| `read_file` | read | tidak | Teks UTF-8; rentang baris yang diminta dialirkan, jadi juga bekerja untuk file di atas batas baca. |
|
|
644
|
+
| `file_info` | read | tidak | Ukuran, jenis, timestamp, jumlah baris. |
|
|
645
|
+
| `search_files` | read | tidak | Pencarian nama/isi dengan pengecualian. |
|
|
646
|
+
| `diff_file` | read | tidak | Diff terpadu tanpa menulis apa pun. |
|
|
647
|
+
| `inspect_git` | read | tidak | Status/diff Git bila tersedia. |
|
|
648
|
+
| `project_summary` | read | tidak | Manifes dan struktur dari file sungguhan. |
|
|
649
|
+
| `web_search` | read | tidak | Hasil web dari provider MCP/REST terkonfigurasi, dengan fallback otomatis. Terdaftar ketika setidaknya satu provider tersedia (You.com dan Firecrawl bisa dipakai tanpa kunci). |
|
|
650
|
+
| `read_url` | read | tidak | Mengambil halaman http(s) publik dan mengekstrak teks yang bisa dibaca. Selalu tersedia. |
|
|
651
|
+
| `create_file` | tulis | ya | File baru; menimpa file lama hanya dengan `overwrite`. |
|
|
652
|
+
| `write_file` | tulis | ya | Penulisan seluruh file dengan penjaga mtime opsional. |
|
|
653
|
+
| `edit_file` | tulis | ya | Penggantian terarah unik, mengembalikan diff. |
|
|
654
|
+
| `move_file` | destruktif | ya | Memindah/mengganti nama di dalam workspace. |
|
|
655
|
+
| `delete_file` | destruktif | ya | Menghapus file atau direktori kosong; `confirm: true` wajib. |
|
|
656
|
+
| `run_command` | exec | ya | Menjalankan argv, menunggu, menangkap output/exit/durasi. |
|
|
657
|
+
| `start_process` | exec | ya | Server/watcher di background. |
|
|
658
|
+
| `list_processes` | read | tidak | Daftar proses. |
|
|
659
|
+
| `get_process_output` | read | tidak | Output terbatas untuk sebuah proses. |
|
|
660
|
+
| `stop_process` | exec | ya | Penghentian bersih, lalu pemutusan paksa. |
|
|
661
|
+
|
|
662
|
+
Katalog tool juga ditulis ke dalam system prompt (nama, argumen, gerbang
|
|
663
|
+
persetujuan, tujuan satu baris), bersama skrip npm milik project itu sendiri dan
|
|
664
|
+
tata letak modulnya, sehingga model memilih tool yang benar alih-alih keluar ke
|
|
665
|
+
`grep` untuk sesuatu yang sudah dikerjakan `search_files`.
|
|
666
|
+
|
|
667
|
+
### Pencarian web (MCP multi-provider dengan fallback)
|
|
668
|
+
|
|
669
|
+
`web_search` tetap satu tool bagi model, tetapi didukung oleh `WebSearchManager`
|
|
670
|
+
yang memiliki beberapa provider dan mencobanya sesuai urutan yang bisa
|
|
671
|
+
dikonfigurasi. Setiap provider dinormalkan ke bentuk yang sama: `results`
|
|
672
|
+
(`title`, `url`, `snippet`, `date` opsional), `answer_box`, `people_also_ask`,
|
|
673
|
+
dan `related_searches`. `depth: \"deep\"` meminta dua kali lipat hasil (maksimal
|
|
674
|
+
10).
|
|
675
|
+
|
|
676
|
+
| Provider | Transport | Kunci | Kapabilitas | Catatan |
|
|
677
|
+
| --- | --- | --- | --- | --- |
|
|
678
|
+
| You.com MCP | Streamable HTTP | opsional (`webSearch.youApiKey`) | pencarian (tanpa kunci); ekstraksi/konten dengan kunci | Tanpa kunci memakai `?profile=free`; penemuan langsung mengembalikan `you-search`, `you-discover`. |
|
|
679
|
+
| Firecrawl MCP | Streamable HTTP | opsional (`webSearch.firecrawlApiKey`) | pencarian + scrape | Tingkat tanpa kunci punya batas kredit harian; penemuan langsung mengembalikan `firecrawl_search`, `firecrawl_scrape`, `firecrawl_parse`. |
|
|
680
|
+
| DuckDuckGo MCP | stdio | tidak ada | pencarian + ekstrak (sebagaimana diumumkan server) | Server komunitas opsional (`uvx free-search-mcp`, MIT). **Nonaktif secara bawaan** karena menjalankan kode pihak ketiga; butuh `uv` terpasang. |
|
|
681
|
+
| Tavily MCP | Streamable HTTP | wajib (`webSearch.tavilyApiKey`) | pencarian + ekstrak | Endpoint remote butuh kunci; tanpa itu provider dilewati, tidak pernah dihubungi. |
|
|
682
|
+
| Serper REST | HTTPS | wajib (`webSearch.serperApiKey`) | pencarian | Backend asli; ikut dalam rantai fallback yang sama. |
|
|
683
|
+
|
|
684
|
+
Bagaimana ia berperilaku:
|
|
685
|
+
|
|
686
|
+
- **Koneksi malas.** Tidak ada yang menghubungkan pada saat start. Sebuah
|
|
687
|
+
provider dihubungkan saat pertama dipakai, tool-nya ditemukan dengan
|
|
688
|
+
`tools/list`, dan koneksinya dipakai ulang selama sisa sesi. `/web test`
|
|
689
|
+
hanya melakukan handshake + penemuan (tanpa kueri).
|
|
690
|
+
- **Pemetaan tool, bukan nama yang di-hard-code.** Tool pencarian/ekstraksi
|
|
691
|
+
dipilih menurut nama, deskripsi, dan skema input, sehingga sebuah server bisa
|
|
692
|
+
mengganti nama tool-nya tanpa membuat agent rusak. Argumen wajib diisi dari
|
|
693
|
+
skema tool itu sendiri (`query`, `q`, `url`, `urls`, `limit`, `formats`,
|
|
694
|
+
`objective`).
|
|
695
|
+
- **Fallback hanya untuk kegagalan sungguhan.** Timeout, jaringan/DNS, HTTP
|
|
696
|
+
401/403/429/5xx, kegagalan handshake/penemuan, tool yang hilang, skema salah,
|
|
697
|
+
dan payload tidak valid semuanya pindah ke provider berikutnya. Hasil kosong
|
|
698
|
+
yang valid dicatat dan boleh juga mencoba provider berikutnya, tetapi tidak
|
|
699
|
+
dilaporkan sebagai kegagalan. Pembatalan tidak pernah memicu fallback.
|
|
700
|
+
- **Retry terbatas.** Maksimal `webSearch.mcpMaxRetries` retry per provider untuk
|
|
701
|
+
kegagalan *pemanggilan* sesaat (bukan handshake), dengan backoff eksponensial
|
|
702
|
+
dan jitter. `429` langsung diteruskan ke provider berikutnya alih-alih
|
|
703
|
+
membekukan agent. Dua kegagalan berturut-turut membuka circuit breaker 60
|
|
704
|
+
detik untuk provider itu.
|
|
705
|
+
- **Satu kegagalan bertipe.** Jika semua provider gagal, tool melempar
|
|
706
|
+
`SEARCH_ALL_PROVIDERS_FAILED` (atau `SEARCH_EXTRACT_FAILED`) dengan daftar
|
|
707
|
+
alasan singkat per provider; agent tetap berjalan tanpa pencarian web alih-alih
|
|
708
|
+
crash dan diberi tahu untuk tidak mengarang hasil.
|
|
709
|
+
- **Terminal menampilkan fallback**, bukan hanya pemenangnya: satu pohon `WEB
|
|
710
|
+
SEARCH` ringkas per pencarian dengan `✓`/`✕`/`!`/`○`, durasi, dan alasan
|
|
711
|
+
singkat. Stack trace tetap di log debug; kunci dan header otorisasi tidak
|
|
712
|
+
pernah dicetak.
|
|
713
|
+
- **Fallback ekstraksi halaman.** `read_url` tetap mengambil secara lokal lebih
|
|
714
|
+
dulu. Jika pengambilan lokal gagal (jaringan, timeout, 401/403, jenis tidak
|
|
715
|
+
didukung) atau tidak mengekstrak teks dari halaman yang dirender JavaScript,
|
|
716
|
+
sebuah provider berkemampuan ekstraksi (Firecrawl/Tavily) dicoba dan hasilnya
|
|
717
|
+
menyebutkan provider mana yang menghasilkan teksnya.
|
|
718
|
+
- **Keamanan.** Kueri dan URL keluar dari mesin; file tidak. Teks halaman adalah
|
|
719
|
+
data tak terpercaya, bukan instruksi. Server MCP stdio mendapat environment
|
|
720
|
+
minimal (PATH/HOME/TMP), bukan kunci NVIDIA atau pencarian Anda. Server MCP
|
|
721
|
+
tidak pernah diberi akses filesystem atau shell oleh agent ini.
|
|
722
|
+
- **Privasi dan kuota.** Firecrawl tanpa kunci punya batas kredit harian yang
|
|
723
|
+
kecil; manajer tidak pernah menguji dengan kueri sungguhan saat start. `/web
|
|
724
|
+
test` secara eksplisit menyatakan tidak ada kueri yang dijalankan. Nonaktifkan
|
|
725
|
+
semuanya dengan `webSearch.enabled: false` atau `webSearch.providers: []`.
|
|
726
|
+
- **Worklog:** setiap pencarian dicatat (`web_search \"...\" -> N result(s) ·
|
|
727
|
+
top: ...`), sehingga tugas lanjutan memakai temuan yang ada alih-alih membayar
|
|
728
|
+
kueri yang sama.
|
|
729
|
+
|
|
730
|
+
### Membaca sebuah halaman (`read_url`)
|
|
731
|
+
|
|
732
|
+
`read_url` mengambil satu URL http(s) dan mengembalikan teks hasil ekstraksi,
|
|
733
|
+
judul, dan meta deskripsinya, sehingga model bisa memverifikasi snippet
|
|
734
|
+
pencarian terhadap halaman sumbernya.
|
|
735
|
+
|
|
736
|
+
- **Selalu tersedia.** Tidak butuh kunci, ia tool read-only, dan tidak pernah
|
|
737
|
+
meminta konfirmasi.
|
|
738
|
+
- **Terbatas.** Batas badan 2 MB, `max_chars` 1.000–50.000 (bawaan 20.000),
|
|
739
|
+
timeout 15 detik, dan maksimal 5 redirect.
|
|
740
|
+
- **Skema diperiksa.** Hanya http/https; URL dengan kredensial tertanam ditolak,
|
|
741
|
+
setiap hop redirect diperiksa ulang, dan penurunan https→http ditolak.
|
|
742
|
+
- **Dijaga SSRF.** Alamat loopback, privat, link-local, CGNAT, multicast, dan
|
|
743
|
+
metadata cloud ditolak, begitu pula `localhost`, `*.local`, `*.internal`, dan
|
|
744
|
+
hostname ber-label tunggal. Pengambilan sungguhan melakukan resolusi DNS lebih
|
|
745
|
+
dulu dan menolak bila ada alamat privat; setiap redirect diperiksa ulang. DNS
|
|
746
|
+
rebinding dikendalikan tetapi tidak dihilangkan sepenuhnya tanpa agen HTTP
|
|
747
|
+
ber-IP-pinned.
|
|
748
|
+
- **Teks saja.** `text/*`, HTML/XHTML, JSON, dan XML dibaca; gambar, PDF, dan
|
|
749
|
+
biner lain mengembalikan `READ_URL_UNSUPPORTED`.
|
|
750
|
+
- **Fallback ekstraksi MCP.** Jika pengambilan lokal tidak bisa membaca halaman
|
|
751
|
+
(galat jaringan, timeout, konten terblokir/tidak didukung) atau tidak
|
|
752
|
+
mengekstrak teks dari halaman yang dirender JavaScript, sebuah provider
|
|
753
|
+
pencarian web berkemampuan ekstraksi dicoba; hasilnya menyebutkan provider di
|
|
754
|
+
`provider` dan menetapkan `extraction: \"mcp\"`.
|
|
755
|
+
- **Tidak ada JavaScript secara lokal.** Halaman yang dirender sisi-klien bisa
|
|
756
|
+
saja tidak mengembalikan teks; hasilnya menyatakan hal itu alih-alih
|
|
757
|
+
berpura-pura halaman itu kosong, dan fallback MCP di atas bisa memulihkannya.
|
|
758
|
+
- **Konten tak terpercaya.** Prompt memperlakukan teks yang diambil sebagai
|
|
759
|
+
data, bukan instruksi, sehingga sebuah halaman tidak bisa mengalihkan
|
|
760
|
+
perilaku agent.
|
|
761
|
+
- **Privasi:** URL diminta dari mesin Anda, jadi situs itu melihat IP Anda.
|
|
762
|
+
- **Worklog:** setiap pengambilan dicatat (`read_url <url> -> HTTP 200 · N chars`).
|
|
763
|
+
|
|
764
|
+
### Model prompt dan konteks
|
|
765
|
+
|
|
766
|
+
Protokol provider ini tidak punya keadaan (stateless): setiap permintaan
|
|
767
|
+
membawa seluruh percakapan. Ryuu membuat hal itu stabil dan murah alih-alih
|
|
768
|
+
berpura-pura sebaliknya.
|
|
769
|
+
|
|
770
|
+
- System prompt dirakit **sekali per sesi** dan dipakai ulang byte-per-byte. Ia
|
|
771
|
+
identik pada setiap langkah (sehingga prefix caching provider bisa kena) dan
|
|
772
|
+
tidak pernah tumbuh seiring berjalannya tugas.
|
|
773
|
+
- Setiap tugas menambahkan tepat satu pesan `TASK BRIEF`: tugas, sisa batas
|
|
774
|
+
langkah dan waktu, serta worklog sesi. Itulah satu-satunya blok instruksi
|
|
775
|
+
per-tugas; model tidak pernah diberi tahu ulang untuk \"mulai dengan rencana\".
|
|
776
|
+
- Hasil tool tetap berada di percakapan selama langkah-langkah yang
|
|
777
|
+
membutuhkannya. Worklog membawa fakta terverifikasi (file yang dibaca beserta
|
|
778
|
+
rentang baris, file yang diubah, command dan exit code, temuan, rencana) ke
|
|
779
|
+
tugas-tugas berikutnya, sehingga tindak lanjut melanjutkan pekerjaan alih-alih
|
|
780
|
+
memulai lagi. File yang sudah dibaca dan tidak berubah di disk tidak dibaca
|
|
781
|
+
lagi: agent menerima balasan `cached: true` yang memberi tahu bahwa isinya
|
|
782
|
+
sudah diketahui.
|
|
783
|
+
- `finish_reason: \"length\"` ditangani: pemanggilan tool yang terpotong pada
|
|
784
|
+
batas token output dibuang dan dilaporkan, tidak pernah dieksekusi sebagai
|
|
785
|
+
file yang tertulis setengah jalan.
|
|
786
|
+
- Pada 70% anggaran waktu, model diberi tahu untuk menyatu (konvergen), dan
|
|
787
|
+
aliran respons yang tidak mengirim byte selama
|
|
788
|
+
`agent.streamIdleTimeoutMs` dibatalkan dengan `STREAM_STALLED` alih-alih
|
|
789
|
+
menahan langkah tetap terbuka.
|
|
790
|
+
|
|
791
|
+
## Model persetujuan dan izin
|
|
792
|
+
|
|
793
|
+
Kebijakannya diatur dengan `agent.approvalPolicy`:
|
|
794
|
+
|
|
795
|
+
| Risiko | `ask` (bawaan) | `auto` | `read-only` |
|
|
796
|
+
| --- | --- | --- | --- |
|
|
797
|
+
| read | izinkan | izinkan | izinkan |
|
|
798
|
+
| tulis | prompt | izinkan | tolak |
|
|
799
|
+
| exec | prompt | prompt | tolak |
|
|
800
|
+
| destruktif | prompt | prompt | tolak |
|
|
801
|
+
|
|
802
|
+
- `--yes` menyetujui otomatis **hanya penulisan**; eksekusi dan aksi destruktif
|
|
803
|
+
tetap memakai prompt.
|
|
804
|
+
- Di sesi non-interaktif tidak ada prompt, jadi aksi yang butuh persetujuan
|
|
805
|
+
ditolak dan penolakannya dilaporkan ke model.
|
|
806
|
+
- Persetujuan ditegakkan di loop agent, bukan di dalam tool masing-masing,
|
|
807
|
+
sehingga model tidak bisa melewatinya dengan memanggil tool secara langsung.
|
|
808
|
+
- Prompt persetujuan menampilkan tool, tingkat risiko, argumen, dan pratinjau
|
|
809
|
+
(diff atau command beserta direktori kerjanya) sebelum Anda menjawab.
|
|
810
|
+
- Penilaian risiko adalah sinyal UX best-effort, **bukan batas keamanan**.
|
|
811
|
+
|
|
812
|
+
### Undo
|
|
813
|
+
|
|
814
|
+
`/undo` memakai snapshot before/after yang tepat, direkam oleh proses agent ini
|
|
815
|
+
untuk `create_file`, `write_file`, `edit_file`, `move_file`, dan `delete_file`. Ia
|
|
816
|
+
menolak mengembalikan perubahan jika file berubah setelah suntingan agent,
|
|
817
|
+
alih-alih menimpa pekerjaan Anda. Cakupannya mencakup perubahan yang dibuat pada
|
|
818
|
+
tugas/sesi saat ini dan bukan pengganti kontrol versi. Pakai `git` untuk sejarah
|
|
819
|
+
yang tahan lama.
|
|
820
|
+
|
|
821
|
+
## Referensi konfigurasi
|
|
822
|
+
|
|
823
|
+
Semua pengaturan berasal dari satu file `config.json` (lihat
|
|
824
|
+
[Pengaturan global](#pengaturan-global-ryuu---settings)). Tidak ada `.env` dan
|
|
825
|
+
tidak ada variabel environment; flag CLI menimpa nilai file untuk satu run.
|
|
826
|
+
Workspace tetap ditentukan per run (cwd atau `--workspace`), bukan dari file
|
|
827
|
+
global ini. Nilai bawaan divalidasi saat start; nilai tidak valid membuat proses
|
|
828
|
+
gagal sebelum ada panggilan API.
|
|
829
|
+
|
|
830
|
+
| Kunci `config.json` | Bawaan | Makna |
|
|
831
|
+
| --- | --- | --- |
|
|
832
|
+
| *(kosong)* | bawaan katalog | Nilai kosong pada kunci mana pun berarti "pakai bawaan" di kolom Bawaan. |
|
|
833
|
+
| `provider` | — | Provider aktif (`nvidia`, `tokenharbor`, atau id dari `extraProviders`). Bila kosong: `nvidia` kalau kuncinya ada, jika tidak provider pertama yang punya kunci. |
|
|
834
|
+
| `providerModel.<id>` | model bawaan provider | Model untuk provider itu. Menang atas bawaan katalog. |
|
|
835
|
+
| `providers.<id>.apiKey` | — | Kunci provider. Tidak pernah dicetak, ditulis owner-only. |
|
|
836
|
+
| `providers.<id>.baseURL` | URL bawaan provider | Base URL kompatibel OpenAI. |
|
|
837
|
+
| `extraProviders` | — | Array provider tambahan yang kompatibel OpenAI (lihat [Menambah provider sendiri](#menambah-provider-sendiri-extraproviders)). |
|
|
838
|
+
| `agent.logLevel` | `info` | `debug`, `info`, `warn`, `error`, `silent`. |
|
|
839
|
+
| `agent.maxSteps` | `0` | Batas langkah agent opsional (0 = tanpa batas, 1–100000). |
|
|
840
|
+
| `agent.approvalPolicy` | `ask` | `ask`, `auto`, `read-only`. |
|
|
841
|
+
| `agent.maxOutputTokens` | `4096` | Batas token output (64–32768). Nilai tinggi bisa ditolak atau mahal. |
|
|
842
|
+
| `agent.requestTimeoutMs` | `120000` | Timeout per permintaan (1s–10menit). |
|
|
843
|
+
| `agent.streamIdleTimeoutMs` | `45000` | Membatalkan aliran respons yang tidak mengirim byte selama ini (0 menonaktifkan). |
|
|
844
|
+
| `agent.maxRetries` | `3` | Retry untuk kegagalan sesaat (0–10). |
|
|
845
|
+
| `agent.maxRecoveryAttempts` | `0` | Percobaan sambung ulang saat tautan provider putus. `0` = tanpa batas (coba sampai tenggat tugas atau `/cancel`); 1–1000 membatasinya. |
|
|
846
|
+
| `agent.recoveryBackoffMs` | `1000` | Jeda dasar antar-percobaan sambung ulang (100ms–60s). |
|
|
847
|
+
| `agent.maxFileBytes` | `262144` | Batas baca per file (1KB–5MB). |
|
|
848
|
+
| `agent.maxSearchResults` | `50` | Batas hasil pencarian (1–500). |
|
|
849
|
+
| `agent.maxToolOutputBytes` | `32768` | Batas hasil tool yang dikirim balik ke model. |
|
|
850
|
+
| `agent.maxTaskDurationMs` | `900000` | Batas waktu nyata tugas (10s–24jam). |
|
|
851
|
+
| `agent.maxContextChars` | `120000` | Ambang pemadatan konteks lokal. |
|
|
852
|
+
| `agent.allowShell` | `false` | Mengizinkan sintaks shell mentah (tetap bergerbang persetujuan). |
|
|
853
|
+
| `agent.debug` | `false` | Log debug dan stack trace. |
|
|
854
|
+
| `agent.historyDir` | `<workspace>/.ryuu/sessions` | Penyimpanan sesi, relatif ke workspace. |
|
|
855
|
+
| `agent.logDir` | `<workspace>/.ryuu/logs` | Penyimpanan log (`agent.log`, dirotasi pada 5MB), relatif ke workspace. |
|
|
856
|
+
| `webSearch.enabled` | `true` | Mendaftarkan `web_search` sama sekali. `false` membuangnya bersama fallback ekstraksi `read_url`. |
|
|
857
|
+
| `webSearch.fallback` | `true` | Mencoba provider berikutnya setelah kegagalan. `false` berhenti pada kandidat pertama. |
|
|
858
|
+
| `webSearch.providers` | `serper` (bila ada kunci) → `you` → `firecrawl` → `duckduckgo` → `tavily` | Urutan provider; `[]` atau `none` menonaktifkan semuanya. |
|
|
859
|
+
| `webSearch.disabled` | `[]` | Daftar id provider yang dilewati. `/web enable`/`disable` hanya mengubah sesi saat ini. |
|
|
860
|
+
| `webSearch.mcpTimeoutMs` | `6000` | Timeout handshake, penemuan, dan pemanggilan per percobaan (1s–30s). |
|
|
861
|
+
| `webSearch.mcpMaxRetries` | `1` | Retry per provider untuk kegagalan pemanggilan sesaat (0–5). |
|
|
862
|
+
| `webSearch.debug` | `false` | Diagnostik provider tambahan di log (tanpa kunci). |
|
|
863
|
+
| `webSearch.youApiKey` | — | Kunci You.com opsional; tanpa kunci memakai profil pencarian gratis. |
|
|
864
|
+
| `webSearch.firecrawlApiKey` | — | Kunci Firecrawl opsional; tanpa kunci memakai tingkat kredit gratis. |
|
|
865
|
+
| `webSearch.tavilyApiKey` | — | Wajib untuk Tavily; tanpa itu Tavily dilewati. |
|
|
866
|
+
| `webSearch.duckduckgoEnabled` | `false` | Menjalankan server stdio `uvx free-search-mcp` lokal saat pertama dipakai. |
|
|
867
|
+
| `webSearch.duckduckgoCommand` / `webSearch.duckduckgoArgs` | `uvx` / `free-search-mcp` | Command untuk provider stdio lokal. |
|
|
868
|
+
| `webSearch.serperApiKey` | — | Kunci Serper-kompatibel; menambahkan Serper ke rantai fallback. |
|
|
869
|
+
| `webSearch.endpoint` | `https://google.serper.dev/search` | Endpoint SERP (`http`/`https`). |
|
|
870
|
+
| `webSearch.authHeader` | `X-API-KEY` | `X-API-KEY` atau `Authorization` (Bearer). |
|
|
871
|
+
| `webSearch.results` | `5` | Hasil per kueri (1–10); `deep` menggandakan sampai batas. |
|
|
872
|
+
| `webSearch.timeoutMs` | `15000` | Timeout permintaan Serper (1s–60s). |
|
|
873
|
+
|
|
874
|
+
State lokal (`.ryuu/`) di-gitignore dan dikecualikan dari operasi file agent.
|
|
875
|
+
|
|
876
|
+
## Arsitektur
|
|
877
|
+
|
|
878
|
+
```
|
|
879
|
+
src/
|
|
880
|
+
index.js Entri CLI, penguraian argumen, validasi start
|
|
881
|
+
cli/
|
|
882
|
+
app.js menghubungkan UI, agent, tool, provider, proses, storage
|
|
883
|
+
commands.js slash command
|
|
884
|
+
renderer.js banner, feed aktivitas, baris telemetri, diff, ringkasan
|
|
885
|
+
tui.js layar retained-mode --tui: model transkrip, tata letak, input
|
|
886
|
+
markdown.js Markdown terminal, tabel sadar-lebar, blok kode
|
|
887
|
+
prompts.js sesi prompt readline dan penanganan Ctrl+C
|
|
888
|
+
agent/
|
|
889
|
+
agent.js loop pemanggilan-tool eksplisit dan ringkasan bukti
|
|
890
|
+
approvals.js penegakan kebijakan persetujuan
|
|
891
|
+
context.js pemadatan konteks dengan batas
|
|
892
|
+
planner.js prompt sesi, task brief, ekstraksi rencana, ringkasan
|
|
893
|
+
worklog.js fakta sesi terverifikasi yang dipakai ulang antar langkah dan tugas
|
|
894
|
+
providers/
|
|
895
|
+
catalog.js katalog provider + model (nvidia, tokenharbor, river), kapabilitas, extraProviders
|
|
896
|
+
registry.js registry provider dinamis (factory per id)
|
|
897
|
+
index.js pembuatan provider aktif dan resolusi pilihan provider/model
|
|
898
|
+
nvidia.js klien SDK OpenAI (dipakai semua provider), normalisasi, retry, pemetaan galat
|
|
899
|
+
tokenharbor.js provider Token Harbor: default dan pass-through field request
|
|
900
|
+
river.js provider River AI: reasoning_effort untuk DeepSeek + profil reasoning per model
|
|
901
|
+
vendor-extras.js tabel field request per provider yang dibaca klien bersama
|
|
902
|
+
tools/
|
|
903
|
+
registry.js allowlist, skema, risiko, antarmuka plugin
|
|
904
|
+
filesystem.js baca/tulis/edit/pindah/hapus/diff file
|
|
905
|
+
search.js pencarian nama dan isi
|
|
906
|
+
git.js inspeksi git read-only
|
|
907
|
+
project.js ringkasan manifes/project
|
|
908
|
+
shell.js tool command dan proses background
|
|
909
|
+
url.js read_url: pengambilan halaman terbatas, ekstraksi teks, fallback MCP
|
|
910
|
+
web.js web_search: satu tool di atas manajer multi-provider
|
|
911
|
+
services/
|
|
912
|
+
websearch/
|
|
913
|
+
manager.js urutan provider, fallback, retry, circuit breaker, normalisasi
|
|
914
|
+
mcp.js klien MCP (Streamable HTTP + stdio), timeout, galat bertipe
|
|
915
|
+
providers.js preset provider dan deskriptor berbasis config
|
|
916
|
+
normalize.js normalisasi hasil pencarian/ekstraksi yang agnostik provider
|
|
917
|
+
serper.js provider REST Serper-kompatibel (backend yang sudah ada)
|
|
918
|
+
workspace.js keamanan path, penulisan atomik, pemblokiran rahasia
|
|
919
|
+
ushell.js /bash dan !cmd: tangkapan shell pengguna, group kill, env bersih
|
|
920
|
+
processes.js spawn, buffer streaming, timeout, stop, log
|
|
921
|
+
sessions.js penyimpanan sesi yang disunting dan cache ringkasan
|
|
922
|
+
undo.js snapshot before/after dengan pemeriksaan basi
|
|
923
|
+
diff.js diff terpadu dan statistik
|
|
924
|
+
logger.js log bertingkat, disunting, berotasi
|
|
925
|
+
doctor.js diagnostik tanpa rahasia
|
|
926
|
+
config/ pemuatan dan validasi env
|
|
927
|
+
utils/ galat, validasi skema, redaksi, penjaga jaringan (SSRF),
|
|
928
|
+
versi (dibaca dari package.json — satu-satunya sumber versi)
|
|
929
|
+
tests/
|
|
930
|
+
unit/ uji modul fokus
|
|
931
|
+
integration/ uji proses CLI sungguhan + aplikasi terhubung
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
Tool call dieksekusi **secara berurutan**, sehingga dua pemanggilan tidak bisa
|
|
935
|
+
berlomba pada file yang sama. Setiap hasil tool ditambahkan ke percakapan dalam
|
|
936
|
+
format tool-call OpenAI dengan `tool_call_id`-nya yang sesuai.
|
|
937
|
+
|
|
938
|
+
## Model keamanan
|
|
939
|
+
|
|
940
|
+
Apa yang dilakukan implementasinya:
|
|
941
|
+
|
|
942
|
+
- Meresolusi setiap path terhadap realpath workspace dan menolak traversal
|
|
943
|
+
serta escape symlink. Path absolut di luar workspace ditolak.
|
|
944
|
+
- Memblokir `.env`, `.env.local`, private key/sertifikat, penyimpan kredensial
|
|
945
|
+
umum (`.ssh`, `.aws`, `.gnupg`, `.kube`, `.docker`, `.npmrc`, `id_rsa*`, ...),
|
|
946
|
+
serta `*.pem`/`*.key`/`*.p12`/`*.pfx`/`*.jks`/`*.keystore` secara bawaan.
|
|
947
|
+
`.env.example`, `.env.sample`, `.env.template`, dan `.env.dist` tetap bisa
|
|
948
|
+
dibaca sebagai dokumentasi.
|
|
949
|
+
- Mengecualikan `node_modules`, `.git`, `dist`, `build`, `coverage`, dan
|
|
950
|
+
direktori hasil-generate sejenis dari daftar/pencarian secara bawaan; tool bisa
|
|
951
|
+
memasukkannya secara eksplisit.
|
|
952
|
+
- `read_url` hanya menerima http/https, menolak URL dengan kredensial tertanam,
|
|
953
|
+
memeriksa ulang setiap hop redirect (https→http ditolak), hanya membaca jenis
|
|
954
|
+
konten tekstual, dan membatasi badan hingga 2 MB.
|
|
955
|
+
- Menegakkan batas file, hasil pencarian, output tool, konteks, langkah,
|
|
956
|
+
serta durasi tugas.
|
|
957
|
+
- Memakai penulisan atomik file-temp + rename, mempertahankan CRLF vs LF, dan
|
|
958
|
+
bisa membatalkan ketika mtime file berubah sejak pemeriksaan.
|
|
959
|
+
- Menjalankan command dengan `spawn(command, args, { shell: false })` dan array
|
|
960
|
+
argumen. Sintaks shell mentah dinonaktifkan kecuali `agent.allowShell: true`,
|
|
961
|
+
dan selalu bergerbang persetujuan dengan command serta direktori kerjanya
|
|
962
|
+
ditampilkan persis.
|
|
963
|
+
- Membuang variabel yang tampak seperti kredensial (`*API_KEY*`, `*TOKEN*`,
|
|
964
|
+
`*SECRET*`, `*PASSWORD*`, ...) dari environment proses anak.
|
|
965
|
+
- Menyunting (redact) kunci API yang dikonfigurasi dan pola token dari log,
|
|
966
|
+
output command, file sesi, dan pesan galat.
|
|
967
|
+
- Membatasi isi sesi/transkrip yang dipersistensi dan menyimpannya di bawah
|
|
968
|
+
`.ryuu/` dengan izin khusus pemilik bila didukung.
|
|
969
|
+
|
|
970
|
+
Apa yang **tidak** dilakukannya:
|
|
971
|
+
|
|
972
|
+
- **Eksekusi shell bukan sandbox.** Command yang disetujui berjalan dengan izin
|
|
973
|
+
pengguna Anda dan bisa membaca atau mengubah apa pun yang bisa dilakukan
|
|
974
|
+
pengguna itu.
|
|
975
|
+
- Label risiko persetujuan hanyalah heuristik. Periksa command persisnya sebelum
|
|
976
|
+
menyetujui.
|
|
977
|
+
- Ia tidak memasang dependensi otomatis, mendorong commit, men-*deploy*, atau
|
|
978
|
+
meningkatkan hak istimewa. Command yang disetujui tetap bisa melakukan hal-hal
|
|
979
|
+
itu — itu keputusan Anda.
|
|
980
|
+
- Ia tidak mengindeks atau mengunggah seluruh workspace; hanya file yang dibaca
|
|
981
|
+
model yang dikirim ke provider.
|
|
982
|
+
- Ia tidak mengarang atau merekonstruksi rantai-pikir privat. Saat provider
|
|
983
|
+
mengalirkan delta `reasoning_content`, Ryuu menampilkan teks itu langsung di
|
|
984
|
+
kotak tertutup yang lebarnya sesuai dengan pratinjau lima baris. Setiap
|
|
985
|
+
giliran mendapat id stabil; klik sebuah blok (atau jalankan `/expand <id>`)
|
|
986
|
+
untuk membuka ulang teks lengkapnya, dan Esc atau klik lain menutup panel.
|
|
987
|
+
Teks lengkapnya juga ditulis ke `.ryuu/logs/reasoning/`. Satu baris aktivitas
|
|
988
|
+
yang selalu menyala berada di bagian bawah UI percakapan dan membawa seluruh
|
|
989
|
+
keadaan run: fase, waktu berjalan per fase, total waktu run, langkah, tool
|
|
990
|
+
yang sedang berjalan beserta posisi antriannya, jumlah token live, dan latensi
|
|
991
|
+
token pertama; output command yang berjalan mengalirkan ekornya tepat di atas
|
|
992
|
+
baris itu. Jawaban akhir tidak dikotak: ia dicetak langsung sebagaimana
|
|
993
|
+
provider menulisnya, dengan Markdown inline (bold, italic, code, link)
|
|
994
|
+
dirender live, header ATX (`###`) dirender tebal tanpa tanda pagarnya, dan
|
|
995
|
+
tabel pipe / blok kode bersal die render sebagai blok segera setelah
|
|
996
|
+
selesai dialirkan. Token kontrol chat-template yang bocor dibuang; jawaban
|
|
997
|
+
tidak dirender ulang setelahnya.
|
|
998
|
+
|
|
999
|
+
## Pengujian dan pengembangan
|
|
1000
|
+
|
|
1001
|
+
```bash
|
|
1002
|
+
npm test # 300+ uji unit + integrasi (tanpa jaringan, tanpa kunci asli)
|
|
1003
|
+
npm run test:unit
|
|
1004
|
+
npm run test:integration
|
|
1005
|
+
npm run check # pemeriksaan sintaks di seluruh src/, scripts/, tests/
|
|
1006
|
+
npm run verify # check + test
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
Uji memakai runner bawaan Node `node:test`, workspace sementara, provider palsu
|
|
1010
|
+
terskrip, dan `fetch` yang disuntikkan untuk uji tingkat-SDK. Mereka tidak pernah
|
|
1011
|
+
memanggil NVIDIA.
|
|
1012
|
+
|
|
1013
|
+
Pemeriksaan *smoke* paket opsional:
|
|
1014
|
+
|
|
1015
|
+
```bash
|
|
1016
|
+
npm pack --dry-run
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
## Pemecahan masalah
|
|
1020
|
+
|
|
1021
|
+
### `Provider nvidia has no API key` / `Provider tokenharbor has no API key`
|
|
1022
|
+
|
|
1023
|
+
Pesan itu menyebut provider aktif dan path kunci yang diharapkan
|
|
1024
|
+
(`providers.<id>.apiKey`). Isi lewat `ryuu --settings` (baris
|
|
1025
|
+
`providers.nvidia.apiKey` atau `providers.tokenharbor.apiKey`). Jalankan
|
|
1026
|
+
`ryuu --doctor` untuk melihat provider mana yang aktif dan path kunci mana yang
|
|
1027
|
+
belum terisi. Provider tanpa kunci tidak bisa dipilih lewat `/provider`.
|
|
1028
|
+
|
|
1029
|
+
### 401 / 403
|
|
1030
|
+
|
|
1031
|
+
`401` berarti kunci hilang, tidak valid, atau sudah dicabut. `403` biasanya
|
|
1032
|
+
berarti kunci tidak punya akses ke model terpilih. Periksa path kunci yang
|
|
1033
|
+
disebut pesan galat (`providers.nvidia.apiKey` atau
|
|
1034
|
+
`providers.tokenharbor.apiKey`), verifikasi
|
|
1035
|
+
akses model di dashboard provider, lalu jalankan `ryuu --doctor --live`.
|
|
1036
|
+
Ryuu tidak mencoba kunci provider lain sebagai pengganti.
|
|
1037
|
+
|
|
1038
|
+
### 404
|
|
1039
|
+
|
|
1040
|
+
Periksa model provider aktif (`--model`, `/model`, atau `providerModel.<id>`) dan
|
|
1041
|
+
base URL-nya (`providers.<id>.baseURL`). Base URL harus berupa root yang
|
|
1042
|
+
kompatibel dengan OpenAI, biasanya berakhiran `/v1`.
|
|
1043
|
+
|
|
1044
|
+
### Model tidak tersedia / tidak ditemukan
|
|
1045
|
+
|
|
1046
|
+
Daftar model adalah id yang ditawarkan CLI, bukan jaminan model itu aktif di
|
|
1047
|
+
server. Untuk Token Harbor, model `deepseek-v4.1-flash:free` bisa berubah atau
|
|
1048
|
+
dibatasi ketersediaannya. Cek `/provider` dan `/model`, lalu coba model lain atau
|
|
1049
|
+
hubungi provider. Ryuu menolak id dengan karakter tidak valid sebelum mengirim
|
|
1050
|
+
apa pun, tetapi tidak melakukan pemeriksaan ketersediaan ke server.
|
|
1051
|
+
|
|
1052
|
+
### 429 / batas laju
|
|
1053
|
+
|
|
1054
|
+
Kuota dan batas laju ditentukan provider dan tidak dijamin tanpa batas (termasuk
|
|
1055
|
+
untuk model bertanda `:free`). Tunggu lalu coba lagi, perkecil ukuran
|
|
1056
|
+
konteks/tugas, atau pindah model/provider. Ryuu mencoba ulang kegagalan sesaat
|
|
1057
|
+
`429`/`5xx`/jaringan dengan backoff eksponensial terbatas beserta jitter, serta
|
|
1058
|
+
menghormati `Retry-After` bila ada.
|
|
1059
|
+
|
|
1060
|
+
### Model bawaan sangat lambat atau habis waktu
|
|
1061
|
+
|
|
1062
|
+
Model bawaan sekarang `minimaxai/minimax-m3.1-flash` (entri ke-6 di `/model`).
|
|
1063
|
+
Endpoint `deepseek-ai/deepseek-v4.1-flash` dihapus dari bawaan karena sering timeout di sisi provider. Forum NVIDIA punya laporan terbuka tentang
|
|
1064
|
+
respons 3–5+ menit untuk model ini, jadi ini latensi sisi-provider, bukan
|
|
1065
|
+
kegagalan autentikasi. `GET /v1/models` dan
|
|
1066
|
+
`GET /v1/models/deepseek-ai/deepseek-v4.1-flash` tetap berhasil dengan kunci yang
|
|
1067
|
+
valid.
|
|
1068
|
+
|
|
1069
|
+
Pakai model berkemampuan-tool yang cepat sebagai solusi, tanpa mengubah bawaan
|
|
1070
|
+
project:
|
|
1071
|
+
|
|
1072
|
+
```bash
|
|
1073
|
+
ryuu --model z-ai/glm-5.3 "your task"
|
|
1074
|
+
# atau set "providerModel": { "nvidia": "z-ai/glm-5.3" } di config.json
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
Jika Anda tetap memakai model deepseek, naikkan `agent.requestTimeoutMs` dan
|
|
1078
|
+
turunkan `agent.maxRetries` agar satu langkah lambat tidak berulang selama
|
|
1079
|
+
banyak menit. Periksa status terkini di <https://build.nvidia.com/> sebelum
|
|
1080
|
+
menganggap kunci rusak.
|
|
1081
|
+
|
|
1082
|
+
### "Model may not support tool calling"
|
|
1083
|
+
|
|
1084
|
+
Ryuu butuh dukungan `tool_calls` bergaya OpenAI pada endpoint terpilih. Coba
|
|
1085
|
+
model berkemampuan-tool lewat `providerModel.nvidia` atau `/model`. Tanpa tool call,
|
|
1086
|
+
agent tetap bisa menjawab secara percakapan, tetapi tidak bisa memeriksa atau
|
|
1087
|
+
mengubah file.
|
|
1088
|
+
|
|
1089
|
+
### Galat jaringan / timeout
|
|
1090
|
+
|
|
1091
|
+
Periksa DNS, proxy, dan akses firewall ke base URL. Naikkan
|
|
1092
|
+
`agent.requestTimeoutMs` untuk endpoint lambat. `--debug` menampilkan
|
|
1093
|
+
diagnostik yang sudah disunting.
|
|
1094
|
+
|
|
1095
|
+
### Sebuah langkah menggantung tanpa output terlihat
|
|
1096
|
+
|
|
1097
|
+
Jika aliran berhenti mengirim byte, Ryuu membatalkannya setelah
|
|
1098
|
+
`agent.streamIdleTimeoutMs` (bawaan 45s) dan melaporkan `STREAM_STALLED`;
|
|
1099
|
+
langkah hanya dicoba ulang ketika belum ada apa pun yang dicetak. Baris aktivitas
|
|
1100
|
+
selalu menunjukkan waktu berjalan, langkah, dan jumlah token, sehingga
|
|
1101
|
+
penggantunganan terlihat berbeda dari respons lambat yang tetap berkembang.
|
|
1102
|
+
Naikkan nilainya untuk endpoint yang memang lambat, set `0` untuk menonaktifkan
|
|
1103
|
+
watchdog, lalu periksa `/status` untuk rata-rata per-pemanggilan.
|
|
1104
|
+
|
|
1105
|
+
### Tautan terputus di tengah run (heartbeat)
|
|
1106
|
+
|
|
1107
|
+
Saat permintaan provider gagal dengan galat yang bisa dipulihkan (jaringan,
|
|
1108
|
+
timeout, `5xx`, `429`), agent tidak menyerah: ia menampilkan **heartbeat** di
|
|
1109
|
+
feed aktivitas (`♥ heartbeat · reconnecting · attempt 2 (unlimited) in 1.0s`)
|
|
1110
|
+
dan memutar ulang permintaan dengan backoff eksponensial (maksimal 30 detik
|
|
1111
|
+
antar-percobaan). Baris `♥ link restored` menandai saat provider menjawab lagi,
|
|
1112
|
+
dan run melanjutkan dari tempat ia berhenti. Baris aktivitas tetap berputar
|
|
1113
|
+
selama penantian, sehingga terminal tidak terlihat membeku.
|
|
1114
|
+
|
|
1115
|
+
`agent.maxRecoveryAttempts: 0` (bawaan) berarti **tanpa batas percobaan**: agent
|
|
1116
|
+
terus menyambung ulang sampai provider menjawab, tenggat tugas tercapai, atau
|
|
1117
|
+
Anda menekan `Ctrl+C`/mengirim `/cancel`. Set nilai positif (1–1000) bila Anda
|
|
1118
|
+
menginginkan penghentian keras. Hanya kegagalan yang tidak bisa dicoba ulang
|
|
1119
|
+
(seperti kunci API tidak valid atau galat validasi permintaan `400`) yang
|
|
1120
|
+
mengakhiri run seketika.
|
|
1121
|
+
|
|
1122
|
+
### Model terus menjawab tanpa isi
|
|
1123
|
+
|
|
1124
|
+
Giliran model kosong diperlakukan sebagai percobaan ulang, bukan galat. Agent
|
|
1125
|
+
menambahkan dorongan ("your previous response was empty… call the next tool or
|
|
1126
|
+
give the final answer"), menampilkan
|
|
1127
|
+
`♥ heartbeat · empty response · attempt 3 (unlimited) in 2.0s`, menunggu dengan
|
|
1128
|
+
backoff yang dimulai dari `agent.recoveryBackoffMs` dan tumbuh hingga 15s,
|
|
1129
|
+
lalu bertanya lagi dengan nomor langkah yang sama — sehingga batas opsional
|
|
1130
|
+
`agent.maxSteps` tidak dikonsumsi oleh percobaan ulang. Tidak ada kegagalan
|
|
1131
|
+
`EMPTY_RESPONSE`: run hanya berakhir saat model menjawab, tenggat tugas lewat,
|
|
1132
|
+
atau Anda membatalkan. Jika ini terjadi terus-menerus, kemungkinan endpoint
|
|
1133
|
+
sedang mengembalikan aliran kosong (periksa `/status`, file log, atau coba model
|
|
1134
|
+
lain dengan `/model`).
|
|
1135
|
+
|
|
1136
|
+
Setiap percobaan ulang dicatat (`empty model response; retrying`) dengan nomor
|
|
1137
|
+
percobaan dan jedanya, dan jumlah percobaan hanya dibatasi oleh tenggat tugas.
|
|
1138
|
+
|
|
1139
|
+
### "must be a valid JSON object string" (HTTP 400)
|
|
1140
|
+
|
|
1141
|
+
Provider memvalidasi setiap tool call di percakapan pada setiap permintaan, jadi
|
|
1142
|
+
dulu satu payload terpotong bisa menggagalkan permintaan *berikutnya* dan
|
|
1143
|
+
membunuh seluruh run. Ryuu kini memperbaiki payload terpotong (menutup
|
|
1144
|
+
string/array/objek yang masih terbuka) dan mengeksekusi pemanggilannya; jika
|
|
1145
|
+
payload tidak bisa diperbaiki, pemanggilan yang rusak diganti dengan `{}` dalam
|
|
1146
|
+
sejarah tersimpan dan model diberi tahu untuk mengirimnya ulang. Permintaan
|
|
1147
|
+
disederhanakan sekali lagi di sisi provider, sehingga payload rusak tidak lagi
|
|
1148
|
+
bisa sampai ke API.
|
|
1149
|
+
|
|
1150
|
+
### Sebuah tool terus gagal
|
|
1151
|
+
|
|
1152
|
+
Mengulang pemanggilan gagal yang sama tidak bisa menghasilkan informasi baru.
|
|
1153
|
+
Setelah dua kegagalan identik, agent memblokir yang ketiga dan memberi tahu model
|
|
1154
|
+
untuk mengganti tool, argumen, atau melaporkan temuannya. Command yang keluar
|
|
1155
|
+
dengan `1` tanpa output juga dihitung kegagalan — itu biasanya berarti "tidak ada
|
|
1156
|
+
yang cocok", bukan "coba lagi".
|
|
1157
|
+
|
|
1158
|
+
### Galat panjang konteks
|
|
1159
|
+
|
|
1160
|
+
Mulai sesi baru, persempit tugas, turunkan `agent.maxContextChars`, atau
|
|
1161
|
+
kecilkan `agent.maxToolOutputBytes`. Pemadatan lokal mempertahankan tugas,
|
|
1162
|
+
rencana, file yang berubah, command, dan masalah yang menggantung, tetapi tidak
|
|
1163
|
+
bisa melampaui konteks provider.
|
|
1164
|
+
|
|
1165
|
+
### Ketidaksesuaian versi runtime
|
|
1166
|
+
|
|
1167
|
+
Node 25.x adalah target terverifikasi; Node 22+ diterima dengan peringatan di
|
|
1168
|
+
doctor. Versi lebih lama gagal saat start. Tingkatkan dengan
|
|
1169
|
+
`nvm install 25 && nvm use 25`.
|
|
1170
|
+
|
|
1171
|
+
### Di mana lognya?
|
|
1172
|
+
|
|
1173
|
+
`.ryuu/logs/agent.log` di dalam workspace (dirotasi pada 5MB). Jalankan dengan
|
|
1174
|
+
`--debug` untuk stack trace dan metadata provider yang verbose. Log sudah
|
|
1175
|
+
disingkat, tetapi tinjau dulu sebelum dibagikan.
|
|
1176
|
+
|
|
1177
|
+
### Perilaku proses
|
|
1178
|
+
|
|
1179
|
+
Di Linux/macOS, proses anak berjalan di grup prosesnya sendiri; menghentikannya
|
|
1180
|
+
menyinyalkan grup itu, lalu meningkat ke `SIGKILL` setelah timeout. Di Windows,
|
|
1181
|
+
grup proses dan semantik sinyal berbeda: Ryuu menghentikan PID anak dan
|
|
1182
|
+
mengandalkan perilaku bawaan Node, sehingga cucu proses yatim masih mungkin.
|
|
1183
|
+
Utamakan `start_process`/`stop_process` untuk dev server dan verifikasi pembersihan
|
|
1184
|
+
secara manual di Windows.
|
|
1185
|
+
|
|
1186
|
+
## Keterbatasan yang diketahui
|
|
1187
|
+
|
|
1188
|
+
- **Pengujian API NVIDIA langsung membutuhkan kunci Anda.** Uji otomatis repositori
|
|
1189
|
+
ini sepenuhnya offline. Validasi langsung pada 2026-10-20 lolos dengan
|
|
1190
|
+
`z-ai/glm-5.3` (tool call sungguhan + jawaban akhir); model DeepSeek bawaan
|
|
1191
|
+
sedang habis waktu di sisi provider saat itu. Jalankan ulang
|
|
1192
|
+
`ryuu --doctor --live` untuk kunci dan region Anda.
|
|
1193
|
+
- Perilaku model, ukuran konteks, kuota gratis, batas laju, dan dukungan tool
|
|
1194
|
+
calling bergantung pada provider/model dan bisa berubah. Kapabilitas provider
|
|
1195
|
+
(`streaming`, `tools`, `reasoning`) hanya dipakai untuk memutuskan apa yang
|
|
1196
|
+
dikirim; reasoning tetap hanya ditampilkan bila provider mengirimnya.
|
|
1197
|
+
- Daftar model di katalog hanyalah id yang ditawarkan CLI. Ryuu tidak memeriksa
|
|
1198
|
+
ketersediaan model ke server, dan tidak melakukan fallback otomatis ke
|
|
1199
|
+
provider AI lain saat provider aktif gagal — itu mencegah kunci/data berpindah
|
|
1200
|
+
tanpa keputusan Anda, tetapi berarti Anda harus memilih provider lain dengan
|
|
1201
|
+
`/provider` atau `--provider`.
|
|
1202
|
+
- Token Harbor menyediakan model `deepseek-v4.1-flash:free`; Ryuu tidak menjamin
|
|
1203
|
+
layanan itu gratis tanpa batas. Kuota, ketersediaan, dan harga mengikuti
|
|
1204
|
+
ketentuan Token Harbor.
|
|
1205
|
+
- Respons dialirkan dan dikumpulkan sisi-klien: reasoning muncul langsung di
|
|
1206
|
+
kotaknya dan jawaban akhir dicetak langsung saat tiba (tanpa kotak, tanpa
|
|
1207
|
+
render ulang). Mode plain/non-TTY menyembunyikan aliran langsung dan hanya
|
|
1208
|
+
melaporkan jumlah karakter reasoning.
|
|
1209
|
+
- Tool call berjalan berurutan, bukan paralel. Prompt meminta model untuk
|
|
1210
|
+
menggabungkan pemanggilan independen ke dalam satu respons (beberapa baca
|
|
1211
|
+
sekaligus) untuk memotong bolak-balik.
|
|
1212
|
+
- Transport-nya stateless, jadi prompt dikirim ulang dengan setiap permintaan. Ia
|
|
1213
|
+
dirakit sekali dan identik byte-per-byte, tidak dibangun ulang; brief per-tugas
|
|
1214
|
+
adalah satu-satunya bagian yang bervariasi.
|
|
1215
|
+
- Worklog adalah lembar fakta ringkas, bukan isi file. Ia menghentikan pembacaan
|
|
1216
|
+
ulang dan analisis ulang yang redundan, tetapi file besar tetap harus dibaca
|
|
1217
|
+
sekali.
|
|
1218
|
+
- `--tui` menyimpan seluruh transkrip di memori karena setiap frame digambar ulang
|
|
1219
|
+
darinya. Tangkapan per-blok dibatasi, tetapi sesi yang sangat panjang tumbuh
|
|
1220
|
+
seiring jumlah blok; belum ada pencarian dalam aplikasi atau mode salin, dan
|
|
1221
|
+
pengubahan ukuran mengalirkan kembali frame dari model alih-alih mempertahankan
|
|
1222
|
+
tata letak piksel sebelumnya.
|
|
1223
|
+
- Penyalinan clipboard memakai OSC 52. Sebagian terminal menonaktifkannya, dan
|
|
1224
|
+
tmux perlu `set -g set-clipboard on`; ketika sekuensnya diabaikan, clipboard
|
|
1225
|
+
mempertahankan isi lamanya, sementara `/copy` tetap melaporkan jumlah karakter
|
|
1226
|
+
yang dikirim.
|
|
1227
|
+
- `/bash` dan `!cmd` sengaja melewati prompt persetujuan: Anda yang mengetik
|
|
1228
|
+
commandnya, jadi ia berjalan dengan izin Anda sendiri. `--read-only` adalah
|
|
1229
|
+
satu-satunya yang memblokirnya.
|
|
1230
|
+
- `/undo` terbatas pada sesi/tugas dan menolak saat file berubah di bawahnya.
|
|
1231
|
+
- Sesi disimpan lokal dan bukan log kejadian lengkap yang bisa diputar ulang.
|
|
1232
|
+
- Tidak ada sandbox atau isolasi kontainer bawaan.
|
|
1233
|
+
- Sintaks shell mentah harus diaktifkan secara eksplisit dan disetujui; penulisan
|
|
1234
|
+
atomik tidak melindungi dari proses eksternal yang crash di tengah penulisan.
|
|
1235
|
+
- Render Markdown mencakup sintaks umum; gambar, tabel bersarang, dan HTML
|
|
1236
|
+
kompleks ditampilkan sebagai teks.
|
|
1237
|
+
- `read_url` memakai ekstraktor HTML bawaan kecil: halaman yang dirender
|
|
1238
|
+
JavaScript, PDF, dan gambar tidak bisa dibaca, dan teks hasil ekstraksi adalah
|
|
1239
|
+
penyederhanaan dari halaman tersebut.
|
|
1240
|
+
- Ini project 0.3.1: harapkannya masih berkekakuan. Tidak ada klaim bebas bug.
|
|
1241
|
+
|
|
1242
|
+
## Daftar periksa validasi API langsung
|
|
1243
|
+
|
|
1244
|
+
Dengan kunci asli yang dikonfigurasi:
|
|
1245
|
+
|
|
1246
|
+
1. `ryuu --doctor` → semua pemeriksaan non-konektivitas lolos, kunci tidak
|
|
1247
|
+
dicetak.
|
|
1248
|
+
2. `ryuu --doctor --live` → `provider.connectivity` lolos dan melaporkan
|
|
1249
|
+
latensi untuk provider aktif. Jika model bawaan habis waktu, konfirmasi dengan
|
|
1250
|
+
`--model z-ai/glm-5.3` sebelum menganggap kunci buruk (lihat bagian
|
|
1251
|
+
pemecahan masalah latensi).
|
|
1252
|
+
3. Token Harbor (dengan `providers.tokenharbor.apiKey`): `ryuu --doctor --provider
|
|
1253
|
+
tokenharbor --live` → `provider.catalog` menandai `tokenharbor*` dan
|
|
1254
|
+
konektivitas lolos bila endpoint-nya dapat dijangkau. Bila provider tidak
|
|
1255
|
+
dapat dijangkau, itu dilaporkan sebagai kegagalan, bukan dianggap berhasil.
|
|
1256
|
+
4. `npm link && ryuu` → banner menampilkan model, provider, workspace, versi
|
|
1257
|
+
Node. `/provider` menampilkan status kunci tanpa nilainya.
|
|
1258
|
+
5. Tanya: `List the files in this project and summarize what it does.` → amati
|
|
1259
|
+
pemanggilan `list_files`/`read_file` sungguhan dan ringkasan akhir.
|
|
1260
|
+
6. Tanya: `Add a comment to the top of <file> and show me the diff.` → setujui
|
|
1261
|
+
diff → konfirmasi file berubah dan ringkasannya menyebutkannya.
|
|
1262
|
+
7. Tanya: `Run npm test and report the result.` → setujui command persisnya →
|
|
1263
|
+
verifikasi exit code asli, durasi, dan outputnya.
|
|
1264
|
+
8. `/undo` bekerja untuk perubahan file; `/status`, `/diff`, `/sessions`,
|
|
1265
|
+
`/logs` memperlihatkan bukti.
|
|
1266
|
+
|
|
1267
|
+
## Lisensi
|
|
1268
|
+
|
|
1269
|
+
MIT (lihat `package.json`).
|
|
2
1270
|
|
|
3
|
-
This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
|