Channel-neutral provider management service.
Everything a channel needs to render and mutate the provider fleet
— status probing, account limits, live model catalogs, presets, and
config persistence — WITHOUT any UI. Hoisted from the TUI extension
(channel_tui/provider.clj) so the web channel, Telegram, and any
future surface manage the SAME fleet through the SAME primitives;
the channels keep only their interaction layer (lanterna dialogs,
HTMX fragments, ...).
Auth is classified, not implemented, here: auth-kind tells a
channel whether a provider wants an API key, an interactive OAuth
flow (owned by the provider extension + channel), or nothing
(local). The registry's :provider/*-fn contract stays the single
integration point for provider extensions, so a provider extension
automatically works in every channel.
Channel-neutral provider management service. Everything a channel needs to render and mutate the provider fleet — status probing, account limits, live model catalogs, presets, and config persistence — WITHOUT any UI. Hoisted from the TUI extension (`channel_tui/provider.clj`) so the web channel, Telegram, and any future surface manage the SAME fleet through the SAME primitives; the channels keep only their interaction layer (lanterna dialogs, HTMX fragments, ...). Auth is classified, not implemented, here: `auth-kind` tells a channel whether a provider wants an API key, an interactive OAuth flow (owned by the provider extension + channel), or nothing (local). The registry's `:provider/*-fn` contract stays the single integration point for provider extensions, so a provider extension automatically works in every channel.
(add-config-provider! provider-cfg)(add-config-provider! provider-cfg source)Append a provider config to the persisted fleet (no-op when the id is already configured). Returns the new fleet or nil on no-op.
Append a provider config to the persisted fleet (no-op when the id is already configured). Returns the new fleet or nil on no-op.
(auth-kind pid)How a provider id authenticates: :oauth (interactive flow owned by
the provider extension), :none (local, no credentials), or
:api-key.
How a provider id authenticates: `:oauth` (interactive flow owned by the provider extension), `:none` (local, no credentials), or `:api-key`.
(available-presets)Provider presets not yet in the configured fleet — the 'Add Provider' picker contents.
Provider presets not yet in the configured fleet — the 'Add Provider' picker contents.
(configured-providers)The persisted provider fleet (global + project overlay), priority order, catalog metadata applied (base-url/api-style filled in).
The persisted provider fleet (global + project overlay), priority order, catalog metadata applied (base-url/api-style filled in).
(default-model-configs preset)Preset :default-models as persisted {:name str} model maps.
Preset `:default-models` as persisted `{:name str}` model maps.
(default-model-names provider)Union of model names already on the provider map plus the preset /
provider :default-models, deduped. The list-building below sorts,
so order here is irrelevant.
Union of model names already on the provider map plus the preset / provider `:default-models`, deduped. The list-building below sorts, so order here is irrelevant.
(demote-unreachable-providers router)Health-order a ROUTER (svar shape, {:providers [...]}) for one
turn: LOCAL providers that fail the liveness probe sink to the END
of the fleet — kept as last resort, never silently dropped — so a
dead local endpoint can't catch a turn (or an svar fallback) that a
healthy provider should have taken. Probes run ONLY when local
providers are configured (≤ ~2.5s each; zero cost otherwise).
Returns {:router r :demoted [provider-ids]}. NEVER throws —
routing must survive a broken probe (falls back to the router
as-is), so callers need no defensive wrapping.
Health-order a ROUTER (svar shape, `{:providers [...]}`) for one
turn: LOCAL providers that fail the liveness probe sink to the END
of the fleet — kept as last resort, never silently dropped — so a
dead local endpoint can't catch a turn (or an svar fallback) that a
healthy provider should have taken. Probes run ONLY when local
providers are configured (≤ ~2.5s each; zero cost otherwise).
Returns `{:router r :demoted [provider-ids]}`. NEVER throws —
routing must survive a broken probe (falls back to the router
as-is), so callers need no defensive wrapping.(fetch-models provider)List models for a vis provider via svar/models!.
Returns vec of chat model id strings, or nil on failure. Filters out TTS / embedding / speech / image and provider-excluded models.
Routing through svar means the call automatically picks up
provider-specific OAuth headers (anthropic-version,
anthropic-beta for the Anthropic Claude subscription;
chatgpt-account-id for OpenAI Codex; bare Bearer for everyone
else).
provider is a vis-shaped provider map. We coerce to svar shape
(resolving OAuth tokens via the provider's :provider/get-token-fn
when :api-key is absent) and ask svar.
List models for a vis provider via `svar/models!`. Returns vec of chat model id strings, or nil on failure. Filters out TTS / embedding / speech / image and provider-excluded models. Routing through svar means the call automatically picks up provider-specific OAuth headers (`anthropic-version`, `anthropic-beta` for the Anthropic Claude subscription; `chatgpt-account-id` for OpenAI Codex; bare Bearer for everyone else). `provider` is a vis-shaped provider map. We coerce to svar shape (resolving OAuth tokens via the provider's `:provider/get-token-fn` when `:api-key` is absent) and ask svar.
(format-limit-row {:keys [label scope kind unlimited? used limit remaining note
window]})GitHub Copilot preset id -> device-flow account type.
GitHub Copilot preset id -> device-flow account type.
(initial-provider-limits provider)Placeholder limits report while the real fetch runs.
Placeholder limits report while the real fetch runs.
(initial-provider-status provider)Placeholder status while a real probe runs in the background.
Placeholder status while a real probe runs in the background.
Local OpenAI-compatible providers that need no credentials.
Local OpenAI-compatible providers that need no credentials.
(model-options provider)(model-options provider default-models show-all?)Selectable model ids for a provider: live-fetched + defaults,
deduped, sorted, env default pinned first. When show-all? is
false, dated snapshot variants (gpt-4o-2024-08-06) are hidden.
Returns {:models [id ...] :hidden-count n} — channels render
their own 'show all' affordance from :hidden-count.
Selectable model ids for a provider: live-fetched + defaults,
deduped, sorted, env default pinned first. When `show-all?` is
false, dated snapshot variants (gpt-4o-2024-08-06) are hidden.
Returns `{:models [id ...] :hidden-count n}` — channels render
their own 'show all' affordance from `:hidden-count`.Providers whose credentials come from an interactive OAuth flow and live OUTSIDE config.edn (keychain / token files owned by the provider extension).
Providers whose credentials come from an interactive OAuth flow and live OUTSIDE config.edn (keychain / token files owned by the provider extension).
(persisted-provider-config provider)Convert an in-memory provider entry to the durable on-disk shape.
Convert an in-memory provider entry to the durable on-disk shape.
(probe-local-reachable provider)Probe a local OpenAI-compatible provider (Ollama / LM Studio) by
GETting its <base-url>/models endpoint with a short timeout.
Reachable → {:authenticated? true …}; refused / timeout / other →
{:authenticated? false :error "<human hint>"} so the channel can
SAY why the dot is red. Blocking ≤ ~2.5s — call off the render path.
Probe a local OpenAI-compatible provider (Ollama / LM Studio) by
GETting its `<base-url>/models` endpoint with a short timeout.
Reachable → `{:authenticated? true …}`; refused / timeout / other →
`{:authenticated? false :error "<human hint>"}` so the channel can
SAY why the dot is red. Blocking ≤ ~2.5s — call off the render path.(provider-config-with-models preset models)Minimal persistable provider config for a preset + chosen models.
Minimal persistable provider config for a preset + chosen models.
(provider-limits-safe provider)Normalized limits report for a provider id; an error report instead of a throw.
Normalized limits report for a provider id; an error report instead of a throw.
(provider-reachable? provider)Cheap ROUTING-time liveness verdict: local providers (Ollama / LM Studio) get the real HTTP probe; remote providers are assumed reachable — their auth/network failures surface as call errors svar already fails over on, and a per-turn network check against every remote backend would tax every turn.
Cheap ROUTING-time liveness verdict: local providers (Ollama / LM Studio) get the real HTTP probe; remote providers are assumed reachable — their auth/network failures surface as call errors svar already fails over on, and a per-turn network check against every remote backend would tax every turn.
(provider-status provider)Auth/liveness status for a CONFIGURED provider map. Local providers
are probed for real; an explicit :api-key is trusted; otherwise
the registered extension's status/detect fns answer. Never throws.
Auth/liveness status for a CONFIGURED provider map. Local providers are probed for real; an explicit `:api-key` is trusted; otherwise the registered extension's status/detect fns answer. Never throws.
(remove-provider! provider-id)(remove-provider! provider-id source)Remove a provider from the persisted fleet AND run the registered extension's logout when present. Returns true when config changed.
Remove a provider from the persisted fleet AND run the registered extension's logout when present. Returns true when config changed.
(safe-provider-status provider)Status of a REGISTERED provider descriptor via its :provider/status-fn
(falling back to :provider/detect-fn). Never throws.
Status of a REGISTERED provider descriptor via its `:provider/status-fn` (falling back to `:provider/detect-fn`). Never throws.
(save-providers! providers)(save-providers! providers source)Replace the :providers vec in the GLOBAL config file (project
overlay files are never edited), preserving unrelated keys, then
reload the in-memory config so the running router sees the change.
Returns the persisted vec.
Replace the `:providers` vec in the GLOBAL config file (project overlay files are never edited), preserving unrelated keys, then reload the in-memory config so the running router sees the change. Returns the persisted vec.
(status-md provider)(status-md provider status limits)The provider status + limits report as MARKDOWN — one rich canonical
form every channel renders natively: the web through its markdown
pipeline, the TUI through markdown->ir + the IR walker. The same
facts as status-text, structured instead of flat.
The provider status + limits report as MARKDOWN — one rich canonical form every channel renders natively: the web through its markdown pipeline, the TUI through `markdown->ir` + the IR walker. The same facts as [[status-text]], structured instead of flat.
(status-text provider)(status-text provider status limits)Multi-line human status + limits report for a configured provider. The single source for the TUI 'Show Status + Limits' dialog and the web status view.
Multi-line human status + limits report for a configured provider. The single source for the TUI 'Show Status + Limits' dialog and the web status view.
(update-config-provider! provider-id f)(update-config-provider! provider-id f source)Apply f to the persisted provider entry with provider-id and
save. Returns the new fleet.
Apply `f` to the persisted provider entry with `provider-id` and save. Returns the new fleet.
(url-host url)Extract host from URL for display. 'https://llm.blockether.com/v1' -> 'llm.blockether.com'.
Extract host from URL for display. 'https://llm.blockether.com/v1' -> 'llm.blockether.com'.
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 |