Direct LLM Gateway
Use Wiro LLMs through OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages.
https://llm.wiro.ai/v1. Clients that append /v1 themselves, including Anthropic SDKs and Claude Code, use origin https://llm.wiro.ai. Asynchronous Run, Task, and the original Wiro File API remain on https://api.wiro.ai/v1; WebSocket remains on wss://socket.wiro.ai/v1. The Direct LLM Gateway also provides compatible /v1/files routes backed by the same authenticated project storage.
The gateway uses the same Wiro task, project-access, team-policy, and billing system as the Run API. Discover a model before calling it: supported endpoints, parameters, modalities, tools, reasoning, and limits are model-specific.
Direct LLM responses never expose Wiro Run/Sync segments. Each route returns only its selected protocol's native JSON and streaming events: OpenAI Chat chunks, OpenAI Responses events, or Anthropic Messages events. OpenClaw and Hermes receive the native transport they configure.
In this release, stream: true provides protocol-compatible SSE ordering after the provider request completes and the authenticated structured turn is persisted. Do not interpret first-event timing as live provider token latency.
Model IDs use lowercase owner/model form. Do not send a provider-only model name: discover the exact ID and protocol capabilities first.
Choose an endpoint
POST /v1/Run/{owner}/{project}remains the asynchronous task-creation endpoint onapi.wiro.ai.POST /v1/Run/{owner}/{project}/syncis the generic finite-model wait onapi.wiro.ai; see Run a Model. It is not a Direct LLM protocol.GET /v1/modelslists verifiedllm-tool-callmodels. The list is not filtered by a team's Model Access settings; those apply when a model runs.GET /v1/chat/modelsis equivalent.GET /v1/models/{owner}/{model}returns one model's contract.POST,GET, andDELETE /v1/filescompatibility routes use the authenticated project's existing Wiro file storage.POST /v1/chat/completionsuses OpenAI Chat JSON/SSE.POST /v1/responsesuses OpenAI Responses JSON and named SSE.POST /v1/messagesuses Anthropic Messages JSON/SSE.POST /v1/messages/count_tokensestimates Anthropic input tokens before a run.GET /v1/generation?id=...returns authorized generation metadata.
/sync is a newly added generic wait method on api.wiro.ai; it does not replace asynchronous Run. Direct LLM routes remain separate on llm.wiro.ai.
The asynchronous Run route returns taskid and socketaccesstoken immediately; retrieve its result through Task Detail, WebSocket, or a callback. The generic /sync wait is an additional method on api.wiro.ai; it does not replace asynchronous Run. Direct LLM routes remain separate on llm.wiro.ai.
Training and realtime models are not accepted by /sync or the Direct LLM Gateway. Use their existing training or realtime APIs.
Authentication
Project credentials
Model discovery/detail, the protocol routes, and /generation all use the authenticated project's credentials. Compatible clients should use project Bearer authentication:
- API Key Only:
Authorization: Bearer YOUR_API_KEY - Signature:
Authorization: Bearer YOUR_API_KEY:YOUR_API_SECRET, or the base64 encoding of that pair
The same endpoints also accept x-api-key containing either YOUR_API_KEY or YOUR_API_KEY:YOUR_API_SECRET. Direct LLM routes do not accept the Run API's x-nonce/x-signature HMAC trio. If Bearer and x-api-key are sent together, they must contain the same complete project credential. Mismatched keys or secrets and malformed credentials return 401 without cross-project fallback.
Never expose a project key or secret in browser or mobile application code.
Anthropic Messages takes the credential in x-api-key, where Anthropic SDKs send it, or in an Authorization: Bearer header. Send YOUR_API_KEY for an API Key Only project or YOUR_API_KEY:YOUR_API_SECRET for a Signature project. Generic /sync waits stay on api.wiro.ai and use normal Run headers.
Session identifier
session_id is the only public session field. It is optional on Chat Completions and Anthropic Messages, and must contain 1–128 letters, digits, ., _, :, or -. Reuse the same value for related turns. Wiro maps it to a project-scoped internal session; it does not replace the protocol's normal client-history requirements. Responses uses previous_response_id instead, and /v1/messages/count_tokens does not accept session_id.
Connect an agent
Point a compatible client at llm.wiro.ai. Use a project Bearer credential: API Key Only projects send YOUR_API_KEY; Signature projects send YOUR_API_KEY:YOUR_API_SECRET. Generic finite-model waits stay on Run a Model /sync.
Every client below needs the exact lowercase owner/model ID. Two places give it to you:
- The catalog, filtered to gateway models — browse them, open one, and copy the ID from its page.
GET /v1/models— the same set as JSON.GET /v1/models/{owner}/{model}then reports that model's routes, modalities, tool support and token limits.
Cursor
Cursor reaches the gateway through its OpenAI base URL override, which it appends /chat/completions to. Point it at the normal /v1 base.
-
Open the model settings Command Palette (
Cmd+Shift+P,Ctrl+Shift+Pon Windows) →Cursor Settings: Models. -
View All Models The settings pane lists only the models Cursor ships with.
View All Models, at the bottom, opens the full list where custom ones live. -
+ Add Custom Model Type the exact lowercase
owner/modelID — the same IDs VS Code takes, listed below. Repeat for each model you want. Cursor shows whatever you type in its picker, so a parenthesised label is read and discarded at either end:(Wiro) claude/sonnet-5andclaude/sonnet-5 (Wiro)both resolve toclaude/sonnet-5. Leading keeps every Wiro model together in the picker.
-
OpenAI API Key Put the project credential in the
OpenAI API Keyfield — that is the field Cursor uses for the overridden endpoint.YOUR_API_KEY:YOUR_API_SECRETfor a Signature project,YOUR_API_KEYalone for API Key Only. -
Turn the key on Flip the switch beside the field. It reads
Secret savedonce Cursor has stored the credential. - Override OpenAI Base URL Turn that switch on too. It sits directly under the key.
-
Enter the base URL
https://llm.wiro.ai/v1. Cursor appends/chat/completionsitself, so do not add it. - Disable the built-in models While the override is on, Cursor sends its own model names to your endpoint too, and those do not exist in the Wiro catalog. Leave only the models you added enabled, or every request fails with an unknown model.
-
Verify Press
Verify. A failure here is normally the base URL carrying/chat/completions, or a built-in model still switched on.
Every model the gateway serves today, labelled and ready to paste one at a time; drop the (Wiro) part, or move it to the end, as you prefer. The same set is in the catalog and behind GET /v1/models.
(Wiro) bytedance/seed-v2-1-turbo
(Wiro) bytedance/seed-v2-lite
(Wiro) bytedance/seed-v2-mini
(Wiro) bytedance/seed-v2-pro
(Wiro) claude/fable-5
(Wiro) claude/fable-5-1
(Wiro) claude/opus-5
(Wiro) claude/opus-5-5
(Wiro) claude/sonnet-5
(Wiro) deepseek/v4-flash
(Wiro) deepseek/v4-pro
(Wiro) glm/5-2
(Wiro) google/gemini-2-5-flash
(Wiro) google/gemini-3-5-flash
(Wiro) google/gemini-3-5-flash-lite
(Wiro) google/gemini-3-6-flash
(Wiro) google/gemini-3-7-flash
(Wiro) google/gemini-3-8-flash
(Wiro) google/gemini-3-flash
(Wiro) google/gemini-3-pro
(Wiro) google/gemini-4-argon
(Wiro) meta-llama/llama-3-2-3b-instruct
(Wiro) mistralai/mistral-7b-instruct-v0-3
(Wiro) mistralai/mistral-nemo-instruct-2407
(Wiro) openai/gpt-5-2
(Wiro) openai/gpt-5-4
(Wiro) openai/gpt-5-4-mini
(Wiro) openai/gpt-5-4-nano
(Wiro) openai/gpt-5-5
(Wiro) openai/gpt-5-6-luna
(Wiro) openai/gpt-5-6-sol
(Wiro) openai/gpt-5-6-terra
(Wiro) openai/gpt-5-mini
(Wiro) openai/gpt-5-nano
(Wiro) openai/gpt-6-1-sol
(Wiro) openai/gpt-6-astra
(Wiro) openai/gpt-6-luna
(Wiro) openai/gpt-6-sol
(Wiro) qwen/qwen2-5-0-5b-instruct
(Wiro) qwen/qwen2-5-1-5b-instruct
(Wiro) qwen/qwen2-5-14b-instruct
(Wiro) qwen/qwen2-5-32b-instruct
(Wiro) qwen/qwen2-5-3b-instruct
(Wiro) qwen/qwen2-5-7b-instruct
(Wiro) qwen/qwen2-5-coder-32b-instruct
(Wiro) qwen/qwen2-5-coder-7b-instruct
(Wiro) qwen/qwen3-30b-a3b
(Wiro) qwen/qwen3-30b-a3b-thinking-2507
(Wiro) qwen/qwen3-32b
(Wiro) qwen/qwen3-5-27b
(Wiro) qwen/qwen3-5-27b-heretic
(Wiro) qwen/qwen3-5-4b
(Wiro) qwen/qwen3-5-4b-heretic
(Wiro) qwen/qwen3-5-9b
(Wiro) qwen/qwen3-5-9b-heretic
(Wiro) qwen/qwen3-6-27b
(Wiro) qwen/qwen3-8-27b
(Wiro) qwen/qwen3-8-27b-obliterated
(Wiro) qwen/qwen3-8-27b-uncensored
(Wiro) xai/grok-4-1-fast
(Wiro) xai/grok-4-20
(Wiro) xai/grok-4-5
The override covers the chat and agent panel. Tab autocomplete and inline edit keep using Cursor's own backend whatever you configure here, so they are unaffected either way.
Claude Code
Claude Code reads the gateway through the Anthropic Messages protocol. This is the terminal Claude Code: the desktop app manages its own provider and cannot be pointed at a gateway, so its model picker keeps listing Anthropic’s models whatever you configure.
-
Install the CLI In a terminal:
npm i -g @anthropic-ai/claude-code -
Write the settings file Two places take it, and the file is the same in both. Pick by how widely you want the gateway used.
Every folder on this machine —
~/.claude/settings.json:{ "env": { "ANTHROPIC_BASE_URL": "https://llm.wiro.ai", "ANTHROPIC_API_KEY": "YOUR_API_KEY:YOUR_API_SECRET", "ANTHROPIC_MODEL": "(Wiro) openai/gpt-5-6-sol", "CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "1", "CLAUDE_CODE_MAX_CONTEXT_TOKENS": "1050000" } }One project only —
<project>/.claude/settings.json, in the folder you will open Claude Code in. Your other projects keep whatever they were using. If that folder is a git repository, put it in.claude/settings.local.jsoninstead, which is not committed — the credential should not reach the shared file:{ "env": { "ANTHROPIC_BASE_URL": "https://llm.wiro.ai", "ANTHROPIC_API_KEY": "YOUR_API_KEY:YOUR_API_SECRET", "ANTHROPIC_MODEL": "(Wiro) openai/gpt-5-6-sol", "CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "1", "CLAUDE_CODE_MAX_CONTEXT_TOKENS": "1050000" } }ANTHROPIC_BASE_URLcarries no/v1here — Anthropic clients append the path themselves.ANTHROPIC_API_KEYtakesYOUR_API_KEY:YOUR_API_SECRETfor a Signature project, orYOUR_API_KEYalone for API Key Only.ANTHROPIC_MODELis the model the session opens with, and is any ID from the list below, not only theclaude/ones; the(Wiro)prefix is optional and the gateway strips it, but Claude Code prints whatever you write in its session header.CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERYadds gateway models to the/modelpicker, but Claude Code keeps only IDs containingclaudeoranthropic, so the picker gains theclaude/models alone; open any other model withANTHROPIC_MODELor--model.CLAUDE_CODE_MAX_CONTEXT_TOKENSmust match the context window of the model you set — Claude Code does not recognise these names, so it otherwise assumes 200k and discards history long before it needs to. -
Open Claude Code in that folder
cd /path/to/your/project && claude -
Answer the first-run prompts A new install asks three things in a row: a colour theme, its security notes (
Press Enter to continue), and whether to applyClaude Code’s terminal setup. Answer them once. -
Allow the project’s MCP servers, if it has any A folder that declares MCP servers gets
New MCP server found in this projectbefore the session opens. Nothing here concerns the gateway — choose whatever you would normally choose. -
Answer the key prompt
Do you want to use this API key?→No. It asks about a key exported in your shell, not the one you just put in the settings file. -
Check the header, then start It names the model you configured:
(Wiro) openai/gpt-5-6-sol · API Usage Billing. Your Claude subscription is not used while a gateway credential is set. -
Switching models Open on another model for one session:
Or changecd /path/to/your/project && claude --model "(Wiro) xai/grok-4-1-fast" cd /path/to/your/project && claude --model "(Wiro) bytedance/seed-v2-pro" cd /path/to/your/project && claude --model "(Wiro) openai/gpt-5-nano"ANTHROPIC_MODELin the settings file, which every session in that scope then opens on. MoveCLAUDE_CODE_MAX_CONTEXT_TOKENSwith it — Grok 4.1 Fast holds 2M where GPT 5.6 Sol holds 1.05M:{ "env": { "ANTHROPIC_BASE_URL": "https://llm.wiro.ai", "ANTHROPIC_API_KEY": "YOUR_API_KEY:YOUR_API_SECRET", "ANTHROPIC_MODEL": "(Wiro) xai/grok-4-1-fast", "CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "1", "CLAUDE_CODE_MAX_CONTEXT_TOKENS": "2000000" } }
Every model the gateway serves today, with the context window for CLAUDE_CODE_MAX_CONTEXT_TOKENS. The same values come from GET /v1/models as context_length. For a Wiro-hosted model that number is the prompt the GPU it runs on actually has room for, measured on the fleet — usually well below the window its checkpoint was built for, and below what its model card advertises. Set the variable to the number the catalog reports, not the card’s.
Model ID Context
----------------------------------------------------
(Wiro) bytedance/seed-v2-1-turbo 256000
(Wiro) bytedance/seed-v2-lite 256000
(Wiro) bytedance/seed-v2-mini 256000
(Wiro) bytedance/seed-v2-pro 256000
(Wiro) claude/fable-5 1000000
(Wiro) claude/fable-5-1 1000000
(Wiro) claude/opus-5 1000000
(Wiro) claude/opus-5-5 1000000
(Wiro) claude/sonnet-5 1000000
(Wiro) deepseek/v4-flash 1048576
(Wiro) deepseek/v4-pro 1048576
(Wiro) glm/5-2 1048576
(Wiro) google/gemini-2-5-flash 1048576
(Wiro) google/gemini-3-5-flash 1048576
(Wiro) google/gemini-3-5-flash-lite 1048576
(Wiro) google/gemini-3-6-flash 1048576
(Wiro) google/gemini-3-7-flash 1048576
(Wiro) google/gemini-3-8-flash 1048576
(Wiro) google/gemini-3-flash 1048576
(Wiro) google/gemini-3-pro 1048576
(Wiro) google/gemini-4-argon 1048576
(Wiro) meta-llama/llama-3-2-3b-instruct 51200
(Wiro) mistralai/mistral-7b-instruct-v0-3 17408
(Wiro) mistralai/mistral-nemo-instruct-2407 35840
(Wiro) openai/gpt-5-2 400000
(Wiro) openai/gpt-5-4 1050000
(Wiro) openai/gpt-5-4-mini 400000
(Wiro) openai/gpt-5-4-nano 400000
(Wiro) openai/gpt-5-5 1050000
(Wiro) openai/gpt-5-6-luna 1050000
(Wiro) openai/gpt-5-6-sol 1050000
(Wiro) openai/gpt-5-6-terra 1050000
(Wiro) openai/gpt-5-mini 400000
(Wiro) openai/gpt-5-nano 400000
(Wiro) openai/gpt-6-1-sol 1050000
(Wiro) openai/gpt-6-astra 1050000
(Wiro) openai/gpt-6-luna 1050000
(Wiro) openai/gpt-6-sol 1050000
(Wiro) qwen/qwen2-5-0-5b-instruct 32768
(Wiro) qwen/qwen2-5-1-5b-instruct 32768
(Wiro) qwen/qwen2-5-14b-instruct 29696
(Wiro) qwen/qwen2-5-32b-instruct 17408
(Wiro) qwen/qwen2-5-3b-instruct 32768
(Wiro) qwen/qwen2-5-7b-instruct 32768
(Wiro) qwen/qwen2-5-coder-32b-instruct 17408
(Wiro) qwen/qwen2-5-coder-7b-instruct 32768
(Wiro) qwen/qwen3-30b-a3b 7168
(Wiro) qwen/qwen3-30b-a3b-thinking-2507 7168
(Wiro) qwen/qwen3-32b 17408
(Wiro) qwen/qwen3-5-27b 25600
(Wiro) qwen/qwen3-5-27b-heretic 25600
(Wiro) qwen/qwen3-5-4b 72704
(Wiro) qwen/qwen3-5-4b-heretic 72704
(Wiro) qwen/qwen3-5-9b 25600
(Wiro) qwen/qwen3-5-9b-heretic 25600
(Wiro) qwen/qwen3-6-27b 25600
(Wiro) qwen/qwen3-8-27b 25600
(Wiro) qwen/qwen3-8-27b-obliterated 25600
(Wiro) qwen/qwen3-8-27b-uncensored 25600
(Wiro) xai/grok-4-1-fast 2000000
(Wiro) xai/grok-4-20 2000000
(Wiro) xai/grok-4-5 500000
If Claude Code opens to the login screen instead of a session, the settings file was not read in time: a project .claude/settings.json applies only after the first-run prompts and the folder trust prompt above. Answer those once and reopen, or put the same env block in ~/.claude/settings.json, which is read before them and applies to every folder.
VS Code
VS Code Chat reaches the gateway through its own built-in custom endpoint — no extension required.
-
Open the model manager Command Palette (
Cmd+Shift+P,Ctrl+Shift+Pon Windows) →Chat: Manage Language Models. -
Add a provider
+ Add Modelsopens a provider list — Anthropic, Azure, Google, OpenAI, OpenRouter, xAI, Ollama. PickCustom Endpoint, last, below the separator. -
Group Name Arrives pre-filled with “Custom Endpoint”; replace it with
Wiro AI. It is a label — it titles the next two prompts and groups the models in the picker. -
API Key
YOUR_API_KEY:YOUR_API_SECRETfor a Signature project,YOUR_API_KEYalone for API Key Only. VS Code keeps it in its secret store; the file holds only a${input:…}reference. -
API Type Choose
Chat Completions. Responses and Messages change the request shape VS Code sends. -
Describe the models VS Code opens
chatLanguageModels.jsonwith one empty model. Leavename,vendor,apiKeyandapiTypeas generated and fill themodelsarray. Below is every model the gateway serves today, ready to paste; the same set is in the catalog and behindGET /v1/models.
[
{
"name": "Wiro AI",
"vendor": "customendpoint",
"apiKey": "${input:chat.lm.secret.xxxxxxxx}",
"apiType": "chat-completions",
"models": [
{
"id": "bytedance/seed-v2-1-turbo",
"name": "(Wiro) Seed V2.1 Turbo",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 256000,
"maxOutputTokens": 65536
},
{
"id": "bytedance/seed-v2-lite",
"name": "(Wiro) Seed V2 Lite",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 256000,
"maxOutputTokens": 65536
},
{
"id": "bytedance/seed-v2-mini",
"name": "(Wiro) Seed V2 Mini",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 256000,
"maxOutputTokens": 65536
},
{
"id": "bytedance/seed-v2-pro",
"name": "(Wiro) Seed V2 Pro",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 256000,
"maxOutputTokens": 65536
},
{
"id": "claude/fable-5",
"name": "(Wiro) Fable 5",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1000000,
"maxOutputTokens": 128000
},
{
"id": "claude/fable-5-1",
"name": "(Wiro) Fable 5.1",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1000000,
"maxOutputTokens": 128000
},
{
"id": "claude/opus-5",
"name": "(Wiro) Opus 5",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1000000,
"maxOutputTokens": 128000
},
{
"id": "claude/opus-5-5",
"name": "(Wiro) Opus 5.5",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1000000,
"maxOutputTokens": 128000
},
{
"id": "claude/sonnet-5",
"name": "(Wiro) Sonnet 5",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1000000,
"maxOutputTokens": 128000
},
{
"id": "deepseek/v4-flash",
"name": "(Wiro) DeepSeek V4 Flash",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 1048576,
"maxOutputTokens": 384000
},
{
"id": "deepseek/v4-pro",
"name": "(Wiro) DeepSeek V4 Pro",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 1048576,
"maxOutputTokens": 384000
},
{
"id": "glm/5-2",
"name": "(Wiro) GLM 5.2",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 1048576,
"maxOutputTokens": 128000
},
{
"id": "google/gemini-2-5-flash",
"name": "(Wiro) Gemini 2.5 Flash",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "google/gemini-3-5-flash",
"name": "(Wiro) Gemini 3.5 Flash",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "google/gemini-3-5-flash-lite",
"name": "(Wiro) Gemini 3.5 Flash-Lite",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "google/gemini-3-6-flash",
"name": "(Wiro) Gemini 3.6 Flash",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "google/gemini-3-7-flash",
"name": "(Wiro) Gemini 3.7 Flash",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "google/gemini-3-8-flash",
"name": "(Wiro) Gemini 3.8 Flash",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "google/gemini-3-flash",
"name": "(Wiro) Gemini 3 Flash",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "google/gemini-3-pro",
"name": "(Wiro) Gemini 3 Pro",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "google/gemini-4-argon",
"name": "(Wiro) Gemini 4 Argon",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1048576,
"maxOutputTokens": 65536
},
{
"id": "meta-llama/llama-3-2-3b-instruct",
"name": "(Wiro) Llama 3.2 3B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 51200,
"maxOutputTokens": 2048
},
{
"id": "mistralai/mistral-7b-instruct-v0-3",
"name": "(Wiro) Mistral 7B Instruct v0.3",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 17408,
"maxOutputTokens": 2048
},
{
"id": "mistralai/mistral-nemo-instruct-2407",
"name": "(Wiro) Mistral Nemo Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 35840,
"maxOutputTokens": 2048
},
{
"id": "openai/gpt-5-2",
"name": "(Wiro) GPT-5.2",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 400000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-4",
"name": "(Wiro) GPT-5.4",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-4-mini",
"name": "(Wiro) GPT-5.4 Mini",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 400000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-4-nano",
"name": "(Wiro) GPT-5.4 Nano",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 400000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-5",
"name": "(Wiro) GPT-5.5",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-6-luna",
"name": "(Wiro) GPT-5.6 Luna",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-6-sol",
"name": "(Wiro) GPT-5.6 Sol",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-6-terra",
"name": "(Wiro) GPT-5.6 Terra",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-mini",
"name": "(Wiro) GPT-5 Mini",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 400000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-5-nano",
"name": "(Wiro) GPT-5 Nano",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 400000,
"maxOutputTokens": 65536
},
{
"id": "openai/gpt-6-1-sol",
"name": "(Wiro) GPT-6.1 Sol",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 128000
},
{
"id": "openai/gpt-6-astra",
"name": "(Wiro) GPT-6 Astra",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 128000
},
{
"id": "openai/gpt-6-luna",
"name": "(Wiro) GPT-6 Luna",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 128000
},
{
"id": "openai/gpt-6-sol",
"name": "(Wiro) GPT-6 Sol",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 1050000,
"maxOutputTokens": 128000
},
{
"id": "qwen/qwen2-5-0-5b-instruct",
"name": "(Wiro) Qwen2.5 0.5B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 32768,
"maxOutputTokens": 2048
},
{
"id": "qwen/qwen2-5-1-5b-instruct",
"name": "(Wiro) Qwen2.5 1.5B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 32768,
"maxOutputTokens": 2048
},
{
"id": "qwen/qwen2-5-14b-instruct",
"name": "(Wiro) Qwen2.5 14B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 29696,
"maxOutputTokens": 2048
},
{
"id": "qwen/qwen2-5-32b-instruct",
"name": "(Wiro) Qwen2.5 32B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 17408,
"maxOutputTokens": 2048
},
{
"id": "qwen/qwen2-5-3b-instruct",
"name": "(Wiro) Qwen2.5 3B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 32768,
"maxOutputTokens": 2048
},
{
"id": "qwen/qwen2-5-7b-instruct",
"name": "(Wiro) Qwen2.5 7B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 32768,
"maxOutputTokens": 2048
},
{
"id": "qwen/qwen2-5-coder-32b-instruct",
"name": "(Wiro) Qwen2.5 Coder 32B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 17408,
"maxOutputTokens": 2048
},
{
"id": "qwen/qwen2-5-coder-7b-instruct",
"name": "(Wiro) Qwen2.5 Coder 7B Instruct",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 32768,
"maxOutputTokens": 2048
},
{
"id": "qwen/qwen3-30b-a3b",
"name": "(Wiro) Qwen3 30B A3B",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 7168,
"maxOutputTokens": 4096
},
{
"id": "qwen/qwen3-30b-a3b-thinking-2507",
"name": "(Wiro) Qwen3 30B A3B Thinking",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 7168,
"maxOutputTokens": 4096
},
{
"id": "qwen/qwen3-32b",
"name": "(Wiro) Qwen3 32B",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 17408,
"maxOutputTokens": 4096
},
{
"id": "qwen/qwen3-5-27b",
"name": "(Wiro) Qwen3.5 27B",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 25600,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-5-27b-heretic",
"name": "(Wiro) Qwen3.5 27B Heretic",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 25600,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-5-4b",
"name": "(Wiro) Qwen3.5 4B",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 72704,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-5-4b-heretic",
"name": "(Wiro) Qwen3.5 4B Heretic",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 72704,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-5-9b",
"name": "(Wiro) Qwen3.5 9B",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 25600,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-5-9b-heretic",
"name": "(Wiro) Qwen3.5 9B Heretic",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 25600,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-6-27b",
"name": "(Wiro) Qwen3.6 27B",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 25600,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-8-27b",
"name": "(Wiro) Qwen3.8 27B",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 25600,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-8-27b-obliterated",
"name": "(Wiro) Qwen3.8 27B Obliterated",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 25600,
"maxOutputTokens": 16384
},
{
"id": "qwen/qwen3-8-27b-uncensored",
"name": "(Wiro) Qwen3.8 27B Uncensored",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": false,
"maxInputTokens": 25600,
"maxOutputTokens": 16384
},
{
"id": "xai/grok-4-1-fast",
"name": "(Wiro) Grok 4.1 Fast",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 2000000,
"maxOutputTokens": 65536
},
{
"id": "xai/grok-4-20",
"name": "(Wiro) Grok 4.20",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 2000000,
"maxOutputTokens": 65536
},
{
"id": "xai/grok-4-5",
"name": "(Wiro) Grok 4.5",
"url": "https://llm.wiro.ai/v1/chat/completions",
"toolCalling": true,
"vision": true,
"maxInputTokens": 500000,
"maxOutputTokens": 65536
}
]
}
]
id— the lowercaseowner/modelfromGET /v1/models.name— a free label, shown in the picker.url— the full endpoint, not the base URL. Every model repeats it.toolCalling,vision,maxInputTokens,maxOutputTokens— read them fromGET /v1/models/{owner}/{model}:capabilities.function_tools,capabilities.input_modalities,max_input_tokens,max_tokens. Do not guess.maxInputTokensis not optional. VS Code sizes every conversation against it and answers “Could not compact conversation” on each turn when a model omits it, before any request reaches the gateway. Take the number frommax_input_tokens; every catalog model reports one. For a Wiro-hosted model the number is the input that deployment actually admits, measured on the running fleet — not the model family’s advertised maximum, and not the window of the checkpoint either. Qwen2.5 7B reports 32,768, which is what its shipped configuration sets although its card says 131,072; Qwen3.8 27B reports 25,600 even though the checkpoint it runs was built for 262,144, because that is roughly how much prompt fits beside the model on the GPUs that serve it. It is the lowest limit measured across them: most requests get somewhat more in and an occasional one slightly less, so leave some headroom. Send a Wiro-hosted model more than fits and the input is trimmed before the model sees it: the oldest history messages are dropped first, and if it still does not fit, the end of the latest user message is cut off. On a turn that returns tool results, nothing from the latest user message onward is cut; if dropping older history is not enough, the request is rejected withcontext_length_exceeded. Tool definitions are never trimmed, and neither is the system message, except on the two Mistral models: their chat format has no system role, so the system text travels with the oldest message and is dropped with it. Both count toward the limit. If even the question would be cut away entirely, the request is rejected withcontext_length_exceededand nothing is charged. In a long prompt, put the question at the start, so a cut takes the material after it rather than the question itself.
Save the file and reopen the model picker; the models appear under Wiro AI. Any other VS Code extension that takes a custom OpenAI base URL — Cline, Roo Code, Continue — works the same way: point it at https://llm.wiro.ai/v1 with the same credential and a model ID from the catalog.
Windsurf
Windsurf now ships as Devin Desktop; the application is Devin.app and its docs redirect to docs.devin.ai. Cascade, its own agent, has no setting for an external provider — there is no base URL to override and no custom model to register, so it cannot be pointed at this gateway. What does work is running a different agent inside the same editor. The steps below use Cline, which is free and Apache-2.0; Roo Code and Continue configure the same way.
-
Open the extension marketplace Command Palette (
Cmd+Shift+P,Ctrl+Shift+Pon Windows) →Extensions: Install Extensions. The menu bar gets you to the same place:Devin → Preferences → Extensions. -
Install Cline Search
clineand install the one published bysaoudrizwan. Devin resolves extensions through the Open VSX mirror, so this is the same build VS Code carries. -
Open the panel Command Palette (
Cmd+Shift+P,Ctrl+Shift+Pon Windows) →Cline: Focus on View. -
Bring my own API key Cline asks how you will use it. Pick the fourth option,
Bring my own API key, thenContinue. The other three are Cline's own billing;Login to Clineis not needed. -
API Provider Choose
OpenAI Compatible, notOpenAI— that one goes to the official OpenAI API. -
Base URL
https://llm.wiro.ai/v1. Cline appends the route itself. -
OpenAI Compatible API Key
YOUR_API_KEY:YOUR_API_SECRETfor a Signature project,YOUR_API_KEYalone for API Key Only. Cline keeps it locally. -
Model ID One ID from the list below — Cline holds a single model per configuration rather than a list. The
(Wiro)prefix is optional and the gateway strips it; it earns its place here by showing up in the status bar, asopenai-compat: (Wiro) openai/gpt-5-6-sol. -
Open
MODEL CONFIGURATIONand set the context window This one matters. Cline does not know a custom model, so it assumes128Kand starts dropping history long before it needs to. Put the real number from the list below intoContext Window size, and tickComputer Useso tool calling is enabled — without it the agent cannot run tools.Max Output Tokensand the price fields are in the same section. -
Continue, and send a message The status bar names the model you configured.
PlanandActcan each hold a different model, and saved API configuration profiles let you keep one per model and switch between them.
Every model the gateway serves today, with the context window Cline needs. The same numbers come from GET /v1/models as context_length and max_tokens.
Model ID Context Max Output
----------------------------------------------------------------
(Wiro) bytedance/seed-v2-1-turbo 256000 65536
(Wiro) bytedance/seed-v2-lite 256000 65536
(Wiro) bytedance/seed-v2-mini 256000 65536
(Wiro) bytedance/seed-v2-pro 256000 65536
(Wiro) claude/fable-5 1000000 128000
(Wiro) claude/fable-5-1 1000000 128000
(Wiro) claude/opus-5 1000000 128000
(Wiro) claude/opus-5-5 1000000 128000
(Wiro) claude/sonnet-5 1000000 128000
(Wiro) deepseek/v4-flash 1048576 384000
(Wiro) deepseek/v4-pro 1048576 384000
(Wiro) glm/5-2 1048576 128000
(Wiro) google/gemini-2-5-flash 1048576 65536
(Wiro) google/gemini-3-5-flash 1048576 65536
(Wiro) google/gemini-3-5-flash-lite 1048576 65536
(Wiro) google/gemini-3-6-flash 1048576 65536
(Wiro) google/gemini-3-7-flash 1048576 65536
(Wiro) google/gemini-3-8-flash 1048576 65536
(Wiro) google/gemini-3-flash 1048576 65536
(Wiro) google/gemini-3-pro 1048576 65536
(Wiro) google/gemini-4-argon 1048576 65536
(Wiro) meta-llama/llama-3-2-3b-instruct 51200 2048
(Wiro) mistralai/mistral-7b-instruct-v0-3 17408 2048
(Wiro) mistralai/mistral-nemo-instruct-2407 35840 2048
(Wiro) openai/gpt-5-2 400000 65536
(Wiro) openai/gpt-5-4 1050000 65536
(Wiro) openai/gpt-5-4-mini 400000 65536
(Wiro) openai/gpt-5-4-nano 400000 65536
(Wiro) openai/gpt-5-5 1050000 65536
(Wiro) openai/gpt-5-6-luna 1050000 65536
(Wiro) openai/gpt-5-6-sol 1050000 65536
(Wiro) openai/gpt-5-6-terra 1050000 65536
(Wiro) openai/gpt-5-mini 400000 65536
(Wiro) openai/gpt-5-nano 400000 65536
(Wiro) openai/gpt-6-1-sol 1050000 128000
(Wiro) openai/gpt-6-astra 1050000 128000
(Wiro) openai/gpt-6-luna 1050000 128000
(Wiro) openai/gpt-6-sol 1050000 128000
(Wiro) qwen/qwen2-5-0-5b-instruct 32768 2048
(Wiro) qwen/qwen2-5-1-5b-instruct 32768 2048
(Wiro) qwen/qwen2-5-14b-instruct 29696 2048
(Wiro) qwen/qwen2-5-32b-instruct 17408 2048
(Wiro) qwen/qwen2-5-3b-instruct 32768 2048
(Wiro) qwen/qwen2-5-7b-instruct 32768 2048
(Wiro) qwen/qwen2-5-coder-32b-instruct 17408 2048
(Wiro) qwen/qwen2-5-coder-7b-instruct 32768 2048
(Wiro) qwen/qwen3-30b-a3b 7168 4096
(Wiro) qwen/qwen3-30b-a3b-thinking-2507 7168 4096
(Wiro) qwen/qwen3-32b 17408 4096
(Wiro) qwen/qwen3-5-27b 25600 16384
(Wiro) qwen/qwen3-5-27b-heretic 25600 16384
(Wiro) qwen/qwen3-5-4b 72704 16384
(Wiro) qwen/qwen3-5-4b-heretic 72704 16384
(Wiro) qwen/qwen3-5-9b 25600 16384
(Wiro) qwen/qwen3-5-9b-heretic 25600 16384
(Wiro) qwen/qwen3-6-27b 25600 16384
(Wiro) qwen/qwen3-8-27b 25600 16384
(Wiro) qwen/qwen3-8-27b-obliterated 25600 16384
(Wiro) qwen/qwen3-8-27b-uncensored 25600 16384
(Wiro) xai/grok-4-1-fast 2000000 65536
(Wiro) xai/grok-4-20 2000000 65536
(Wiro) xai/grok-4-5 500000 65536
None of this touches Cascade, which keeps using Windsurf's own models. The editor is Devin, the agent is Cline, and the models are Wiro's.
OpenClaw
OpenClaw registers the gateway as a custom provider in its own config file. Everything below lives in one file:
~/.openclaw/openclaw.json macOS, Linux
%USERPROFILE%\.openclaw\openclaw.json Windows
Set OPENCLAW_CONFIG_PATH to put it elsewhere, or run openclaw --profile <name> to keep a separate one under ~/.openclaw-<name>.
-
Install
npm i -g openclaw. -
Name the provider The key under
providers—wirobelow — becomes the prefix you select a model with, aswiro/<id>. Pick any name; the rest of this page assumeswiro. -
Match
apito the model transport Read it fromGET /v1/models/{owner}/{model}.openai-completionsandopenai-responsestake the/v1base;anthropic-messagestakes the origin,https://llm.wiro.ai, with no/v1. One provider block per transport if you mix them. -
Fill
apiKeyYOUR_API_KEY:YOUR_API_SECRETfor a Signature project,YOUR_API_KEYalone for API Key Only. -
List the models Each entry takes an
idand a displayname. Theidis what reaches the gateway, so the(Wiro)label is optional there and stripped on arrival; thenameis only ever shown to you. Both carry it below so the CLI and the picker read the same. -
Run a turn
openclaw agent --local --model "wiro/(Wiro) xai/grok-4-1-fast" -m "your prompt".--localruns the embedded agent against these credentials; without it the turn goes through an OpenClaw gateway instead.
Every model the gateway serves today, ready to paste as the whole models array. The same set is in the catalog and behind GET /v1/models.
{
"models": {
"providers": {
"wiro": {
"baseUrl": "https://llm.wiro.ai/v1",
"apiKey": "YOUR_API_KEY:YOUR_API_SECRET",
"api": "openai-completions",
"models": [
{ "id": "(Wiro) bytedance/seed-v2-1-turbo", "name": "(Wiro) Seed V2.1 Turbo" },
{ "id": "(Wiro) bytedance/seed-v2-lite", "name": "(Wiro) Seed V2 Lite" },
{ "id": "(Wiro) bytedance/seed-v2-mini", "name": "(Wiro) Seed V2 Mini" },
{ "id": "(Wiro) bytedance/seed-v2-pro", "name": "(Wiro) Seed V2 Pro" },
{ "id": "(Wiro) claude/fable-5", "name": "(Wiro) Fable 5" },
{ "id": "(Wiro) claude/fable-5-1", "name": "(Wiro) Fable 5.1" },
{ "id": "(Wiro) claude/opus-5", "name": "(Wiro) Opus 5" },
{ "id": "(Wiro) claude/opus-5-5", "name": "(Wiro) Opus 5.5" },
{ "id": "(Wiro) claude/sonnet-5", "name": "(Wiro) Sonnet 5" },
{ "id": "(Wiro) deepseek/v4-flash", "name": "(Wiro) DeepSeek V4 Flash" },
{ "id": "(Wiro) deepseek/v4-pro", "name": "(Wiro) DeepSeek V4 Pro" },
{ "id": "(Wiro) glm/5-2", "name": "(Wiro) GLM 5.2" },
{ "id": "(Wiro) google/gemini-2-5-flash", "name": "(Wiro) Gemini 2.5 Flash" },
{ "id": "(Wiro) google/gemini-3-5-flash", "name": "(Wiro) Gemini 3.5 Flash" },
{ "id": "(Wiro) google/gemini-3-5-flash-lite", "name": "(Wiro) Gemini 3.5 Flash-Lite" },
{ "id": "(Wiro) google/gemini-3-6-flash", "name": "(Wiro) Gemini 3.6 Flash" },
{ "id": "(Wiro) google/gemini-3-7-flash", "name": "(Wiro) Gemini 3.7 Flash" },
{ "id": "(Wiro) google/gemini-3-8-flash", "name": "(Wiro) Gemini 3.8 Flash" },
{ "id": "(Wiro) google/gemini-3-flash", "name": "(Wiro) Gemini 3 Flash" },
{ "id": "(Wiro) google/gemini-3-pro", "name": "(Wiro) Gemini 3 Pro" },
{ "id": "(Wiro) google/gemini-4-argon", "name": "(Wiro) Gemini 4 Argon" },
{ "id": "(Wiro) meta-llama/llama-3-2-3b-instruct", "name": "(Wiro) Llama 3.2 3B Instruct" },
{ "id": "(Wiro) mistralai/mistral-7b-instruct-v0-3", "name": "(Wiro) Mistral 7B Instruct v0.3" },
{ "id": "(Wiro) mistralai/mistral-nemo-instruct-2407", "name": "(Wiro) Mistral Nemo Instruct" },
{ "id": "(Wiro) openai/gpt-5-2", "name": "(Wiro) GPT-5.2" },
{ "id": "(Wiro) openai/gpt-5-4", "name": "(Wiro) GPT-5.4" },
{ "id": "(Wiro) openai/gpt-5-4-mini", "name": "(Wiro) GPT-5.4 Mini" },
{ "id": "(Wiro) openai/gpt-5-4-nano", "name": "(Wiro) GPT-5.4 Nano" },
{ "id": "(Wiro) openai/gpt-5-5", "name": "(Wiro) GPT-5.5" },
{ "id": "(Wiro) openai/gpt-5-6-luna", "name": "(Wiro) GPT-5.6 Luna" },
{ "id": "(Wiro) openai/gpt-5-6-sol", "name": "(Wiro) GPT-5.6 Sol" },
{ "id": "(Wiro) openai/gpt-5-6-terra", "name": "(Wiro) GPT-5.6 Terra" },
{ "id": "(Wiro) openai/gpt-5-mini", "name": "(Wiro) GPT-5 Mini" },
{ "id": "(Wiro) openai/gpt-5-nano", "name": "(Wiro) GPT-5 Nano" },
{ "id": "(Wiro) openai/gpt-6-1-sol", "name": "(Wiro) GPT-6.1 Sol" },
{ "id": "(Wiro) openai/gpt-6-astra", "name": "(Wiro) GPT-6 Astra" },
{ "id": "(Wiro) openai/gpt-6-luna", "name": "(Wiro) GPT-6 Luna" },
{ "id": "(Wiro) openai/gpt-6-sol", "name": "(Wiro) GPT-6 Sol" },
{ "id": "(Wiro) qwen/qwen2-5-0-5b-instruct", "name": "(Wiro) Qwen2.5 0.5B Instruct" },
{ "id": "(Wiro) qwen/qwen2-5-1-5b-instruct", "name": "(Wiro) Qwen2.5 1.5B Instruct" },
{ "id": "(Wiro) qwen/qwen2-5-14b-instruct", "name": "(Wiro) Qwen2.5 14B Instruct" },
{ "id": "(Wiro) qwen/qwen2-5-32b-instruct", "name": "(Wiro) Qwen2.5 32B Instruct" },
{ "id": "(Wiro) qwen/qwen2-5-3b-instruct", "name": "(Wiro) Qwen2.5 3B Instruct" },
{ "id": "(Wiro) qwen/qwen2-5-7b-instruct", "name": "(Wiro) Qwen2.5 7B Instruct" },
{ "id": "(Wiro) qwen/qwen2-5-coder-32b-instruct", "name": "(Wiro) Qwen2.5 Coder 32B Instruct" },
{ "id": "(Wiro) qwen/qwen2-5-coder-7b-instruct", "name": "(Wiro) Qwen2.5 Coder 7B Instruct" },
{ "id": "(Wiro) qwen/qwen3-30b-a3b", "name": "(Wiro) Qwen3 30B A3B" },
{ "id": "(Wiro) qwen/qwen3-30b-a3b-thinking-2507", "name": "(Wiro) Qwen3 30B A3B Thinking" },
{ "id": "(Wiro) qwen/qwen3-32b", "name": "(Wiro) Qwen3 32B" },
{ "id": "(Wiro) qwen/qwen3-5-27b", "name": "(Wiro) Qwen3.5 27B" },
{ "id": "(Wiro) qwen/qwen3-5-27b-heretic", "name": "(Wiro) Qwen3.5 27B Heretic" },
{ "id": "(Wiro) qwen/qwen3-5-4b", "name": "(Wiro) Qwen3.5 4B" },
{ "id": "(Wiro) qwen/qwen3-5-4b-heretic", "name": "(Wiro) Qwen3.5 4B Heretic" },
{ "id": "(Wiro) qwen/qwen3-5-9b", "name": "(Wiro) Qwen3.5 9B" },
{ "id": "(Wiro) qwen/qwen3-5-9b-heretic", "name": "(Wiro) Qwen3.5 9B Heretic" },
{ "id": "(Wiro) qwen/qwen3-6-27b", "name": "(Wiro) Qwen3.6 27B" },
{ "id": "(Wiro) qwen/qwen3-8-27b", "name": "(Wiro) Qwen3.8 27B" },
{ "id": "(Wiro) qwen/qwen3-8-27b-obliterated", "name": "(Wiro) Qwen3.8 27B Obliterated" },
{ "id": "(Wiro) qwen/qwen3-8-27b-uncensored", "name": "(Wiro) Qwen3.8 27B Uncensored" },
{ "id": "(Wiro) xai/grok-4-1-fast", "name": "(Wiro) Grok 4.1 Fast" },
{ "id": "(Wiro) xai/grok-4-20", "name": "(Wiro) Grok 4.20" },
{ "id": "(Wiro) xai/grok-4-5", "name": "(Wiro) Grok 4.5" }
]
}
}
}
}
Tool calling works through the gateway, so the agent can run its own tools across as many turns as the task needs.
Hermes
Hermes Agent, from Nous Research, reaches the gateway as a custom provider. Its whole configuration is one file:
~/.hermes/config.yaml
Set HERMES_HOME to put it elsewhere; the project’s own Docker image already points it at /opt/data. The file the repository ships as cli-config.yaml.example is read under the name config.yaml.
-
Install
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bashon macOS, Linux and WSL2;iex (irm https://hermes-agent.nousresearch.com/install.ps1)in PowerShell. The repository also carries aDockerfileand adocker-compose.yml. -
Choose the custom provider
provider: "custom"is Hermes’ name for any OpenAI-compatible endpoint —ollama,vllmandllamacppare aliases of it. With it,base_urlis what decides where the request goes. -
Fill
api_keyYOUR_API_KEY:YOUR_API_SECRETfor a Signature project,YOUR_API_KEYalone for API Key Only. -
Name the model
model.defaulttakes one ID from the list below. Hermes holds a single default rather than a list, so the(Wiro)label is there for your own benefit; the gateway strips it either way. -
Run a turn
hermes -z "your prompt"for one shot,hermes chatfor a session. Add--yolowhen you want the agent to use its tools without stopping for approval. -
Switch models
hermes -m "(Wiro) xai/grok-4-1-fast" -z "your prompt"overrides the default for one run;hermes modelchanges it for good.
model:
default: "(Wiro) openai/gpt-5-6-sol"
provider: "custom"
base_url: "https://llm.wiro.ai/v1"
api_key: "YOUR_API_KEY:YOUR_API_SECRET"
Every model the gateway serves today. The same set is in the catalog and behind GET /v1/models.
(Wiro) bytedance/seed-v2-1-turbo
(Wiro) bytedance/seed-v2-lite
(Wiro) bytedance/seed-v2-mini
(Wiro) bytedance/seed-v2-pro
(Wiro) claude/fable-5
(Wiro) claude/fable-5-1
(Wiro) claude/opus-5
(Wiro) claude/opus-5-5
(Wiro) claude/sonnet-5
(Wiro) deepseek/v4-flash
(Wiro) deepseek/v4-pro
(Wiro) glm/5-2
(Wiro) google/gemini-2-5-flash
(Wiro) google/gemini-3-5-flash
(Wiro) google/gemini-3-5-flash-lite
(Wiro) google/gemini-3-6-flash
(Wiro) google/gemini-3-7-flash
(Wiro) google/gemini-3-8-flash
(Wiro) google/gemini-3-flash
(Wiro) google/gemini-3-pro
(Wiro) google/gemini-4-argon
(Wiro) meta-llama/llama-3-2-3b-instruct
(Wiro) mistralai/mistral-7b-instruct-v0-3
(Wiro) mistralai/mistral-nemo-instruct-2407
(Wiro) openai/gpt-5-2
(Wiro) openai/gpt-5-4
(Wiro) openai/gpt-5-4-mini
(Wiro) openai/gpt-5-4-nano
(Wiro) openai/gpt-5-5
(Wiro) openai/gpt-5-6-luna
(Wiro) openai/gpt-5-6-sol
(Wiro) openai/gpt-5-6-terra
(Wiro) openai/gpt-5-mini
(Wiro) openai/gpt-5-nano
(Wiro) openai/gpt-6-1-sol
(Wiro) openai/gpt-6-astra
(Wiro) openai/gpt-6-luna
(Wiro) openai/gpt-6-sol
(Wiro) qwen/qwen2-5-0-5b-instruct
(Wiro) qwen/qwen2-5-1-5b-instruct
(Wiro) qwen/qwen2-5-14b-instruct
(Wiro) qwen/qwen2-5-32b-instruct
(Wiro) qwen/qwen2-5-3b-instruct
(Wiro) qwen/qwen2-5-7b-instruct
(Wiro) qwen/qwen2-5-coder-32b-instruct
(Wiro) qwen/qwen2-5-coder-7b-instruct
(Wiro) qwen/qwen3-30b-a3b
(Wiro) qwen/qwen3-30b-a3b-thinking-2507
(Wiro) qwen/qwen3-32b
(Wiro) qwen/qwen3-5-27b
(Wiro) qwen/qwen3-5-27b-heretic
(Wiro) qwen/qwen3-5-4b
(Wiro) qwen/qwen3-5-4b-heretic
(Wiro) qwen/qwen3-5-9b
(Wiro) qwen/qwen3-5-9b-heretic
(Wiro) qwen/qwen3-6-27b
(Wiro) qwen/qwen3-8-27b
(Wiro) qwen/qwen3-8-27b-obliterated
(Wiro) qwen/qwen3-8-27b-uncensored
(Wiro) xai/grok-4-1-fast
(Wiro) xai/grok-4-20
(Wiro) xai/grok-4-5
Tool calling works through the gateway, so the agent can run its own tools across as many turns as the task needs.
OpenAI SDK
The official openai package talks to the gateway unchanged — only baseURL moves. Everything below was run against every model the gateway serves.
-
Install
npm i openai. The Python package works the same way withbase_url. -
Point the client at the gateway
baseURLishttps://llm.wiro.ai/v1.apiKeytakesYOUR_API_KEY:YOUR_API_SECRETfor a Signature project,YOUR_API_KEYalone for API Key Only. -
Name a model Any ID from the list below. The
(Wiro)label is optional and stripped on arrival, soopenai/gpt-5-6-solworks just as well. -
Give reasoning models room
max_completion_tokenscovers reasoning as well as the answer. Too small a budget returnsfinish_reason: "length"with empty content — not an error, just a spent budget. 512 is a safe floor, more for long answers.
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY:YOUR_API_SECRET",
baseURL: "https://llm.wiro.ai/v1",
});
const completion = await client.chat.completions.create({
model: "(Wiro) openai/gpt-5-6-sol",
max_completion_tokens: 512,
messages: [{ role: "user", content: "Hello" }],
});
console.log(completion.choices[0].message.content);
client.models.list() returns the same catalog, and client.responses.create() reaches the Responses route. Streaming works on both.
Tool calling runs the whole loop — the call, the result, and further turns after it:
const tools = [{
type: "function",
function: {
name: "get_weather",
description: "Get weather",
parameters: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
},
},
}];
const messages = [{ role: "user", content: "Weather in Istanbul?" }];
const first = await client.chat.completions.create({
model: "(Wiro) openai/gpt-5-6-sol", max_completion_tokens: 512, tools, messages,
});
const call = first.choices[0].message.tool_calls[0];
messages.push(first.choices[0].message, {
role: "tool",
tool_call_id: call.id,
content: JSON.stringify({ temperature_c: 21 }),
});
const second = await client.chat.completions.create({
model: "(Wiro) openai/gpt-5-6-sol", max_completion_tokens: 512, tools, messages,
});
Every model the gateway serves today. The same set is in the catalog and behind GET /v1/models.
(Wiro) bytedance/seed-v2-1-turbo
(Wiro) bytedance/seed-v2-lite
(Wiro) bytedance/seed-v2-mini
(Wiro) bytedance/seed-v2-pro
(Wiro) claude/fable-5
(Wiro) claude/fable-5-1
(Wiro) claude/opus-5
(Wiro) claude/opus-5-5
(Wiro) claude/sonnet-5
(Wiro) deepseek/v4-flash
(Wiro) deepseek/v4-pro
(Wiro) glm/5-2
(Wiro) google/gemini-2-5-flash
(Wiro) google/gemini-3-5-flash
(Wiro) google/gemini-3-5-flash-lite
(Wiro) google/gemini-3-6-flash
(Wiro) google/gemini-3-7-flash
(Wiro) google/gemini-3-8-flash
(Wiro) google/gemini-3-flash
(Wiro) google/gemini-3-pro
(Wiro) google/gemini-4-argon
(Wiro) meta-llama/llama-3-2-3b-instruct
(Wiro) mistralai/mistral-7b-instruct-v0-3
(Wiro) mistralai/mistral-nemo-instruct-2407
(Wiro) openai/gpt-5-2
(Wiro) openai/gpt-5-4
(Wiro) openai/gpt-5-4-mini
(Wiro) openai/gpt-5-4-nano
(Wiro) openai/gpt-5-5
(Wiro) openai/gpt-5-6-luna
(Wiro) openai/gpt-5-6-sol
(Wiro) openai/gpt-5-6-terra
(Wiro) openai/gpt-5-mini
(Wiro) openai/gpt-5-nano
(Wiro) openai/gpt-6-1-sol
(Wiro) openai/gpt-6-astra
(Wiro) openai/gpt-6-luna
(Wiro) openai/gpt-6-sol
(Wiro) qwen/qwen2-5-0-5b-instruct
(Wiro) qwen/qwen2-5-1-5b-instruct
(Wiro) qwen/qwen2-5-14b-instruct
(Wiro) qwen/qwen2-5-32b-instruct
(Wiro) qwen/qwen2-5-3b-instruct
(Wiro) qwen/qwen2-5-7b-instruct
(Wiro) qwen/qwen2-5-coder-32b-instruct
(Wiro) qwen/qwen2-5-coder-7b-instruct
(Wiro) qwen/qwen3-30b-a3b
(Wiro) qwen/qwen3-30b-a3b-thinking-2507
(Wiro) qwen/qwen3-32b
(Wiro) qwen/qwen3-5-27b
(Wiro) qwen/qwen3-5-27b-heretic
(Wiro) qwen/qwen3-5-4b
(Wiro) qwen/qwen3-5-4b-heretic
(Wiro) qwen/qwen3-5-9b
(Wiro) qwen/qwen3-5-9b-heretic
(Wiro) qwen/qwen3-6-27b
(Wiro) qwen/qwen3-8-27b
(Wiro) qwen/qwen3-8-27b-obliterated
(Wiro) qwen/qwen3-8-27b-uncensored
(Wiro) xai/grok-4-1-fast
(Wiro) xai/grok-4-20
(Wiro) xai/grok-4-5
Discover models and capabilities
GET /v1/models
curl "https://llm.wiro.ai/v1/models?search=openai%2Fgpt-5-6-sol&limit=1" \
-H "Authorization: Bearer YOUR_API_KEY"
GET /v1/chat/models returns the same authenticated list. The gateway catalog is separate from the full catalog at POST /v1/Tool/List.
{
"object": "list",
"data": [
{
"id": "openai/gpt-5-6-sol",
"canonical_slug": "openai/gpt-5-6-sol",
"name": "(Wiro) GPT 5.6 Sol by OpenAI (Vision)",
"description": "OpenAI’s GPT 5.6 Sol is a flagship reasoning model that can analyze images and produce detailed text answers for coding, research, and visual Q&A.",
"context_length": 1050000,
"architecture": {
"modality": "text+image+file->text",
"input_modalities": ["text", "image", "file"],
"output_modalities": ["text"]
},
"pricing": {
"prompt": "0.000005",
"completion": "0.00003"
},
"top_provider": {
"context_length": 1050000,
"max_completion_tokens": 65536
},
"supported_parameters": [
"max_completion_tokens",
"max_tokens",
"parallel_tool_calls",
"reasoning_effort",
"response_format",
"structured_outputs",
"tool_choice",
"tools"
],
"default_parameters": {},
"object": "model",
"type": "model",
"created": 1783670833,
"created_at": "2026-07-10T08:07:13.000Z",
"owned_by": "openai",
"display_name": "(Wiro) GPT 5.6 Sol by OpenAI (Vision)",
"max_input_tokens": 1050000,
"max_tokens": 65536,
"capabilities": {
"endpoints": ["anthropic", "chat", "responses"],
"input_modalities": ["text", "image", "document"],
"output": ["text", "function_calls", "custom_tool_calls"],
"function_tools": true,
"custom_tools": true,
"structured_outputs": true,
"structured_output_modes": ["json_object", "json_schema"],
"strict_json_schema": true,
"generation_controls": ["max_output_tokens", "reasoning_effort", "verbosity"]
},
"x_wiro": {
"pricing_source": {
"name": "wiro-pricing-catalog",
"schema_version": 1,
"revision": "3a2430b5188fcaf69b5d7af1cb40d0a59062cc37",
"sha256": "f74c5d378dfd8b28360b2464dc2590711550df501a7c6c7f9b673db105f7798f",
"source_model": "openai/gpt-5.6-sol",
"basis": "local-rate"
},
"pricing_tiers": null
}
}
],
"total_count": 1,
"links": {
"next": null
},
"has_more": false,
"first_id": "openai/gpt-5-6-sol",
"last_id": "openai/gpt-5-6-sol"
}
The example is intentionally explicit about nullable values that have a Wiro source. Context, modalities, and pricing come from the audited local gateway catalog; live Run parameters and capability flags come from the selected model's current Tool/Detail contract. Fields without a Wiro source are omitted instead of being copied from OpenRouter with null placeholders. pricing.prompt and pricing.completion are USD-per-token strings. Models with tiered rates expose those exact bands in x_wiro.pricing_tiers. Pricing and context fields can be null for catalog entries without audited local metadata.
The list accepts:
search(at most 256 bytes),order=asc|desc, andlimit=1..1000after/after_idorbefore/before_idcursors
The default order is ascending and the default limit is 1000. total_count counts the filtered catalog. links.next is a relative next-page URL or null.
The discovery list contains the models verified with the llm-tool-call category. It is not filtered by team Model Access: a model your team blocks is still listed, but calling it fails. Other LLMs are not advertised by this endpoint; when you already know an exact owner/model ID, you can still submit it to a compatible Direct LLM route or use the normal Run API.
Before each request:
- Confirm
anthropic,chat, orresponsesincapabilities.endpoints. - Use
supported_parametersto gate optional public request controls. Required protocol fields such asmodel,input,messages, or Anthropicmax_tokensare not repeated there. - Check
capabilities.input_modalitiesfor canonicaltext,image, ordocument. OpenRouter-stylearchitecture.input_modalitiesrepresents documents asfile. - Check
capabilities.output,function_tools,custom_tools,structured_outputs,structured_output_modes,strict_json_schema, andgeneration_controls. - Treat
context_length,max_input_tokens,max_tokens, pricing, and usage as model-specific. A nullable field is not permission to infer a value from another model.
Every discoverable model currently publishes the same endpoint labels. Capability differences are expressed through modalities, supported parameters, tool flags, structured-output flags, reasoning controls, and limits.
Structured-output support is per model, not per family: read structured_output_modes and strict_json_schema on the model you are about to call. Some models declare both json_object and json_schema, some declare only one of them, and some declare no structured output at all. A model whose runtime cannot constrain decoding can promise a valid JSON document but nothing about the schema, so it declares json_object alone. strict_json_schema is separate again: a model can accept json_schema and still refuse "strict": true.
GET /v1/models/{owner}/{model}
curl "https://llm.wiro.ai/v1/models/openai/gpt-5-6-sol" \
-H "Authorization: Bearer YOUR_API_KEY"
The detail route returns the same complete model object as the matching list entry. Query parameters are rejected on detail routes. An unavailable or non-gateway model returns model_not_found without exposing private catalog state. Team Model Access is checked when the model runs, not on this route.
Generic finite task completion
POST /v1/Run/{owner}/{project}/sync lives on https://api.wiro.ai/v1, not this gateway. See Run a Model for JSON wait, SSE, and timeout recovery. Direct LLM clients should use Chat, Responses, or Messages below.
Usage contract
When the upstream model reports usage, Wiro returns normalized counters in the selected protocol's native shape:
- Chat uses
prompt_tokens, optionalprompt_tokens_details,completion_tokens, optionalcompletion_tokens_details, andtotal_tokens. - Responses uses
input_tokens,input_tokens_details,output_tokens,output_tokens_details, andtotal_tokens. - Anthropic Messages uses cache-exclusive
input_tokens,output_tokens, optionalcache_read_input_tokens, optionalcache_creation_input_tokens, and optional five-minute/one-hourcache_creationdetail.
For Chat and Responses, input/prompt totals are cache-inclusive. Their input detail objects (optional on Chat, always present on Responses) can identify cached_tokens, cache_write_tokens, cache_write_5m_tokens, cache_write_1h_tokens, and reported text/audio/image/video tokens. Output/completion totals are reasoning-inclusive; the corresponding output detail can identify reasoning_tokens, reported text/audio/image/video tokens, and accepted/rejected prediction tokens. Cache TTL values are subsets of cache_write_tokens, and all detail counters are already included in their parent total. Never add them to total_tokens.
There is intentionally no cached_output_tokens field. Provider prompt caches reuse input context; they do not report previously generated output as cached output usage.
Optional server_tool_use values count requests, not tokens. Providers omit unsupported counters, so clients must not require every detail key. Chat and Responses expose Wiro's billed amount as usage.cost; Anthropic exposes it as usage.cost_usd. The asynchronous Run/Task contract keeps the billed amount at task-level totalcost.
Files compatibility
The gateway's Files routes are a compatibility view over the authenticated Wiro project's existing upload folder. Uploads, lists, retrieval, and deletion use the same storage as File/Upload, File/List, and File/Delete on api.wiro.ai; the gateway does not create a second file database.
The supported routes are:
| Method | Route | Behavior |
|---|---|---|
| POST | /v1/files |
Uploads one multipart field named file |
| GET | /v1/files |
Lists files in the authenticated project's upload folder |
| GET | /v1/files/{file_id} |
Returns file metadata |
| GET | /v1/files/{file_id}/content |
Checks ownership, then redirects with 307 to the validated public CDN URL |
| DELETE | /v1/files/{file_id} |
Deletes the project file |
File IDs use file-... form and are valid only inside the project whose credentials created or listed them. A missing, deleted, or foreign ID returns file_not_found; the gateway never falls back to another project.
OpenAI Files
OpenAI clients use Bearer authentication. The only supported OpenAI purpose is assistants:
import fs from 'node:fs';
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.WIRO_BEARER_CREDENTIAL,
baseURL: 'https://llm.wiro.ai/v1',
});
const file = await client.files.create({
file: fs.createReadStream('input.png'),
purpose: 'assistants',
});
const page = await client.files.list({ limit: 20, order: 'desc' });
const metadata = await client.files.retrieve(file.id);
const content = await client.files.content(file.id);
await client.files.delete(file.id);
OpenAI list queries accept after/after_id, before/before_id, limit=1..1000, order=asc|desc, and purpose=assistants. The default limit is 20 and the default order is descending. File metadata uses OpenAI's object: "file", bytes, Unix created_at, filename, purpose, status, and status_details fields.
Anthropic Files
Anthropic SDKs use origin https://llm.wiro.ai and send the required anthropic-version: 2023-06-01 header; that header selects the Anthropic file metadata shape:
import fs from 'node:fs';
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
baseURL: 'https://llm.wiro.ai',
apiKey: process.env.WIRO_API_KEY,
});
const file = await client.files.upload({
file: fs.createReadStream('context.pdf'),
});
const page = await client.files.list({ limit: 20 });
const metadata = await client.files.retrieveMetadata(file.id);
const content = await client.files.download(file.id);
await client.files.delete(file.id);
Anthropic list queries accept page, legacy after_id/before_id, and limit=1..1000. The response includes next_page, has_more, first_id, and last_id. Metadata uses ISO created_at, filename, mime_type, size_bytes, type: "file", downloadable, and expires_at. Wiro-backed files do not expire, so expires_at is null.
Limits and model input
Gateway uploads are limited to 50 MiB per file. Empty files, multiple file parts, unknown multipart fields, and filenames over 1024 bytes are rejected. ZIP uploads are rejected because Wiro's standard File API extracts archives, which cannot represent the one-upload/one-file contract expected by these SDKs. The compatibility catalog reads at most 10,000 project files; that safety bound is not a storage quota. The original Wiro File API has its own documented limits.
Use the returned ID only where the selected protocol accepts file references. For example, OpenAI Responses image input can use { "type": "input_image", "file_id": "file-..." }, while Anthropic document input uses { "type": "file", "file_id": "file-..." } inside its source object. Before Run, the gateway verifies project ownership and MIME type, then replaces the Wiro file ID with its existing public URL. Image references accept GIF, JPEG, PNG, or WebP; document references accept PDF or plain text. Invalid MIME combinations return invalid_media_type before model execution.
Public HTTPS URLs and validated data/base64 content remain available when the model advertises the corresponding modality. A Wiro file-... ID is not a provider file ID and is never forwarded to OpenAI, Anthropic, xAI, or another provider.
OpenAI Chat Completions
POST /v1/chat/completions
Use a model that includes chat in capabilities.endpoints.
curl -X POST "https://llm.wiro.ai/v1/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5-6-sol",
"messages": [
{ "role": "system", "content": "You are a concise assistant." },
{ "role": "user", "content": "What is SSE?" }
],
"stream": false
}'
The endpoint accepts system, developer, user, and assistant messages, plus tool results for preceding assistant tool calls. Each request is client-history: send the required conversation history in messages. Calls do not create a saved Wiro Chat session.
Text is always available. OpenAI-style image and document content parts are accepted only when the selected model advertises those input modalities. Gateway output is text; this route is not an image, audio, or video generation API. Remote media must use a public HTTPS URL or a validated data/base64 source; supported Wiro gateway file IDs may also be used. Private-network and non-HTTP fetch targets are rejected. Provider-native file IDs are not accepted as Wiro file IDs.
Generation fields such as temperature, top_p, max_tokens, max_completion_tokens, penalties, seed, stop, reasoning, and response_format are capability-gated. n must be 1, logprobs must be false, and stop accepts at most four non-empty values without semicolons. Use capabilities.structured_outputs before requesting a non-text response_format, then match the exact mode: json_object and json_schema are declared independently in capabilities.structured_output_modes, and "strict": true inside a json_schema request additionally requires capabilities.strict_json_schema. A mode the model does not declare is refused with HTTP 400, code unsupported_capability and param: "response_format", before any task is created or billed.
Structured output uses OpenAI's two response_format shapes. json_object asks only for a valid JSON document:
{ "response_format": { "type": "json_object" } }
json_schema is nested: the definition sits under a json_schema key rather than beside type.
{
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "person",
"schema": {
"type": "object",
"properties": { "full_name": { "type": "string" } },
"required": ["full_name"],
"additionalProperties": false
},
"strict": true
}
}
}
The definition accepts name, schema, description, and strict, and rejects any other key. name is required and must match ^[A-Za-z0-9_-]{1,64}$; a missing or invalid name returns invalid_schema. schema must have an object root, may reference only local # fragments, and may nest at most 24 levels. json_object guarantees parseable JSON but guarantees nothing about which keys appear, so use json_schema when the key names matter.
Standard function tools use tools, tool_choice, and parallel_tool_calls. Returned function calls use { "id": "...", "type": "function", "function": { "name": "...", "arguments": "..." } } entries in message.tool_calls. Execute calls only when finish_reason is tool_calls; length and content_filter turns can contain partial tool data that must not be executed. Preserve the returned assistant message unchanged, then append matching role: "tool" results with tool_call_id. Wiro does not execute tools on the caller's behalf.
When the model advertises custom_tools, Chat also accepts the nested custom tool shape:
{
"type": "custom",
"custom": {
"name": "airport_code",
"format": {
"type": "grammar",
"syntax": "regex",
"definition": "[A-Z]{3}"
}
}
}
Use a matching nested custom tool_choice. Returned custom calls use { "id": "...", "type": "custom", "custom": { "name": "...", "input": "..." } } entries in message.tool_calls. Execute them client-side and append role: "tool" results with the same tool_call_id, just as for function calls.
Reasoning is model-specific. Public model reasoning can appear in message.reasoning and message.reasoning_details; use the advertised reasoning controls and supported efforts. Tool/reasoning combinations are also model-specific, so do not infer support from another model.
Final responses use chat.completion. Native usage is conditional: a successful completion is still returned when usage counters remain unavailable.
For streaming, set body-level "stream": true. Text arrives in choices[0].delta.content, reasoning in delta.reasoning and reasoning_details, and function calls in delta.tool_calls. Concatenate tool argument fragments by call index. The stream terminates with data: [DONE]. With stream_options.include_usage: true, Wiro emits a final empty-choices usage chunk before [DONE] only when native counters are available.
If a failure happens after Chat SSE has started, Wiro emits an OpenAI error object in a data: frame, then data: [DONE], and closes the connection.
The official openai package reaches this route with nothing changed but baseURL; the full setup, with tool calling and the model list, is under OpenAI SDK above.
OpenAI Responses
POST /v1/responses
Use a model that includes responses in capabilities.endpoints. input can be a string or Responses items; instructions, tools, text.format structured output, multimodal input, reasoning, and generation controls are capability-gated. Remote media follows the same public-HTTPS/data/base64/Wiro-file-ID restrictions as Chat.
curl -X POST "https://llm.wiro.ai/v1/responses" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5-6-sol",
"instructions": "Answer in one paragraph.",
"input": "Explain server-sent events.",
"store": true,
"stream": false
}'
Structured output on this route is text.format, and it uses the flat shape rather than Chat's nested one: name, schema, and strict sit beside type.
{
"text": {
"format": {
"type": "json_schema",
"name": "person",
"schema": {
"type": "object",
"properties": { "full_name": { "type": "string" } },
"required": ["full_name"],
"additionalProperties": false
},
"strict": true
}
}
}
{ "text": { "format": { "type": "json_object" } } } is also accepted. The same capabilities.structured_output_modes and capabilities.strict_json_schema gates apply; the responses endpoint label does not by itself mean structured output is available. A top-level response_format is accepted as an alternative to text.format, but sending both returns HTTP 400 with param: "text".
Final responses use the official response object with an opaque ID such as resp_... and an output item array. Items can include messages, public reasoning, function calls, and custom tool calls. Execute only tool items with status: "completed" from a completed response; never execute tool items from an incomplete response. Native usage can be absent.
Stored response continuation
store defaults to true for OpenAI compatibility. Set store: false for a one-off response that will not be used as previous_response_id.
Use the ID of a stored completed or incomplete response as previous_response_id. Never execute partial tool calls from an incomplete parent:
{
"model": "openai/gpt-5-6-sol",
"previous_response_id": "resp_2221",
"input": [{
"type": "message",
"role": "user",
"content": [{
"type": "input_text",
"text": "Give me one concrete example."
}]
}],
"store": true
}
previous_response_id is the public continuation field for this gateway route. Do not send previousTaskToken to /v1/responses. Direct Run clients use previousTaskToken as described in Run a Model. session_id is not accepted by Responses; use stored previous_response_id continuation instead.
A stored response can be continued for up to 30 days by the same authenticated user, project, team, and model. Expired, unstored, unavailable, or mismatched responses return response_not_found; failed and cancelled responses are not continuable. Chains are limited to 32 responses, and the conversation plus requested output must fit the selected model's context window.
store is not accepted on /v1/chat/completions; these persistence rules apply specifically to /v1/responses.
Stored response retrieval and deletion
Retrieve a stored response with GET /v1/responses/{response_id}. Delete it with DELETE /v1/responses/{response_id}; a successful deletion returns HTTP 204 with an empty body. POST /v1/responses/{response_id}/cancel is not supported and returns response_cancel_not_supported.
Function and custom grammar tools
Responses function tools use the standard top-level name, description, parameters, and optional strict shape. When a function call is returned, submit its result in the next request as a function_call_output input item with the same call_id.
Models with capabilities.custom_tools: true also accept free-form or grammar-constrained tools:
{
"type": "custom",
"name": "sql_query",
"description": "Produce one read-only SQL query.",
"format": {
"type": "grammar",
"syntax": "regex",
"definition": "^SELECT .+;$"
}
}
Grammar syntax is regex or lark. Use format: { "type": "text" } for a free-form custom tool. When a custom_tool_call is returned, submit its result in the next request as a custom_tool_call_output input item with the matching call_id. function_call_output and custom_tool_call_output are next-request input types, distinct from the returned function_call and custom_tool_call output items. Tool execution always remains in your application.
Responses SSE
Set "stream": true for official named Responses events, including response.created, response.in_progress, output-item/content-part events, text and reasoning deltas, response.function_call_arguments.delta/.done, and response.custom_tool_call_input.delta/.done. Every response.* payload carries a monotonically increasing sequence_number, starting at 0. Ignore : keep-alive comments.
The terminal event is response.completed or response.incomplete. A midstream failure emits response.failed. Wiro then emits data: [DONE] and closes the Responses stream; the official SDK consumes that sentinel.
Anthropic Messages
POST /v1/messages
Use a model that includes anthropic in capabilities.endpoints.
Anthropic SDKs normally send:
x-api-key: YOUR_API_KEYfor an API Key Only project, orx-api-key: YOUR_API_KEY:YOUR_API_SECRETfor a Signature projectanthropic-version: 2023-06-01- Optional
anthropic-betalabels, comma-separated or repeated
anthropic-version is required. The credential can arrive in x-api-key or in an Authorization: Bearer header; when both are sent, they must resolve to the same complete credential. Beta headers identify requested compatibility features; they do not override model capabilities. ?beta=true is also accepted as a beta-route marker.
curl -X POST "https://llm.wiro.ai/v1/messages" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude/sonnet-5",
"max_tokens": 1024,
"system": "Be concise.",
"messages": [{
"role": "user",
"content": "What is SSE?"
}],
"stream": false
}'
max_tokens is required and positive. Messages use Anthropic user and assistant roles; system instructions belong in the top-level system field. Content can include text, model-advertised image or document input, tool_use, tool_result, and supported thinking blocks. Remote media uses validated public HTTPS, data/base64, or Wiro gateway file references.
Messages is client-history: resend the prior user/assistant content and tool blocks required for each turn. It does not use Responses storage or previous_response_id.
Anthropic function tools use name, description, and input_schema. tool_choice supports Anthropic auto, any, tool, and none choices. Anthropic's optional type: "custom" still denotes an ordinary client function tool with input_schema; it is not OpenAI's free-form custom grammar shape. Tool calls are returned as tool_use; your application executes them and sends tool_result. Provider-hosted tools, hosted containers, and remote MCP servers are rejected by this release. Execute tool_use blocks only when stop_reason is tool_use; do not execute tool data from max_tokens or refusal turns.
Structured output uses output_config, not response_format. This route accepts json_schema only, and always requests it strictly:
curl -X POST "https://llm.wiro.ai/v1/messages" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude/sonnet-5",
"max_tokens": 1024,
"messages": [{
"role": "user",
"content": "Who wrote Dune, and in what year?"
}],
"output_config": {
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"author": { "type": "string" },
"year": { "type": "integer" }
},
"required": ["author", "year"],
"additionalProperties": false
}
}
}
}'
output_config.format takes exactly type and schema. Both are required, and any other key is rejected, including OpenAI's name and strict. The gateway applies strict JSON Schema output on this route unconditionally, so the model must declare capabilities.strict_json_schema as well as json_schema in capabilities.structured_output_modes. {"type": "json_object"} is refused here for every model. output_config.effort is the separate reasoning control and can be sent alongside format. A top-level response_format is not a Messages field and is rejected as an unsupported parameter. Anthropic error bodies carry only type and message, so a capability refusal arrives here without the code and param fields the OpenAI routes return.
Thinking controls use:
{ "thinking": { "type": "enabled", "budget_tokens": 2048 } }
type can be enabled, adaptive, or disabled. Check supported_parameters for public reasoning controls and capabilities.output for reasoning output. Do not fabricate or alter signature or redacted-thinking blocks returned by the model.
Final responses use the Anthropic message object with opaque msg_... request IDs; they are not Wiro task IDs. Public output content contains text and tool_use blocks. Internal model reasoning is not projected as Anthropic thinking or redacted_thinking output. Usage is included only when native counters are available.
For streaming, set "stream": true. The SSE sequence uses Anthropic events such as message_start, content_block_start, content_block_delta, content_block_stop, message_delta, and message_stop, with ping keepalives. A midstream failure emits Anthropic's native error event and closes the connection. A successful stream ends with message_stop and connection close; it does not emit [DONE]. Text blocks use text_delta, and tool_use blocks use input_json_delta. The gateway does not emit thinking_delta.
Anthropic SDKs and Claude Code
The official Node and Python SDKs must use origin https://llm.wiro.ai, not the OpenAI /v1 base:
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
baseURL: 'https://llm.wiro.ai',
apiKey: process.env.WIRO_API_KEY,
});
const message = await client.messages.create({
model: 'claude/sonnet-5',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello' }],
});
WIRO_API_KEY is YOUR_API_KEY for an API Key Only project or YOUR_API_KEY:YOUR_API_SECRET for a Signature project. Python uses the equivalent base_url and api_key options.
For Claude Code with a Signature project:
ANTHROPIC_BASE_URL="https://llm.wiro.ai" \
ANTHROPIC_API_KEY="YOUR_API_KEY:YOUR_API_SECRET" \
ANTHROPIC_MODEL="claude/sonnet-5" \
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 \
claude
For an API Key Only project, set ANTHROPIC_API_KEY to YOUR_API_KEY. Model discovery uses Wiro's authenticated /v1/models route with limit=1000. Claude Code adds only discovered IDs containing claude or anthropic to its picker; set ANTHROPIC_MODEL explicitly for any other compatible ID. Native Messages, client tools, streaming, beta headers, thinking continuation, and token-counting calls remain subject to the selected model's advertised capabilities. Provider-hosted tools remain outside this release even when a client beta can describe them.
POST /v1/messages/count_tokens
curl -X POST "https://llm.wiro.ai/v1/messages/count_tokens" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude/sonnet-5",
"system": "Be concise.",
"messages": [{ "role": "user", "content": "Hello" }]
}'
{ "input_tokens": 28 }
This is a local preflight estimate over the submitted Anthropic payload, not authoritative billing or provider-native usage. The estimate endpoint is part of the Anthropic compatibility route; the model catalog does not label it as native token counting.
Generation metadata
GET /v1/generation?id=
Look up terminal metadata using the exact public ID emitted by the protocol route: the response id for Chat or Responses, and the request-id response header for Messages. The equivalent path form is GET /v1/generation/{public-id}.
curl "https://llm.wiro.ai/v1/generation?id=resp_01HZX7Y8Q9" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"data": {
"id": "resp_01HZX7Y8Q9",
"model": "openai/gpt-5-6-sol",
"protocol": "responses",
"status": "completed",
"created_at": "2026-08-21T12:00:00.000Z",
"completed_at": "2026-08-21T12:00:03.000Z",
"usage": {
"input_tokens": 20,
"input_tokens_details": {
"cached_tokens": 0,
"cache_write_tokens": 0
},
"output_tokens": 12,
"output_tokens_details": {
"reasoning_tokens": 4
},
"total_tokens": 32
},
"upstream_metered_cost": 0.0021,
"upstream_elapsed_seconds": 3
}
}
protocol is chat, messages, or responses. status is completed, failed, or incomplete. created_at and completed_at are ISO 8601 strings.
When token counters are available, usage follows the selected protocol:
responses:input_tokens,input_tokens_detailswithcached_tokensandcache_write_tokens,output_tokens,output_tokens_details.reasoning_tokens, andtotal_tokens.chat:prompt_tokens, optionalprompt_tokens_details,completion_tokens, optionalcompletion_tokens_details, andtotal_tokens.messages:input_tokens,output_tokens, and nullablecache_creation_input_tokensandcache_read_input_tokens. This shape does not addtotal_tokens.
usage is null when no valid counters were recorded. upstream_metered_cost and upstream_elapsed_seconds are finite upstream task counters when available, otherwise null; cost is not duplicated inside metadata usage.
Only the owning authenticated project can read a generation. Missing, expired, and foreign IDs all return generation_not_found. This endpoint is terminal observability metadata, not task output: it does not return a Wiro task ID, generated content, or continuation state. Read generated content from the original protocol JSON or SSE response.
Deliberate boundaries
The Direct LLM Gateway does not currently provide:
- Provider-hosted web search, file search, code interpreter, computer-use, or remote MCP tool execution; Wiro returns tool calls for your client to run
- A native Gemini
generateContentprotocol - Embeddings or reranking
- Automatic model routing or fallback routing
- Bring-your-own-provider-key (BYOK) execution
- Dedicated image, audio, or video generation through the Chat, Responses, or Messages routes
- The legacy
/v1/completionsendpoint
Use Wiro's normal Run or /sync APIs for supported finite media-generation models. Image and document input to an LLM is distinct from media generation and remains available when the selected model advertises it.
Remote media fetches must use public HTTPS; validated data/base64 sources and Wiro gateway file IDs are accepted only where the selected protocol/model supports them. Provider-native file IDs are not interchangeable.
Errors
Error responses preserve the selected public protocol:
- Chat, Responses, model, and generation errors use the OpenAI-style
{ "error": { "message", "type", "param", "code" } }shape. - Anthropic routes use
{ "type": "error", "error": { "type", "message" } }.
Generic /sync waits on api.wiro.ai use the normal Wiro result/errors envelope.
After a stream starts, inspect SSE events rather than the HTTP status: Chat emits an error data: frame followed by [DONE], Responses emits response.failed, and Anthropic emits error.
A model blocked by your team's Model Access settings is refused before it runs with HTTP 403 and the message This model is not available for your team. Chat and Responses return type permission_error, code permission_denied and param model; Anthropic routes return type permission_error. A streamed Responses request is different: its stream is already open, so it answers 200 and ends with response.failed carrying code permission_denied and the same message, like other errors that happen when the run is submitted.
Common codes include invalid_model, model_not_found, unsupported_model_type, unsupported_parameter, response_not_found, response_chain_too_deep, invalid_generation_id, generation_not_found, completion_timeout, model_execution_failed, task_cancelled, and unsupported_capability. Files routes can also return file_not_found, file_too_large, invalid_multipart, missing_file, invalid_filename, invalid_media_type, invalid_pagination, invalid_query, file_catalog_too_large, file_content_unavailable, file_api_unavailable, and invalid_file_response.
unsupported_capability means the model does not declare something the request asked for. A structured-output mode missing from capabilities.structured_output_modes carries param: "response_format" and the message Model '<id>' does not support json_object structured output; "strict": true on a model without capabilities.strict_json_schema uses the same code with does not support strict JSON Schema output; tool controls on a model that declares neither function_tools nor custom_tools carry param: "tool_choice". The request is refused during validation, so no task is created and nothing is billed. Anthropic routes report the same refusal in the Anthropic error shape, which carries only type and message.
Gateway-origin and upstream execution failures use HTTP 500 with their specific error code; the public protocol does not return HTTP 502. Responses under /v1 include ratelimit-limit, ratelimit-remaining, ratelimit-reset, request-id, and x-request-id. A rate-limit response also includes retry-after.
Protocol execution POST bodies must be JSON and are limited to 16 MiB. Files uploads are multipart and use the separate 50 MiB file limit. Unsupported fields that could change execution fail instead of being silently accepted. A model task can also fail after HTTP validation; preserve the protocol error and status rather than treating every 2xx task creation as a successful model answer.