Prompt assembly.
Provider messages are explicit blocks in send order: core system rules,
project instructions (AGENTS.md / CLAUDE.md when present), extension
fragments, current user message. Per-iteration user-role context is the
engine snapshot rendered as a Python dict (session) by the loop.
Prompt assembly. Provider messages are explicit blocks in send order: core system rules, project instructions (AGENTS.md / CLAUDE.md when present), extension fragments, current user message. Per-iteration user-role context is the engine snapshot rendered as a Python dict (`session`) by the loop.
(active-extensions environment)Returns the seq of registered extensions whose :ext/activation-fn returns
truthy for environment, in registration order. Single source of truth for
activation; call ONCE at the top of a turn.
Returns the seq of registered extensions whose `:ext/activation-fn` returns truthy for `environment`, in registration order. Single source of truth for activation; call ONCE at the top of a turn.
(assemble-initial-messages {:keys [initial-user-content turn-context user-images
skipped-images vision? image-descriptions]
:or {vision? true}})The user message that opens the current turn.
:turn-context is the current append-only turn/utilization assignment block
and rides immediately before the current user request. Prior turns are not
assembled here: the conversation trailer carries each one as its own request,
step and answer messages.
:image-descriptions carries the vision fallback's {label {:text … :model …}}
for images this turn's target cannot see. Pure input: deciding whether that
report is worth paying for belongs to the caller, never to message assembly.
The user message that opens the current turn.
`:turn-context` is the current append-only turn/utilization assignment block
and rides immediately before the current user request. Prior turns are not
assembled here: the conversation trailer carries each one as its own request,
step and answer messages.
`:image-descriptions` carries the vision fallback's `{label {:text … :model …}}`
for images this turn's target cannot see. Pure input: deciding whether that
report is worth paying for belongs to the caller, never to message assembly.(assemble-stable-prompt-messages
environment
{:keys [system-prompt active-extensions session-context] :as opts})Assemble provider-prefix messages.
Send order is explicit and tested:
SYSTEM-PROMPT - CORE_SYSTEM_PROMPT + caller addendum
PROJECT-INSTRUCTIONS - AGENTS.md / CLAUDE.md contents (when present)
TURN-SYSTEM-CONTEXT - turn-scoped runtime capability context. Today
it contains extension prompt fragments; future
message, never append a second extension
context.
Extension fragments are separate from the core system prompt and are not repeated in per-iteration trailers.
Required opts:
:active-extensions - vec from (active-extensions env). Drives
environment, extension prompt, and hint collection.
Optional opts:
:system-prompt - caller addendum appended to CORE.
:session-context - rendered fenced-Python session = {…} block
(standing session state: workspace / env / routing / tools). Embedded
ONCE here as a cached system message; the loop re-emits only the
session[...] = … structural delta in the conversation when it changes
mid-turn.
Assemble provider-prefix messages.
Send order is explicit and tested:
`SYSTEM-PROMPT` - CORE_SYSTEM_PROMPT + caller addendum
`PROJECT-INSTRUCTIONS` - AGENTS.md / CLAUDE.md contents (when present)
`TURN-SYSTEM-CONTEXT` - turn-scoped runtime capability context. Today
it contains extension prompt fragments; future
message, never append a second extension
context.
Extension fragments are separate from the core system prompt and are not
repeated in per-iteration trailers.
Required opts:
`:active-extensions` - vec from `(active-extensions env)`. Drives
environment, extension prompt, and hint collection.
Optional opts:
`:system-prompt` - caller addendum appended to CORE.
`:session-context` - rendered fenced-Python `session = {…}` block
(standing session state: workspace / env / routing / tools). Embedded
ONCE here as a cached system message; the loop re-emits only the
`session[...] = …` structural delta in the conversation when it changes
mid-turn.(build-system-prompt opts)Core system prompt + optional caller addendum + config prompt + SYSTEM.md / APPEND_SYSTEM.md file overrides.
Assembled in send order (later blocks positionally reinforce earlier):
base, then the caller's :system-prompt addendum, then the
:system-prompt pulled from Vis config (~/.vis/config.yml / state.yml /
<project>/vis.yml / .vis/config.yml, deep-merged), then ~/.vis/APPEND_SYSTEM.md, then
<workspace>/.vis/APPEND_SYSTEM.md. The config + file hooks let a project
append house rules without any caller having to pass them.
Full rewrite precedence for the base: <workspace>/.vis/SYSTEM.md >
~/.vis/SYSTEM.md > config :system-prompt map with :replace? true >
CORE_SYSTEM_PROMPT. When a file/config replaces the base, addenda and
append files are still appended after it. workspace-root scopes all project
config and file lookups; an omitted root keeps the caller's workspace binding.
Core system prompt + optional caller addendum + config prompt + SYSTEM.md / APPEND_SYSTEM.md file overrides. Assembled in send order (later blocks positionally reinforce earlier): base, then the caller's `:system-prompt` addendum, then the `:system-prompt` pulled from Vis config (`~/.vis/config.yml` / `state.yml` / `<project>/vis.yml` / `.vis/config.yml`, deep-merged), then `~/.vis/APPEND_SYSTEM.md`, then `<workspace>/.vis/APPEND_SYSTEM.md`. The config + file hooks let a project append house rules without any caller having to pass them. Full rewrite precedence for the base: `<workspace>/.vis/SYSTEM.md` > `~/.vis/SYSTEM.md` > config `:system-prompt` map with `:replace? true` > `CORE_SYSTEM_PROMPT`. When a file/config replaces the base, addenda and append files are still appended after it. `workspace-root` scopes all project config and file lookups; an omitted root keeps the caller's workspace binding.
Override injected ONLY for the non-interactive :cli channel (headless
bin/vis-agent '<task>' one-shot runs). No human is in the loop, so the model
must never wait for input — it makes reasonable assumptions and drives the
work to a finished prose answer.
Override injected ONLY for the non-interactive `:cli` channel (headless `bin/vis-agent '<task>'` one-shot runs). No human is in the loop, so the model must never wait for input — it makes reasonable assumptions and drives the work to a finished prose answer.
(extensions-snapshot active-extensions)Build the active extension summary placed under (:extensions ctx) from a
precomputed active-extensions vec.
Returns a vec of compact, fully-realized data maps - NO functions,
NO atoms, NO opaque runtime objects. The model walks this with a
comprehension / filter / any exactly like any other Python list of
dicts; never has to reach into an extensions() call just to discover
what's loaded.
Per element:
:alias - short symbol the model calls under ('v, 'z,
'git, ...). nil when the extension didn't declare
an :ext.engine/alias.
:namespace - fully-qualified ns symbol of the extension.
:doc - one-line LLM description from :ext/description (when set).
:kind - categorical bucket (providers, channels, foundation,
persistance, ...) used as the section
label both in this snapshot and in vis-agent extension list (when set).
:registry-id - canonical manifest id, usually the alias symbol.
:symbols - vec of bare symbol names the extension intern'd into
the sandbox.
The vec is bound ONCE at turn start (see iteration-loop) and
stays frozen for the rest of the turn - every iteration sees the
same value.
Build the active extension summary placed under `(:extensions ctx)` from a
precomputed active-extensions vec.
Returns a vec of compact, fully-realized data maps - NO functions,
NO atoms, NO opaque runtime objects. The model walks this with a
comprehension / `filter` / `any` exactly like any other Python list of
dicts; never has to reach into an `extensions()` call just to discover
what's loaded.
Per element:
:alias - short symbol the model calls under (`'v`, `'z`,
`'git`, ...). nil when the extension didn't declare
an `:ext.engine/alias`.
:namespace - fully-qualified ns symbol of the extension.
:doc - one-line LLM description from `:ext/description` (when set).
:kind - categorical bucket (providers, channels, foundation,
persistance, ...) used as the section
label both in this snapshot and in `vis-agent extension
list` (when set).
:registry-id - canonical manifest id, usually the alias symbol.
:symbols - vec of bare symbol names the extension intern'd into
the sandbox.
The vec is bound ONCE at turn start (see `iteration-loop`) and
stays frozen for the rest of the turn - every iteration sees the
same value.The single opt-in planning workflow shared by every interactive channel.
The single opt-in planning workflow shared by every interactive channel.
(prior-turn-messages {:keys [turn request answer partial-answer interrupted?
cancelled?]})Provider messages that open and close one prior turn of the conversation.
:request is the user message that opened turn turn: the turn marker and
the user's request, in the shape the current turn is sent in. :closing is
the turn's answer as an assistant message. An unfinished turn closes with
what the model had said by then plus an explicit cancellation or
interruption notice. A finished turn without an answer closes with nothing.
Provider messages that open and close one prior turn of the conversation. `:request` is the user message that opened turn `turn`: the turn marker and the user's request, in the shape the current turn is sent in. `:closing` is the turn's answer as an assistant message. An unfinished turn closes with what the model had said by then plus an explicit cancellation or interruption notice. A finished turn without an answer closes with nothing.
(recording-transcript transcription transcription-status)The manifest's two lines about a recording's words: what was said, and — when nobody could say — why there is nothing to read.
A status is NEVER rendered as a blank: turn 35's session had a recording whose transcription silently failed, and neither the model nor the human could tell that from a memo with no speech in it.
The manifest's two lines about a recording's words: what was said, and — when nobody could say — why there is nothing to read. A status is NEVER rendered as a blank: turn 35's session had a recording whose transcription silently failed, and neither the model nor the human could tell that from a memo with no speech in it.
(request-health environment
messages
tools
&
[model accounting message-token-counter])Content-free provenance for one request. Prefer Svar's final :request-accounting over recounting canonical messages: Responses replay filtering, tool shaping and body overrides have already happened. Its components are not rescaled to usage. Wires without prepared accounting retain explicitly labelled logical estimates. Neither estimate replaces same-request provider usage for utilization. Root guidance is disk-only; logical metadata attributes guidance without rereading it. An optional iteration-local message counter shares exact logical estimates with budgeting; prepared accounting never invokes it, splitting its single instructions total across the same labelled parts with the shared tokenizer.
Content-free provenance for one request. Prefer Svar's final :request-accounting over recounting canonical messages: Responses replay filtering, tool shaping and body overrides have already happened. Its components are not rescaled to usage. Wires without prepared accounting retain explicitly labelled logical estimates. Neither estimate replaces same-request provider usage for utilization. Root guidance is disk-only; logical metadata attributes guidance without rereading it. An optional iteration-local message counter shares exact logical estimates with budgeting; prepared accounting never invokes it, splitting its single instructions total across the same labelled parts with the shared tokenizer.
(request-token-counter)(request-token-counter opts)Create one iteration's tokenizer-aware Svar estimate. Reuse each model/message's marginal count across budgeting and health without retaining a cross-request cache. Provider usage remains the authority for an accepted request.
Create one iteration's tokenizer-aware Svar estimate. Reuse each model/message's marginal count across budgeting and health without retaining a cross-request cache. Provider usage remains the authority for an accepted request.
(stable-prompt-text messages)Join stable prompt message contents for token budgeting and debug bindings only. Provider sends the original message vector; this is not a send path.
Join stable prompt message contents for token budgeting and debug bindings only. Provider sends the original message vector; this is not a send path.
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 |