Model provider¶
A model provider is a first-class SwarmKit artifact (kind: ModelProvider) that points the runtime at an LLM endpoint. It is data: a base URL, an auth shape, a model catalogue, capabilities and request quirks — layered over a wire-format family that stays code. A new OpenAI- or Ollama-compatible endpoint is a YAML file and nothing else; no Python, no runtime release.
The decision — what is data and what is code — is in the declarative model providers design note. This page is the artifact reference.
The four families¶
There are four wire formats. They are Python, and they are the only Python:
| family | speaks | what extends it |
|---|---|---|
openai-compatible |
OpenAI chat-completions | OpenAI, OpenRouter, Groq, Together, llama.cpp llama-server, OpenVINO Model Server, vLLM, mlx-lm, Lemonade — every OpenAI-compatible server |
ollama |
Ollama's native /api/chat |
Ollama, rkllama (Rockchip NPU) |
anthropic |
Anthropic Messages | Anthropic |
google |
Google GenAI | Google (API-key mode) |
A provider YAML names one via extends and parameterises it. Anything a family cannot express — OAuth token acquisition, a fifth wire format — is a new family, added as code, exactly as an executor past the declarative ceiling becomes a Tier-1 Python executor.
The artifact¶
apiVersion: swarmkit/v1
kind: ModelProvider
metadata:
id: rkllama
name: rkllama — Rockchip NPU
description: Ollama-API server for RK3588/RK3576 NPUs, running pre-converted .rkllm models.
spec:
extends: ollama
base_url: ${RKLLAMA_HOST:-http://localhost:8080}
capabilities:
tools: false # narrows the family; may never widen it
provenance:
authored_by: human
version: 1.0.0
Same envelope as every other artifact — apiVersion, kind, metadata, spec, provenance — so the validator, the portal and the codegen treat it like one.
spec fields¶
Required: extends. spec refuses unknown fields — the DSL is deliberately small and a template language cannot grow in by accident.
Field (spec.) |
Type | What it does |
|---|---|---|
extends |
id | Required. A family, or another provider's id. Resolved at load: the chain must end at a family and may not revisit an id. extends: ollama always means the family, never the bundled ollama.yaml — families and providers share a namespace and the family wins. |
base_url |
string | Endpoint. ${VAR:-default} substitution applies, the same resolver as workspace env config. |
auth.api_key_env |
string | Env var holding the key. Absent means no auth — a local runtime, which registers unconditionally. |
auth.header |
string | Default Authorization. Azure's key mode is api-key. openai-compatible and ollama only. |
auth.scheme |
string | Default Bearer; empty string for a bare key. openai-compatible and ollama only. |
models.pattern |
regex | What supports() accepts. Default is the family's own catalogue (^gpt-…, ^claude-, ^gemini-). |
models.accept_any |
bool | Aggregators and local runtimes: the catalogue is unbounded and the server validates. Ollama's default. |
capabilities.* |
bool | images, tools, streaming, structured_output. Narrow-only — a true the family does not offer is a load-time error. A narrowed capability is enforced: a request carrying tools to a tools: false provider is refused before the wire. structured_output: false withholds response_format and keeps the schema in the prompt. |
options.lift_to_root |
list | Option keys moved from options to the payload root. Ollama's default is [think, keep_alive]. ollama only. |
headers |
map | Static extra request headers (OpenRouter's HTTP-Referer, X-Title). |
extra_body |
map | Fields merged into every request body that the base API does not define — OpenRouter's usage: {include: true} for per-call cost. openai-compatible and ollama only. |
requires |
code |
Declares the provider cannot be expressed here. Load refuses it with the file and reason, so a YAML past the ceiling fails loudly rather than half-works. |
A field the family would ignore (extra_body on anthropic, say) is refused at load, not dropped: a declared quirk that never reaches the wire is exactly the half-working provider this artifact exists to prevent.
Inheritance¶
extends names a family or another provider. Resolution walks the chain to a family, merging each hop's fields over its parent's: auth, models, capabilities, headers and extra_body merge by key; base_url and lift_to_root replace. A child overriding auth.header keeps its parent's api_key_env.
Depth is unbounded; every bundled provider is one hop. A provider three hops from its family is one nobody can read — that is a review norm, not a schema limit.
Where providers come from¶
bundled packages/runtime/src/swarmkit_runtime/model_providers/providers/*.yaml
workspace <workspace>/providers/*.yaml overrides a bundled id
Registration is by readiness, not by a list. Every loaded provider registers if its auth.api_key_env is set, or if it declares no auth. Adding a provider is adding a file; there is nothing in Python to keep in step.
The bundled library: anthropic, openai, google, ollama, openrouter, groq, together, plus the edge runtimes rkllama, llama-server, openvino-model-server, mlx-lm, lemonade. Each local runtime's base_url reads an env var with a default (RKLLAMA_HOST, LLAMA_SERVER_URL, OVMS_URL, MLX_LM_URL, LEMONADE_URL; Ollama's is OLLAMA_BASE_URL).
Inspecting¶
$ swarmkit providers list
anthropic anthropic bundled needs ANTHROPIC_API_KEY
groq openai-compatible bundled ready (GROQ_API_KEY set)
llama-server openai-compatible workspace ready (no auth)
rkllama ollama bundled ready (no auth)
…
$ swarmkit providers show rkllama
id: rkllama
chain: rkllama -> ollama
base_url: http://localhost:8080
auth: none
models: any
capabilities: images=yes, tools=no, streaming=yes, structured_output=yes
lift_to_root: think, keep_alive
A workspace YAML declaring requires: code stops list with its file name and the reason.
Adding one¶
Point a workspace at an OpenAI-compatible server SwarmKit has never heard of:
mkdir -p workspace/providers
cat > workspace/providers/vllm.yaml <<'YAML'
apiVersion: swarmkit/v1
kind: ModelProvider
metadata: { id: vllm, name: vLLM, description: vLLM's OpenAI-compatible server on the GPU box. }
spec:
extends: openai-compatible
base_url: ${VLLM_URL:-http://gpu-box:8000/v1}
models: { accept_any: true }
provenance: { authored_by: human, version: 1.0.0 }
YAML
swarmkit providers list workspace # vllm openai-compatible workspace ready (no auth)
Then provider: vllm in a topology or archetype, or SWARMKIT_PROVIDER=vllm for a run.