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.Improve settings. Automatic permits bounded model analysis, not command replay or deployment.
Improve settings. Automatic permits bounded model analysis, not command replay or deployment.
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 |