Configuration: paths, JVM lifecycle, provider presets, svar-native coercion, config file I/O, and the active-provider state every channel reads through.
Two halves:
~/.vis/: state.yml (machine-written), vis.mdb/, and
this process's role/start-time/pid-stamped file under logs/ (log-path).
init! / init-cli! / shutdown! redirect stdout/stderr into
that log file and bring up Telemere's file handler.active-config atom holds the
currently-selected provider config; current-config,
active-provider, active-model, provider-ids,
has-provider? are the read API. reload-config! re-reads
from disk.The ->svar-provider helper resolves :api-key lazily by calling
the registered provider's :provider/get-token-fn, so the
token-refresh policy stays inside each provider implementation
instead of leaking up here.
Configuration: paths, JVM lifecycle, provider presets, svar-native
coercion, config file I/O, and the active-provider state every
channel reads through.
Two halves:
- On-disk config under `~/.vis/`: `state.yml` (machine-written), `vis.mdb/`, and
this process's role/start-time/pid-stamped file under `logs/` (`log-path`).
`init!` / `init-cli!` / `shutdown!` redirect stdout/stderr into
that log file and bring up Telemere's file handler.
- Live process state: the `active-config` atom holds the
currently-selected provider config; `current-config`,
`active-provider`, `active-model`, `provider-ids`,
`has-provider?` are the read API. `reload-config!` re-reads
from disk.
The `->svar-provider` helper resolves `:api-key` lazily by calling
the registered provider's `:provider/get-token-fn`, so the
token-refresh policy stays inside each provider implementation
instead of leaking up here.Per-eval / per-call runtime knobs for the loop: Python-sandbox eval timeouts
(with clamping and a shell-timeout-aware widener), the svar/ask-code! stream
watchdog defaults, and the dynamic vars the loop binds per call.
Also the HOST half of the cancel contract: park-blocking-wall stops a
wall's clock while host code legitimately blocks.
A LEAF — depends on nothing else in the engine, so the loop and its tests read these settings from one place instead of carrying them in the loop namespace.
Per-eval / per-call runtime knobs for the loop: Python-sandbox eval timeouts (with clamping and a shell-timeout-aware widener), the `svar/ask-code!` stream watchdog defaults, and the dynamic vars the loop binds per call. Also the HOST half of the cancel contract: [[park-blocking-wall]] stops a wall's clock while host code legitimately blocks. A LEAF — depends on nothing else in the engine, so the loop and its tests read these settings from one place instead of carrying them in the loop namespace.
Process-wide feature-toggle registry.
Replaces the two parallel toggle plumbings we had drifting apart:
:show-thinking, :show-iterations,
:show-silent) wired into state/default-settings,if (some-flag …) … else … checks scattered through
internal/render.clj and channel-tui's render layer.A toggle has stable metadata (id, label, description, default,
owner) and a current ON/OFF value. Anyone — internal modules,
extensions, channels — registers their toggles into the same
registry; any caller flips a toggle through the same set!. The
TUI settings dialog walks the registry to render the list, so
adding a new toggle from an extension shows up in the user's UI
without any TUI patch.
Persistence is opt-in: register-toggle! accepts :persist? true
and on set! the wrapper writes {:toggles {id value}} into the
machine store ~/.vis/state.yml via vis.config/save-config!.
Hand-authored vis.yml / config.yml may ALSO declare a toggles:
block. Ids are plain snake_case strings there (reasoning_level: deep),
identical to the registered id. coerce-config-value maps YAML strings
onto each toggle's type, so a config-declared toggle behaves exactly like
a UI flip. Hydration happens at process start (call
hydrate-from-config! once after config/load-config-raw) and again on
/reload, so editing the YAML applies without a restart.
Contract:
reasoning_level,
shell, ...) — no keywords, namespaces, slashes, or kebab-case.
YAML config uses the same string verbatim (reasoning_level: deep).:description is ONE line within the portable bound owned by
com.blockether.vis.contract.toggle — the settings row is a label
plus a single sentence of help in every channel; longer rationale
lives in the owning namespace's docstring.enabled? is cheap (single atom deref + string lookup), called
per-paint per-row by the render layer; do not turn it into a
function-call indirection.state is left alone so a
user override survives a reload.Process-wide feature-toggle registry.
Replaces the two parallel toggle plumbings we had drifting apart:
- hard-coded TUI booleans (`:show-thinking`, `:show-iterations`,
`:show-silent`) wired into `state/default-settings`,
- per-render `if (some-flag …) … else …` checks scattered through
`internal/render.clj` and channel-tui's render layer.
A toggle has stable metadata (`id`, label, description, default,
owner) and a current ON/OFF value. Anyone — internal modules,
extensions, channels — registers their toggles into the same
registry; any caller flips a toggle through the same `set!`. The
TUI settings dialog walks the registry to render the list, so
adding a new toggle from an extension shows up in the user's UI
without any TUI patch.
Persistence is opt-in: `register-toggle!` accepts `:persist? true`
and on `set!` the wrapper writes `{:toggles {id value}}` into the
machine store `~/.vis/state.yml` via `vis.config/save-config!`.
Hand-authored `vis.yml` / `config.yml` may ALSO declare a `toggles:`
block. Ids are plain snake_case strings there (`reasoning_level: deep`),
identical to the registered id. `coerce-config-value` maps YAML strings
onto each toggle's type, so a config-declared toggle behaves exactly like
a UI flip. Hydration happens at process start (call
`hydrate-from-config!` once after `config/load-config-raw`) and again on
`/reload`, so editing the YAML applies without a restart.
Contract:
- Toggle ids are non-blank snake_case strings (`reasoning_level`,
`shell`, ...) — no keywords, namespaces, slashes, or kebab-case.
YAML config uses the same string verbatim (`reasoning_level: deep`).
- A `:description` is ONE line within the portable bound owned by
`com.blockether.vis.contract.toggle` — the settings row is a label
plus a single sentence of help in every channel; longer rationale
lives in the owning namespace's docstring.
- `enabled?` is cheap (single atom deref + string lookup), called
per-paint per-row by the render layer; do not turn it into a
function-call indirection.
- Defaults are immutable once registered. Re-registering the
same id is allowed (idempotent boot path) and merges over
prior metadata; the live VALUE in `state` is left alone so a
user override survives a reload.Validates raw configuration with the contract JSON Schema and derives runtime policy maps.
Validates raw configuration with the contract JSON Schema and derives runtime policy maps.
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 |