Providers
A provider in kanros is anything that turns a CompletionRequest into a
CompletionResponse. The trait lives in kanros-core::provider::Provider
and is implemented once per backend in a dedicated crate under
crates/kanros-providers/.
Providers are referenced in config by id, in family:model form:
providers:
- id: openai:gpt-4o-mini
- id: anthropic:claude-3-5-haiku
- id: ollama:llama3.1
The segment before the colon (openai, anthropic, ollama, …) is the
provider family; it selects which crate handles the request. The
segment after the colon is forwarded verbatim as the model id.
Bundled provider families
The workspace currently ships the following provider crates. Every name
below corresponds to a directory in crates/kanros-providers/ and to a
provider family id.
| Family | Crate | Notes |
|---|---|---|
echo | kanros-provider-echo | Identity provider — returns the rendered prompt. |
openai | kanros-provider-openai | OpenAI chat completions + embeddings + moderation. |
anthropic | kanros-provider-anthropic | Claude chat completions. |
azure-openai | kanros-provider-azure-openai | Azure OpenAI Service. |
ollama | kanros-provider-ollama | Local Ollama daemon. |
http | kanros-provider-http | Generic HTTP provider with templated request/response. |
llama-cpp | kanros-provider-llama-cpp | llama.cpp server protocol. |
lm-studio | kanros-provider-lm-studio | LM Studio local server. |
subprocess | kanros-provider-subprocess | Run your own script: JSON request on stdin, JSON reply on stdout — see Subprocess provider. |
bedrock | kanros-provider-bedrock | Amazon Bedrock. |
browser | kanros-provider-browser | Chromium via CDP — for E2E flows. |
cloudflare | kanros-provider-cloudflare | Cloudflare Workers AI. |
cohere | kanros-provider-cohere | Cohere Command and embeddings. |
deepseek | kanros-provider-deepseek | DeepSeek API. |
fireworks | kanros-provider-fireworks | Fireworks AI. |
groq | kanros-provider-groq | Groq inference. |
huggingface | kanros-provider-huggingface | Hugging Face Inference API. |
mistral | kanros-provider-mistral | Mistral AI. |
openrouter | kanros-provider-openrouter | OpenRouter (routes to many backends). |
perplexity | kanros-provider-perplexity | Perplexity online models. |
replicate | kanros-provider-replicate | Replicate. |
together | kanros-provider-together | Together AI. |
voyage | kanros-provider-voyage | Voyage embeddings + reranker. |
vertex | kanros-provider-vertex | Google Vertex AI / Gemini. |
vllm | kanros-provider-vllm | vLLM OpenAI-compatible server. |
websocket | kanros-provider-websocket | Bidirectional WebSocket provider. |
xai | kanros-provider-xai | xAI Grok. |
Inline provider config
Per-provider configuration is forwarded as a JSON value:
providers:
- id: openai:gpt-4o-mini
config:
base_url: "https://api.openai.com/v1"
timeout_ms: 30000
- id: ollama:llama3.1
config:
base_url: "http://localhost:11434"
The config block is provider-specific and each provider crate documents its own keys in its README. Unknown keys are rejected — a typo fails the run rather than being silently ignored.
The key for pointing a family at a different host is base_url, not
endpoint. For OpenAI-compatible third-party endpoints, give the full
prefix that precedes the API path, including any version segment: the
provider appends /chat/completions to whatever you supply. For example,
Alibaba DashScope's OpenAI-compatible mode takes
https://dashscope-intl.aliyuncs.com/compatible-mode/v1.
Generation parameters
Sampling and output-shape parameters can be written directly on the
provider entry, or inside its config: block. When the same key appears
in both places, the provider-level value wins.
providers:
- id: openai:gpt-4o-mini
temperature: 0
top_p: 1
max_tokens: 512
seed: 42
stop: ["\n\n"]
- id: anthropic:claude-3-5-haiku-latest
config:
temperature: 0.2 # same keys also work inside config:
max_tokens: 1024
prompts:
- "Answer in one sentence: {{ question }}"
tests:
- vars: { question: "What is the boiling point of water at sea level?" }
assert:
- type: icontains
value: "100"
| Key | Type / range | Notes |
|---|---|---|
temperature | number, >= 0 | 0 is the most deterministic setting. |
top_p | number, 0–1 | Nucleus-sampling probability mass. |
max_tokens | integer, >= 1 | Maximum tokens to generate. |
seed | integer, >= 0 | Best-effort determinism. Ignored by anthropic and bedrock; mistral sends it as random_seed. |
stop | string or list of strings | Stop sequence(s). |
response_schema | JSON Schema object | Structured output — see Structured output. |
response_format | { type: text | json_object | json_schema } | OpenAI-style format; json_schema needs json_schema.schema (or schema). |
These values apply to every request made through the provider: eval
cells, model-graded assertion graders, red-team probes and agent loops.
Out-of-range or wrongly typed values fail kanros validate (exit code
2) instead of being silently ignored.
For anthropic, bedrock and vertex, max_tokens is also a native
config key that sets the provider's default; the per-request value
derived from the table above overrides that default.
fallback is also accepted on a provider entry: a list of provider ids
tried in order when the provider fails with a retryable error after
exhausting its retries.
providers:
- id: openai:gpt-4o-mini
fallback: [anthropic:claude-3-5-haiku-latest]
Credentials
For network providers, kanros looks for an API key in this order:
config.api_keyin the provider's inline config block. Write it asenv:NAMEto read the key from the environment variableNAMEinstead of committing a secret — for exampleapi_key: env:OPENAI_API_KEY.- The provider-specific environment variable (e.g.
OPENAI_API_KEY,ANTHROPIC_API_KEY,GROQ_API_KEY). - The system keyring (see
kanros auth), under the service namekanrosand account name equal to the provider family.
If none of the three resolve, the provider cannot be constructed: the
run stops before any cell executes, prints which variable or keyring
entry it looked for, and exits with code 2. Errors a provider returns
while a cell runs (HTTP failures, rate limits after the retry budget)
are recorded on that cell's provider_error field instead and make the
run exit with code 1.
The env:NAME form works for every credential key a provider accepts:
api_key, api_token, access_key_id, secret_access_key and
session_token. If NAME is not set, the run stops with a clear error
naming the variable; kanros does not fall back to the next source.
providers:
- id: bedrock:anthropic.claude-3-5-haiku-20241022-v1:0
config:
region: us-east-1
access_key_id: env:AWS_ACCESS_KEY_ID
secret_access_key: env:AWS_SECRET_ACCESS_KEY
Adding a provider
Each provider is a small crate that implements
kanros_core::provider::Provider:
use async_trait::async_trait;
use kanros_core::{CompletionRequest, CompletionResponse, Provider, ProviderError};
#[derive(Debug)]
struct MyProvider { /* … */ }
#[async_trait]
impl Provider for MyProvider {
fn id(&self) -> &str { "myprovider:demo" }
async fn complete(&self, req: CompletionRequest) -> Result<CompletionResponse, ProviderError> {
// …
todo!()
}
}
Register the provider with the kanros-providers registry (see
crates/kanros-providers/src/lib.rs). Once registered, users can refer to
it by id from any kanros config.
The echo provider
The echo:identity provider is special: it returns the rendered prompt
verbatim. It has no dependencies, no I/O, and no per-call cost. It is the
right pick for smoke tests, schema fixtures, and CI bootstraps.
providers:
- id: echo:identity
prompts:
- "say {{ word }}"
tests:
- vars: { word: hello }
assert:
- type: contains
value: hello