The extension-authoring API: build an extension map, declare its sandbox symbols and values, register its feature toggles and register the extension.
It depends only on the extension and toggle registries, so a namespace that
ships a built-in extension requires it instead of com.blockether.vis.core,
which loads the whole engine. The facade re-exports every name here, so code
written against vis/extension or vis/register-extension! keeps working.
(require '[com.blockether.vis.extension :as ext])
(def my-extension
(ext/extension {:ext/name "my-tools" ... :ext/symbols [(ext/symbol #'my-tool {...})]}))
(defn register! [] (ext/register-extension! my-extension))
The extension-authoring API: build an extension map, declare its sandbox
symbols and values, register its feature toggles and register the extension.
It depends only on the extension and toggle registries, so a namespace that
ships a built-in extension requires it instead of `com.blockether.vis.core`,
which loads the whole engine. The facade re-exports every name here, so code
written against `vis/extension` or `vis/register-extension!` keeps working.
(require '[com.blockether.vis.extension :as ext])
(def my-extension
(ext/extension {:ext/name "my-tools" ... :ext/symbols [(ext/symbol #'my-tool {...})]}))
(defn register! [] (ext/register-extension! my-extension))(extension spec)Build extension spec and stamp caller namespace for reload/source tracking.
Build extension spec and stamp caller namespace for reload/source tracking.
(register-extension! ext)Register an extension in the global process-level registry.
This is THE single entry point for everything an extension
contributes to vis. Whatever the extension declares -- Python sandbox
symbols (:ext.engine/symbols), CLI commands (:ext/cli), channels
(:ext/channels), LLM providers (:ext/providers) -- gets routed here and dispatched into
the matching sub-registry as a side effect.
Also computes source-file markers (paths, max-mtime, sha256) and stores them in a sidecar atom read by the tool-envelope emitter (UI extension provenance label).
Idempotent on :ext/name. Returns the validated extension.
Register an extension in the global process-level registry. This is THE single entry point for everything an extension contributes to vis. Whatever the extension declares -- Python sandbox symbols (`:ext.engine/symbols`), CLI commands (`:ext/cli`), channels (`:ext/channels`), LLM providers (`:ext/providers`) -- gets routed here and dispatched into the matching sub-registry as a side effect. Also computes source-file markers (paths, max-mtime, sha256) and stores them in a sidecar atom read by the tool-envelope emitter (UI extension provenance label). Idempotent on `:ext/name`. Returns the validated extension.
(register-toggle! contribution)Register one toggle that satisfies the contract-owned contribution shape.
Re-registering the same :id is idempotent: metadata MERGES, the
live VALUE in state is preserved (user overrides survive reload).
Returns the normalized contribution.
Register one toggle that satisfies the contract-owned contribution shape. Re-registering the same `:id` is idempotent: metadata MERGES, the live VALUE in `state` is preserved (user overrides survive reload). Returns the normalized contribution.
(render-prompt {:keys [heading usage-note notes] :as opts})Render canonical :ext/prompt-fn text for an extension's symbols.
A prompt fragment states ROUTING and POLICY only: when this extension is the
right approach, and what it refuses. It NEVER restates a signature, an
argument name, a return shape or an example call — that text is the symbol's
own :ext.symbol/description, reached on demand with doc(name). A fragment
is pushed into EVERY request; a docstring is pulled once, so a signature
copied up here is paid for on every turn and drifts from the one that runs.
Accepts an extension map or any map with:
Returns a prompt string suitable for :ext/prompt-fn.
Render canonical `:ext/prompt-fn` text for an extension's symbols.
A prompt fragment states ROUTING and POLICY only: when this extension is the
right approach, and what it refuses. It NEVER restates a signature, an
argument name, a return shape or an example call — that text is the symbol's
own `:ext.symbol/description`, reached on demand with `doc(name)`. A fragment
is pushed into EVERY request; a docstring is pulled once, so a signature
copied up here is paid for on every turn and drifts from the one that runs.
Accepts an extension map or any map with:
- :ext/description or :heading
- :ext.engine/alias optional {:alias 'v}
- :ext.engine/symbols vector of symbol + value entries
- :usage-note optional extra note added to the heading
- :notes optional string or seq of extra lines appended verbatim
Returns a prompt string suitable for :ext/prompt-fn.(symbol v)(symbol v opts)Build a function symbol entry FROM A CLOJURE VAR.
The 3-arg form (symbol sym-name f opts) is a test-friendly direct
constructor: pass the sandbox-visible symbol, the implementation fn, and
an opts map whose :doc / :arglists are read directly from opts
instead of var meta. Production code uses the var form.
The var supplies :symbol (var name), :fn (the var's value), :doc and
:arglists (read from var metadata - i.e. the underlying defn's
docstring + arglists). Pass it as #'my-tool.
Observed tools return canonical internal envelope maps. Declare :activity
beside every observed binding: {:headline "Read file" :show-start false :render callback}.
Activity is for people: use understandable sentence-case English, not identifiers
or all-caps sentences. Quick reads and patches use :show-start false to show only
the end result; slow operations keep the default true to show running progress.
This hides presentation, never internal timing, failure or cancellation tracking. The
optional callback receives invocation details and a bounded, redacted public
result, and returns a canonical Activity presentation. Tools can instead call
publish-activity! while running. No generic result presentation is generated;
the engine owns identity, state, timing, errors and file-change evidence.
Raw helpers pass :raw? true and return plain values directly, with no
envelope enforcement, channel sink, or tool metadata.
Optional opts:
:symbol - override the Python sandbox name (default: var name).
:doc-fn - compute doc lazily from (sym v) when the var
lacks a docstring (third-party vars only).
:raw? - true for plain composable helpers.
:tag - REQUIRED :observation | :mutation for observed
tools (unless :raw? true).
:params - options-dict key vocabulary [{:name "paths" :required? true} {:name "ranges"}], exposed as keyword-only parameters by
inspect.signature and as a Keys line by doc. REQUIRED of every
tool whose call ends in an options dict. Optional defaults are
withheld as ...; required keys have no default.
:before-fn :after-fn :on-error-fn :ticker-fn
Observed tool functions return canonical internal envelope maps. The wrapper records the envelope, then returns only its payload to Python; failure envelopes are converted into thrown ex-info so Python reports normal errors.
:doc and :arglists ALWAYS come from var metadata — the previous
test-only (symbol sym-name f opts) 3-arg form is RETIRED. Tests
that want to register an inline fn must defn it first and pass
#'the-fn.
See docs/src/extensions/hooks.md for hook semantics.
Build a function symbol entry FROM A CLOJURE VAR.
The 3-arg form `(symbol sym-name f opts)` is a test-friendly direct
constructor: pass the sandbox-visible symbol, the implementation fn, and
an opts map whose `:doc` / `:arglists` are read directly from opts
instead of var meta. Production code uses the var form.
The var supplies `:symbol` (var name), `:fn` (the var's value), `:doc` and
`:arglists` (read from var metadata - i.e. the underlying defn's
docstring + arglists). Pass it as `#'my-tool`.
Observed tools return canonical internal envelope maps. Declare `:activity`
beside every observed binding: `{:headline "Read file" :show-start false :render callback}`.
Activity is for people: use understandable sentence-case English, not identifiers
or all-caps sentences. Quick reads and patches use `:show-start false` to show only
the end result; slow operations keep the default true to show running progress.
This hides presentation, never internal timing, failure or cancellation tracking. The
optional callback receives invocation details and a bounded, redacted public
result, and returns a canonical Activity presentation. Tools can instead call
`publish-activity!` while running. No generic result presentation is generated;
the engine owns identity, state, timing, errors and file-change evidence.
Raw helpers pass `:raw? true` and return plain values directly, with no
envelope enforcement, channel sink, or tool metadata.
Optional opts:
:symbol - override the Python sandbox name (default: var name).
:doc-fn - compute doc lazily from `(sym v)` when the var
lacks a docstring (third-party vars only).
:raw? - true for plain composable helpers.
:tag - REQUIRED `:observation | :mutation` for observed
tools (unless `:raw? true`).
:params - options-dict key vocabulary `[{:name "paths" :required? true}
{:name "ranges"}]`, exposed as keyword-only parameters by
inspect.signature and as a Keys line by doc. REQUIRED of every
tool whose call ends in an options dict. Optional defaults are
withheld as ...; required keys have no default.
:before-fn :after-fn :on-error-fn :ticker-fn
Observed tool functions return canonical internal envelope maps. The
wrapper records the envelope, then returns only its payload to Python; failure
envelopes are converted into thrown ex-info so Python reports normal errors.
`:doc` and `:arglists` ALWAYS come from var metadata — the previous
test-only `(symbol sym-name f opts)` 3-arg form is RETIRED. Tests
that want to register an inline fn must `defn` it first and pass
`#'the-fn`.
See `docs/src/extensions/hooks.md` for hook semantics.(value v)(value v opts-or-val)(value sym-name val opts)Build a value symbol entry FROM A CLOJURE VAR - a plain constant/data binding.
The var supplies :symbol (var name), :val (the var's value, unless :val
is provided in opts to override - used by macro-shim entries), and :doc
(from var metadata, i.e. the defn's docstring).
(def ^{:doc "Maximum retry attempts."} max-retries 3) (vis/value #'max-retries)
Opts: :symbol - override the Python sandbox name (default: var name). :val - explicit value override (rare; for macro shims that bind a marker map instead of the var's own value).
Build a value symbol entry FROM A CLOJURE VAR - a plain constant/data binding.
The var supplies `:symbol` (var name), `:val` (the var's value, unless `:val`
is provided in opts to override - used by macro-shim entries), and `:doc`
(from var metadata, i.e. the defn's docstring).
(def ^{:doc "Maximum retry attempts."} max-retries 3)
(vis/value #'max-retries)
Opts:
:symbol - override the Python sandbox name (default: var name).
:val - explicit value override (rare; for macro shims that bind a
marker map instead of the var's own value).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 |