Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.session.cancellation

Cancellation token - leaf module.

The cancellation token is a tiny two-atom record that lets a UI thread (TUI, REPL caller) cooperatively abort an in-flight turn! AND interrupt the worker future hosting the blocking provider call. The cooperative side is checked at every iteration boundary; the future side hard-cancels any HTTP call that has already started.

Public API:

(cancellation-token) - fresh token (cancellation-atom token) - cooperative flag atom (pass to turn!) (cancellation-set-future! token fut) - register the worker future (cancel! token) - set flag + interrupt registered future (cancel! token reason) - same, stamping WHO cancelled (cancel-reason token) - the recorded origin of the cancel (cancelled? token) - true once cancel! has been called (cancellation? throwable) - true if exception was caused by cancel! (preserve-interrupt! t) - re-arm the interrupt flag a catch-all ate

This namespace has zero side effects at load time and depends only on Java interop - channels and the runtime can require it directly without pulling in the rest of the SDK.

Cancellation token - leaf module.

The cancellation token is a tiny two-atom record that lets a UI
thread (TUI, REPL caller) cooperatively abort an
in-flight `turn!` AND interrupt the worker future hosting the
blocking provider call. The cooperative side is checked at every
iteration boundary; the future side hard-cancels any HTTP call
that has already started.

Public API:

  `(cancellation-token)`       - fresh token
  `(cancellation-atom token)`  - cooperative flag atom (pass to `turn!`)
  `(cancellation-set-future! token fut)` - register the worker future
  `(cancel! token)`            - set flag + interrupt registered future
  `(cancel! token reason)`     - same, stamping WHO cancelled
  `(cancel-reason token)`      - the recorded origin of the cancel
  `(cancelled? token)`         - true once `cancel!` has been called
  `(cancellation? throwable)`  - true if exception was caused by `cancel!`
  `(preserve-interrupt! t)`    - re-arm the interrupt flag a catch-all ate

This namespace has zero side effects at load time and depends only
on Java interop - channels and the runtime can require it
directly without pulling in the rest of the SDK.
raw docstring

com.blockether.vis.internal.session.goals

Explicit, durable session goals. Only the slash/SDK user path creates or replaces an objective. The model can mark that exact objective complete or blocked, but cannot resume, replace, cancel or increase its budget. Every mutation is a CAS on the persisted revision; the lifecycle version also rejects stale model work. Completion is a model declaration supported by evidence, not an independent judge.

Explicit, durable session goals. Only the slash/SDK user path creates or replaces
an objective. The model can mark that exact objective complete or blocked, but
cannot resume, replace, cancel or increase its budget. Every mutation is a CAS
on the persisted revision; the lifecycle version also rejects stale model work.
Completion is a model declaration supported by evidence, not an independent judge.
raw docstring

com.blockether.vis.internal.session.iteration

Canonical iteration-entry shape — the single source of truth shared by the LIVE progress tracker (internal/progress) and the RESUME projection (channel-tui/chat).

Background: the live-vs-resume split was the root cause of every TUI regression. The live tracker accumulated chunks into one map shape; the resume path rebuilt a different map shape from persisted rows. This ns pins ONE shape both paths populate.

Vocabulary

form envelope — one block = one form record (the engine :forms BLOB), carrying :code, :stdout, :error, and its settled Activity snapshot. Printed stdout is the single success surface; op cards / render-fns are gone.

Canonical iteration-entry

{:position n ;; 0-based display position of the iteration :scope "tN/iM" ;; BLOCK-level scope, never /fK :thinking string-or-nil ;; reasoning text for this iteration :code "<block source>" :forms [<form> ...] ;; form envelopes (engine :forms BLOB) :status :ok|:error|:running|:cancelled|:timeout :duration-ms long :error error-map-or-nil}

Canonical iteration-entry shape — the single source of truth shared by
the LIVE progress tracker (`internal/progress`) and the RESUME projection
(`channel-tui/chat`).

Background: the live-vs-resume split was the root cause of every TUI
regression. The live tracker accumulated chunks into one map shape; the
resume path rebuilt a *different* map shape from persisted rows. This ns
pins ONE shape both paths populate.

## Vocabulary

  form envelope — one block = one form record (the engine `:forms`
                  BLOB), carrying `:code`, `:stdout`, `:error`, and its
                  settled Activity snapshot. Printed stdout is the single
                  success surface; op cards / render-fns are gone.

## Canonical iteration-entry

  {:position    n              ;; 0-based display position of the iteration
   :scope       "tN/iM"        ;; BLOCK-level scope, never /fK
   :thinking    string-or-nil  ;; reasoning text for this iteration
   :code        "<block source>"
   :forms       [<form> ...]   ;; form envelopes (engine :forms BLOB)
   :status      :ok|:error|:running|:cancelled|:timeout
   :duration-ms long
   :error       error-map-or-nil}
