Models and routing
How zerd talks to providers and picks which model handles a request.
-
Claude models go through
/messages, everything else through/chat/completions, picked from the live/modelscatalog (cached 24h). Codex models use the Responses API over SSE with automatic token refresh. -
Role chains in
.zerd/config.toml:[routing] default = ["claude-sonnet-5-5", "deepseek/deepseek-v4-pro"] fast = ["deepseek/deepseek-v4.1-flash"] # easy requests strong = ["claude-opus-5-5"] # hard ones, and escalation summarize = ["deepseek/deepseek-v4.1-flash"] # context compaction review = ["gpt-5.6-sol"] advisor = ["deepseek/deepseek-v4-pro"] -
Difficulty tiers. Each request is classified without a model call: small, well-defined work goes
fast; debugging, concurrency, security, architecture and multi-file work gostrong. A failed repair or a loop escalates tostrong.-mor/modelpins a model.--effort low|medium|highor/effort low|medium|high|autosets how hard it thinks. -
Per-family sampling and output caps. Temperature and top_p follow the model family unless you set
temperature.max_tokensis clamped to the window and learned from a provider's 400 message; a reply cut off by the limit is continued, and a tool call cut mid-arguments is never run. -
Thinking switches. Easy requests turn thinking down, hard ones up, in each server's own wording: DeepSeek
thinking.type, z.aithinking(withclear_thinkingoff), OpenRouterreasoning.effort, Togetherreasoning.enabled,chat_template_kwargson your own vLLM/SGLang/LM Studio,reasoning_effortfor gpt-oss. A server that refuses the switch gets the request again without it. -
zerd probe-modelsshows which of your configured models actually answer. -
zerd insights [--days 7] [--json]reads zerd's own trace files and shows, per model, how many calls failed or were retried, how much of the prompt came from cache, how many tool calls were malformed, and how often the loop had to step in (empty reply, tool call written as text, cut-off reply, loop). Per tool it shows the error rate and the most common error. It ends with a short "worth a look" list, so prompts and compat settings get tuned from what happened, not from memory. -
Any provider, directly.
provider:modelskips the gateway and calls that API with its own key:zerd -m groq:llama-3.3-70b,-m anthropic:claude-sonnet-5-5,-m ollama:qwen3:8b. Built in: openai, anthropic, gemini, openrouter, groq, deepseek, mistral, xai, together, fireworks, cerebras, moonshot, zai, ollama, lmstudio. Set the key (GROQ_API_KEY=...), or type/connect groq: it asks for the key, saves it to zerd's.env, and lists the models for/model groq:<Tab>. These ids also work in[routing]chains, so a fallback can live on a different provider. Anything else that speaks the OpenAI or Anthropic format takes three lines:[providers.work] base_url = "https://llm.internal.example.com/v1" api_key_env = "WORK_LLM_KEY" # leave out for a local server that needs no key protocol = "anthropic" # default "openai"A server that is only mostly OpenAI-compatible (llama.cpp, vLLM, SGLang, a company proxy) is tuned the same way, no code:
[providers.box.compat] max_tokens_field = "max_completion_tokens" # or "none" to send no cap stream_usage = false # the server rejects stream_options tool_result_name = true # tool messages must carry the tool's name assistant_after_tool = true # the chat template refuses a user message right after a tool result cache_control = true # Anthropic cache marks (on by itself for anthropic/* on OpenRouter) extra_body = { thinking_token_budget = 4096, chat_template_kwargs = { enable_thinking = true } }A model that garbles several tool calls in one reply can be held to one at a time with
extra_body = { parallel_tool_calls = false }. A reply that carries its thinking inline as<think>...</think>is split automatically: the thinking is kept out of the answer.extra_bodyis merged into every request last, so it also overrides zerd's own thinking switch for that server. A thinking budget matters on local models: thinking and the answer sharemax_tokens, and without a cap the thinking can use all of it and leave no tool call.A project's own
.zerd/config.tomlcan only set[providers]once you trust it, because it could otherwise send your keys to its own server.