Streaming progress tracker - leaf module.
Channels (TUI, CLI agent, Telegram) 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.
: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, :result/:error,
and :envelope timestamps. The tracker writes
the completed form record into :forms at the
chunk's display index. Chunks tagged :silent?
(or returning :vis/silent) keep their :silent?
flag so channels can toggle visibility.
: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 :result-render str-or-IR-or-nil ;; pre-rendered tool result :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} ...] :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, Telegram) 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.
: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`, `:result`/`:error`,
and `:envelope` timestamps. The tracker writes
the completed form record into `:forms` at the
chunk's display index. Chunks tagged `:silent?`
(or returning `:vis/silent`) keep their `:silent?`
flag so channels can toggle visibility.
: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
:result-render str-or-IR-or-nil ;; pre-rendered tool result
: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} ...]
: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.(make-progress-tracker)(make-progress-tracker {:keys [on-update]})Create a phased progress tracker.
Returns {:on-chunk fn :get-timeline fn}. The :on-chunk fn
accepts the loop's phased chunks and returns nil. The
:get-timeline fn returns the accumulated timeline vec
(oldest-iteration first).
on-update (when supplied) is called (on-update timeline chunk)
after every chunk update, so the consumer can re-render
incrementally.
Create a phased progress tracker.
Returns `{:on-chunk fn :get-timeline fn}`. The `:on-chunk` fn
accepts the loop's phased chunks and returns nil. The
`:get-timeline` fn returns the accumulated timeline vec
(oldest-iteration first).
`on-update` (when supplied) is called `(on-update timeline chunk)`
after every chunk update, so the consumer can re-render
incrementally.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 |