raw docstring

com.blockether.vis.internal.session.model

Persistent, channel-NEUTRAL per-session model preference.

ONE source of truth — session_soul.llm_pref_provider + llm_pref_model in the DB — for every channel (web gateway + TUI), so a session routes through the same PROVIDER + MODEL wherever it's opened and the choice survives restarts. Provider + model (not just a model name) mirrors how a turn records its route and disambiguates a model name shared by >1 provider.

The engine reads it at turn start (prepare-turn-context in loop.clj) as the default route when the caller passes none; router-for-model hoists the chosen model (the provider follows, since it's the one carrying that model).

DEBOUNCED WRITE-BACK: set-model! updates an in-memory value IMMEDIATELY (footer + engine see it at once) and coalesces the DB write, so cycling the model (TUI Ctrl+T) many times in a row produces a SINGLE write. Reads prefer the pending in-memory value, falling back to the DB.

Values are {:provider <id-string-or-nil> :model <name>} or nil. Keyed by the session-soul id (the gateway's sid and the engine env's :session-id).

Persistent, channel-NEUTRAL per-session model preference.

ONE source of truth — `session_soul.llm_pref_provider` + `llm_pref_model`
in the DB — for every channel (web gateway + TUI), so a session routes
through the same PROVIDER + MODEL wherever it's opened and the choice
survives restarts. Provider + model (not just a model name) mirrors how a
turn records its route and disambiguates a model name shared by >1 provider.

The engine reads it at turn start (`prepare-turn-context` in loop.clj) as
the default route when the caller passes none; `router-for-model` hoists the
chosen model (the provider follows, since it's the one carrying that model).

DEBOUNCED WRITE-BACK: `set-model!` updates an in-memory value IMMEDIATELY
(footer + engine see it at once) and coalesces the DB write, so cycling the
model (TUI Ctrl+T) many times in a row produces a SINGLE write. Reads prefer
the pending in-memory value, falling back to the DB.

Values are `{:provider <id-string-or-nil> :model <name>}` or nil. Keyed by
the session-soul id (the gateway's `sid` and the engine env's `:session-id`).
raw docstring

com.blockether.vis.internal.session.progress

Streaming progress tracker - leaf module.

Channels (TUI, CLI agent) consume the iteration loop's PHASED chunks via this tracker. Every chunk carries a :phase keyword that tells the tracker what to do with it; the tracker accumulates the chunks into a per-iteration timeline that the channel re-renders incrementally.

Phases (every chunk has exactly one):

:reasoning LLM is streaming reasoning text. Updates the iteration entry's :thinking field.

:tool-preview LLM is streaming the block's code. Carries the cumulative source separately from reasoning/content; the first real form replaces this ephemeral slot.

:form-start One block is about to evaluate. Carries :position and :code. The tracker writes the code immediately so channels can show the currently-running block before the result lands.

:form-result One block finished evaluating. Carries :position, :code, :stdout/:error, and :envelope timestamps. The tracker writes the completed form record into :forms at the chunk's display index. Chunks tagged :silent? keep their flag so channels can toggle visibility.

:form-activity One block's bounded Activity snapshot — what it has DONE beside what it will return. Running and settled revisions are full REPLACEMENTS into the form slot :position names, so a dropped running frame costs a repaint and never a wrong picture. :iteration-final Iteration is complete. Carries :final (nil when the turn isn't done yet) and :done? (true when this iteration produced the turn-terminal answer). The block chunk has already streamed; this is the trim "iteration done" marker.

:iteration-error Iteration aborted before forms could run (e.g. LLM call failed). Carries :thinking and :error.

:provider-retry-reset Provider stream failed before code eval and Vis is retrying the provider call. Clears stale live reasoning/content for this attempt and keeps a retry recap in :provider-fallbacks.

Public API:

(make-progress-tracker) - fresh tracker, no callback (make-progress-tracker {:on-update}) - invokes (on-update timeline chunk) on every chunk

Returns {:on-chunk fn :get-timeline fn}. Pass the :on-chunk fn under :hooks {:on-chunk ...} of sessions/send!. Each timeline entry has the shape:

{:iteration N :thinking str-or-nil :forms [{:code str :comment str-or-nil :render-segments [{:kind ...} ...] ;; source classification :stdout str-or-nil ;; canonical printed output :result-kind :tool|:value|:error :result-detail map-or-nil ;; tool metadata :error map-or-nil :duration-ms int :success? bool :silent? bool :started-at-ms int-or-nil :activity map-or-nil ;; bounded tool-call trace} ...] :provider-fallbacks [map ...] ;; routed provider fallback notices :activity nil-or-keyword ;; live coarse phase (:provider-call/:response-parse) :elided-form-idxs #{int ...} ;; original loop indices hidden from :forms :error nil-or-iteration-error :final nil-or-{:answer :iteration-count :status} :done? bool}

The pre-existing :events interleaving log was removed: it lived only in memory (never persisted), and resumed bubbles re-render from this single flat layout. One layout path is enough.

Streaming progress tracker - leaf module.

Channels (TUI, CLI agent) consume the iteration loop's
PHASED chunks via this tracker. Every chunk carries a `:phase`
keyword that tells the tracker what to do with it; the tracker
accumulates the chunks into a per-iteration timeline that the
channel re-renders incrementally.

Phases (every chunk has exactly one):

  :reasoning        LLM is streaming reasoning text. Updates the
                    iteration entry's `:thinking` field.

  :tool-preview     LLM is streaming the block's code. Carries the
                    cumulative source separately from reasoning/content;
                    the first real form replaces this ephemeral slot.

  :form-start       One block is about to evaluate. Carries
                    `:position` and `:code`. The tracker writes the
                    code immediately so channels can show the
                    currently-running block before the result lands.

  :form-result      One block finished evaluating. Carries
                    `:position`, `:code`, `:stdout`/`:error`,
                    and `:envelope` timestamps. The tracker writes
                    the completed form record into `:forms` at the
                    chunk's display index. Chunks tagged `:silent?`
                    keep their flag so channels can toggle visibility.

  :form-activity    One block's bounded Activity snapshot — what it has DONE
                    beside what it will return. Running and settled revisions are
                    full REPLACEMENTS into the form slot `:position` names, so a
                    dropped running frame costs a repaint and never a wrong picture.
  :iteration-final  Iteration is complete. Carries `:final` (nil
                    when the turn isn't done yet) and `:done?`
                    (true when this iteration produced the
                    turn-terminal answer). The block chunk has
                    already streamed; this is the trim
                    "iteration done" marker.

  :iteration-error  Iteration aborted before forms could run
                    (e.g. LLM call failed). Carries `:thinking`
                    and `:error`.

  :provider-retry-reset
                    Provider stream failed before code eval and Vis is
                    retrying the provider call. Clears stale live
                    reasoning/content for this attempt and keeps a retry
                    recap in `:provider-fallbacks`.

Public API:

  `(make-progress-tracker)`              - fresh tracker, no callback
  `(make-progress-tracker {:on-update})` - invokes `(on-update timeline chunk)`
                                           on every chunk

Returns `{:on-chunk fn :get-timeline fn}`. Pass the `:on-chunk` fn
under `:hooks {:on-chunk ...}` of `sessions/send!`. Each timeline
entry has the shape:

  {:iteration N
   :thinking  str-or-nil
   :forms     [{:code            str
                :comment         str-or-nil
                :render-segments [{:kind ...} ...] ;; source classification
               :stdout          str-or-nil        ;; canonical printed output
               :result-kind     :tool|:value|:error
                :result-detail   map-or-nil        ;; tool metadata
                :error           map-or-nil
                :duration-ms     int
                :success?        bool
                :silent?         bool
                 :started-at-ms   int-or-nil
                 :activity        map-or-nil        ;; bounded tool-call trace} ...]
   :provider-fallbacks [map ...]   ;; routed provider fallback notices
   :activity           nil-or-keyword ;; live coarse phase (:provider-call/:response-parse)
   :elided-form-idxs   #{int ...}  ;; original loop indices hidden from :forms
   :error              nil-or-iteration-error
   :final              nil-or-{:answer :iteration-count :status}
   :done?              bool}

The pre-existing `:events` interleaving log was removed: it lived
only in memory (never persisted), and resumed bubbles re-render
from this single flat layout. One layout path is enough.
raw docstring

com.blockether.vis.internal.session.titling

Session-title subsystem, lifted out of the loop namespace: the three listener registries (per-session value, global, and the pending/spinner channel), the single set-title-with-broadcast! mutation point, and the async auto-title side-channel (an off-surface ask! that names a session on its first real turn). A LEAF — depends only on persistance + svar + runtime-settings, never back on the loop.

Session-title subsystem, lifted out of the loop namespace: the three listener
registries (per-session value, global, and the pending/spinner channel), the
single `set-title-with-broadcast!` mutation point, and the async auto-title
side-channel (an off-surface `ask!` that names a session on its first
real turn). A LEAF — depends only on persistance + svar + runtime-settings,
never back on the loop.
raw 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