Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.loop


answer-markdownclj

(answer-markdown answer)

Disposable text projection of a final answer. Canonical typed content remains structured; this projection exists only for legacy text-only model context and will not be transported as a second answer shape.

Disposable text projection of a final answer. Canonical typed content remains
structured; this projection exists only for legacy text-only model context and
will not be transported as a second answer shape.
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

assign-project!clj

(assign-project! session-id project-id)

Assign the session soul to project-id (nil clears / removes from project).

Assign the session soul to `project-id` (nil clears / removes from project).
sourceraw docstring

auth-refresh-metricsclj

(auth-refresh-metrics)

Observability snapshot of the OAuth-refresh circuit breaker. Returns the rolling window, the trip threshold, the per-provider count of forced refreshes still inside the window, and the set of providers currently OVER budget (breaker OPEN). Surfaced by the gateway /metrics endpoint so an auth-refresh flap is visible at a glance instead of needing a vis.log grep.

Observability snapshot of the OAuth-refresh circuit breaker. Returns the
rolling window, the trip threshold, the per-provider count of forced
refreshes still inside the window, and the set of providers currently OVER
budget (breaker OPEN). Surfaced by the gateway `/metrics` endpoint so an
auth-refresh flap is visible at a glance instead of needing a `vis.log`
grep.
sourceraw docstring

auto-archive-hot-symbols!clj

(auto-archive-hot-symbols! _environment)

Deprecated NOOP. Cross-turn def survival was removed when the definition_* sidecar tables were dropped; the Python sandbox starts fresh each turn, so there is nothing to archive.

Deprecated NOOP. Cross-turn def survival was removed when the
`definition_*` sidecar tables were dropped; the Python sandbox starts
fresh each turn, so there is nothing to archive.
sourceraw docstring

by-channelclj

(by-channel channel)
source

by-idclj

(by-id id)

Return the session record (UUID :id) or nil.

Return the session record (UUID `:id`) or nil.
sourceraw docstring

cacheclj

In-process env cache.

Keyed by java.util.UUID session-soul-id. Under the 1:1 session ↔ workspace invariant this key is isomorphic to (:workspace/id env) — one cache entry = one session = one workspace = one Python sandbox lineage. Lookups normalize incoming strings to UUID via cache-key so string-id callers keep working alongside the UUID key.

In-process env cache.

Keyed by `java.util.UUID` session-soul-id. Under the 1:1 session ↔
workspace invariant this key is isomorphic to `(:workspace/id env)`
— one cache entry = one session = one workspace = one Python sandbox
lineage. Lookups normalize incoming strings to UUID via `cache-key`
so string-id callers keep working alongside the UUID key.
sourceraw docstring

cache-env!clj

(cache-env! session-id env)

Insert env into the cache under session-id (UUID, or string normalized via cache-key). Returns {:id <UUID> :environment env}.

Insert `env` into the cache under `session-id` (UUID, or string
normalized via `cache-key`). Returns `{:id <UUID> :environment env}`.
sourceraw docstring

child-workspace!clj

(child-workspace! db-info parent-ws)

Spawn the child's workspace. An isolation backend available for the parent's root → a CoW clone of the parent's workspace (workspace/create! {:from parent-ws}): isolated writes, and workspace/apply! later lands the since-fork diff back into the parent root. Else (Windows / non-POSIX, or no backend) → a trunk row at the parent's root (create-trunk-at!): SHARED files, no clone (safety = disjoint :files). Returns the workspace row.

