docs(rfc): Transparent Stream activity display mode (#3820) (#3862)

* docs(rfc): add Transparent Stream activity display mode RFC (#3820)

Proposes Transparent Stream as an opt-in, chronological activity display
mode alongside the default Compact Worklog (#3400/#3401). Captures the
display-mode split agreed in #3820: each tool call as a first-class
chronological event, interleaved with reasoning/progress, with compact
previews, consistent across live, settled, and reload/replay paths.

Documents the asymmetry in the existing `simplified_tool_calling` toggle
(live-only, no settled/reload branch) and the three concrete integration
points so the follow-up can be sliced safely. Doc-only; no behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(rfc): refine Transparent Stream rollout scope

---------

Co-authored-by: Frank Song <franksong2702@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Frank Song
2026-06-09 11:38:41 +08:00
committed by GitHub
parent 8d4ed1f90d
commit c6ac6aa5c9
2 changed files with 237 additions and 0 deletions

View File

@@ -49,6 +49,10 @@ First-time contributor RFCs should be discussed in an issue before opening a PR.
- [`live-to-final-assistant-replies.md`](live-to-final-assistant-replies.md)
#3400 product model for long-running assistant replies, live process prose,
tool activity, recovery, terminal outcomes, and the final-answer boundary.
- [`transparent-stream-activity-mode.md`](transparent-stream-activity-mode.md)
#3820 opt-in display mode for power users who need a transparent,
chronological Thinking / progress / tool-call stream alongside the default
Compact Worklog model.
- [`canonical-session-resolution.md`](canonical-session-resolution.md) — #2361
focused contract for resolving URL, query parameter, localStorage, sidebar,
and compression-lineage session IDs to one canonical visible chat target.

View File

@@ -0,0 +1,233 @@
# Transparent Stream — A Chronological Activity Display Mode
- **Status:** Proposed
- **Author:** @franksong2702
- **Created:** 2026-06-09
- **Tracking issue:** [#3820](https://github.com/nesquena/hermes-webui/issues/3820)
- **Parent contract:** [Live-to-Final Assistant Replies](./live-to-final-assistant-replies.md) ([#3400](https://github.com/nesquena/hermes-webui/issues/3400) / #3401 / #3741)
## Problem
After the live-to-final redesign (#3401/#3741), the execution trace of a turn
is presented as a **Compact Worklog / Activity** abstraction: reasoning, progress
text, and tool calls are grouped and summarized into rows like:
```text
Thinking
terminal
Checked the web 6 times, ran 3 tools
```
For the default Web UI audience this is the intended direction — the final
answer stays primary and supporting activity is quieter.
But a class of power users runs the Web UI as an **agent cockpit**: they want to
watch the model work step by step, in real execution order. #3820 documents that
the pre-#3401 *transparent chronological stream* is no longer reachable. The
old behavior exposed concrete events directly in the transcript:
```text
assistant progress text
Thinking / reasoning preview
tool: web_search query / compact output preview
assistant progress text
tool: memory action preview / result preview
assistant progress text
```
Two rounds of investigation on the issue established that **this is not a
discoverability problem** and **cannot be fixed by the existing
`Compact tool activity` toggle** (`simplified_tool_calling`):
1. **The toggle is asymmetric.** The live path branches on
`isSimplifiedToolCalling()` (`static/ui.js``ensureLiveWorklogShell`,
`appendThinking`, `finalizeThinkingCard`), but the **static rebuild path does
not**: the tool-call loop in `renderMessages()` unconditionally buckets tool
calls into an Activity group and summarizes them via `_toolWorklogSummary`.
So the moment a turn settles or the page reloads, the per-tool view collapses
back into the grouped Activity card regardless of the flag.
2. **Even with the flag off, the live view is not a usable cockpit stream.**
Measured in the running UI with `_simplifiedToolCalling=false`: individual
`.tool-card-row` nodes do exist in the DOM, but the running `terminal` card
was pushed out of the viewport (`top=-24`) while the `Thinking` card
dominated the readable area (`top=55 bottom=296`). "Tool cards exist in the
DOM" is **not** equivalent to "the concrete tool call is the primary,
readable item in the transcript flow."
The issue discussion has converged on treating this as a real
**display-mode split**, not another overloaded disclosure default. The
maintainer has invited a PR that rebuilds the desired visual behavior on top of
the refactored codebase, and this RFC records the proposed product boundary for
that work.
## Goals
Introduce **Transparent Stream** as an opt-in display mode that satisfies the
following acceptance criteria. All four must hold; any one missing means #3820
is not solved.
1. **Each tool call is a first-class chronological event** in the main
transcript, in real execution order — never aggregated into
`Ran 11 commands` / `Checked the web 6 times`.
2. **Reasoning, progress text, and tool calls interleave** in the order they
actually occurred (`progress → Thinking → tool → result → progress → …`).
3. **Each tool card exposes a compact preview by default** — tool name, the key
argument (command / query / path / URL / action), a short output preview, and
running/success/error status — with full args and output available on expand.
4. **The mode is consistent across all three render paths**: live streaming,
settled transcript render, and reload/replay. It must not look transparent
live and collapse back into Worklog after settle or reload.
Plus two boundaries:
- **The final answer keeps a clear boundary.** The settled final answer stays
primary and visually separated from the execution trace; the trace does not
bleed into it.
- **During live runs, the currently-running (or latest) tool call is the
primary visible item** — not pushed below a viewport-dominating Thinking card.
This is the specific UX failure documented in the issue and is part of the
live acceptance criteria, not a nice-to-have.
## Non-goals
- **Not a rollback of #3400/#3401.** Compact Worklog remains the default Web UI
mode. Transparent Stream is opt-in.
- **Not a safety/blocking mechanism.** Transparent Stream improves *visibility*
of destructive tool calls (relevant to #3813), but actual interruption/blocking
remains the responsibility of approval gating. Visibility is not a substitute
for a gate.
- **Not reusing `simplified_tool_calling`.** That flag stays only to preserve
existing stored preferences; the new mode does not read it. We do not extend
the old `Compact tool activity` checkbox semantics.
- **Not full transcript virtualization.** Performance hardening for very long
transparent transcripts (#3714) is acknowledged but scoped to a later slice.
## Proposal
### 1. A new, dedicated preference
A new preference, independent of `simplified_tool_calling`:
```python
# api/config.py preferences
"chat_activity_display_mode": "compact_worklog", # | "transparent_stream"
```
- Default `compact_worklog` — existing users see no change.
- Surfaced in Settings as an explicit **segmented choice** (not a checkbox):
- **Compact Worklog** — default; results-first, supporting activity quiet.
- **Transparent Stream** — advanced; every step shown chronologically.
- The legacy `Compact tool activity` checkbox is marked deprecated. It is not
the seam for this feature.
Mirrored to the front end as `window._chatActivityDisplayMode`, with a single
predicate used everywhere:
```js
function chatActivityMode(){ return window._chatActivityDisplayMode || 'compact_worklog'; }
function isTransparentStream(){ return chatActivityMode() === 'transparent_stream'; }
```
### 2. Decouple "event sequence" from "grouping strategy"
The live backend emits ordered SSE events (`token`, `interim_assistant`,
`reasoning`, `tool`, `tool_complete`, `done`, ...). Transparent Stream should
preserve that order instead of applying the Compact Worklog grouping strategy on
top. Settled messages and replay snapshots may not already expose the exact same
event shape, so each implementation slice must normalize the available
transcript, journal, reasoning, and tool-call metadata into an ordered activity
event sequence before rendering.
The fix should therefore be a strategy seam queried at the three render paths,
all feeding a shared renderer where the data is sufficiently normalized:
```text
SSE live ─────────┐
journal replay ───┼──► normalizeToEvents() ──► renderActivityEvent() ──► DOM
settled messages ─┘ (single source of render truth)
```
Using one `renderActivityEvent()` for all three paths is what prevents the
live-vs-static asymmetry that #3820 keeps hitting.
### 3. Concrete integration points (current tree, `static/ui.js`)
These are the three regions that currently fail the criteria above. Line
numbers refer to the tree observed when this RFC was written and are expected to
drift; the function names are the durable anchors.
- **A. Settled rebuild** — the tool-call loop in `renderMessages()`. It has
**no transparent-stream branch at all** today.
Add `if(isTransparentStream())`: for each `tc`, build a standalone card with
the existing `buildToolCard(tc)`, anchor it to its assistant segment via
`_assistantAnchorForActivity(...)`, and insert it
inline in `aIdx/segmentSeq/burstId` order — bypassing `ensureActivityGroup`
and `_syncToolCallGroupSummary`. This is the "missing half" the maintainer
identified, and the highest-value fix because it kills the settle/reload
collapse.
- **B. Live** — `ensureLiveWorklogShell()` and the live
`reasoning`/`tool`/`interim_assistant` handlers. The transparent branch must
**not** just fall back to the old `thinkingRow` (that is the path that pushed
the running tool card off-screen). It must append each event as an
independent row and keep the **currently-running tool card as the primary
visible item**, with Thinking shown as a preview above it rather than the
dominant block.
- **C. Summary bypass** — in transparent mode, `_syncToolCallGroupSummary()` /
`_toolWorklogSummary()` do not run. No "Checked the web 6 times" aggregation
rows.
### 4. Reload/replay consistency
The journal replay path already replays events one by one. In transparent mode
it simply must not invoke the settle-time collapse
(`_convertLiveActivityGroupToSettled`) and must route events through the same
`renderActivityEvent()` as live and settled. Replaying a session in transparent
mode should reproduce the same picture the live stream left.
## Open questions
- **Default on upgrade.** Stay `compact_worklog` for everyone (current proposal),
or honor a prior `simplified_tool_calling=false` as a hint to start in
transparent mode? Leaning toward: no implicit migration — keep it an explicit
opt-in.
- **Per-session vs global.** Is display mode a global preference, or should it be
switchable per session/pane? Proposal: global preference first; per-session
override is a possible follow-up.
- **Tool preview density.** How much output preview is shown by default before
"show more"? This is the dimension we agreed is negotiable; needs a concrete
default (e.g. first N lines / M chars).
- **Performance ceiling.** At what transcript length does transparent rendering
need windowing/virtualization (#3714)? Proposal: gate transparent rendering to
the existing render window first, measure, then decide on virtualization.
## Rollout plan
Shipped as independently-mergeable slices. Ordering principle: **certain,
testable, small-footprint changes first; subjective, hard-to-test, viewport-feel
changes later.**
1. **PR-1 — Internal mode scaffold (no user-facing selector yet).** Add the
`chat_activity_display_mode` preference, boot-time plumbing, and the
`isTransparentStream()` predicate behind tests, but do **not** expose a
Settings control that appears to do nothing. This keeps the first slice safe
without creating a confusing empty toggle.
2. **PR-2 — Settled/reload path + visible selector (integration point A).** Add
the Settings segmented control when transparent mode has at least one visible
behavior: after settle and after reload, tool calls render as inline
chronological cards instead of a collapsed Activity summary. Deterministic
test: reload a transparent-mode session -> tool calls remain per-tool and in
order.
3. **PR-3 — Live path (integration points B + C).** Interleaved per-event live
rendering with the running tool card as the primary visible item; bypass the
summary aggregation. Includes the viewport acceptance check from the issue
evidence. Most subjective, so it follows the deterministic PR-2.
4. **PR-4 — Replay consistency + performance.** Same `renderActivityEvent()` on
the replay path; gate to the render window for long transcripts.
Per the [RFCs README](./README.md): this RFC is a design direction, not an
invitation to implement fragments. Before opening any implementation PR, confirm
in #3820 that the slice is wanted and that @ai-ag2026 is not already building it,
to avoid duplicate work.