Messages
Диалект Anthropic Messages — голый base URL, два носителя ключа, члены запроса, блоки ответа, события потока и подсчёт токенов, который не тратит квоту.
Быстро
Диалект Anthropic Messages обслуживается как есть, а не переведён из другого: max_tokens обязателен и умолчания не имеет, системный промпт — член запроса, инструменты несут input_schema без обёртки-функции, а ответ говорит блоками и stop_reason.
Base URL для клиентов Anthropic — голый origin https://api.kumorouter.com, без /v1. Такой клиент дописывает путь сам: он берёт base URL и добавляет к нему /v1/messages. Base URL со своим префиксом отправит его туда, где ничего не обслуживается, и вы получите 404 вместо ответа модели.
curl https://api.kumorouter.com/v1/messages \
-H "x-api-key: $KUMO_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "<model>",
"max_tokens": 256,
"system": "Отвечай одним предложением.",
"messages": [{ "role": "user", "content": "Объясни токены." }]
}'Два носителя ключа
Ключ предъявляется либо как Authorization: Bearer <ключ>, либо, как это делает нативный API, голым в заголовке x-api-key. Оба носителя называют один и тот же ключ Kumo, и любой из них допускает вызов. SDK Anthropic шлёт второй и никакого Authorization не отправляет вовсе — поэтому он и объявлен на этих операциях.
Предъявить оба сразу законно. Побеждает Authorization: если он присутствует и корректно оформлен, именно он аутентифицирует запрос, а голый x-api-key в этом случае не читается вовсе. Обычный клиент шлёт ровно один из двух — второй появляется только у самодельных обёрток, дописывающих заголовки поверх готового SDK.
Как пишется заголовок → Проверить ключ →
Члены запроса
modelОбязателен. Модель каталога в том имени, которым её называет клиент.max_tokensОбязателен. Сколько токенов максимум произвести; умолчания у этой поверхности нет.messagesОбязателен. Разговор, старший ход первым; от одного до 512.systemСистемный промпт — рядом с разговором, а не ходом его. Принимается в обоих написаниях протокола: голой строкой либо списком текстовых блоков. Строка несётся как список из одного блока.streamОтвечать ли потоком собственных именованных событий этого протокола.toolsИнструменты этого хода; до 128 объявлений.tool_choiceОбъект с `type`: `auto`, `any`, `none` или `tool`. `auto` оставляет выбор модели, `any` требует вызова любого объявленного инструмента, а `none` запрещает вызов. Только `tool` требует `name` с именем объявленного инструмента; остальные режимы отвергают `name`.temperatureСлучайность, от 0 до 1. Несётся поставщику без изменений.top_pNucleus sampling, от 0 до 1. Несётся поставщику без изменений.top_kЦелое число от 1 до 1048576. Передаётся совместимому поставщику без изменений; отсутствие не превращается в ноль. Маршрут, который не может передать этот параметр, отвергает его до обращения к поставщику.stop_sequencesПоследовательности, появление которых заканчивает ответ; до 16. Сработавшая возвращается как `stop_reason: "stop_sequence"`; какая именно, не публикуется.metadataПринимается и не пересылается: платформа не описывает поставщику вашего пользователя.thinkingПринимается и не пересылается.output_configПринимается и не пересылается.context_managementПринимается и не пересылается: серверного контекста здесь нет, свой контекст присылает клиент.Ход разговора несёт role (user, assistant, system) и content — строкой либо списком типизированных блоков: text, tool_use, tool_result. Ход system ходом разговора не считается: его текст поднимается в системный промпт, после блоков, которые назвал сам член system.
tool_result.content принимает строку либо до 32 блоков с типом text или image. Изображение передаётся источником base64 с полями media_type и data; источники URL отвергаются. Нативный Messages передаёт эти блоки без изменений. Маршрут Chat Completions не может представить изображение внутри результата инструмента и отвергает такой результат, а не удаляет изображение.
Ответ
idЛичность запроса в Kumo.typeВсегда `message`.roleВсегда `assistant`.modelМодель, которую назвал клиент.contentБлоки ответа по порядку: `text` и `tool_use`.stop_reasonПочему ответ кончился: `end_turn`, `max_tokens`, `stop_sequence` или `tool_use`.usage`input_tokens`, `output_tokens`, `cache_read_input_tokens`, `cache_creation_input_tokens`.{
"id": "msg-71c3d0aa4e",
"type": "message",
"role": "assistant",
"model": "<model>",
"content": [{ "type": "text", "text": "Токены — куски текста, которыми модель меряет ввод и вывод." }],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 16,
"output_tokens": 22,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
}Поток
"stream": true отвечает text/event-stream в именованных событиях протокола: message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop. Кроме них приходят ping и error.
Отказ, решённый до первого события, приходит обычной JSON-ошибкой этого протокола. Сбой после первого события выражается только в потоке — событием error, — и дальше поток кончается без message_stop. Поэтому целый ответ здесь виден по message_stop, и по нему одному.
Подсчёт токенов
POST /v1/messages/count_tokens принимает подмножество членов /v1/messages — model, messages, system, tools, tool_choice, thinking, metadata и context_management — и отвечает детерминированной локальной оценкой входных токенов. К провайдеру она не обращается, запроса и резерва не создаёт, баланса не трогает и квоту темпа не тратит — поэтому её удобно ставить перед крупным вызовом.
Всё остальное относится к генерации, а не ко входу, и на этой операции отвергается: max_tokens, stream, output_config, stop_sequences, temperature и top_p.
curl https://api.kumorouter.com/v1/messages/count_tokens \
-H "x-api-key: $KUMO_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "<model>",
"system": "Отвечай одним предложением.",
"messages": [{ "role": "user", "content": "Объясни токены." }]
}'Ответ несёт два члена: input_tokens — саму оценку, и estimated, который остаётся true, пока нет точного локального токенизатора.
{ "input_tokens": 16, "estimated": true }