Spawn the child's workspace. An isolation backend available for the parent's
root → a CoW clone of the parent's workspace (`workspace/create! {:from
parent-ws}`): isolated writes, and `workspace/apply!` later lands the
since-fork diff back into the parent root. Else (Windows / non-POSIX, or no
backend) → a trunk row at the parent's root (`create-trunk-at!`): SHARED
files, no clone (safety = disjoint `:files`). Returns the workspace row.
sourceraw docstring

close!clj

(close! id)
source

close-all!clj

(close-all!)
source

create!clj

(create! channel)
(create! channel {:keys [title external-id workspace-id prewarm?]})

Create a brand-new session.

Opts (all optional): :title display title :external-id channel-specific external id :workspace-id pre-spawned workspace to pin the new session to. When omitted, a trunk workspace is auto-minted in create-environment.

Create a brand-new session.

Opts (all optional):
  :title         display title
  :external-id   channel-specific external id
  :workspace-id  pre-spawned workspace to pin the new session to.
                 When omitted, a trunk workspace is auto-minted in
                 create-environment.
sourceraw docstring

create-environmentclj

(create-environment router
                    {:keys [db session channel external-id title workspace-id
                            child prewarm?]})

Creates a vis environment (component) for session lifecycle and querying.

The environment holds:

  • Python sandbox context with custom bindings + bindings cache
  • DB connection (or shared-mem datasource)
  • Router (LLM provider config)
  • Extension registry atom

Params: router - Required. Result of llm/make-router. opts - Map with :db and optional :session, :channel, :external-id, :title.

:db accepted forms: nil - no DB (sandbox-only execution) :memory - ephemeral in-process SQLite DB path string - persistent SQLite DB at path {:path p} - persistent SQLite DB at path {:datasource ds} - caller-owned DataSource (not closed on dispose)

Returns the vis environment map.

Creates a vis environment (component) for session lifecycle and
querying.

The environment holds:
  - Python sandbox context with custom bindings + bindings cache
  - DB connection (or shared-mem datasource)
  - Router (LLM provider config)
  - Extension registry atom

Params:
  `router` - Required. Result of `llm/make-router`.
  `opts`   - Map with `:db` and optional `:session`,
              `:channel`, `:external-id`, `:title`.

  `:db` accepted forms:
    nil               - no DB (sandbox-only execution)
    :memory           - ephemeral in-process SQLite DB
    path string       - persistent SQLite DB at path
    {:path p}         - persistent SQLite DB at path
    {:datasource ds}  - caller-owned DataSource (not closed on dispose)

Returns the vis environment map.
sourceraw docstring

create-project!clj

(create-project! opts)
source

custom-bindingsclj

(custom-bindings env)

Current custom sandbox bindings {sym -> value}.

Current custom sandbox bindings {sym -> value}.
sourceraw docstring

db-infoclj

(db-info)

Return the process-wide shared DB connection bound to (config/resolve-db-spec). Thin wrapper over persistance.core/db-shared-connection! that fills in the default db-spec so frontend callers stay clear of config resolution.

Return the process-wide shared DB connection bound to
`(config/resolve-db-spec)`. Thin wrapper over
`persistance.core/db-shared-connection!` that fills in the default db-spec
so frontend callers stay clear of config resolution.
sourceraw docstring

db-sweep-orphaned-running-turns!clj

(db-sweep-orphaned-running-turns!)
(db-sweep-orphaned-running-turns! db)

Mark every :running turn as :interrupted. Run at process start to clean up turns that crashed or were killed mid-write so the next turn's handover digest renders the right outcome instead of guessing. Returns the number of turns swept.

Mark every `:running` turn as `:interrupted`. Run at process start
to clean up turns that crashed or were killed mid-write so the next
turn's handover digest renders the right outcome instead of guessing.
Returns the number of turns swept.
sourceraw docstring

delete!clj

(delete! id)
source

delete-project!clj

(delete-project! project-id)
source

dispose-environment!clj

(dispose-environment! environment)

Disposes a vis environment and releases resources. For persistent DBs (created with :path), data is preserved. For disposable DBs, all data is deleted.

A sub_loop CHILD env BORROWS the parent's DB connection (:owns-db? false) — disposing the child must NOT close it, or the parent loses its DB mid-turn.

Disposes a vis environment and releases resources. For persistent DBs
(created with `:path`), data is preserved. For disposable DBs, all
data is deleted.

A sub_loop CHILD env BORROWS the parent's DB connection (`:owns-db?` false) —
disposing the child must NOT close it, or the parent loses its DB mid-turn.
sourceraw docstring

ensure-project-for-root!clj

(ensure-project-for-root! root)
(ensure-project-for-root! owner-id root name)

Get-or-create the project bound to canonical workspace root (a project IS a tab set). Race-safe: on a UNIQUE(owner_id, workspace_root) collision from a creator the insert throws and we re-read. name seeds a freshly created project (falls back to the root path).

Get-or-create the project bound to canonical workspace `root` (a project IS a
tab set). Race-safe: on a UNIQUE(owner_id, workspace_root) collision from a
creator the insert throws and we re-read. `name` seeds a freshly created
project (falls back to the root path).
sourceraw docstring

env-forclj

(env-for id)
source

final-answer-gate-errorclj

(final-answer-gate-error environment iteration blocks)
(final-answer-gate-error environment iteration blocks answer-value)
(final-answer-gate-error environment
                         iteration
                         blocks
                         answer-value
                         active-extensions)
(final-answer-gate-error environment
                         iteration
                         blocks
                         answer-value
                         active-extensions
                         extra-ctx)

Dispatch :turn.answer/validate extension hooks against the candidate answer. Returns nil when every hook accepts, otherwise a single string surfaced as the rejected answer's validation error.

A final answer is plain prose with no tool calls, so it inherently never shares an iteration with extension/tool calls: the model uses one iteration to observe tool output, then a later iteration replies with the answer. Extensions that need an additional veto (e.g. user-facing safety / format gates) still get their :turn.answer/validate hook fired here.

active-extensions is passed by the turn loop so activation is computed once per turn; direct callers may omit it and provide :extensions on the environment.

Dispatch `:turn.answer/validate` extension hooks against the
candidate answer. Returns nil when every hook accepts,
otherwise a single string surfaced as the rejected answer's
validation error.

A final answer is plain prose with no tool calls, so it inherently
never shares an iteration with extension/tool calls: the model uses
one iteration to observe tool output, then a later iteration replies
with the answer. Extensions that need an additional veto (e.g.
user-facing safety / format gates) still get their
`:turn.answer/validate` hook fired here.

`active-extensions` is passed by the turn loop so activation is
computed once per turn; direct callers may omit it and provide
`:extensions` on the environment.
sourceraw docstring

gateway-runtime-metricsclj

(gateway-runtime-metrics)

Bounded process/runtime gauges for the gateway metrics endpoint. Values are sampled on demand; no profiler or background allocation is required.

Bounded process/runtime gauges for the gateway metrics endpoint. Values are
sampled on demand; no profiler or background allocation is required.
sourceraw docstring

get-localsclj

(get-locals _environment)

User-defined sandbox vars surface. Live-vars introspection is cosmetic-off for the Python engine (the agent uses its own Python scope + stdlib), so this returns an empty map. Kept as a stable seam for the trailer/renderer callers.

User-defined sandbox vars surface. Live-vars introspection is cosmetic-off
for the Python engine (the agent uses its own Python scope + stdlib), so this
returns an empty map. Kept as a stable seam for the trailer/renderer callers.
sourceraw docstring

get-projectclj

(get-project project-id)
source

get-project-by-rootclj

(get-project-by-root root)
(get-project-by-root owner-id root)

Project bound to canonical workspace root for owner-id (default "local"), or nil.

Project bound to canonical workspace `root` for `owner-id` (default
"local"), or nil.
sourceraw docstring

get-routerclj

(get-router)

Get or create the shared LLM router.

Honors :router opts from ~/.vis/config.edn (:rate-limit, :network, :budget, ...). Without that block svar's built-in defaults apply. See config/router-opts for the supported keys.

Get or create the shared LLM router.

Honors `:router` opts from `~/.vis/config.edn` (`:rate-limit`,
`:network`, `:budget`, ...). Without that block svar's built-in
defaults apply. See `config/router-opts` for the supported keys.
sourceraw docstring

handle-iteration-exception!clj

(handle-iteration-exception! e ctx)

Error path for the main-loop try/catch around run-iteration. Infrastructure failures are terminal for the turn; model/format/code failures still return {::iteration-error ...} for RLM self-correction.

Error path for the main-loop try/catch around `run-iteration`.
Infrastructure failures are terminal for the turn; model/format/code
failures still return `{::iteration-error ...}` for RLM self-correction.
sourceraw docstring

install-extension!clj

(install-extension! environment ext)

Register a validated extension into environment (per-env registration, distinct from the global-registry register-extension! defined earlier in this file).

Checks :ext/requires - if the extension declares dependencies, all listed extension namespaces must already be registered. Throws on missing dependencies.

If an extension with the same :ext/name is already registered, it is replaced (not duplicated). Enables hot-swap via reload-extension! (removed for GraalVM native-image compatibility).

Returns environment for chaining.

Register a validated extension into `environment` (per-env registration,
distinct from the global-registry `register-extension!` defined earlier
in this file).

Checks `:ext/requires` - if the extension declares dependencies, all
listed extension namespaces must already be registered. Throws on
missing dependencies.

If an extension with the same `:ext/name` is already registered,
it is replaced (not duplicated). Enables hot-swap via
`reload-extension!` (removed for GraalVM native-image compatibility).

Returns `environment` for chaining.
sourceraw docstring

iteration-loopclj

(iteration-loop environment
                user-request
                {:keys [system-prompt session-turn-id max-context-tokens hooks
                        cancel-atom cancel-token reasoning-default routing
                        extra-body reasoning-effort turn-features
                        allow-copilot-claude-deep? workspace-overrides]})

The core iteration loop. Runs assemble -> ask LLM -> execute -> persist until the model emits :answer or the user cancels.

The core iteration loop. Runs assemble -> ask LLM -> execute -> persist
until the model emits `:answer` or the user cancels.
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

log-stage!clj

(log-stage! stage iteration data)
source

mark-policy-reload!clj

(mark-policy-reload!)

Invalidate every cached env's frozen security-policy snapshot. Registered as a /reload hook: live sessions recycle at their next turn so vis.yml edits to network domains / filesystem roots actually take effect. Returns nil.

Invalidate every cached env's frozen security-policy snapshot. Registered as
a `/reload` hook: live sessions recycle at their next turn so vis.yml edits
to network domains / filesystem roots actually take effect. Returns nil.
sourceraw docstring

markdown-answer?clj

(markdown-answer? v)

True for the canonical final-answer VALUE: {:answer string}. The answer is the plain prose the model replies with; answer-fn wraps that string into this {:answer string} shape. The only other accepted value is the needs-input-answer? map.

True for the canonical final-answer VALUE: `{:answer string}`.
The answer is the plain prose the model replies with; `answer-fn` wraps that
string into this `{:answer string}` shape. The only other accepted value is
the `needs-input-answer?` map.
sourceraw docstring

model-pricingclj

(model-pricing model)

Per-model price table entry (USD per MILLION tokens) for model, looked up by exact model name in svar's MODEL_PRICING{:input :output :cache-read :cached-input …} — or nil when the model isn't priced. Read-only view over the same table estimate-token-cost bills against, so channel pickers show the price that actually gets charged.

Per-model price table entry (USD per MILLION tokens) for `model`, looked up
by exact model name in svar's `MODEL_PRICING` — `{:input :output :cache-read
:cached-input …}` — or nil when the model isn't priced. Read-only view over
the same table `estimate-token-cost` bills against, so channel pickers show
the price that actually gets charged.
sourceraw docstring

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

needs-input-answer?clj

(needs-input-answer? v)

True for explicit clarification/needs-input answer payloads.

Foundation exposes this through (needs-input ...); the loop keeps the predicate data-shaped instead of depending on foundation namespaces so the core runtime has no extension cycle.

True for explicit clarification/needs-input answer payloads.

Foundation exposes this through `(needs-input ...)`; the loop
keeps the predicate data-shaped instead of depending on foundation
namespaces so the core runtime has no extension cycle.
sourceraw docstring

normalize-reasoning-levelclj

(normalize-reasoning-level v)
source

parallel-sub-loops!clj

(parallel-sub-loops! parent-env specs)

Run several sub-loop!s CONCURRENTLY on Clojure futures, bounded by MAX-PARALLEL-SUBLOOPS (a Semaphore), and return their results as a vector in INPUT ORDER. specs is a seq of {:prompt :subctx :models} maps (the model passes a list of dicts; keys arrive keyword-snake at the GraalPy boundary).

All children share the parent's ONE db-info + depth-cap; the fast rift clone / merge-back steps serialize on workspace-mutation-lock while the expensive child LLM turns overlap. A child that throws does NOT sink the batch — its slot becomes a {:status "failed" :error …} result so the coordinator can see the failure and merge the rest. The sandbox denies Python threads, so concurrency lives Clojure-side on the shared GraalVM Engine (forks are safe mid-eval).

Run several `sub-loop!`s CONCURRENTLY on Clojure futures, bounded by
`MAX-PARALLEL-SUBLOOPS` (a Semaphore), and return their results as a vector in
INPUT ORDER. `specs` is a seq of `{:prompt :subctx :models}` maps (the model
passes a list of dicts; keys arrive keyword-snake at the GraalPy boundary).

All children share the parent's ONE db-info + depth-cap; the fast rift clone /
merge-back steps serialize on `workspace-mutation-lock` while the expensive
child LLM turns overlap. A child that throws does NOT sink the batch — its slot
becomes a `{:status "failed" :error …}` result so the coordinator can see the
failure and merge the rest. The sandbox denies Python threads, so concurrency
lives Clojure-side on the shared GraalVM Engine (forks are safe mid-eval).
sourceraw docstring

policy-reload-epochclj

Monotonic /reload epoch. Every /reload bumps it (via a reload hook). A cache entry stamped with an older epoch is recycled at its NEXT turn boundary so its immutable security-policy snapshot rebuilds from the freshly-reloaded vis.yml. This is the sanctioned way /reload replaces the frozen network-domain / filesystem-root policy: the snapshot drives the GraalPy context, egress proxy, and process jail at env-creation time, so it can only change by rebuilding the env — never by an in-place reseat.

Monotonic `/reload` epoch. Every `/reload` bumps it (via a reload hook).
A cache entry stamped with an older epoch is recycled at its NEXT turn
boundary so its immutable security-policy snapshot rebuilds from the
freshly-reloaded vis.yml. This is the sanctioned way `/reload` replaces the
frozen network-domain / filesystem-root policy: the snapshot drives the
GraalPy context, egress proxy, and process jail at env-creation time, so it
can only change by rebuilding the env — never by an in-place reseat.
sourceraw docstring

projectsclj

(projects)
(projects opts)

List projects (cross-channel). opts: :owner-id (default "local"), :include-archived?. Each carries a live :session-count.

List projects (cross-channel). `opts`: :owner-id (default "local"),
:include-archived?. Each carries a live :session-count.
sourceraw docstring

reap-idle-envs!clj

(reap-idle-envs!)

One reaper sweep: dispose + evict cached session envs idle past env-idle-ttl-ms (or, under heap pressure past env-heap-watermark-pct, EVERY idle env this sweep — TTL ignored), then — if the cache still exceeds env-cache-max — force-evict the least-recently-active idle entries until back under the cap. Every eviction is lock-guarded (a running turn is skipped). Returns the number of entries evicted. Safe to call directly (tests / manual sweeps).

One reaper sweep: dispose + evict cached session envs idle past
`env-idle-ttl-ms` (or, under heap pressure past `env-heap-watermark-pct`,
EVERY idle env this sweep — TTL ignored), then — if the cache still exceeds
`env-cache-max` — force-evict the least-recently-active idle entries until
back under the cap. Every eviction is lock-guarded (a running turn is
skipped). Returns the number of entries evicted. Safe to call directly
(tests / manual sweeps).
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

refresh-cached-routers!clj

(refresh-cached-routers! router)

Reseat :router on every cached env's environment map.

create-environment snapshots the router into (:router env) at construction time, and the iteration loop calls (svar/ask-code! (:router environment) ...) - not the global router-atom. So when a frontend changes provider config and rebuilds the global router, every long-lived env in the cache (TUI keeps one for the whole session) keeps talking to the previous model until disposed.

Call this immediately after rebuild-router! so the next send! on any cached session picks up the new router.

Reseat `:router` on every cached env's environment map.

`create-environment` snapshots the router into
`(:router env)` at construction time, and the iteration loop calls
`(svar/ask-code! (:router environment) ...)` - not the global
`router-atom`. So when a frontend changes provider
config and rebuilds the global router, every long-lived env in the
cache (TUI keeps one for the whole session) keeps talking to the
*previous* model until disposed.

Call this immediately after `rebuild-router!` so the
next `send!` on any cached session picks up the new router.
sourceraw docstring

reorder-project-sessions!clj

(reorder-project-sessions! project-id session-ids)

Atomically adopt any loose named session into project-id, then persist the manual order. Guests owned by another project are never stolen.

Atomically adopt any loose named session into `project-id`, then persist the
manual order. Guests owned by another project are never stolen.
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

retry-sub-loop!clj

(retry-sub-loop! parent-env spec n)

DECORATOR (not a composite): re-run the SAME spec until its child SUCCEEDS, up to n total attempts (default 2). Returns the first successful result, else the last failure — stamped with the :attempts made. (Contrast selector-sub-loops!, which tries DIFFERENT alternatives.)

DECORATOR (not a composite): re-run the SAME `spec` until its child SUCCEEDS,
up to `n` total attempts (default 2). Returns the first successful result,
else the last failure — stamped with the `:attempts` made. (Contrast
`selector-sub-loops!`, which tries DIFFERENT alternatives.)
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). Coordinator: sub_loop(prompt, subctx, {"models": ["haiku", "sonnet"]}) (or a single "model") — try the cheap one first, fall back.

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). Coordinator: `sub_loop(prompt, subctx, {"models": ["haiku",
"sonnet"]})` (or a single `"model"`) — try the cheap one first, fall back.
sourceraw docstring

router-initialized?clj

(router-initialized?)

True once the shared router has been built (via get-router/rebuild-router!). 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 shared router has been built (via `get-router`/`rebuild-router!`).
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

run-iterationclj

(run-iteration environment
               messages
               &
               [{:keys [routing iteration reasoning-level reasoning-effort
                        resolved-model on-chunk extra-body llm-headers
                        active-extensions answer-validation-context]}])

Runs a single RLM iteration: ask! -> check final -> execute code. Returns map with :thinking :blocks :final-result :api-usage etc.

Runs a single RLM iteration: ask! -> check final -> execute code.
Returns map with :thinking :blocks :final-result :api-usage etc.
sourceraw docstring

run-turn!clj

(run-turn! env user-request loop-opts)

Store turn -> iteration-loop -> update turn -> return result.

Derives :prior-outcome (one of :complete, :cancelled, :error) from the loop result and persists it on the session_turn_state row. The next turn's <system_state> digest reads it.

BEFORE the LLM round-trip, every turn is passed through slash/dispatch. When the user-message resolves to a registered slash, the turn is fully handled by a synthetic iteration (tag :user-slash) and the LLM is never called. The transcript still shows the user message + the slash envelope.

A slash NO extension claims (:reason :unknown) gets one more chance as a PROMPT TEMPLATE (.vis/prompts/*.md, ~/.vis/prompts, provider-contributed templates like /<name>): when a template matches, the expanded text runs as a NORMAL LLM turn. Registered slashes always win over templates.

Store turn -> iteration-loop -> update turn -> return result.

Derives `:prior-outcome` (one of `:complete`, `:cancelled`, `:error`)
from the loop result and
persists it on the `session_turn_state` row. The next turn's
`<system_state>` digest reads it.

BEFORE the LLM round-trip, every turn is passed through
`slash/dispatch`. When the user-message resolves
to a registered slash, the turn is fully handled by a synthetic
iteration (`tag :user-slash`) and the LLM is never called. The
transcript still shows the user message + the slash envelope.

A slash NO extension claims (`:reason :unknown`) gets one more
chance as a PROMPT TEMPLATE (`.vis/prompts/*.md`, `~/.vis/prompts`,
provider-contributed templates like `/<name>`): when a
template matches, the expanded text runs as a NORMAL LLM turn.
Registered slashes always win over templates.
sourceraw docstring

selector-sub-loops!clj

(selector-sub-loops! parent-env specs)

:selector composite (a.k.a. fallback) — try specs IN ORDER until one child SUCCEEDS, then STOP. Serial. Returns the vector of results tried, in order: the failed alternatives followed by the first success (the last result), or — if every alternative failed — all of them (all failures). Mirrors the BT selector: any-succeed. (Unlike retry, the alternatives are DIFFERENT specs.)

`:selector` composite (a.k.a. fallback) — try `specs` IN ORDER until one
child SUCCEEDS, then STOP. Serial. Returns the vector of results tried, in
order: the failed alternatives followed by the first success (the last
result), or — if every alternative failed — all of them (all failures).
Mirrors the BT selector: any-succeed. (Unlike `retry`, the alternatives are
DIFFERENT specs.)
sourceraw docstring

send!clj

(send! id messages)
(send! id messages opts)
source

sequence-sub-loops!clj

(sequence-sub-loops! parent-env specs)

:sequence composite — run specs IN ORDER, each only after the prior SUCCEEDS, SHORT-CIRCUITING on the first failure. Serial by nature (each child may depend on the last). Returns the vector of results ACTUALLY RUN, in order: all of them when every child succeeded, or up to and INCLUDING the first failure when it stopped early (that last result carries the failure). Mirrors the BT sequence: all-succeed, fail-fast.

`:sequence` composite — run `specs` IN ORDER, each only after the prior
SUCCEEDS, SHORT-CIRCUITING on the first failure. Serial by nature (each child
may depend on the last). Returns the vector of results ACTUALLY RUN, in order:
all of them when every child succeeded, or up to and INCLUDING the first
failure when it stopped early (that last result carries the failure). Mirrors
the BT sequence: all-succeed, fail-fast.
sourceraw docstring

set-provider!clj

(set-provider! provider)

Set the single active provider config. Persists to disk, updates in-memory state, rebuilds the global router, and reseats cached session envs. provider is a svar-native provider map {:id :base-url :api-key :models [...]}. Replaces an existing provider with the same :id or appends a new entry.

Set the single active provider config. Persists to disk, updates
in-memory state, rebuilds the global router, and reseats cached
session envs. `provider` is a svar-native provider map
`{:id :base-url :api-key :models [...]}`. Replaces an existing
provider with the same `:id` or appends a new entry.
sourceraw docstring

set-title!clj

(set-title! id title)

Host-driven title change. Resolves the live env (if any) so the in-memory atom + listener fan-out stay in sync; falls back to a plain DB write when no env is live for this session (e.g. vis-agent sessions rename ops).

Host-driven title change. Resolves the live env (if any) so the
in-memory atom + listener fan-out stay in sync; falls back to a
plain DB write when no env is live for this session (e.g.
`vis-agent sessions` rename ops).
sourceraw docstring

sub-loop!clj

(sub-loop! parent-env {:keys [prompt subctx models system-prompt]})

Run a CHILD agentic loop for prompt over subctx (the model-supplied focused slice; see subctx->seed-ctx). Forks a child session env (own ctx-atom seeded from subctx, own forked Context on the shared Engine, own workspace per the parent root's isolation backend, reusing the parent's SINGLE DB connection + depth-cap), optionally on a cheaper PROPOSED model preference list models (router-for-model — always a vector, svar falls back). Runs run-turn!, merges the child's workspace diff back (rift path), then ALWAYS tears the child down — env disposed, rift clone trashed (both via guard, failures logged) so nothing leaks across parallel/retry. Returns: {:task_id <focus> :status <string> :answer :changed_files} Throws :vis/subloop-depth-exceeded past MAX-SUBLOOP-DEPTH.

Run a CHILD agentic loop for `prompt` over `subctx` (the model-supplied focused
slice; see `subctx->seed-ctx`). Forks a child session env (own ctx-atom seeded
from subctx, own forked Context on the shared Engine, own workspace per
the parent root's isolation backend, reusing the parent's SINGLE DB
connection + depth-cap),
optionally on a cheaper PROPOSED model preference list `models`
(`router-for-model` — always a vector, svar falls back). Runs `run-turn!`,
merges the child's workspace diff back (rift path), then ALWAYS tears the child
down — env disposed, rift clone trashed (both via `guard`, failures logged) so
nothing leaks across `parallel`/`retry`. Returns:
  {:task_id <focus> :status <string> :answer :changed_files}
Throws `:vis/subloop-depth-exceeded` past `MAX-SUBLOOP-DEPTH`.
sourceraw docstring

subctx->seed-ctxclj

(subctx->seed-ctx _subctx)

Seed ctx for a sub_loop child's ctx-atom from the model-supplied subctx. Child contexts start from an empty engine ctx. PURE. Kept as the named seed site.

Seed ctx for a sub_loop child's ctx-atom from the model-supplied `subctx`.
Child contexts start from an empty engine ctx. PURE. Kept as the named seed site.
sourceraw docstring

sync-active-extension-symbols!clj

(sync-active-extension-symbols! environment)
(sync-active-extension-symbols! environment active-extensions)

Make the Python sandbox's callable globals match active extension state.

install-extension! keeps every extension row in :extensions, but only active extensions contribute callable symbols. Called after per-env installation and again at turn start so :ext/activation-fn changes become real tool availability, not just prompt visibility.

The Python sandbox is FLAT globals (no namespaces/aliases/macros): active extensions putMember their symbols straight into the top scope; deactivated extensions have theirs removed (putMember nil). Symbol names are snake-ified by env/set-python-binding!.

Make the Python sandbox's callable globals match active extension state.

`install-extension!` keeps every extension row in `:extensions`, but only
active extensions contribute callable symbols. Called after per-env
installation and again at turn start so `:ext/activation-fn` changes become
real tool availability, not just prompt visibility.

The Python sandbox is FLAT globals (no namespaces/aliases/macros): active
extensions putMember their symbols straight into the top scope; deactivated
extensions have theirs removed (putMember nil). Symbol names are snake-ified
by env/set-python-binding!.
sourceraw docstring

sync-cached-extension-symbols!clj

(sync-cached-extension-symbols!)

Synchronize extension bindings in every idle cached session immediately.

A Settings change is process-wide while each session owns a persistent Python context. Busy contexts retain their started tool surface and are synchronized at the next turn boundary. Returns the refreshed count.

Synchronize extension bindings in every idle cached session immediately.

A Settings change is process-wide while each session owns a persistent
Python context. Busy contexts retain their started tool surface and are
synchronized at the next turn boundary. Returns the refreshed count.
sourceraw docstring

turn!clj

(turn! environment messages)
(turn! environment messages opts)

Runs one session turn on an RLM environment using iterative LLM code evaluation.

Params: environment - RLM environment from create-environment. messages - Vector of message maps. Always a vector, e.g.: [(svar/user <prompt-text>)] [(svar/user <prompt-text> (svar/image <b64> <mime-type>))] opts - Map, optional:

  • :spec - Output spec for structured answers.
  • :model - Override config's default model.
  • :max-context-tokens - Token budget for context.
  • :debug? - Enable verbose debug logging (default: false). Logs iteration details, code evaluation, LLM responses at :debug level with :rlm-phase context.
  • :reasoning-default - Optional base reasoning effort for reasoning-capable models. Accepts :low/:medium/:high or low/medium/high strings. Adaptive escalation still applies.
  • :reasoning-effort - Exact provider-native effort string, high or max. Catalog-gated and threaded unchanged through every iteration.
  • :extra-body - Optional provider-specific request-body params merged into the upstream LLM call after auto max_tokens + reasoning translation.

Returns: Map with:

  • :trace - Vector of iteration trace entries, each containing: {:iteration N :response <llm-response-text> :blocks [{:id 0 :code <code-str> :result <value> :error nil :envelope {:started-at-ms 10 :finished-at-ms 15 ...}} ...]}
  • :iteration-count - Number of iterations used.
  • :duration-ms - Turn duration in milliseconds.
  • :tokens - Token usage map {"input" N "output" N "total" N} (canonical string keys).
  • :cost - Cost map {"input_cost" N "output_cost" N "total_cost" N} (canonical string keys).
  • :confidence - Confidence level (:high/:medium/:low) from final iteration.
  • :reasoning - String summary of how the answer was derived (from LLM's FINAL call).
  • :status - Only present on failure (:error or :cancelled).
Runs one session turn on an RLM environment using iterative LLM code evaluation.

 Params:
 `environment` - RLM environment from create-environment.
 `messages` - Vector of message maps. Always a vector, e.g.:
              [(svar/user <prompt-text>)]
              [(svar/user <prompt-text> (svar/image <b64> <mime-type>))]
`opts` - Map, optional:
  - :spec - Output spec for structured answers.
  - :model - Override config's default model.
   - :max-context-tokens - Token budget for context.
   - :debug? - Enable verbose debug logging (default: false). Logs iteration details,
     code evaluation, LLM responses at :debug level with :rlm-phase context.
   - :reasoning-default - Optional base reasoning effort for reasoning-capable models.
     Accepts :low/:medium/:high or low/medium/high strings. Adaptive escalation still applies.
   - :reasoning-effort - Exact provider-native effort string, `high` or `max`.
     Catalog-gated and threaded unchanged through every iteration.
   - :extra-body - Optional provider-specific request-body params merged into the
     upstream LLM call after auto max_tokens + reasoning translation.

 Returns:
Map with:
   - :trace - Vector of iteration trace entries, each containing:
       {:iteration N
        :response <llm-response-text>
        :blocks [{:id 0 :code <code-str> :result <value> :error nil
                  :envelope {:started-at-ms 10 :finished-at-ms 15 ...}}
                    ...]}
  - :iteration-count - Number of iterations used.
  - :duration-ms - Turn duration in milliseconds.
  - :tokens - Token usage map {"input" N "output" N "total" N} (canonical string keys).
  - :cost - Cost map {"input_cost" N "output_cost" N "total_cost" N} (canonical string keys).
  - :confidence - Confidence level (:high/:medium/:low) from final iteration.
   - :reasoning - String summary of how the answer was derived (from LLM's FINAL call).
   - :status - Only present on failure (`:error` or `:cancelled`).
sourceraw docstring

update-project!clj

(update-project! project-id opts)
source

validate-iteration-blocks!clj

(validate-iteration-blocks! blocks)

Fail fast if a stored/evaluated block lost mandatory envelope. Tool-result envelopes enforce their nested info separately; this spec enforces the outer block-level eval envelope for every executed block.

Fail fast if a stored/evaluated block lost mandatory envelope.
Tool-result envelopes enforce their nested info separately;
this spec enforces the outer block-level eval envelope for every
executed block.
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