Untuk pemilihan model berdasarkan kode Claude, gunakan Haiku untuk perubahan kecil yang dapat diuji, Sonnet untuk implementasi rutin, dan Opus untuk pekerjaan yang melibatkan ambiguitas lebih besar atau membutuhkan penalaran yang lebih mendalam. Saat ini, Anthropic merekomendasikan Opus 5.5 sebagai titik awal yang umum; tugas Anda, beban peninjauan, dan anggaran akan menentukan apakah model yang lebih kecil lebih sesuai.
Untuk mengganti model, buka /model. Pers Masuk untuk menyimpan pengaturan default, atau s untuk mengganti hanya sesi saat ini. Untuk satu kali peluncuran, gunakan claude --model opus. Pilihan-pilihan tersebut memiliki tingkat ketahanan yang berbeda-beda, sehingga menentukan berapa lama sakelar tersebut harus aktif sama pentingnya dengan memilih modelnya.
Pekerjaan pemrograman juga mencakup riset, penjelasan, dokumentasi, dan aset kreatif. GlobalGPT menghadirkan model AI terkemuka dan berbagai alat AI dalam satu dasbor yang terjangkau, sementara CLI-nya menghubungkan alat-alat tersebut ke terminal dan alur kerja pengembangan. Bangun alur kerja Anda dengan GlobalGPT agar tugas-tugas yang terkait tersebut tetap terkelola secara terpadu saat Anda mengembangkan ide menjadi kode yang berfungsi.

Model mana yang sebaiknya Anda gunakan dalam Kode Claude?
Mulailah dengan bentuk pekerjaan tersebut. Fungsi pendek dengan hasil yang diharapkan jelas memerlukan evaluasi yang berbeda dibandingkan dengan bug yang muncul sesekali dan tersebar di beberapa layanan. Pertanyaan yang relevan adalah apakah model tersebut dapat menghasilkan perubahan yang dapat diterima melalui proses peninjauan dan iterasi yang wajar.
| Model saat ini | Untuk apa produk ini ditujukan | Tugas awal yang praktis |
|---|---|---|
| Claude Haiku 4.5 | Pekerjaan yang cepat dan efisien dengan ruang lingkup kontrak yang terbatas | Refaktor kecil, transformasi berulang, atau kasus uji yang sederhana |
| Claude Soneta 5 | Perpaduan antara kecerdasan dan kecepatan untuk kegiatan pemrograman sehari-hari | Sebuah fitur dengan pola yang sudah mapan, perbaikan bug rutin, atau penjelasan kode |
| Claude Opus 5,5 | Penalaran yang kompleks dan pekerjaan pengkodean agensial yang lebih panjang | Kegagalan yang ambigu, kompromi dalam arsitektur, atau perubahan yang melibatkan berbagai kendala yang saling berinteraksi |
| Claude Fable 5.1 | Penyelidikan yang paling sulit dan berlangsung paling lama | Sebuah eskalasi ketika pekerjaan yang sulit masih mampu mengalahkan tingkat upaya Opus yang lebih besar |
Haiku layak dipertimbangkan ketika kesalahan mudah terdeteksi dan perubahannya kecil. Sonnet merupakan pilihan yang masuk akal ketika implementasi sehari-hari membutuhkan lebih banyak konteks dan penilaian. Opus layak dipertimbangkan ketika pemahaman terhadap masalah merupakan bagian penting dari tugas tersebut. Fable layak mendapat pertimbangan tersendiri untuk pekerjaan yang menuntut; model ini tidak termasuk dalam uji pengkodean tiga model kami.
Ini hanyalah titik awal, bukan jaminan kualitas otomatis. Tanggapan yang lebih murah bisa jadi justru mahal jika memerlukan beberapa revisi atau peninjauan mendalam. Sebaliknya, model yang lebih besar mungkin tidak memberikan kontribusi berarti pada transformasi sederhana yang sudah lolos pemeriksaan Anda. Untuk penggunaan yang lebih luas di luar Claude Code, bandingkan rangkaian model Claude.

The gambaran umum model resmi Mencantumkan jendela konteks 1 juta token untuk Fable 5.1, Opus 5.5, dan Sonnet 5, serta 200 ribu token untuk Haiku 4.5. Ini adalah spesifikasi API. Penyedia kode Claude, akun, dan konfigurasi Anda menentukan opsi konteks yang tersedia dalam suatu sesi. Jendela yang besar berguna untuk konteks yang diperlukan; mengisinya dengan materi yang tidak relevan tetap akan membebani model.
Cara mengganti model dalam satu sesi
Dalam sesi interaktif, jalankan /model untuk membuka pemilih model. Pilih baris model, lalu tekan s jika ini merupakan perubahan satu kali saja. Menekan Masuk menyimpan pilihan tersebut sebagai pengaturan default Anda. Dengan mengetikkan /model soneta Secara langsung juga menyimpannya di versi saat ini.
Pilih perintah berdasarkan berapa lama perubahan tersebut harus berlaku
| Tujuan Anda | Apa yang harus dilakukan | Apakah perubahan pengaturan default sudah disimpan? |
|---|---|---|
| Hanya alihkan sesi interaktif ini | Buka /model, pilih model, tekan s. | Tidak. |
| Simpan model pilihan | Buka /model dan tekan Masuk, atau ketik /model soneta. | Ya, jika pengaturan pengguna dapat ditulis. |
| Mulai satu sesi di Opus | Peluncuran claude --model opus. | Tidak. |
| Kembali ke pengaturan default saat runtime akun | Gunakan /model default. | Menghapus penggantian model; nilai default yang ditetapkan dapat bergantung pada pengaturan akun dan organisasi. |
| Periksa model yang aktif | Jalankan /status. | Tidak. |
Pengaturan proyek atau pengaturan yang dikelola, penggantian pengaturan lingkungan, dan sesi yang dilanjutkan dapat memengaruhi peluncuran berikutnya. Periksa model yang aktif jika reproduktibilitas menjadi hal yang penting.
Untuk sesi terminal baru, pilih model saat memulai. Perintah-perintah ini juga berlaku saat Claude Code dijalankan di terminal terintegrasi VS Code. Contoh-contoh berikut secara eksplisit memilih sebuah rilis:
claude --model claude-opus-5-5
claude --model claude-sonnet-5Jalankan perintah untuk sesi yang Anda inginkan; contoh-contoh tersebut merupakan alternatif. Anda dapat membuka terminal yang berbeda dengan --model nilai tanpa harus terus-menerus mengubah nilai default bersama yang telah disimpan. Gunakan /status untuk memeriksa model yang sedang aktif.
Nama keluarga seperti opus dan soneta dapat beralih ke versi yang lebih baru. Resolusi mereka juga bergantung pada penyedia layanan: API Anthropic saat ini memetakan resolusi tersebut ke Opus 5.5 dan Sonnet 5, sementara pemetaan dari penyedia layanan cloud bisa berbeda-beda. Gunakan ID model lengkap jika Anda memerlukan eksekusi yang dapat direproduksi, dan periksa nama khusus penyedia jika lingkungan Anda mengharuskannya.
Opus 5.5 memerlukan Claude Code versi 2.1.280 atau yang lebih baru; Sonnet 5 memerlukan versi 2.1.197 atau yang lebih baru. The dokumentasi konfigurasi model merupakan referensi untuk alias saat ini, persyaratan versi, dan pemetaan penyedia. Perintah-perintah di sini merupakan contoh dalam dokumentasi; bagian praktik langsung kami menguji kode yang dihasilkan secara terpisah.

