Model and Provider Day-0 Support
Built-in support is a validated resource graph, not a name added to several
independent lists. The repository catalog under config/catalog/ generates the
runtime registry, CLI bundle, Dashboard Model Hub and Add Model cards, and the
public Models page.
Choose the smallest change
| Change | Catalog resources | Code adapter |
|---|---|---|
| New model on an existing compatible provider | Model Card; one entry in that provider's models[]; reasoning/evaluation records when known | No |
| New OpenAI- or Anthropic-compatible provider | One provider file with its built-in models[] mappings | No |
| New wire protocol or genuinely different semantics | Protocol and provider definitions, conformance fixtures | Yes, at the protocol/auth/transport seam |
| Self-hosted model used by one operator | None required; write a normal custom model binding and optional Model Card | No |
A provider card is not a claim that every model is built in. A built-in model
has a validated Model Card, and a hosted model is selectable only when a
provider's models[] maps it to the provider-native ID. Every active physical
Model Card must therefore have at least one provider mapping. Virtual recipes are different: their
recommended pools may name operator-defined custom models and are not foreign
keys into the built-in catalog.
Curated catalog admission
The built-in physical catalog is curated by mainstream model creator, not by a
global top-model count. For an existing creator, a Day-0 contribution normally
adds or rotates the catalog toward roughly its latest three generations or
representative product lines. Adding a new creator changes the reviewed
baseline in catalog.yaml.inventory.physical; it should explain why the company
belongs in the mainstream set and which current lines form a useful operator
surface. The generator enforces creator membership and minimum depth, while the
human review decides recency and relevance.
Provider support is independent. A new Provider ID may have no built-in model mapping and still be valuable for handwritten custom models in Add Model. Do not add an obscure Model Card merely to make a provider card look populated.
Add a model
- Add or update a focused family file under
config/catalog/resources/models/single/. Record intrinsic facts only: canonical ID, publisher and presentation, distribution source/license, revision, limits, modalities, capabilities, protocols, lifecycle, and reasoning-family reference. Recipe-backed logical models belong inmodels/virtual/instead. - Add a mapping under
config/catalog/resources/providers/<provider>.yamlmodels[]when vLLM-SR should know a provider-native model ID, protocol restriction, price, or other provider-specific fact. Do not create a second provider/model inventory. - Reuse a reasoning family. Add a new family only when the request projection itself is new; do not duplicate a built-in family in user configuration.
- Add benchmark records under
evaluations/single/only when the result is attributable to a primary model source and redistributable. Keep each benchmark version, exact subject, and raw metric explicit. Virtual-model recipe runs use the identical schema underevaluations/virtual/. Recordmeasured_atwhen the run date is known; otherwise recordobserved_atas the date the published value was reviewed, without presenting it as a run date. - Add conformance fixtures for capabilities or protocol behavior claimed by the card/provider mapping.
Model IDs are namespaced, for example organization/model. Benchmark and
index IDs use full semantic versions. A changed dataset, grader, prompt
protocol, or aggregation rule requires a new benchmark version.
The default intelligence index uses MMLU-Pro, GPQA Diamond, Humanity's Last
Exam, SWE-bench Verified, and Terminal-Bench 2.1 at equal weight. It emits a
headline score only at 60% coverage. A new model may ship with less evidence;
the Hub then shows the available components and Not yet measured rather than
inventing a value. Two available values for one model and versioned metric are
rejected. Vendor-published results retain their exact model variant, reasoning
mode, tool mode, and harness metadata and are labeled claimed; only a frozen
vLLM-SR run with its artifact can be labeled reproduced.
reasoning_effort names a runtime control, not an evidence source. If a score
does not disclose the runtime effort, use unspecified; keep whether the result
was vendor-published or independently measured in evidence.provenance and
evidence.verification.
Generation emits exactly those five benchmark slots for every model and every
selectable reasoning effort. A slot without trustworthy evidence is explicit
missing, never zero. When a source reports several efforts, author a separate
evaluation record for each effort; results from high, xhigh, or max are
not copied across rows. Extra benchmarks remain visible as evidence without
silently entering this version of the default index.
Add a provider
- Give the provider one stable lowercase Provider ID in a focused file under
config/catalog/resources/providers/. - Declare only protocols the provider actually transports and the exact
fully-qualified
supported_operationssubset it implements. Every declared protocol must include#create; add#list_modelsonly when that provider surface really exposes compatible discovery. Usenativefor a first-class semantic integration,compatiblefor a compatibility API, andruntimefor private serving runtimes such as vLLM or SGLang. - Add the default base URL, auth strategy, header/prefix, non-secret default
request headers, path overrides, API-version behavior, and an existing
reasoning_transportonly when the provider changes reasoning-field placement. Secrets and credential-bearing default headers are rejected by generation. Reuseoutput_config_effortwhen the provider carries the selected level asoutput_config.effort. Useactivation_parameteronly when activation is a separate boolean control from the model's effort ladder. For mixed-thinking Chat APIs, selecttop_level_effort_template_switchwhen the switch belongs in localchat_template_kwargs, ortop_level_effort_boolean_switchwhen both fields are top-level provider extensions. Responses keeps the standardreasoning.effortshape. - Add display name, category, logo source or monogram fallback, and conformance status. A missing image must never block configuration.
- Add code only when generic protocol, URL, and auth handling cannot represent the provider. Keep that adapter beside its conformance tests; do not add a provider case to a generic config helper.
Provider API operations are defined in
config/catalog/resources/protocols.yaml. A provider selects a subset with
supported_operations and may override a selected operation path; it cannot
invent or override an undeclared operation. Runtime dispatch, Dashboard model discovery, and connection
verification resolve paths, auth, and non-secret headers from these same
definitions. Provider-specific reasoning placement reuses one of the catalog's
validated transport modes; endpoint hostnames are never used as provider
identity.
Reasoning wire contract
Operators use one protocol-neutral decision surface:
use_reasoning, optional reasoning_mode, and optional reasoning_effort.
The built-in model family limits the selectable values, and a provider-model
mapping may narrow them further. The selected protocol and catalog transport
then produce exactly one provider-native shape:
| Provider/runtime surface | Final request control |
|---|---|
| Local vLLM/SGLang template control | switch and/or effort inside chat_template_kwargs |
| Local mixed effort plus template switch | top-level effort plus chat_template_kwargs.<activation_parameter> |
| Local template effort flags | activation boolean plus one mutually exclusive effort flag; default/full may be omission |
| OpenAI-compatible Chat effort | top-level reasoning_effort |
| OpenAI Responses effort | reasoning.effort |
| Provider boolean switch | top-level <parameter>: true|false |
| Gateway-normalized reasoning | reasoning.effort or reasoning.enabled |
| Thinking-object API | thinking.type: enabled|disabled|adaptive |
| Thinking object plus effort | thinking.type plus top-level reasoning_effort |
| DeepSeek Chat | thinking.type plus top-level reasoning_effort when enabled |
| Anthropic Messages | thinking.type plus output_config.effort when enabled |
DeepSeek Responses remains a standard Responses request and therefore uses
reasoning.effort, rather than the Chat-specific two-field shape. Provider
adaptation removes competing reasoning, thinking, top-level effort,
output_config.effort, and local template controls before writing the selected
shape. A Day-0 contribution that changes reasoning semantics must add a final
encoded-request fixture for every claimed protocol, including enabled,
disabled, adaptive, and effort variants that the model actually exposes.
For a custom model whose template uses boolean effort flags, keep the public
decision on reasoning_effort and map only the wire names in its inline
reasoning.effort_flags. One active level may be intentionally unmapped to
mean “all effort flags omitted”; every other active level must have a unique
flag. Built-in models already carry this mapping and require no user YAML.
Dashboard discovery applies a stricter network boundary than ordinary runtime dispatch. A cloud Model API must use the exact built-in origin. A self-hosted runtime may intentionally use a private or loopback address, but link-local and metadata endpoints are rejected. Redirects and environment proxies are disabled, and resolved addresses are checked again by the dialer before credentials are sent.
Built-in and custom user configuration
A built-in card is selected with one optional catalog reference. The model
name remains the request-facing alias, while backend_refs[].provider is the
catalog Provider ID:
version: v0.3
providers:
defaults:
model: production
reasoning_effort: medium
models:
- name: production
catalog: organization/model
backend_refs:
- name: primary
provider: provider-id
api_key_env: PROVIDER_API_KEY
Built-in cards do not require routing.modelCards. An intentional override
uses the canonical catalog identity as its card name:
routing:
modelCards:
- name: organization/model
tags: [production, approved]
api_format only selects the upstream wire contract; never use it to infer the
Provider from the current registry contents. A physical model behind a
Router-owned listener must have an explicit backend_refs[].provider so a
future Provider addition cannot change the meaning of existing YAML.
When a provider binding declares an operator-defined deployment_name, its
catalog ID only records availability; the user must set
providers.models[].provider_model_id (or that provider's
external_model_ids entry) explicitly.
Treat multiple backend_refs on one alias as homogeneous replicas in one
Envoy pool. HTTP endpoint address, port, and weight may differ; HTTPS replicas
may vary by port and weight but keep one DNS hostname. Provider ID,
protocol/model mapping, credential source, auth and default headers, effective
request path, and DNS/TLS behavior must otherwise match. Split heterogeneous providers or
credentials into separate aliases so Router request shaping cannot diverge
from the endpoint Envoy selects. The config loader and CLI generator reject an
unsafe mixed pool with the differing semantic fields named and never include
credential values in the error.
Built-in reasoning comes from that card. A providers.models[].reasoning
block is accepted only when catalog is omitted for a custom model.
Custom cards may also declare optional publisher, presentation, and
distribution metadata. That lets a private or newly released model render as
a complete effective card without adding a repository resource; none of these
fields stores credentials.
For a private model, omit catalog. Its alias is its local card identity, and
both reasoning and evaluations remain optional:
providers:
defaults:
model: private-reasoner
models:
- name: private-reasoner
provider_model_id: private-awq
reasoning:
family: qwen3
backend_refs:
- name: lab
provider: vllm
endpoint: model-gateway.example:8000/v1
routing:
modelCards:
- name: private-reasoner
context_window_size: 131072
capabilities: [chat, tools, reasoning]
evaluations:
- benchmark: organization/private-eval@1.0.0
benchmark_profile: published-standard
reasoning_effort: high
metrics:
pass_rate: 0.82
User-authored evaluations intentionally have a small surface: benchmark and
metrics, plus optional benchmark_profile, reasoning_effort, source,
measured_at, and scalar metadata. Omit benchmark_profile to use a known
benchmark's default profile; set reasoning_effort when the measurement came
from a specific model effort. Catalog records retain richer evidence and
provenance internally. Custom benchmark identities remain namespaced and
versioned, while metric values must be finite.
Generate and validate
make model-catalog-generate
make model-catalog-check
make agent-report ENV=cpu CHANGED_FILES="config/catalog/resources/models/organization.yaml"
Commit the authored resources and every generated projection together. Then run the gates reported for the actual changed files. A complete Day-0 pull request demonstrates:
- stable identities and valid references;
- protocol and capability conformance for every support claim;
- generated Dashboard provider/model cards and logo fallback;
- generated website support and benchmark-comparison rows;
- no secrets or restricted benchmark data;
- explicit missing evaluation status rather than a fabricated score.
Do not hand-edit generated JSON, Go, or CLI catalog snapshots. If a generated view is wrong, fix the source resource or generator and regenerate it.