Format Anthropic
Permukaan kedua: Messages API untuk SDK Anthropic dan [CC].
Ringkasan
Selain permukaan OpenAI, NusaRouter melayani permukaan Anthropic: Messages API untuk SDK Anthropic, [CC], dan klien lain yang berbicara format itu. Permukaan lama tetap ada dan tidak berubah; lihat Chat completions.
/v1/messagesbutuh API key/v1/messages/count_tokensbutuh API keyDua permukaan ini hidup di host yang sama dan di namespace /v1 yang sama di kabel. Yang berbeda hanya base URL yang kamu berikan ke SDK-nya, dan itu bagian yang paling sering salah.
# SDK Anthropic / [CC] — base ROOT, tanpa /v1
ANTHROPIC_BASE_URL=https://api.nusarouter.web.id
# SDK OpenAI (permukaan lama) — base TERMASUK /v1
OPENAI_BASE_URL=https://api.nusarouter.web.id/v1Autentikasi dan base URL
Autentikasinya sama seperti permukaan lain: satu API key, dan bisa dikirim dengan dua cara. Keduanya berfungsi di sini.
x-api-key: sk-nusa-... atau Authorization: Bearer sk-nusa-.... SDK Anthropic memakai x-api-key; klien OpenAI memakai Authorization. NusaRouter menerima keduanya, jadi kamu tidak perlu mengubah key yang sudah ada.
Header anthropic-version yang biasa dikirim SDK Anthropic juga diterima. Header itu pula yang membuat GET /v1/models menjawab bentuk Anthropic; tanpa header itu, GET /v1/models tetap menjawab bentuk OpenAI yang sudah kamu kenal.
Chat
Request dan response memakai bentuk Anthropic, tapi modelnya adalah id yang sama dengan permukaan OpenAI.
/v1/messagesbutuh API keymodel diisi public_model_id, persis id yang kamu pakai di permukaan OpenAI. Tidak ada alias claude-*: id yang tidak ada di katalog akan ditolak.
max_tokens diterima. Kalau kamu tidak mengirimnya, NusaRouter memakai batas keluaran yang dikonfigurasi untuk model itu; kalau modelnya tidak punya batas, request ditolak 400. Jadi kirim max_tokens eksplisit.
curl https://api.nusarouter.web.id/v1/messages \
-H "x-api-key: sk-nusa-..." \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-flash-v4.1",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Halo!"}]
}'Response non-streaming berbentuk Anthropic:
{
"id": "msg_...",
"type": "message",
"role": "assistant",
"model": "deepseek-flash-v4.1",
"content": [
{ "type": "text", "text": "Halo! Ada yang bisa saya bantu?" }
],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 9,
"output_tokens": 11,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
}stop_reason bernilai end_turn, max_tokens, tool_use, stop_sequence, atau refusal. stop_sequence selalu null di sini, karena model di balik layar tidak melaporkan string penghenti yang cocok.
Streaming
Set stream: true dan server mengirim Server-Sent Events dengan urutan event Anthropic.
message_start
content_block_start (text) -> content_block_delta (text_delta) -> content_block_stop
content_block_start (tool_use) -> content_block_delta (input_json_delta) -> content_block_stop
message_delta (stop_reason + usage akhir)
message_stopSetiap blok konten dibuka content_block_start, diisi content_block_delta, lalu ditutup content_block_stop. message_start membawa usage awal nol; usage final dan stop_reason ada di message_delta, dan aliran ditutup message_stop.
Pemanggilan tool
Bentuknya mengikuti Messages API. Kamu mendeklarasikan tool dengan input_schema, dan model membalas dengan blok tool_use.
{
"model": "deepseek-flash-v4.1",
"max_tokens": 1024,
"tools": [
{
"name": "get_cuaca",
"description": "Ambil cuaca sebuah kota.",
"input_schema": {
"type": "object",
"properties": { "kota": { "type": "string" } },
"required": ["kota"]
}
}
],
"messages": [{ "role": "user", "content": "Bagaimana cuaca di Bandung?" }]
}tool_choice menerima auto, any, tool, atau none. tool_use.id dikembalikan apa adanya saat kamu mengirim hasilnya balik, jadi replay tetap konsisten.
Untuk mengembalikan hasilnya, kirim pesan user berisi blok tool_result dengan tool_use_id yang cocok. Blok tool_result boleh bercampur dengan teks di pesan yang sama; NusaRouter menerjemahkannya ke giliran tool yang benar di belakang layar.
Hitung token
Hitung perkiraan token input sebelum mengirim request, tanpa menjalankannya.
/v1/messages/count_tokensbutuh API keyMenerima bentuk request Messages yang sama, mengembalikan {"input_tokens": N}.
{ "input_tokens": 42 }Error
Error di permukaan ini memakai envelope Anthropic, bukan envelope permukaan OpenAI.
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "Pesan yang aman untuk ditampilkan.",
"code": "invalid_request"
}
}Status HTTP-nya dipertahankan, dengan satu pengecualian yang penting: validation di sini 400, bukan 422 seperti di permukaan OpenAI.
Contoh tipe yang akan kamu lihat: invalid_request_error, authentication_error, not_found_error (model atau path tidak ada), rate_limit_error, billing_error (saldo atau limit key habis), timeout_error (model di balik layar kehabisan waktu), request_too_large (body melewati 30 MiB), overloaded_error, dan api_error.
Tipe Anthropic lebih kasar dari kode permukaan OpenAI: dua sebab bisa berbagi satu tipe. Karena itu error.code tetap dikirim berisi kode platform yang spesifik (insufficient_balance, spending_limit_exceeded, rate_limit_exceeded, concurrency_exceeded, …), supaya kamu bisa bercabang persis. SDK Anthropic mengabaikan field tambahan ini, jadi klien standar tidak terpengaruh.
Troubleshooting
| Gejala | Penyebab | Solusi |
|---|---|---|
404 | Base URL Anthropic kamu berakhir /v1, jadi SDK memanggil /v1/v1/messages. | setel base-nya ke https://api.nusarouter.web.id (root, tanpa /v1) |
| Permukaan tertukar | Base URL Anthropic butuh root; base URL OpenAI butuh /v1. Keduanya mudah tertukar. | Anthropic SDK → https://api.nusarouter.web.id; OpenAI SDK → https://api.nusarouter.web.id/v1 |
404 not_found_error | Id model salah, atau kamu memakai nama alias claude-*. | pakai public_model_id dari katalog, tanpa alias |
400 soal max_tokens | max_tokens tidak dikirim, dan modelnya tidak punya batas keluaran yang dikonfigurasi. | kirim max_tokens eksplisit |
count_tokens tidak sama dengan tagihan | Tokenizernya berbeda dari tokenizer Anthropic; angkanya perkiraan. | pakai sebagai perkiraan, bukan angka tagihan |