Cara menetapkan model default
Untuk pengaturan default pribadi, pilih model di /model dan tekan Masuk, atau ketikkan pilihan seperti /model soneta. Kode Claude menulis model kolom di pengaturan pengguna Anda jika berkas tersebut dapat ditulis. Buka sesi baru dan periksa model aktifnya untuk memverifikasi hasilnya.
Preferensi yang telah disimpan tidak akan menggantikan semua pengaturan lainnya. Sebuah bendera startup, MODEL_ANTROPIK Di dalam shell, pengaturan proyek atau pengaturan terkelola, atau pengaturan default organisasi yang dikonfigurasi untuk menggantikan pilihan pengguna, dapat memilih opsi lain saat diluncurkan. Sesi yang dilanjutkan juga mungkin mempertahankan model dari transkrip yang disimpannya. Periksa informasi saat startup dan /status sebelum menyimpulkan bahwa kesempatan itu telah hilang.
/model default menghapus pengaturan khusus model Anda dan mengembalikan ke pengaturan default runtime untuk akun dan konfigurasi Anda. Kata default merupakan nilai reset, bukan nama dari satu model Claude yang tetap. Nilai ini tidak boleh digunakan sebagai pengenal model yang dapat direproduksi.
Untuk pengaturan lanjutan, MODEL_ANTROPIK_DEFAULT menyediakan opsi awal cadangan mulai dari versi v2.1.236 dan seterusnya. Opsi ini ditempatkan di bawah pilihan peluncuran eksplisit, lingkungan, pengaturan, dan organisasi, serta mengabaikan nilai-nilai termasuk haiku dan opusplan. Untuk preferensi pribadi pada umumnya, pemilih tersebut lebih mudah diverifikasi. Lihat Pengaturan Kode Claude ketika konfigurasi bersama terlibat.
Apa yang sebenarnya dilakukan oleh Opusplan
opusplan Menggunakan Opus saat dalam mode perencanaan dan Sonnet untuk tahap pelaksanaan. Keunggulannya cukup jelas: gunakan model penalaran yang lebih kuat untuk merumuskan pendekatan, lalu model pemrograman sehari-hari untuk melaksanakan rencana tersebut.
Opusplan mengikuti cara kerja berikut
Perilaku perutean yang terdokumentasi. Versi yang mendasari nama-nama keluarga ini bergantung pada penyedia layanan dan konfigurasi Anda.
Ini adalah aturan yang bergantung pada mode. Aturan ini tidak memeriksa setiap prompt dan secara otomatis memilih keluarga model yang paling murah dan sesuai. Pemetaan penyedia dan batasan akses tetap berlaku untuk model-model yang mendasarinya. Selain itu, nama tersebut juga tidak menjamin penghematan: biaya total bergantung pada seberapa banyak perencanaan, implementasi, revisi, dan pemrosesan konteks yang dibutuhkan oleh tugas tersebut.
Cobalah sekali-sekali menerapkan pendekatan di mana desainnya mendapat manfaat dari analisis yang lebih mendalam dan pelaksanaannya mengikuti rencana yang jelas. Untuk perbaikan kecil, perencanaan tambahan tersebut mungkin tidak diperlukan.
Dua tugas pemrograman apa saja yang ditampilkan
Untuk memberikan gambaran konkret mengenai pemilihan model, kami menguji refaktorisasi Unicode berskala kecil dan perbaikan pemilih rute yang memiliki persyaratan yang saling terkait. Ternyata, perbedaan antara fungsi yang benar dan hasil yang diminta secara lengkap lebih penting daripada sekadar skor.
Bagaimana kami menguji hasil pemrograman
Pada tanggal 28 September 2026, kami memberikan dua tugas JavaScript yang sama kepada Claude Haiku 4.5, Claude Sonnet 5, dan Claude Opus 5.5 melalui GlobalGPT. Setiap model menghasilkan kode sumber; kami memeriksa kode tersebut dan menjalankan pemeriksaan lokal yang tetap. Petunjuk peralihan model Claude di bagian lain panduan ini diambil dari dokumentasi resminya.
Setiap permintaan memiliki batas keluaran sebesar 4.096 token, tanpa alat bantu atau riwayat percakapan, serta pengaturan model default. Kami menyimpan respons pertama yang dapat dievaluasi, termasuk respons yang belum lengkap. Satu kesalahan layanan pada tugas perutean Sonnet diberi satu kesempatan percobaan ulang yang diizinkan: tujuh permintaan menghasilkan enam keluaran.
Dua tugas kecil ini mengukur kode yang dikembalikan dan kelengkapan pengiriman. Keduanya tidak mengukur pelaksanaan agen Claude Code, penjelajahan repositori, atau sesi pengembangan secara keseluruhan. Biaya aktual dalam dolar tidak dilaporkan. Satu pengamatan per tugas tidak dapat dijadikan dasar untuk menentukan peringkat kecepatan atau keandalan secara umum.
Lihat ID model yang tepat dan kondisi evaluasi
ID yang diminta: claude-haiku-4-5-20251001, claude-sonnet-5, dan claude-opus-5-5. Pengujian lokal dilakukan menggunakan Node.js v24.19.0. Petunjuk yang diberikan ditujukan untuk Node.js versi 18 ke atas; Node.js 18 sendiri belum diuji.
Delapan kelompok perilaku ditetapkan untuk tugas siput dan dua belas untuk pemilih rute. Kepatuhan terhadap format dan penyelesaian pengiriman dilaporkan secara terpisah. Pemeriksaan tinjauan kode yang dilakukan kemudian diberi label terpisah dan tidak mengubah jumlah tersebut. Kami tidak mengedit kode sumber yang dikembalikan agar lolos pemeriksaan.
Tugas 1: Mempertahankan Unicode dalam refaktorisasi slug kecil
Fungsi tersebut harus mempertahankan huruf non-Latin dan tanda penggabungan, menormalkan aksen yang terpisah, serta mempertahankan perilaku ASCII yang sudah ada.
| Model | Pemeriksaan perilaku | Format tanggapan | Menyelesaikan pengiriman yang diminta |
|---|---|---|---|
| Claude Haiku 4.5 | 8/8 | Gagal: Pembungkus Markdown | Ya: fungsi lengkap |
| Claude Soneta 5 | 8/8 | Pass: JSON mentah | Ya: fungsi lengkap |
| Claude Opus 5,5 | 8/8 | Pass: JSON mentah | Ya: fungsi lengkap |
Hasil yang diamati: Ketiga fungsi tersebut berhasil melewati delapan kelompok yang sama. Sonnet dan Opus juga memenuhi persyaratan respons JSON mentah. Haiku membungkus responsnya dalam Markdown, dan catatan ulasannya secara keliru menggambarkan NFC sebagai proses penguraian karakter; kode programnya justru memanggil NFC dengan benar.
Dalam refaktorisasi terbatas ini, pembaruan yang dilakukan tidak memperbaiki perilaku fungsi yang diuji. Persyaratan format dan keakuratan penjelasan yang menyertainya masih perlu ditinjau.
Lihat prompt bersama dan kode input selengkapnya
SYSTEM
You are completing a bounded JavaScript coding task. Return only the requested JSON object with complete source files and brief review notes. Do not claim to have edited files, run commands, or used tools. You have no tool access. Do not include hidden reasoning.
USER
Implement the following Node.js 18+ CommonJS function from its current source. Return complete replacement source for src/slugify.js. Do not add dependencies, imports, I/O, or other files.
Required behavior:
1. slugify(value) returns an empty string for every non-string input.
2. Normalize string input to Unicode NFC, then lowercase it using JavaScript toLowerCase().
3. Preserve Unicode letters, numbers, and combining marks. Replace each consecutive run of all other characters with one ASCII hyphen.
4. Trim leading and trailing hyphens. Preserve the CommonJS export { slugify }.
5. Existing ASCII behavior must continue to work. Examples: Hello, World! -> hello-world; two words -> two-words; null -> empty string.
6. Additional examples: Café déjà vu -> café-déjà-vu; decomposed Cafe\u0301 -> café; 中文 测试 42 -> 中文-测试-42; **hi___there** -> hi-there; only punctuation or whitespace -> empty string.
Current src/slugify.js:
```javascript
function slugify(value) {
if (typeof value !== "string") return "";
return value
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
module.exports = { slugify };
```
Return exactly one JSON object with this shape:
{"files":{"src/slugify.js":"complete JavaScript source as a JSON string"},"review_notes":["at most four brief implementation or assumption notes"]}
No Markdown wrapper. You are returning code for someone else to evaluate locally; do not say that tests passed or that you ran them.
Lihat tanggapan lengkap Claude Haiku 4.5 sebagaimana dikirimkan kembali
```json
{
"files": {
"src/slugify.js": "function slugify(value) {\n if (typeof value !== \"string\") return \"\";\n \n // Normalize to NFC and lowercase\n const normalized = value.normalize(\"NFC\").toLowerCase();\n \n // Replace consecutive runs of non-letter, non-number, non-combining-mark characters with a single hyphen\n // Unicode letter categories: L* (Lu, Ll, Lt, Lm, Lo)\n // Unicode number categories: N* (Nd, Nl, No)\n // Unicode combining mark categories: M* (Mn, Mc, Me)\n const slugged = normalized.replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\");\n \n // Trim leading and trailing hyphens\n return slugged.replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };"
},
"review_notes": [
"Uses String.prototype.normalize(\"NFC\") to decompose composed characters like é into base+combining mark, then toLowerCase() applies to normalized string",
"Unicode property escapes (\\p{L}, \\p{N}, \\p{M}) with /u flag preserve all Unicode letters, numbers, and combining marks while replacing other consecutive characters with single hyphens",
"Existing ASCII behavior is preserved: punctuation and whitespace are replaced with hyphens, then leading/trailing hyphens are trimmed",
"Non-string inputs return empty string as required; normalized decomposed characters (e.g., Cafe\\u0301) are handled correctly by NFC normalization"
]
}
```Lihat tanggapan lengkap Claude Sonnet 5 sebagaimana dikirimkan kembali
{"files":{"src/slugify.js":"function slugify(value) {\n if (typeof value !== \"string\") return \"\";\n return value\n .normalize(\"NFC\")\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };\n"},"review_notes":["Used Unicode property escapes (\\p{L}, \\p{N}, \\p{M}) with the u flag to preserve letters, numbers, and combining marks across scripts.","NFC normalization ensures decomposed sequences like Cafe + combining acute compose to café before lowercasing.","Runs of any other characters (punctuation, whitespace, symbols) collapse to a single hyphen, then leading/trailing hyphens are trimmed."]}Lihat tanggapan lengkap Claude Opus 5.5 sebagaimana dikembalikan
{"files":{"src/slugify.js":"function slugify(value) {\n if (typeof value !== \"string\") return \"\";\n return value\n .normalize(\"NFC\")\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };\n"},"review_notes":["The input is normalized to NFC before lowercasing, so decomposed input like Cafe\\u0301 composes to café.","A Unicode property regex with the u flag keeps letters (\\p{L}), numbers (\\p{N}) and combining marks (\\p{M}). Each run of any other characters, including underscores and whitespace, becomes one hyphen.","The explicit trim() was removed because the final step strips leading and trailing hyphens, which covers surrounding whitespace.","Lowercasing happens after NFC normalization, as the spec orders. toLowerCase can occasionally produce non-NFC output for rare characters, and it is not re-normalized here."]}Tugas 2: Memperbaiki pemilih rute dan mengembalikan hasil pengujiannya
Fungsi tersebut harus menangani pencocokan prefiks terpanjang, prioritas metode, batas segmen, aturan yang tidak valid, dan input yang tidak dapat diubah. Respons yang diminta juga mencakup berkas uji baru.
| Model | Pemeriksaan perilaku | Format tanggapan | Menyelesaikan pengiriman yang diminta |
|---|---|---|---|
| Claude Haiku 4.5 | 12/12 hanya pada fungsi lengkap | Kesalahan: JSON terpotong | No: berkas uji terpotong |
| Claude Soneta 5 | 12/12 hanya pada fungsi lengkap | Kesalahan: JSON terpotong | No: berkas uji terpotong |
| Claude Opus 5,5 | 12/12 hanya pada fungsi lengkap | Kesalahan: JSON terpotong | No: berkas uji terpotong |
Hasil yang diamati: Tidak ada model yang berhasil menyelesaikan respons dua berkas yang diminta dalam batas keluaran bersama. Ketiga model tersebut berhenti pada 4.096 token penyelesaian yang dilaporkan. Masing-masing model telah mengembalikan fungsi router yang lengkap, yang lolos dari dua belas kelompok perilaku tetap; berkas uji baru tersebut tidak lengkap dan tidak dieksekusi.
Kami hanya mengekstrak setiap string kode sumber yang sepenuhnya tertutup. Respons asli yang terpotong tetap utuh seperti yang tercantum di bawah ini. Oleh karena itu, skor fungsi yang lulus tidak berarti permintaan secara keseluruhan berhasil.
Temuan tambahan dari tinjauan kode: hasil seri dengan akar yang sama
Setelah pemeriksaan rutin, kami menyadari bahwa Haiku telah dinormalisasi /// menjadi string kosong, bukan /. Pemeriksaan lokal terpisah menggunakan dua aturan GET, dengan awalan /// dan /, dengan sasaran pertama dan kedua dalam urutan itu. Untuk /apa saja, kontrak tersebut mensyaratkan pertama.
Haiku kembali kedua; Sonnet dan Opus kembali pertama. Pemeriksaan tambahan ini dilakukan sebagai tindak lanjut dari tinjauan kode dan terpisah dari dua belas pemeriksaan yang ditetapkan sebelum pengujian. Hal ini tidak memengaruhi skor mereka.
Sonnet mengalami satu kesalahan layanan sebelum upaya percobaan ulang yang diizinkan menghasilkan respons terpotong yang ditampilkan. Kegagalan layanan tersebut tidak terkait dengan kualitas kode. Tidak ada model yang diberi kesempatan lagi untuk memperbaiki atau menyempurnakan jawabannya.
Lihat prompt bersama dan kode input selengkapnya
SYSTEM
You are completing a bounded JavaScript coding task. Return only the requested JSON object with complete source files and brief review notes. Do not claim to have edited files, run commands, or used tools. You have no tool access. Do not include hidden reasoning.
USER
Repair a Node.js 18+ CommonJS route selector. Return complete replacement src/router.js and an additional test/router-added.test.js using node:test and node:assert/strict. Do not add dependencies or edit existing tests. Do not use I/O other than the test runner, network, child processes, timers, or any files beyond the two requested outputs.
Contract for chooseRoute(request, rules):
1. Invalid request or rules returns null, without throwing. Request must be a non-null, non-array object; method must be a nonempty ASCII-letter string; path must be a string beginning with /. Rules must be an array.
2. Before matching, remove the request path's query and fragment starting at the earliest ? or #. Do not URL-decode or collapse interior slashes.
3. Ignore invalid rules. A valid rule is a non-null, non-array object with method '*' or a nonempty ASCII-letter string, prefix a string starting with / containing neither ? nor #, and target a nonempty string.
4. Compare methods case-insensitively. Prefer any matching exact-method rule over all wildcard-method '*' rules, even if a wildcard has a longer prefix. Use wildcard rules only if no exact-method route matches the path.
5. Remove trailing slashes from a rule prefix, except that an all-slash prefix normalizes to /. A prefix matches the path only at a segment boundary: /api matches /api and /api/users, never /apix. Root / matches every valid request path.
6. Within the chosen method group, choose the longest normalized matching prefix. On equal prefix length, choose the earlier rule in the original input array. Return its target. Return null if none matches.
7. Do not mutate the request, rules array, or rule objects, including order or prefix strings. Preserve module.exports = { chooseRoute }.
8. Add tests for segment boundaries, query/fragment removal, method precedence, ties, malformed inputs and immutability. Existing simple GET /api/users and POST-no-match cases must still pass.
Current src/router.js:
```javascript
function chooseRoute(request, rules) {
if (!request || !Array.isArray(rules)) return null;
for (const rule of rules) {
if (request.method === rule.method && request.path.startsWith(rule.prefix)) {
return rule.target;
}
}
return null;
}
module.exports = { chooseRoute };
```
Existing regression cases (unchanged): rules [{method:'GET',prefix:'/api',target:'api'},{method:'GET',prefix:'/api/admin',target:'admin'}]; GET /api/users returns 'api'; POST /api/users returns null.
Return exactly one JSON object with this shape:
{"files":{"src/router.js":"complete JavaScript source as a JSON string","test/router-added.test.js":"complete JavaScript tests as a JSON string"},"review_notes":["at most four brief implementation or assumption notes"]}
No Markdown wrapper. You are returning code for someone else to evaluate locally; do not say you edited files, ran tests, or observed passing results.
Lihat tanggapan lengkap Claude Haiku 4.5 sebagaimana dikirimkan kembali
Inilah tanggapan lengkap yang diterima. Tanggapan ini terhenti di tengah-tengah karena telah mencapai batas; bagian yang hilang belum diisi.
```json
{
"files": {
"src/router.js": "function chooseRoute(request, rules) {\n // Validate request\n if (request === null || Array.isArray(request) || typeof request !== 'object') {\n return null;\n }\n if (typeof request.method !== 'string' || request.method.length === 0 || !/^[a-zA-Z]+$/.test(request.method)) {\n return null;\n }\n if (typeof request.path !== 'string' || !request.path.startsWith('/')) {\n return null;\n }\n\n // Validate rules\n if (!Array.isArray(rules)) {\n return null;\n }\n\n // Remove query and fragment from path\n const cleanPath = request.path.split(/[?#]/)[0];\n\n // Filter and validate rules\n const validRules = [];\n for (const rule of rules) {\n if (rule === null || Array.isArray(rule) || typeof rule !== 'object') {\n continue;\n }\n \n const method = rule.method;\n if (typeof method !== 'string' || (method !== '*' && (method.length === 0 || !/^[a-zA-Z]+$/.test(method)))) {\n continue;\n }\n \n const prefix = rule.prefix;\n if (typeof prefix !== 'string' || !prefix.startsWith('/') || prefix.includes('?') || prefix.includes('#')) {\n continue;\n }\n \n const target = rule.target;\n if (typeof target !== 'string' || target.length === 0) {\n continue;\n }\n \n validRules.push(rule);\n }\n\n // Normalize prefixes and partition into exact-method and wildcard groups\n const exactMethodRules = [];\n const wildcardRules = [];\n \n for (const rule of validRules) {\n const normalizedPrefix = rule.prefix === '/' ? '/' : rule.prefix.replace(/\/+$/, '');\n \n const entry = {\n originalRule: rule,\n normalizedPrefix: normalizedPrefix,\n method: rule.method\n };\n \n if (rule.method === '*') {\n wildcardRules.push(entry);\n } else {\n exactMethodRules.push(entry);\n }\n }\n\n const requestMethod = request.method.toUpperCase();\n\n // Helper to check if a prefix matches the path at a segment boundary\n function prefixMatches(prefix, path) {\n if (prefix === '/') {\n return true;\n }\n if (!path.startsWith(prefix)) {\n return false;\n }\n // Check segment boundary: next character must be '/' or end of string\n const nextChar = path[prefix.length];\n return nextChar === undefined || nextChar === '/';\n }\n\n // Try exact-method rules first\n let bestMatch = null;\n let bestLength = -1;\n \n for (const entry of exactMethodRules) {\n if (entry.method.toUpperCase() === requestMethod) {\n if (prefixMatches(entry.normalizedPrefix, cleanPath)) {\n if (entry.normalizedPrefix.length > bestLength) {\n bestMatch = entry.originalRule;\n bestLength = entry.normalizedPrefix.length;\n }\n }\n }\n }\n \n if (bestMatch !== null) {\n return bestMatch.target;\n }\n\n // Try wildcard rules only if no exact-method match\n bestMatch = null;\n bestLength = -1;\n \n for (const entry of wildcardRules) {\n if (prefixMatches(entry.normalizedPrefix, cleanPath)) {\n if (entry.normalizedPrefix.length > bestLength) {\n bestMatch = entry.originalRule;\n bestLength = entry.normalizedPrefix.length;\n }\n }\n }\n \n if (bestMatch !== null) {\n return bestMatch.target;\n }\n\n return null;\n}\n\nmodule.exports = { chooseRoute };",
"test/router-added.test.js": "const test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router.js');\n\n// Regression: existing test cases\ntest('GET /api/users matches /api prefix (exact method)', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'api' },\n { method: 'GET', prefix: '/api/admin', target: 'admin' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'api');\n});\n\ntest('POST /api/users returns null (no matching method)', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'api' },\n { method: 'GET', prefix: '/api/admin', target: 'admin' }\n ];\n assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, rules), null);\n});\n\n// Invalid request handling\ntest('null request returns null', () => {\n assert.equal(chooseRoute(null, []), null);\n});\n\ntest('array request returns null', () => {\n assert.equal(chooseRoute([], []), null);\n});\n\ntest('request with missing method returns null', () => {\n assert.equal(chooseRoute({ path: '/api' }, []), null);\n});\n\ntest('request with empty method returns null', () => {\n assert.equal(chooseRoute({ method: '', path: '/api' }, []), null);\n});\n\ntest('request with non-letter method returns null', () => {\n assert.equal(chooseRoute({ method: 'GET-POST', path: '/api' }, []), null);\n});\n\ntest('request with numeric method returns null', () => {\n assert.equal(chooseRoute({ method: '123', path: '/api' }, []), null);\n});\n\ntest('request with missing path returns null', () => {\n assert.equal(chooseRoute({ method: 'GET' }, []), null);\n});\n\ntest('request with path not starting with / returns null', () => {\n assert.equal(chooseRoute({ method: 'GET', path: 'api' }, []), null);\n});\n\ntest('null rules returns null', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, null), null);\n});\n\ntest('non-array rules returns null', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, { method: 'GET' }), null);\n});\n\n// Query and fragment removal\ntest('query string is removed before matching', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users?foo=bar' }, rules), 'found');\n});\n\ntest('fragment is removed before matching', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users#section' }, rules), 'found');\n});\n\ntest('earliest ? or # is used as boundary', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users?foo#bar' }, rules), 'found');\n});\n\ntest('fragment before query is used as boundary', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users#foo?bar' }, rules), 'found');\n});\n\n// Segment boundary matching\ntest('prefix /api matches /api/users at segment boundary', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('prefix /api does not match /apix (no segment boundary)', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n});\n\ntest('prefix /api matches /api exactly at segment boundary', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('root / matches any valid path', () => {\n const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/anything/here' }, rules), 'root');\n});\n\ntest('root / matches /', () => {\n const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/' }, rules), 'root');\n});\n\n// Prefix normalization (trailing slash removal)\ntest('trailing slash is removed from prefix', () => {\n const rules = [{ method: 'GET', prefix: '/api/', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('multiple trailing slashes are removed', () => {\n const rules = [{ method: 'GET', prefix: '/api///', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('all-slash prefix normalizes to single /', () => {\n const rules = [{ method: 'GET', prefix: '///', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\n// Method case-insensitivity\ntest('method comparison is case-insensitive', () => {\n const rules = [{ method: 'get', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('request method case does not affect matching', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'get', path: '/api' }, rules), 'found');\n});\n\n// Exact-method vs wildcard precedence\ntest('exact-method rule preferred over wildcard with longer prefix', () => {\n const rules = [\n { method: '*', prefix: '/api/admin/users', target: 'wildcard' },\n { method: 'GET', prefix: '/api', target: 'exact' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/test' }, rules), 'exact');\n});\n\ntest('wildcard rule used when no exact-method matches', () => {\n const rules = [\n { method: '*', prefix: '/api', target: 'wildcard' },\n { method: 'GET', prefix: '/other', target: 'exact' }\n ];\n assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, rules), 'wildcard');\n});\n\n// Longest prefix matching\ntest('longest matching prefix is chosen', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'short' },\n { method: 'GET', prefix: '/api/admin', target: 'long' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/users' }, rules), 'long');\n});\n\n// Tie-breaking (first rule wins on equal prefix length)\ntest('first rule wins on equal prefix length', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'first' },\n { method: 'GET', prefix: '/api', target: 'second' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'first');\n});\n\n// Invalid rules are ignored\ntest('null rule is ignored', () => {\n const rules = [\n null,\n { method: 'GET', prefix: '/api', target: 'found' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('array rule is ignored', () => {\n const rules = [\n [],\n { method: 'GET', prefix: '/api', target: 'found' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('rule with invalid method is ignored', () => {\n const rules = [\n { method: '', prefix: '/api', target: 'invalid' },\n { method: 'GET', prefix: '/api', target: 'valid' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with non-letter method (if not wildcard) is ignored', () => {\n const rules = [\n { method: 'G3T', prefix: '/api', target: 'invalid' },\n { method: 'GET', prefix: '/api', target: 'valid' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with prefix not starting with / is ignored', () => {\n const rules = [\n { method: 'GET', prefix: 'api', target: 'invalid' },\n { method: 'GET', prefix: '/api', target: 'valid' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with query in prefix is ignored', () => {\n const rules = [\n { method: 'GET', prefix: '/api?foo=bar', target: 'invalid' },\n { method: 'GET', prefix: '/api', target: 'valid' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with fragment in prefix is ignored', () => {\n const rules = [\n { method: 'GET', prefix: '/api#section', target: Lihat tanggapan lengkap Claude Sonnet 5 sebagaimana dikirimkan kembali
Inilah tanggapan lengkap yang diterima. Tanggapan ini terhenti di tengah-tengah karena telah mencapai batas; bagian yang hilang belum diisi.
{"files":{"src/router.js":"function isValidRequest(request) {\n return (\n request !== null &&\n typeof request === 'object' &&\n !Array.isArray(request) &&\n typeof request.method === 'string' &&\n request.method.length > 0 &&\n /^[A-Za-z]+$/.test(request.method) &&\n typeof request.path === 'string' &&\n request.path.startsWith('/')\n );\n}\n\nfunction isValidRule(rule) {\n if (rule === null || typeof rule !== 'object' || Array.isArray(rule)) {\n return false;\n }\n const { method, prefix, target } = rule;\n\n if (typeof method !== 'string') return false;\n if (method !== '*' && !(method.length > 0 && /^[A-Za-z]+$/.test(method))) {\n return false;\n }\n\n if (\n typeof prefix !== 'string' ||\n !prefix.startsWith('/') ||\n prefix.includes('?') ||\n prefix.includes('#')\n ) {\n return false;\n }\n\n if (typeof target !== 'string' || target.length === 0) return false;\n\n return true;\n}\n\nfunction normalizePrefix(prefix) {\n if (/^\/+$/.test(prefix)) return '/';\n return prefix.replace(/\/+$/, '');\n}\n\nfunction prefixMatches(normalizedPrefix, path) {\n if (normalizedPrefix === '/') return true;\n if (path === normalizedPrefix) return true;\n return path.startsWith(normalizedPrefix + '/');\n}\n\nfunction stripQueryAndFragment(path) {\n let cutIndex = path.length;\n for (let i = 0; i < path.length; i++) {\n const c = path[i];\n if (c === '?' || c === '#') {\n cutIndex = i;\n break;\n }\n }\n return path.slice(0, cutIndex);\n}\n\nfunction chooseRoute(request, rules) {\n if (!isValidRequest(request) || !Array.isArray(rules)) return null;\n\n const path = stripQueryAndFragment(request.path);\n const reqMethodLower = request.method.toLowerCase();\n\n let bestExact = null; // { len, idx, target }\n let bestWildcard = null;\n\n for (let idx = 0; idx < rules.length; idx++) {\n const rule = rules[idx];\n if (!isValidRule(rule)) continue;\n\n const normPrefix = normalizePrefix(rule.prefix);\n if (!prefixMatches(normPrefix, path)) continue;\n\n const len = normPrefix.length;\n\n if (rule.method === '*') {\n if (\n bestWildcard === null ||\n len > bestWildcard.len ||\n (len === bestWildcard.len && idx < bestWildcard.idx)\n ) {\n bestWildcard = { len, idx, target: rule.target };\n }\n } else if (rule.method.toLowerCase() === reqMethodLower) {\n if (\n bestExact === null ||\n len > bestExact.len ||\n (len === bestExact.len && idx < bestExact.idx)\n ) {\n bestExact = { len, idx, target: rule.target };\n }\n }\n }\n\n if (bestExact !== null) return bestExact.target;\n if (bestWildcard !== null) return bestWildcard.target;\n return null;\n}\n\nmodule.exports = { chooseRoute };\n","test/router-added.test.js":"const test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router');\n\ntest('segment boundary: prefix matches at slash boundary only', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'api' },\n ];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users' }, rules),\n 'api'\n );\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api' }, rules),\n 'api'\n );\n assert.equal(\n chooseRoute({ method: 'GET', path: '/apix' }, rules),\n null\n );\n});\n\ntest('root prefix matches every valid path', () => {\n const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/' }, rules), 'root');\n assert.equal(\n chooseRoute({ method: 'GET', path: '/anything/here' }, rules),\n 'root'\n );\n});\n\ntest('trailing slashes in rule prefix are normalized', () => {\n const rules = [{ method: 'GET', prefix: '/api///', target: 'api' }];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users' }, rules),\n 'api'\n );\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n});\n\ntest('all-slash prefix normalizes to /', () => {\n const rules = [{ method: 'GET', prefix: '////', target: 'root' }];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/whatever' }, rules),\n 'root'\n );\n});\n\ntest('query and fragment are stripped before matching', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'api' }];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users?x=1&y=2' }, rules),\n 'api'\n );\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users#section' }, rules),\n 'api'\n );\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users?x=1#frag' }, rules),\n 'api'\n );\n});\n\ntest('query/fragment stripping does not decode or collapse slashes', () => {\n const rules = [{ method: 'GET', prefix: '/a//b', target: 'weird' }];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/a//b?x=1' }, rules),Lihat tanggapan lengkap Claude Opus 5.5 sebagaimana dikembalikan
Inilah tanggapan lengkap yang diterima. Tanggapan ini terhenti di tengah-tengah karena telah mencapai batas; bagian yang hilang belum diisi.
{"files":{"src/router.js":"'use strict';\n\nconst LETTERS = /^[A-Za-z]+$/;\n\nfunction isPlainObject(value) {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isMethodName(value) {\n return typeof value === 'string' && value.length > 0 && LETTERS.test(value);\n}\n\nfunction stripQueryAndFragment(path) {\n const q = path.indexOf('?');\n const h = path.indexOf('#');\n let cut = -1;\n if (q !== -1 && h !== -1) cut = Math.min(q, h);\n else if (q !== -1) cut = q;\n else if (h !== -1) cut = h;\n return cut === -1 ? path : path.slice(0, cut);\n}\n\nfunction normalizePrefix(prefix) {\n let end = prefix.length;\n while (end > 0 && prefix[end - 1] === '/') end -= 1;\n return end === 0 ? '/' : prefix.slice(0, end);\n}\n\nfunction prefixMatches(path, prefix) {\n if (prefix === '/') return true;\n return path === prefix || path.startsWith(prefix + '/');\n}\n\nfunction chooseRoute(request, rules) {\n try {\n if (!isPlainObject(request) || !Array.isArray(rules)) return null;\n const method = request.method;\n const rawPath = request.path;\n if (!isMethodName(method)) return null;\n if (typeof rawPath !== 'string' || rawPath[0] !== '/') return null;\n\n const path = stripQueryAndFragment(rawPath);\n const upperMethod = method.toUpperCase();\n\n let bestExact = null;\n let bestWildcard = null;\n\n const count = rules.length;\n for (let i = 0; i < count; i += 1) {\n const rule = rules[i];\n if (!isPlainObject(rule)) continue;\n const ruleMethod = rule.method;\n const prefix = rule.prefix;\n const target = rule.target;\n const isWildcard = ruleMethod === '*';\n if (!isWildcard && !isMethodName(ruleMethod)) continue;\n if (typeof prefix !== 'string' || prefix[0] !== '/') continue;\n if (prefix.indexOf('?') !== -1 || prefix.indexOf('#') !== -1) continue;\n if (typeof target !== 'string' || target.length === 0) continue;\n\n const normalized = normalizePrefix(prefix);\n if (!prefixMatches(path, normalized)) continue;\n\n const candidate = { length: normalized.length, target };\n if (isWildcard) {\n if (bestWildcard === null || candidate.length > bestWildcard.length) bestWildcard = candidate;\n } else if (ruleMethod.toUpperCase() === upperMethod) {\n if (bestExact === null || candidate.length > bestExact.length) bestExact = candidate;\n }\n }\n\n if (bestExact !== null) return bestExact.target;\n if (bestWildcard !== null) return bestWildcard.target;\n return null;\n } catch (err) {\n return null;\n }\n}\n\nmodule.exports = { chooseRoute };\n","test/router-added.test.js":"'use strict';\n\nconst test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router.js');\n\nconst baseRules = [\n { method: 'GET', prefix: '/api', target: 'api' },\n { method: 'GET', prefix: '/api/admin', target: 'admin' }\n];\n\ntest('existing regression cases still hold', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, baseRules), 'api');\n assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, baseRules), null);\n});\n\ntest('longest prefix wins within method group', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/x' }, baseRules), 'admin');\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin' }, baseRules), 'admin');\n});\n\ntest('segment boundaries', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'api' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/api/' }, rules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n assert.equal(chooseRoute({ method: 'GET', path: '/ap' }, rules), null);\n});\n\ntest('trailing slashes in prefixes are normalized, all-slash is root', () => {\n const rules = [{ method: 'GET', prefix: '/api///', target: 'api' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n const rootRules = [{ method: 'GET', prefix: '///', target: 'root' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/' }, rootRules), 'root');\n assert.equal(chooseRoute({ method: 'GET', path: '/anything/else' }, rootRules), 'root');\n assert.equal(chooseRoute({ method: 'GET', path: '/x' }, [{ method: 'GET', prefix: '/', target: 'r' }]), 'r');\n});\n\ntest('query and fragment are removed at earliest ? or #', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api?next=/api/admin' }, baseRules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/api#/admin' }, baseRules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/apix?/api' }, baseRules), null);\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin#frag?q' }, baseRules), 'admin');\n assert.equal(chooseRoute({ method: 'GET', path: '/api?q#/admin' }, baseRules), 'api');\n});\n\ntest('no URL decoding and no slash collapsing', () => {\n const rules = [{ method: 'GET', prefix: '/api/admin', target: 'admin' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api%2Fadmin' }, rules), null);\n assert.equal(chooseRoute({ method: 'GET', path: '/api//admin' }, rules), null);\n assert.equal(chooseRoute({ method: 'GET', path: '/api//admin' }, baseRules), 'api');\n});\n\ntest('methods compare case-insensitively', () => {\n const rules = [{ method: 'get', prefix: '/a', target: 'lower' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/a' }, rules), 'lower');\n assert.equal(chooseRoute({ method: 'gEt', path: '/a/b' }, rules), 'lower');\n});\n\ntest('exact method beats longer wildcard; wildcard used only as fallback', () => {\n const rules = [\n { method: '*', prefix: '/api/admin', target: 'wild-admin' },\n { method: 'GET', prefix: '/', target: 'get-root' },\n { method: 'POST', prefix: '/other', target: 'post-other' },\n { method: '*', prefix: '/api', target: 'wild-api' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/x' }, rules), 'get-root');\n assert.equal(chooseRoute({ method: 'POST', path: '/api/admin/x' }, rules), 'wild-admin');\n assert.equal(chooseRoute({ method: 'POST', path: '/api/x' }, rules), 'wild-api');\n assert.equal(chooseRoute({ method: 'POST', path: '/other/1' }, rules), 'post-other');\n assert.equal(chooseRoute({ method: 'PUT', path: '/nothing' }, rules), null);\n});\n\ntest('ties go to earlier rule in input order', () => {\n const rules = [\n { method: 'GET', prefBatas atas 4.096 token merupakan anggaran keluaran yang dipilih untuk pengujian ini, bukan batas maksimum yang tercatat dari model mana pun. Hasil perutean ini menyarankan agar dilakukan pengecekan praktis sebelum mengajukan permintaan yang lebih besar: perkirakan ukuran implementasi, pengujian, dan penjelasan yang Anda harapkan akan diterima. Memecah hasil atau memberikan ruang keluaran yang lebih besar mungkin merupakan langkah yang tepat; kami tidak menjalankan ulang keluaran ini dengan pengaturan yang berbeda.
Untuk tugas Anda sendiri, nilai tiga hal secara terpisah: apakah responsnya lengkap, apakah kode tersebut lulus pemeriksaan yang berguna, dan apakah proses peninjauan menemukan celah yang terlewatkan oleh pemeriksaan tersebut. Meskipun lulus dua belas pemeriksaan fungsi, tidak satu pun dari respons yang terpotong dan terdiri dari dua berkas tersebut dapat dianggap sebagai hasil pengiriman yang lengkap.
Pilihan model apa yang memengaruhi biaya
Claude Code adalah alat pengkodean; Haiku, Sonnet, Opus, dan Fable adalah pilihan model di dalam lingkungan yang didukung. Cara Anda melakukan otentikasi dan pembayaran merupakan pilihan tersendiri. Mengubah model tidak akan mengubah langganan menjadi akun API atau menghilangkan semua batasan penggunaan.
| Rute penagihan | Yang patut ditonton | Bagaimana menafsirkan pemilihan model |
|---|---|---|
| Akses berlangganan Claude | Termasuk penggunaan paket dan kredit penggunaan yang diaktifkan secara terpisah | Setiap model bisa menggunakan kuota dengan cara yang berbeda-beda; silakan periksa model dan batas kuota yang tersedia dalam paket tersebut |
| Akses API Anthropic | Token input/output, penyimpanan dalam cache, dan biaya API yang berlaku | Gunakan daftar tarif terkini dan data penggunaan aktual, lalu konfirmasikan tagihan di konsol penagihan |
| Penyedia layanan awan atau gerbang | ID, tarif, dan catatan penagihan yang didukung oleh penyedia layanan Anda | Contoh harga katalog Anthropic mungkin tidak sama dengan jumlah yang dikenakan oleh penyedia layanan Anda |
Dalam Kode Claude, /penggunaan menampilkan informasi token sesi dan, jika berlaku, bilah penggunaan langganan. Angka dalam dolar tersebut merupakan perkiraan yang dihitung secara lokal berdasarkan daftar tarif atau tarif yang telah dikonfigurasi; ini bukanlah tagihan. Bagi pelanggan Pro dan Max, angka sesi tersebut tidak berarti ada tagihan API tambahan yang ditambahkan ke langganan. Baca selengkapnya tentang Claude: Kode penetapan harga dan rute penagihan jika Anda sedang mempertimbangkan cara pembayarannya.
Harga API terkini dan contoh penggunaan token yang setara
Tarif dasar normal Anthropic per juta token input/output adalah Haiku 4.5: $1/$5; Sonnet 5: $2/$10; Opus 5.5: $4/$20; Fable 5.1: $10/$50, diperiksa pada 28 September 2026. Grafik berikut mempertahankan volume token tetap agar perhitungannya mudah dibandingkan.
Volume token yang sama, empat biaya API yang berbeda
Contoh: 100.000 token masukan yang tidak disimpan dalam cache + 10.000 token keluaran, dengan menggunakan harga katalog API standar Anthropic yang diperiksa pada tanggal 28 September 2026.
Lihat tarif dan perhitungannya
| Model | Masukan / 1M | Keluaran / 1M | Contoh total |
|---|---|---|---|
| Haiku 4.5 | $1 | $5 | $0.15 |
| Soneta 5 | $2 | $10 | $0.30 |
| Opus 5.5 | $4 | $20 | $0.60 |
| Fable 5.1 | $10 | $50 | $1.50 |
Perhitungan: 0,1 × laju masukan + 0,01 × laju keluaran. Untuk Opus 5.5: 0,1 × $4 + 0,01 × $20 = $0,60.
Ini adalah ilustrasi dengan jumlah token tetap. Tugas-tugas yang sebenarnya menggunakan jumlah token yang berbeda-beda; penulisan dan pembacaan cache, upaya ulang, alat bantu, penagihan penyedia layanan, serta batas langganan perlu diperhitungkan secara terpisah.
Sumber: Harga API Anthropic.

Tugas Code Claude yang sesungguhnya merupakan rangkaian permintaan. Konteks sebelumnya mungkin dikirimkan kembali, model mungkin melakukan penyelidikan lebih lanjut, dan alat atau agen tambahan dapat menghasilkan pekerjaan tambahan. Penyimpanan sementara prompt juga memiliki laju penulisan dan pembacaan yang berbeda. Oleh karena itu, batang terendah dalam contoh tersebut tidak menunjukkan biaya terendah per perubahan yang diterima.
Lima cara untuk mengendalikan biaya tanpa mengurangi kualitas pekerjaan
- Tentukan kriteria penerimaan sebelum memilih model. Sampaikan perilaku yang diharapkan, kasus-kasus khusus, dan batasan-batasan yang ada. Tugas kecil yang jelas lebih mudah didelegasikan secara efisien dan lebih mudah ditinjau.
- Berikan konteks yang relevan. Sertakan berkas-berkas dan rincian kegagalan yang dibutuhkan oleh model tersebut. Untuk pekerjaan yang tidak terkait, mulailah percakapan baru daripada meneruskan riwayat percakapan yang panjang hanya karena riwayat tersebut sudah ada.
- Bedakan antara kemampuan dan usaha. Anthropic menyarankan untuk memulai dengan tingkat upaya default model. Jika model telah membaca konteks dengan benar namun tetap tidak dapat menyelesaikan masalah, model yang lebih kuat mungkin dapat membantu. Jika model melewatkan tahap pembacaan atau verifikasi, periksa pengaturan tugas dan pilihan tingkat upaya.
- Anggaran untuk keseluruhan jawaban. Kode sumber, uji coba, dan penjelasan semuanya membutuhkan ruang untuk ditampilkan. Tugas kedua kami menunjukkan mengapa fungsi yang lengkap saja tidak cukup sebagai bukti bahwa hasil yang diminta sesuai dengan anggaran.
- Bandingkan karya yang telah diterima. Catat hasil yang bermanfaat, upaya ulang, waktu peninjauan, dan data penagihan aktual pada tugas-tugas yang representatif. Pisahkan kesalahan penyedia layanan dari kegagalan terkait kualitas model.
Strategi-strategi ini sejalan dengan panduan biaya resmi dan Panduan model dan upaya dari Anthropic. Batas mingguan atau per sesi yang berlaku untuk seluruh rencana dapat tetap berlaku setelah pergantian model; sedangkan batas khusus model merupakan situasi yang berbeda. Periksa batas yang sebenarnya sebelum melakukan pergantian berulang kali.
Jika pekerjaan Anda mencakup pemrograman, penelitian, penulisan, dan media, bandingkan juga alur kerja yang Anda bayar. Ruang kerja multi-model GlobalGPT menggabungkan fungsi-fungsi tersebut ke dalam satu dasbor dengan akses CLI untuk tugas-tugas pengembangan. Nilai alur kerja yang lebih luas ini berguna untuk dipertimbangkan bersamaan dengan rute API berbasis kuota; bagan API di atas bukanlah daftar harga langganan GlobalGPT.
Mengapa model yang Anda pilih mungkin tidak berhasil
| Gejala | Kemungkinan besar akan diperiksa | Langkah praktis selanjutnya |
|---|---|---|
| Sesi berikutnya menggunakan model lama | Sakelar tersebut mungkin hanya berlaku untuk sesi tersebut | Gunakan tindakan "Enter" pada pemilih untuk menyimpan, lalu pilih sesi baru |
| Preferensi telah disimpan, tetapi model yang berbeda mulai berjalan | Pengaturan peluncuran, shell, proyek, pengelolaan, atau organisasi mungkin memiliki prioritas | Baca informasi awal dan periksa konfigurasi yang bersangkutan bersama pemiliknya |
| Percakapan yang dilanjutkan memiliki model yang berbeda | Sesi yang disimpan mungkin akan mengembalikan model sebelumnya | Periksa /status; pilih model yang diinginkan dengan cermat untuk melanjutkan pekerjaan |
| Model tersebut tidak ada atau ditolak | Ketersediaan penyedia layanan, aturan organisasi, atau versi Kode Claude yang sudah usang | Periksa ID model yang didukung, akses akun, dan persyaratan versi |
| Nama keluarga yang sama memiliki arti yang berbeda di tempat lain | Alias dan pemetaan penyedia berbeda | Gunakan ID lengkap yang benar untuk penyedia layanan ketika versi rilis harus tetap tidak berubah |
| Mengganti paket tidak akan menghapus batas penggunaan | Batasan tersebut mungkin berlaku untuk seluruh program | Baca pesan panduan penggunaan dan atur ulang periode, jangan hanya menganggap bahwa mengganti paket keluarga sudah cukup |
Jika Kode Claude tidak dapat menyimpan pengaturan pengguna Anda, pilihan interaktif dapat berlaku untuk sesi saat ini tanpa disimpan secara permanen. Berkas pengaturan yang dikelola atau dihasilkan mungkin memerlukan perubahan dari pemiliknya, bukan upaya pemilihan ulang. Hindari menghapus batasan organisasi hanya untuk menampilkan suatu opsi.
Bangun alur kerja yang lebih luas dengan GlobalGPT
Pemilihan model merupakan salah satu bagian dari alur kerja. Anda mungkin perlu meneliti sebuah pustaka, menyusun draf fungsi, menjelaskan perubahan kepada rekan tim, membuat dokumentasi, dan menyiapkan aset visual. GlobalGPT menggabungkan berbagai model terkemuka dan fungsi AI dalam satu ruang kerja yang terjangkau, sehingga tugas-tugas tersebut dapat dikelola dalam dasbor yang sama.

Untuk pekerjaan di terminal, GlobalGPT CLI menghubungkan alat-alat platform ini dengan lingkungan pengembangan. Proses penyiapan yang terdokumentasi menggunakan detail login akun GlobalGPT Anda dan saldo akun biasa. CLI dapat mendukung alur kerja pemrograman dan pembuatan yang lebih luas, sementara model bawaan Claude Code tetap menjadi pilihan yang disengaja melalui kontrol modelnya.
Misalnya, buat draf dan tinjau rencana implementasi, gunakan model lain untuk penjelasan yang ringkas, lalu buat dokumentasi atau aset yang menyertai rilis tersebut. Ikuti panduan ini untuk Hubungkan CLI GlobalGPT ke Kode Claude ketika Anda menginginkan integrasi alat tersebut. Atur model penalaran kode Claude Anda secara terpisah sesuai dengan tugas pengkodean yang bersangkutan.
Pilih model awal, tuliskan kriteria yang menentukan keberhasilan, dan naikkan levelnya jika tugas mengharuskannya. Periksa hasil akhir secara menyeluruh sebelum menyatakan pekerjaan tersebut selesai. Bangun alur kerja Anda dengan GlobalGPT ketika Anda menginginkan pilihan model, penelitian, pemrograman, dan alat kreatif yang terintegrasi dalam pekerjaan sehari-hari Anda.
PERTANYAAN YANG SERING DIAJUKAN
Bagaimana cara mengubah model dalam Kode Claude?
Jalankan perintah /model untuk membuka jendela pemilihan. Tekan tombol s untuk mengganti model hanya pada sesi saat ini, atau tekan Enter untuk menyimpan model yang dipilih sebagai model default Anda. Untuk memilih model untuk satu sesi baru, jalankan perintah claude –model diikuti dengan nama model.
Apakah /model mengubah pengaturan default yang telah saya simpan?
Pada versi interaktif saat ini, memilih model dengan tombol Enter atau mengetik /model sonnet akan menyimpan pilihan tersebut di pengaturan pengguna jika pengaturan tersebut dapat diedit. Menekan tombol s di jendela pemilihan hanya berlaku untuk sesi saat ini. Pengaturan lain tetap dapat memiliki prioritas saat aplikasi diluncurkan kembali.
Apa model kode Claude bawaan?
Pengaturan default saat runtime bergantung pada akun, penyedia layanan, dan konfigurasi Anda. Nilai default ini menghapus penggantian model; nilai tersebut bukanlah satu ID model yang tetap. Periksa model yang aktif dengan perintah /status dan periksa pemilih model, jangan berasumsi bahwa setiap akun dimulai pada rilis yang sama.
Apa fungsi Opusplan?
Sistem ini menggunakan Opus saat berada dalam mode perencanaan dan Sonnet saat eksekusi. Sistem ini mengikuti transisi mode, bukan secara otomatis memilih model termurah untuk setiap prompt. Biaya sebenarnya bergantung pada pekerjaan yang dilakukan pada setiap fase.
Mengapa ada model yang tidak muncul di picker?
Ketersediaan dapat bergantung pada penyedia layanan Anda, akun, batasan organisasi, dan versi Kode Claude. Periksa dokumentasi model terkini dan model-model yang diizinkan di lingkungan Anda. Alias keluarga juga dapat mengarah ke rilis yang berbeda pada penyedia layanan lain.
Apakah model yang lebih murah selalu membuat suatu tugas menjadi lebih murah?
Tidak. Harga token hanyalah salah satu faktor. Total penggunaan, jawaban yang tidak lengkap, upaya percobaan ulang, dan upaya peninjauan memengaruhi biaya perubahan yang dapat diterima. Dalam refaktor kecil kami, ketiga fungsi tersebut lolos, sedangkan ketiga respons berukuran lebih besar yang terdiri dari dua berkas terpotong karena mencapai batas keluaran bersama.
Sumber
- Konfigurasi model kode Claude — pemilihan model, nilai default, alias, perbedaan penyedia, dan opusplan.
- Biaya Kode Claude — perkiraan penggunaan, kuota langganan, penyimpanan dalam cache, dan pengendalian biaya.
- Gambaran Umum Model Anthropic dan Harga API — spesifikasi model terkini dan harga katalog.
- Panduan model dan upaya — perbedaan praktis antara kemampuan, konteks, dan upaya.
- Dokumentasi CLI GlobalGPT — alur kerja terminal dan pengaturan berbasis akun.







