• v0.6.5 d3569904bc

    refactor(tui): thinking streams into whole pane (v0.6.5)

    vh released this 2026-05-24 19:00:58 -07:00 | 252 commits to main since this release

    Operator: "Why does the thinking scroll a little section at the
    bottom of the thinking pane instead of scrolling the whole pane?"

    Root cause: v0.6.1's thinking-current Static was docked to the
    bottom of the Thinking pane and rendered the last 200 chars of
    streaming content. As deltas arrived, the displayed 200-char tail
    shifted — old text fell off the left, new text appeared on the
    right — visually reading as "a little section scrolling at the
    bottom" while the larger thinking-log RichLog above showed only
    the previous run's closed content (or nothing on first turn).

    Fix: stream directly into thinking-log

    The Static is gone. Thinking deltas now write straight to the
    thinking-log RichLog (one delta = one line in the scrollable
    log). The whole pane scrolls naturally as content arrives —
    operator can switch to Ctrl+3 and see streaming content fill
    the pane top-to-bottom.

    Routing pattern:

    First Thinking delta of run:
    → write Rule(title="turn N · thinking #K start") to thinking_log
    → write delta content as a line
    → set thinking_open = True
    Subsequent Thinking deltas:
    → write delta content as a line
    Non-thinking event (closes the run):
    → write Rule(title="turn N · thinking #K end") to thinking_log
    → reset thinking_open

    The Rule(start) at the top of an in-progress run is now the
    "thinking is happening" indicator. No more separate live-preview
    widget required.

    Trade-off: no markdown re-render

    Pre-v0.6.5 closed runs got a Markdown(full_content) render between
    the start/end Rules. v0.6.5 drops that — the streamed deltas ARE
    the content; re-rendering as Markdown would either need to wait
    for run-end (no streaming) OR re-render incrementally per delta
    (bad UX). Streaming wins for "live observability" framing.

    The downside: if model thinking has Markdown structure (lists,
    code), it renders as raw text. Acceptable per operator's "stream
    in line" framing.

    Removed widgets

    • Static#thinking-current (right column / Thinking pane bottom)
    • TuiPresenterState.render no longer takes a thinking_widget param
    • TuiPresenterState.thinking_buffer field dropped (no accumulation)
    • _stream_turn_worker no longer queries #thinking-current
    • on_mount no longer hides #thinking-current
    • DEFAULT_CSS #thinking-current block removed

    Contract amendment

    INV-022 amended: thinking now streams as raw delta lines, not
    Markdown-rendered on close. INV-024 amended: thinking-current
    Static removed entirely (was relocated v0.6.1, removed v0.6.5).
    Drift-check clean.

    Tests

    238/238 GREEN (was 241 — 3 obsolete widget tests deleted:
    test_thinking_widget_truncation, test_thinking_widget_visibility_lifecycle,
    test_terminal_events_belt_and_braces_widget_cleanup). 5 routing tests
    rewritten for the new streaming shape (test_thinking_streams_into_thinking_log,
    test_thinking_closes_to_thinking_log, test_multiple_thinking_runs_...,
    test_render_exception_fallback, test_cancelled_mid_thinking_closes,
    test_left_column_content_only).

    ruff clean. Manual injection test confirms routing: Rule(start) +
    delta lines write to thinking_log; transcript untouched.

    Patch bump (v0.6.4 → v0.6.5) — internal restructure within Thinking
    pane; presenter signature narrowed; no caller-visible public API
    change (RatatoskrApp + AgentPickerApp surfaces identical).

    Downloads