dvergr talks to LLMs through pluggable providers, each resolved from a model registry. To run anything you need (1) at least one provider's API key and (2) a model in the registry pointing at that provider.
| Provider key | API type | Default endpoint | Source |
|---|---|---|---|
:anthropic | :anthropic-messages | https://api.anthropic.com/v1 | model/api/anthropic.clj |
:openai | :openai-chat | https://api.openai.com/v1 | model/api/openai.clj |
:fireworks | :openai-chat | https://api.fireworks.ai/inference/v1 | model/api/openai.clj (OpenAI-compatible) |
:claude-code | :claude-code-cli | local claude -p CLI (subscription) | model/api/claude_code.clj |
Providers self-register at startup (providers/init-defaults!) only when
their key is available — so a missing key just means that provider is absent,
not an error. If nothing registers, you get a loud boot warning.
Keys are read from environment variables (or passed in a config map to the
register-*! fns):
export ANTHROPIC_API_KEY=sk-ant-… # enables :anthropic
export OPENAI_API_KEY=sk-… # enables :openai
export FIREWORKS_API_KEY=fw-… # enables :fireworks
# :fireworks also accepts OPENAI_API_KEY as a fallback
# override the Fireworks/OpenAI base URL with OPENAI_BASE_URL
FIREWORKS_API_KEY, then falls back to OPENAI_API_KEY;
base URL falls back to OPENAI_BASE_URL before the Fireworks default. This is
the default provider dvergr ships with.claude --version.
If the CLI exits 0, :claude-code registers and bills against your Claude
subscription (model pricing is 0).Provider keys are not in
config.local.edn— they come from the env. Other secrets (Telegram, GitHub, …) live in config; seedoc/configuration.md.
resources/models.ednEdit this file to add/change models without touching source. It's loaded at
startup and is also re-loadable via (registry/load-models-resource!). Shape:
{:models
{"accounts/fireworks/models/minimax-m2p7" ; map key = the model :id
{:name "MiniMax M2.7"
:provider :fireworks ; must match a provider key
:api-type :openai-chat
:capabilities #{:tools :streaming} ; :tools :vision :thinking :streaming
; :system-prompt :cache-control :json-mode
:context 196608 ; context window (tokens)
:max-output 8192
:pricing {:input 0.30 :cache-read 0.03 :output 1.20} ; $/MTok
:quirks {}}} ; e.g. :default-top-p, :tool-id-in-every-chunk?
:aliases {"minimax" "accounts/fireworks/models/minimax-m2p7"} ; short names
:defaults {:primary-model "accounts/fireworks/models/minimax-m2p7"
:compaction-model "accounts/fireworks/models/minimax-m2p7"
:summary-model "accounts/fireworks/models/gpt-oss-20b"}}
To add a model: add an entry under :models keyed by its provider-side id,
set :provider to a registered provider, list :capabilities, and (optionally)
an alias. EDN entries merge over the built-in default-models (current Claude
Opus/Sonnet/Haiku + Claude-Code models, defined in model/registry.clj).
(registry/refresh-from-models-dev! #{:anthropic …}) is an opt-in, network call
that overlays live pricing/context from https://models.dev.
Per request (model/chat.clj), resolution is:
:model opt is required (an id or an alias). Aliases resolve first via
registry/resolve-alias.registry/get-model! — throws if absent.(:provider opts) if given, else (:provider model-def) from the
registry entry, then providers/get-provider! (throws if that provider isn't
registered, i.e. no key).:tools model throws.
:thinking and quirk defaults (like Kimi's top_p) are applied automatically.Agents carry :provider / :model in their config (config.local.edn :agents,
materialised into Datahike actor rows). The registry's :defaults
(:primary-model, :compaction-model, :summary-model) are read via
registry/get-default for system-level model choices.
:agents {:var {:provider :fireworks
:model "accounts/fireworks/models/minimax-m2p7"
:tags #{:secretary}}}
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |