Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.loop.router

Project-scoped routers and per-request provider routing.

Builds and rebuilds each project's svar router from configuration, hydrates provider credentials and model metadata, recovers from a rejected credential by refreshing or rerouting, resolves the effective model and its context budget, and estimates request cost, including a provider's fast mode.

Project-scoped routers and per-request provider routing.

Builds and rebuilds each project's svar router from configuration, hydrates
provider credentials and model metadata, recovers from a rejected credential
by refreshing or rerouting, resolves the effective model and its context
budget, and estimates request cost, including a provider's fast mode.
raw docstring

apply-auth-recovery-routingclj

(apply-auth-recovery-routing routing)

Hand an iteration's auth recovery to Svar. While provider_fallback is on, a provider whose credentials stay rejected after the credential-refresher re-sends is left for the next candidate (:on-auth-error :fallback-provider), and the providers still serving an auth cooldown are excluded up front, so a dead credential is skipped BEFORE the request instead of being rediscovered with another 401.

A PIN does not outrank the cooldown. EVERY main turn is pinned — prepare-turn-context forces the active provider+model into :routing so a provider failure surfaces as an error the user acts on — so exempting a pinned provider exempted every real turn: vis logged a five-minute cooldown and then re-probed, re-minted and re-fell-back on the very next iteration, ~12-16s later (issue #114). A COOLED pin is released the way Svar releases a pin after an auth rejection. A pin on a HEALTHY provider is left alone, and the provider's own accepted request re-admits it immediately.

No-op while provider_fallback is off: with nowhere to route, a rejected credential surfaces as the provider's own error.

Hand an iteration's auth recovery to Svar. While `provider_fallback` is on, a
provider whose credentials stay rejected after the [[credential-refresher]]
re-sends is left for the next candidate (`:on-auth-error :fallback-provider`),
and the providers still serving an auth cooldown are excluded up front, so a
dead credential is skipped BEFORE the request instead of being rediscovered with
another 401.

A PIN does not outrank the cooldown. EVERY main turn is pinned — `prepare-turn-context`
forces the active provider+model into `:routing` so a provider failure surfaces as
an error the user acts on — so exempting a pinned provider exempted every real
turn: vis logged a five-minute cooldown and then re-probed, re-minted and
re-fell-back on the very next iteration, ~12-16s later (issue #114). A COOLED pin
is released the way Svar releases a pin after an auth rejection. A pin on a
HEALTHY provider is left alone, and the provider's own accepted request re-admits
it immediately.

No-op while `provider_fallback` is off: with nowhere to route, a rejected
credential surfaces as the provider's own error.
sourceraw docstring

ask-code!clj

(ask-code! opts)

One-shot routed svar/ask-code! against the global router. Plain-text completion + Markdown-code-block extraction — returns the svar map {:blocks :raw :reasoning :tokens :cost :duration-ms :assistant-message :provider-state}. :blocks is a vec of {:lang :source} (one entry per Markdown code block); concatenate yourself with svar.internal.codes/concat-sources if you need a single string. ask! (JSON-spec) is gone; every Vis caller uses ask-code!.

One-shot routed `svar/ask-code!` against the global router.
Plain-text completion + Markdown-code-block extraction — returns the
svar map `{:blocks :raw :reasoning :tokens :cost :duration-ms
:assistant-message :provider-state}`. `:blocks` is a vec of
`{:lang :source}` (one entry per Markdown code block); concatenate
yourself with `svar.internal.codes/concat-sources` if you need a
single string. `ask!` (JSON-spec) is gone; every Vis caller uses
`ask-code!`.
sourceraw docstring

build-routerclj

(build-router config)

Build a router, retaining network policy and account-scoped model metadata provenance.

Build a router, retaining network policy and account-scoped model metadata provenance.
sourceraw docstring

casual-reasoning-levelclj

(casual-reasoning-level resolved-model user-request reasoning-level)

Return the reasoning level Vis sends for user-request to resolved-model.

Only casual chat to a model that chooses its own thinking depth (:adaptive-reasoning-models in its provider's policy) is special-cased: a bare greeting names no depth, and the model's adaptive thinking then decides for itself whether the turn is worth thinking about. Every other request keeps reasoning-level.

Return the reasoning level Vis sends for `user-request` to `resolved-model`.

Only casual chat to a model that chooses its own thinking depth
(`:adaptive-reasoning-models` in its provider's policy) is special-cased: a
bare greeting names no depth, and the model's adaptive thinking then decides
for itself whether the turn is worth thinking about. Every other request keeps
`reasoning-level`.
sourceraw docstring

context-fold-budgetclj

(context-fold-budget context-limit model)

Soft folding threshold for the model named model: its family budget (ctx-engine/prompt-budget-tokens), capped at 90% of a known input window so a provider rejection always keeps a 10% reserve. An unknown window keeps the historical 200K advisory budget.

Soft folding threshold for the model named `model`: its family budget
(`ctx-engine/prompt-budget-tokens`), capped at 90% of a known input window so a
provider rejection always keeps a 10% reserve. An unknown window keeps the
historical 200K advisory budget.
sourceraw docstring

credential-refresherclj

(credential-refresher environment)

Svar's :refresh-credentials hook for one request: answers the provider that rejected its credentials with freshly hydrated ones, or nil when Vis cannot produce new ones for it.

Only OAuth, managed-login and api_key_command providers qualify. On the first re-send it adopts a peer's newer token or forces one refresh through try-refresh-provider-token!. Later re-sends, and a rejection inside the propagation window of a recent refresh, only re-read storage: minting again would issue another token that is not yet valid. Svar spaces the re-sends by its :auth-retry-delays-ms schedule and then applies :on-auth-error. Session headers are merged back because hydration can replace :llm-headers.

Svar's `:refresh-credentials` hook for one request: answers the provider that
rejected its credentials with freshly hydrated ones, or nil when Vis cannot
produce new ones for it.

Only OAuth, managed-login and `api_key_command` providers qualify. On the first
re-send it adopts a peer's newer token or forces one refresh through
[[try-refresh-provider-token!]]. Later re-sends, and a rejection inside the
propagation window of a recent refresh, only re-read storage: minting again
would issue another token that is not yet valid. Svar spaces the re-sends by its
`:auth-retry-delays-ms` schedule and then applies `:on-auth-error`. Session
headers are merged back because hydration can replace `:llm-headers`.
sourceraw docstring

estimate-token-costclj

(estimate-token-cost model input-tokens output-tokens)
(estimate-token-cost model input-tokens output-tokens opts)

Estimate cost from provider usage while preserving cached/non-cached input split. :cost-multiplier scales every monetary component after svar prices the canonical usage; token counts remain untouched.

Estimate cost from provider usage while preserving cached/non-cached input split.
`:cost-multiplier` scales every monetary component after svar prices the
canonical usage; token counts remain untouched.
sourceraw docstring

fast-mode-cost-multiplierclj

(fast-mode-cost-multiplier extra-body turn-features provider)

The price multiplier of provider's fast mode when this turn requested it, else 1.0. The multiplier stays provider-gated so fast intent cannot change a fallback provider's pricing.

The price multiplier of `provider`'s fast mode when this turn requested it,
else 1.0. The multiplier stays provider-gated so fast intent cannot change a
fallback provider's pricing.
sourceraw docstring

fast-mode-routerclj

(fast-mode-router router extra-body turn-features)

Put a requested fast service tier only on the router entry of the provider that declares it, so Svar fallback cannot carry it to another provider. The router's request bodies are Svar's, spelled with keyword keys.

Put a requested fast service tier only on the router entry of the provider
that declares it, so Svar fallback cannot carry it to another provider. The
router's request bodies are Svar's, spelled with keyword keys.
sourceraw docstring

get-routerclj

(get-router)

Get or create the bound project's LLM router from its merged configuration.

Get or create the bound project's LLM router from its merged configuration.
sourceraw docstring

hydrate-environment-routerclj

(hydrate-environment-router environment)
(hydrate-environment-router environment provider-id)

Hydrate only the router snapshot used by this provider attempt. The two-arity form is the real request boundary: it may run managed first-use authentication for the provider the router already resolved, never for unrelated fleet entries.

Hydrate only the router snapshot used by this provider attempt. The two-arity
form is the real request boundary: it may run managed first-use authentication
for the provider the router already resolved, never for unrelated fleet entries.
sourceraw docstring

hydrate-request-model-metadataclj

(hydrate-request-model-metadata environment routing)

Resolve missing or invalid model limits from the selected provider before preflight. Discovery uses the current credential and Svar's account-scoped cache. Explicit configuration wins; only this request's router snapshot changes. A failed or incomplete catalog leaves Svar's metadata diagnostic intact, never a guessed limit.

Resolve missing or invalid model limits from the selected provider before preflight.
Discovery uses the current credential and Svar's account-scoped cache. Explicit
configuration wins; only this request's router snapshot changes. A failed or
incomplete catalog leaves Svar's metadata diagnostic intact, never a guessed limit.
sourceraw docstring

initiator-llm-headersclj

(initiator-llm-headers resolved-model initiator)

{header initiator} when resolved-model's provider names an :initiator-header in its policy and initiator is "user" or "agent"; nil otherwise. The provider bills by who started the call.

`{header initiator}` when `resolved-model`'s provider names an
`:initiator-header` in its policy and `initiator` is "user" or "agent";
nil otherwise. The provider bills by who started the call.
sourceraw docstring

iteration-context-limitclj

(iteration-context-limit max-context-tokens
                         served-model
                         pinned-model
                         &
                         [request-budget])

Input ceiling shared by CTX and folding. The routed Svar budget already accounts for the requested output and independent input cap; never subtract output again. An optional caller ceiling may only reduce it. Without a resolved request, retain the served-model, pinned-model, then historical advisory fallback.

Input ceiling shared by CTX and folding. The routed Svar budget already accounts
for the requested output and independent input cap; never subtract output again.
An optional caller ceiling may only reduce it. Without a resolved request, retain
the served-model, pinned-model, then historical advisory fallback.
sourceraw docstring

iteration-context-modelclj

(iteration-context-model served-model pinned-model & [request-budget])

Name of the model whose family prices the soft budget: the routed request's model, else the served model, else the pinned model — the same precedence that picks the window in iteration-context-limit.

Name of the model whose family prices the soft budget: the routed request's
model, else the served model, else the pinned model — the same precedence that
picks the window in `iteration-context-limit`.
sourceraw docstring

iteration-fold-budgetclj

(iteration-fold-budget max-context-tokens
                       served-model
                       pinned-model
                       &
                       [request-budget])

Soft folding threshold for the window iteration-context-limit resolves, priced for iteration-context-model. The historical advisory fallback is not a known window, so it keeps the advisory budget instead of a reserve below it.

Soft folding threshold for the window `iteration-context-limit` resolves, priced
for `iteration-context-model`. The historical advisory fallback is not a known
window, so it keeps the advisory budget instead of a reserve below it.
sourceraw docstring

iteration-initiatorclj

(iteration-initiator iteration)

Who started iteration iteration of a turn: the person for the first, Vis for every tool-call continuation.

Who started iteration `iteration` of a turn: the person for the first, Vis
for every tool-call continuation.
sourceraw docstring

kickoff-session-providersclj

(kickoff-session-providers environment)

Run provider kickoff hooks against every provider in this session's router.

Preparing the whole fleet before Svar sees it covers internal fallbacks as well as the selected root. The result is recomputed whenever a router is seated, so providers added or reconfigured during a live session receive current metadata.

Run provider kickoff hooks against every provider in this session's router.

Preparing the whole fleet before Svar sees it covers internal fallbacks as well
as the selected root. The result is recomputed whenever a router is seated, so
providers added or reconfigured during a live session receive current metadata.
sourceraw docstring

llm-text!clj

(llm-text! {:keys [messages system prompt reasoning temperature routing]
            :as opts})

Fast helper LLM call for extensions.

Uses svar routing (:routing {:optimize :cost}) instead of Vis-side model name heuristics. The call still goes through svar/ask-code! because Vis no longer uses the retired ask! structured-output path; :lang "text", :reasoning :off, and :code-tail-pointer? true make the return a plain text string under :text. Callers may pass either :messages or :system + :prompt.

Fast helper LLM call for extensions.

Uses svar routing (`:routing {:optimize :cost}`) instead of Vis-side model
name heuristics. The call still goes through `svar/ask-code!` because Vis no
longer uses the retired `ask!` structured-output path; `:lang "text"`,
`:reasoning :off`, and `:code-tail-pointer? true` make the return a plain
text string under :text. Callers may pass either :messages or :system +
:prompt.
sourceraw docstring

merge-cost-mapsclj

(merge-cost-maps acc extra-cost)
source

model-routing-statusclj

(model-routing-status displayed-provider displayed-model)
(model-routing-status router displayed-provider displayed-model)

Live routing health for the model a channel is DISPLAYING (displayed-provider

  • displayed-model — the per-session pick or the config default the picker shows).

svar opens a circuit breaker on a provider after repeated transient failures (5xx / 'Overloaded' 529 / dropped streams) and routes turns to the next AVAILABLE provider so work keeps flowing. The displayed model is computed from config ORDER and is NOT breaker-aware, so during an outage the picker says opus while turns actually land on zai. This reconciles the two: when the displayed provider's breaker is open/half-open, it reports what svar is actually serving so the channel can surface ⚠ <displayed> overloaded — routing to <serving>.

Returns nil when the displayed provider is healthy, else {:overloaded-provider <kw> :overloaded-model <str> :serving-provider <kw> :serving-model <str>}. serving-* is nil if every provider is down.

Live routing health for the model a channel is DISPLAYING (`displayed-provider`
+ `displayed-model` — the per-session pick or the config default the picker
shows).

svar opens a circuit breaker on a provider after repeated transient failures
(5xx / 'Overloaded' 529 / dropped streams) and routes turns to the next
AVAILABLE provider so work keeps flowing. The displayed model is computed
from config ORDER and is NOT breaker-aware, so during an outage the picker
says `opus` while turns actually land on `zai`. This reconciles the two: when
the displayed provider's breaker is open/half-open, it reports what svar is
actually serving so the channel can surface
`⚠ <displayed> overloaded — routing to <serving>`.

Returns nil when the displayed provider is healthy, else
`{:overloaded-provider <kw> :overloaded-model <str>
  :serving-provider <kw> :serving-model <str>}`. `serving-*` is nil if every
provider is down.
sourceraw docstring

normalize-reasoning-levelclj

(normalize-reasoning-level v)

Coerce a reasoning level to svar's canonical :low, :balanced or :deep, or nil. The reasoning_level setting spells the lowest level quick.

Coerce a reasoning level to svar's canonical `:low`, `:balanced` or `:deep`,
or nil. The `reasoning_level` setting spells the lowest level `quick`.
sourceraw docstring

note-auth-rejections!clj

(note-auth-rejections! trace auth-failed)

Start the auth cooldown for every provider Svar left in one request because it rejected its credentials, so later iterations skip it up front instead of paying another 401, refresh and fallback. trace is the request's routing trace, whose authentication fallbacks name the providers Svar left; auth-failed is the set Svar attaches when every candidate refused. Each provider is noted once per request, and only the first trip of a cooldown logs a warning. Call it before note-provider-request-ok! and reseat-pick-after-auth-rescue!, which read the cooldown. Answers the noted provider ids.

Start the auth cooldown for every provider Svar left in one request because it
rejected its credentials, so later iterations skip it up front instead of paying
another 401, refresh and fallback. `trace` is the request's routing trace, whose
authentication fallbacks name the providers Svar left; `auth-failed` is the set
Svar attaches when every candidate refused. Each provider is noted once per
request, and only the first trip of a cooldown logs a warning. Call it before
[[note-provider-request-ok!]] and [[reseat-pick-after-auth-rescue!]], which read
the cooldown. Answers the noted provider ids.
sourceraw docstring

note-provider-request-ok!clj

(note-provider-request-ok! resolved-model iteration-result)

Clear the just-refreshed propagation marker AND any auth cooldown for the provider that ACCEPTED this iteration's request. Keeps credential-refresher's recency window scoped to the post-refresh settling burst, so a real credential rotation later is treated as a fresh 401 (re-mint), never misread as propagation lag, and lets a re-authenticated provider re-enter routing immediately instead of waiting out [[auth-health/AUTH_COOLDOWN_MS]].

iteration-result's :llm-provider is the provider that actually SERVED the request; resolved-model is only Vis' pre-call guess — resolve-effective-model reads the router HEAD, which the turn's pin hoists — so noting the guess let a turn RESCUED on a peer re-admit the dead credential, and the next iteration re-probed it (issue #114). No-op when the provider has neither marker.

Clear the just-refreshed propagation marker AND any auth cooldown for the provider
that ACCEPTED this iteration's request. Keeps [[credential-refresher]]'s recency
window scoped to the post-refresh settling burst, so a real credential rotation
later is treated as a fresh 401 (re-mint), never misread as propagation lag, and
lets a re-authenticated provider re-enter routing immediately instead of waiting
out [[auth-health/AUTH_COOLDOWN_MS]].

`iteration-result`'s `:llm-provider` is the provider that actually SERVED the
request; `resolved-model` is only Vis' pre-call guess — `resolve-effective-model`
reads the router HEAD, which the turn's pin hoists — so noting the guess let a
turn RESCUED on a peer re-admit the dead credential, and the next iteration
re-probed it (issue #114). No-op when the provider has neither marker.
sourceraw docstring

pick-move-eventclj

(pick-move-event {:keys [from to]})

The routing-trace event for a session pick that moved off a dead credential.

Rides the turn's OWN :llm-routing-trace, which every surface already carries end to end (CLI bracket, TUI bubble footer, companion, read_session usage), so the note under the answer can say why the model chip changed without a new wire key. :scope :session-pick marks it as a SESSION-level change rather than this turn's route, which the summary and the note both anchor on separately.

The routing-trace event for a session pick that moved off a dead credential.

Rides the turn's OWN `:llm-routing-trace`, which every surface already carries end
to end (CLI bracket, TUI bubble footer, companion, `read_session` usage), so the
note under the answer can say why the model chip changed without a new wire key.
`:scope :session-pick` marks it as a SESSION-level change rather than this turn's
route, which the summary and the note both anchor on separately.
sourceraw docstring

pick-moved-chunkclj

(pick-moved-chunk iteration-position {:keys [from to] :as move})

Live-progress chunk announcing that a session pick moved off a dead credential. The :provider-fallback shape every channel already draws, so the CLI trace names the swap and the gateway forwards the routing event unchanged.

Live-progress chunk announcing that a session pick moved off a dead credential. The
`:provider-fallback` shape every channel already draws, so the CLI trace names the
swap and the gateway forwards the routing event unchanged.
sourceraw docstring

pin-routing-to-modelclj

(pin-routing-to-model routing resolved-model)

Routing svar cannot walk away from once the human turned provider_fallback off.

Fallback ON returns routing untouched — today's rescue ladder decides. Fallback OFF stamps the model THIS call already resolved to as an explicit :provider/:model pin, so svar's own provider walk has nowhere to land and a failure comes back as the pinned provider's own error instead of a peer's answer. A half-named resolution (no provider, or a blank name) is left alone: pinning half a route names a different model, not this one.

Routing svar cannot walk away from once the human turned `provider_fallback` off.

Fallback ON returns `routing` untouched — today's rescue ladder decides. Fallback OFF
stamps the model THIS call already resolved to as an explicit `:provider`/`:model` pin,
so svar's own provider walk has nowhere to land and a failure comes back as the pinned
provider's own error instead of a peer's answer. A half-named resolution (no provider,
or a blank name) is left alone: pinning half a route names a different model, not this
one.
sourceraw docstring

pin-routing-to-providerclj

(pin-routing-to-provider routing resolved-model)

Routing a REFUSAL switch cannot walk out of.

svar re-asks a declined request by replacing :routing {:model …} and keeping the rest of that map, so a routing which never named a provider lets the router resolve the fallback name wherever it is cheapest — a peer credential answering for a content decision the original provider made. Stamping the provider this call already resolved to keeps the switch inside it. A resolution with no provider is left alone: half a pin routes to a different model, not this one.

Routing a REFUSAL switch cannot walk out of.

svar re-asks a declined request by replacing `:routing {:model …}` and keeping the
rest of that map, so a routing which never named a provider lets the router resolve
the fallback name wherever it is cheapest — a peer credential answering for a
content decision the original provider made. Stamping the provider this call already
resolved to keeps the switch inside it. A resolution with no provider is left alone:
half a pin routes to a different model, not this one.
sourceraw docstring

provider-extra-bodyclj

(provider-extra-body extra-body)

Remove every fast service tier a provider declares from caller-level options after fast-mode-router scoped it to that provider's router entry. Other tiers and unrelated fields remain.

Remove every fast service tier a provider declares from caller-level options
after [[fast-mode-router]] scoped it to that provider's router entry. Other
tiers and unrelated fields remain.
sourceraw docstring

provider-fallback-allowed?clj

(provider-fallback-allowed?)

True while a failed turn may be rescued on a DIFFERENT provider or model.

OFF makes the session's pick a contract: a dead credential, an exhausted rate limit or a broken wire ends the turn with that provider's own error instead of quietly answering from somewhere else. Fallback is never free — the peer's prompt cache is cold (~4x input spend for the rest of the session, issue #154) and the answer arrives from a model the human did not choose — so whether to pay that is theirs to decide.

Reads the VALUE rather than enabled?: an unregistered id (a JVM that never loaded the toggle defaults) must keep TODAY's rescue behaviour, while enabled? is deliberately fail-CLOSED, which here would strand every turn on one provider.

True while a failed turn may be rescued on a DIFFERENT provider or model.

OFF makes the session's pick a contract: a dead credential, an exhausted rate
limit or a broken wire ends the turn with that provider's own error instead
of quietly answering from somewhere else. Fallback is never free — the peer's
prompt cache is cold (~4x input spend for the rest of the session, issue #154)
and the answer arrives from a model the human did not choose — so whether to pay
that is theirs to decide.

Reads the VALUE rather than `enabled?`: an unregistered id (a JVM that never
loaded the toggle defaults) must keep TODAY's rescue behaviour, while `enabled?`
is deliberately fail-CLOSED, which here would strand every turn on one provider.
sourceraw docstring

provider-network-policyclj

(provider-network-policy router resolved-model)

Provider defaults baked into the current router, resolved at the request boundary.

Provider defaults baked into the current router, resolved at the request boundary.
sourceraw docstring

provider-watchdog-timeoutsclj

(provider-watchdog-timeouts provider-network)

Gateway backstops for one provider attempt, kept outside the deadlines Svar enforces for it, so Svar always names and recovers a silent request first. :first-output-timeout-ms covers an attempt with no output yet: the response header wait plus the longest body watchdog. :stall-timeout-ms covers a quiet stream after output: the longer of the idle and semantic watchdogs. A whole-request :timeout-ms caps both. Svar announces each re-send, and the gateway starts a new attempt window there.

Gateway backstops for one provider attempt, kept outside the deadlines Svar
enforces for it, so Svar always names and recovers a silent request first.
`:first-output-timeout-ms` covers an attempt with no output yet: the response
header wait plus the longest body watchdog. `:stall-timeout-ms` covers a quiet
stream after output: the longer of the idle and semantic watchdogs. A
whole-request `:timeout-ms` caps both. Svar announces each re-send, and the
gateway starts a new attempt window there.
sourceraw docstring

rebuild-router!clj

(rebuild-router! config)

Rebuild the router from the given config. Used when provider settings change.

Forwards :router opts so live config edits (e.g. tuning :same-provider-delays-ms) take effect on the next set-provider! without restarting the JVM.

Rebuild the router from the given config. Used when provider settings change.

Forwards `:router` opts so live config edits (e.g. tuning
`:same-provider-delays-ms`) take effect on the next `set-provider!`
without restarting the JVM.
sourceraw docstring

refusal-fallbacks-forclj

(refusal-fallbacks-for router resolved-model)

The refusal-fallback chain for resolved-model WITHIN its own provider, or nil. The provider's policy names the models whose safety classifier can decline a request (stop_reason: refusal) and the ordered models to retry it on (:refusal-fallback); svar owns the actual client-side switch. The current model is dropped — an identical retry earns the identical decline.

Every candidate is checked against the models router says that provider actually serves. svar switches by handing the name back as :routing {:model …}, which the router turns into :force-model: a name this provider does not serve either dies as a routing failure naming no credential, or resolves on ANOTHER provider — a content decision quietly moving the session's billing and its cache. No router, or no sibling on that provider, therefore means no chain and the refusal surfaces as itself.

nil while refusal_fallback is off.

The refusal-fallback chain for `resolved-model` WITHIN its own provider, or nil.
The provider's policy names the models whose safety classifier can decline a
request (`stop_reason: refusal`) and the ordered models to retry it on
(`:refusal-fallback`); svar owns the actual client-side switch. The current
model is dropped — an identical retry earns the identical decline.

Every candidate is checked against the models `router` says that provider actually
serves. svar switches by handing the name back as `:routing {:model …}`, which the
router turns into `:force-model`: a name this provider does not serve either dies
as a routing failure naming no credential, or resolves on ANOTHER provider — a
content decision quietly moving the session's billing and its cache. No router, or
no sibling on that provider, therefore means no chain and the refusal surfaces as
itself.

nil while `refusal_fallback` is off.
sourceraw docstring

reseat-pick-after-auth-rescue!clj

(reseat-pick-after-auth-rescue! env iteration-result)

Repoint the session's model pick onto the provider that actually answered, once the pinned provider's credentials are proven dead. Returns the move it made as {:from {…} :to {…}} for the caller to announce, or nil when nothing moved.

The pick is what the TUI footer chip and the companion header show, and what prepare-turn-context re-pins on EVERY later turn — so leaving it on a dead provider is not cosmetic. The human reads a model the session is not running on, and each lapsed cooldown buys another 401, another forced refresh and another fallback before the same rescue lands again (issue #154). Moving the pick makes the rescue hold for the whole session instead of being rediscovered per turn.

Prompt-cache continuity is already gone by the time this runs — the peer never saw the pinned provider's cache — so the move does not restore it; it stops the session from paying for the same discovery over and over. set-model! carries the reason, which rides the session.model_updated broadcast to every attached surface.

Repoint the session's model pick onto the provider that actually answered, once the
pinned provider's credentials are proven dead. Returns the move it made as
`{:from {…} :to {…}}` for the caller to announce, or nil when nothing moved.

The pick is what the TUI footer chip and the companion header show, and what
`prepare-turn-context` re-pins on EVERY later turn — so leaving it on a dead
provider is not cosmetic. The human reads a model the session is not running on,
and each lapsed cooldown buys another 401, another forced refresh and another
fallback before the same rescue lands again (issue #154). Moving the pick makes the
rescue hold for the whole session instead of being rediscovered per turn.

Prompt-cache continuity is already gone by the time this runs — the peer never saw
the pinned provider's cache — so the move does not restore it; it stops the session
from paying for the same discovery over and over. `set-model!` carries the reason,
which rides the `session.model_updated` broadcast to every attached surface.
sourceraw docstring

resolve-effective-modelclj

(resolve-effective-model router)
(resolve-effective-model router _routing-overrides)

Best-effort root model descriptor from router config.

The returned map carries :name (model id, e.g. "gpt-4o") AND :provider (provider id keyword, e.g. :openai) so every caller can persist BOTH alongside the model. Earlier versions returned just the model map and the provider id was silently dropped on the way to the DB - leaving the meta layer with no way to render provider/model.

Best-effort root model descriptor from router config.

The returned map carries `:name` (model id, e.g. "gpt-4o") AND
`:provider` (provider id keyword, e.g. `:openai`) so every caller
can persist BOTH alongside the model. Earlier versions returned
just the model map and the provider id was silently dropped on
the way to the DB - leaving the meta layer with no way to render
`provider/model`.
sourceraw docstring

resolve-model-infoclj

(resolve-model-info router provider-id model-name)

Resolved model map for the model a SESSION actually routes to.

resolve-effective-model answers a different question — the router's GLOBAL root — and a channel that asks it about a session's capabilities describes the wrong model whenever the session picked something else (which is the normal case: Ctrl+T and the web picker both write a per-session preference). provider-id/model-name come from that preference; either may be nil, and the first provider/model that matches what IS given wins. Falls back to the root model so a session with no preference still gets an answer.

Resolved model map for the model a SESSION actually routes to.

`resolve-effective-model` answers a different question — the router's GLOBAL
root — and a channel that asks it about a session's capabilities describes
the wrong model whenever the session picked something else (which is the
normal case: Ctrl+T and the web picker both write a per-session preference).
`provider-id`/`model-name` come from that preference; either may be nil, and
the first provider/model that matches what IS given wins. Falls back to the
root model so a session with no preference still gets an answer.
sourceraw docstring

resolved-context-budgetclj

(resolved-context-budget environment resolved-model routing extra-body)

Resolve the same routed generation controls Svar will use for preflight.

Resolve the same routed generation controls Svar will use for preflight.
sourceraw docstring

router-for-modelclj

(router-for-model router prefs)

Return a router variant whose provider/model ORDER reflects a model PREFERENCE, so svar's router picks + falls back accordingly — WE don't pick one model, we express the preference and let the inner router decide (no svar change: it already routes by the router's order). prefs is a model name OR an ORDERED coll of names; matching models are hoisted to the front in preference order (within each provider AND across providers), and the rest of the router follows UNCHANGED as fallback. Blank/unknown prefs → the router as-is (child inherits the parent's order).

Vector order alone is DECORATION to svar, which selects by provider :priority and then by the provider's :root model name. So the hoist is also written into both fields: a matched provider's :root becomes its preferred model and the whole fleet is renumbered from its new position. Without that, a coordinator's models list changed the turn card and the cost row while every child turn still ran the default provider's root model.

Return a router variant whose provider/model ORDER reflects a model PREFERENCE,
so svar's router picks + falls back accordingly — WE don't pick one model, we
express the preference and let the inner router decide (no svar change: it
already routes by the router's order). `prefs` is a model name OR an ORDERED
coll of names; matching models are hoisted to the front in preference order
(within each provider AND across providers), and the rest of the router follows
UNCHANGED as fallback. Blank/unknown prefs → the router as-is (child inherits the
parent's order).

Vector order alone is DECORATION to svar, which selects by provider `:priority`
and then by the provider's `:root` model name. So the hoist is also written into
both fields: a matched provider's `:root` becomes its preferred model and the
whole fleet is renumbered from its new position. Without that, a coordinator's
`models` list changed the turn card and the cost row while every child turn
still ran the default provider's root model.
sourceraw docstring

router-initialized?clj

(router-initialized?)

True once the bound project's router has been built. Lets a frontend defer the FIRST build to lazy first-use instead of forcing it at startup — so OAuth token fetches (Copilot/Codex) never run at TUI boot.

True once the bound project's router has been built.
Lets a frontend defer the FIRST build to lazy first-use instead of forcing it
at startup — so OAuth token fetches (Copilot/Codex) never run at TUI boot.
sourceraw docstring

setting-turn-featuresclj

(setting-turn-features snapshot)

The provider fast-mode turn features a resolved setting snapshot switches on, JSON-keyed like a caller's turn_features, or nil. Each provider policy names its own feature; fast-mode-router keeps its tier on that provider.

The provider fast-mode turn features a resolved setting `snapshot` switches
on, JSON-keyed like a caller's `turn_features`, or nil. Each provider policy
names its own feature; [[fast-mode-router]] keeps its tier on that provider.
sourceraw docstring

status->idclj

(status->id status)
source

token-limitclj

(token-limit v)

One context-window candidate as a usable ceiling, or nil.

Candidates come from provider catalogs and from config a human edits, so a window can arrive as "128000", as 0, or as something that is not a number at all. A ceiling that is not a positive number is not a smaller budget — it is a reading that would carry nonsense into every saturation the session prints — so it is skipped in favour of the next source rather than trusted.

One context-window candidate as a usable ceiling, or nil.

Candidates come from provider catalogs and from config a human edits, so a window
can arrive as `"128000"`, as 0, or as something that is not a number at all. A
ceiling that is not a positive number is not a smaller budget — it is a reading
that would carry nonsense into every saturation the session prints — so it is
skipped in favour of the next source rather than trusted.
sourceraw docstring

try-refresh-provider-token!clj

(try-refresh-provider-token! pid rejected)

Recover a refreshable auth rejection of provider pid without mutating any router.

rejected is the exact token the refused request carried. Before spending refresh budget, resolve current storage once: if a peer already installed a different token, simply adopt it. Otherwise force one persisted refresh. The caller re-reads storage for the re-send; no global rebuild or cached-environment reseat is involved.

A command-backed provider has no OAuth hook at all: its refresh is dropping the memoized api_key_command token so the next hydration re-runs the helper. Same budget, same contract.

Recover a refreshable auth rejection of provider `pid` without mutating any router.

`rejected` is the exact token the refused request carried. Before spending refresh
budget, resolve current storage once: if a peer already installed a different
token, simply adopt it. Otherwise force one persisted refresh. The caller re-reads
storage for the re-send; no global rebuild or cached-environment reseat is involved.

A command-backed provider has no OAuth hook at all: its refresh is dropping
the memoized `api_key_command` token so the next hydration re-runs the
helper. Same budget, same contract.
sourceraw docstring

turn-served-modelclj

(turn-served-model env)

Model map for the provider/model that actually answered this turn's last request, or nil before anything has. Falls back to the router's root through resolve-model-info when the served pair is no longer in the fleet.

Model map for the provider/model that actually answered this turn's last request,
or nil before anything has. Falls back to the router's root through
`resolve-model-info` when the served pair is no longer in the fleet.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close