DSH / Atlas
2026-08-14implementedfeaturearchived 2026-09-04

Web Turn process folding

Web 轮次过程折叠

A model Turn can expose System prompt, Context injection, reasoning, several Assistant replies, Tool calls, and Retry rows before its final answer. Keeping that whole trajectory at full height obscures the answer, while moving independent Chat Nodes under a parent disclosure would remount stateful Tool renderers and disturb chronological evidence. The compact view must hide completed process work without hiding the o

English

Problem

A model Turn can expose System prompt, Context injection, reasoning, several Assistant replies, Tool calls, and Retry rows before its final answer. Keeping that whole trajectory at full height obscures the answer, while moving independent Chat Nodes under a parent disclosure would remount stateful Tool renderers and disturb chronological evidence. The compact view must hide completed process work without hiding the only evidence available while a Turn is still thinking, using a Tool, retrying, or ending without an answer.

Decision

The Host-backed ui-chat.transcriptView preference selects normal or compact and defaults to compact. Normal leaves every process row visible and renders no Turn-process control. Compact applies the disclosure rules below. Switching modes changes wrapper visibility without reparenting or unmounting Chat Node renderers, and the preference remains outside the Session log.

In Compact mode, a Turn remains fully expanded while it is open. At turn/end, its latest Step becomes a final-answer boundary only when it contains user-facing Assistant reply content—non-blank text, an image, or an unknown visible block—and contains no Tool-call block. The answer remains visible. Context injection, reasoning, earlier Assistant material, Tool rows, and Retry rows before that boundary form one process disclosure. System prompt, User, and steering rows remain independent and never join the group. Completed, aborted, interrupted, failed, and max-token Turns use the same terminal projection; error, max-token, and turn-tail rows remain outside the group. A closed Turn with no final answer keeps all process evidence visible.

The Turn-scoped turn-process Definition derives the first model or Tool evidence, the latest Step's finalized answer boundary, reply-bearing durable Assistant-message count before that answer, and Tool-call counts from log events plus Step Location data. Shipped subagent delegation names (subagent and subagent_*) increment the subagent count instead of the ordinary Tool-call count, so the categories never overlap. Context injection remains process evidence without incrementing a summary count; System prompt is independent, stays visible, and remains before the opening User. The Definition publishes one immutable TurnProcessSpec directly to both Turn Location data and its stable control Chat Node; continuing open-stream updates reuse both values while their fields remain unchanged. The Chat target positions opening User or steering input before process candidates from their first projection, then inserts the synthetic control between that input and the process rows. Without opening human input, the control stays before the earliest process candidate from its first appearance. Answer finalization, Retry, later Steps, completion, and manual expansion therefore change visibility without changing existing nodes' relative order, as specified by stable Turn-process ordering.

ChatTurnProcessProjector owns the cross-Node presentation facts. It scans only an affected Turn when Node structure, TurnProcessSpec, or Turn status changes, retains an equal presentation by reference, and publishes a stable process source only to Seats in a changed Turn. Each Seat classifies its own membership and answer role from that shared presentation without reading the global Chat snapshot, scanning the Turn, or encoding and decoding a signature. Turn status and loaded-window completeness gate foldability: an open Turn never folds, and a partial history exposes neither the control nor hidden members. The control Node exists from the first process evidence onward but its Seat remains hidden until the closed Turn has a final answer and complete history. Once visible, it omits every zero-valued segment, uses Thought for a while when all three counts are zero, and places a full-width divider below the summary.

The Chat target binds the durable transcript preference through the shared settings scope and keeps per-Turn interaction state in its session-scoped Chat store. ChatView renders each business Node through one stable keyed ChatNodeSeat; adding the process control does not reorder existing keys, and Compact mode changes the Seat wrapper's hidden attribute without reparenting or unmounting a Tool, Assistant, Context, or Retry renderer. The Seat passes the same process state through ChatNodeOwnerProps, so the final Assistant renderer hides reasoning blocks from its own Step while leaving reply blocks visible; wrapper visibility and inline reasoning therefore share one UI-state source.

Closed process members use hidden="until-found". A beforematch event on any member opens the shared group in supporting browsers. The Chat column applies spacing only between visible siblings because hidden-until-found members retain searchable zero-height boxes; the control's divider spans the content width, and a closed process control uses an 8px answer gap only when no independent input intervenes, while expansion restores the ordinary 16px row spacing. A collapsed Think row follows the latest streamed line through CSS, has one font-axis-adjusted fixed row height, and applies size and layout containment; expansion removes that containment and restores natural prose height. In Compact mode, the non-persisted session store contains only manually expanded Turn-and-answer-Step generations; absence means collapsed, and a different answer generation starts collapsed. Every eligible closed Turn therefore uses the same default regardless of whether it completed live, appeared after Load earlier, or closed while the reader was away from the tail. This can reflow content above the reader when a Turn closes or history becomes complete. An automatic collapse that would hide a focused process descendant opens the shared group instead, leaving keyboard focus in place; a manual close focuses the process control before hiding its members. If Load earlier is present, every process remains expanded and its control stays hidden; once history is complete, eligible groups immediately use the collapsed default. A fresh page load restores the durable Normal or Compact preference; per-Turn manual expansion survives only view remounts within the same page lifetime. Switching to Normal reveals every process row, while switching back to Compact reapplies the page-lifetime manual overrides over the collapsed default.

This presentation composes with Conversation Node assembly: Definitions own deterministic process facts, the Seat owns shared interaction state, and keyed renderers remain independent. The log-ordered human transcript remains complete because folding changes no session event or model input.

Alternatives considered

Fold only earlier Assistant replies. Rejected because a common Think → Tool → answer Turn has only one reply-bearing Step and would expose no compact control, leaving the user's requested process content at full height.

Keep Context injection outside the process. Rejected because injected runtime context is part of the pre-answer trajectory rather than a new human instruction. Its own disclosure and label remain intact when the process is expanded. System prompt is kept outside because moving or hiding the request-wide instruction changes the visible frame around the opening User.

Reparent the whole Turn under one summary row. Rejected because eligibility changes while the Turn runs, and moving existing Chat Nodes across React parents remounts stateful Tool views. Stable Seats provide one disclosure without moving their children.

Store manual expansion in Turn Location data. Rejected because Location data is a deterministic projection of session events and has no browser-action write path. UI gestures belong to a declared, non-persisted store.

Reuse DisclosureRow and unmount closed members. Rejected because browser find could not discover their text and reopening would reconstruct stateful renderer subtrees.

Fold a live answer candidate before turn/end. Rejected because streamed text can still be followed by a Tool call, Retry, or later thinking Step. Waiting for the terminal boundary prevents automatic collapse–expand–collapse cycles and the resulting layout jumps.

Defer a newly eligible collapse while the reader is away from the tail. Rejected because it requires transient completion tracking and deferred state, and makes identical closed Turns start in different states depending on how they entered the viewport. Closed Turns use one deterministic default; scroll anchoring preserves position, while the focus guard preserves an active interaction.

Consequences

Compact mode keeps the final answer prominent even when the Turn contains only injected Context, reasoning, or Tools before it, while expansion restores every process row in original order. Normal mode preserves the complete transcript without Turn-level controls. Hidden wrappers and Markdown subtrees remain mounted, trading browser memory for stable Tool state, manual expansion across view remounts, and browser-find recovery. Ordinary cross-message selection excludes closed members only in Compact mode; users expand the group before selecting them or choose Normal. Browsers without hidden="until-found" and beforematch retain manual disclosure but cannot reveal closed process text through page search. Unit coverage pins finalized answer boundaries, Retry and interruption, shared cross-kind expansion, final-Step reasoning, mode switching, manual expansion, immediate history-completion folding, off-tail folding, focus preservation, and content-only final-page revisions; assembled browser snapshots pin running, aborted, completed, paged-history, and persisted-setting trajectories.

中文

问题

一个模型轮次可能会在最终正文之前展示系统提示词、上下文注入、推理、多条 Assistant 回复、工具调用与重试行。完整展示整条轨迹会淹没正文,而把独立 Chat Node 移入一个父级 disclosure 会重挂载有状态的工具 renderer,并扰乱按时间排列的证据。紧凑视图必须收起已完成的过程工作,同时在轮次仍处于推理、使用工具、重试或没有正文便结束时,保留当下唯一可用的证据。

决策

由 Host 支撑的 ui-chat.transcriptView 偏好提供 normal 与 compact 两种模式,默认值为 compact。Normal 保持所有过程行可见且不渲染轮次过程控件;Compact 应用下述 disclosure 规则。切换模式只改变 wrapper 可见性,不会重新挂接或卸载 Chat Node renderer;该偏好不写入 Session log。

在 Compact 模式下,轮次打开期间始终完整展开。到 turn/end 时,只有当最近步骤包含面向用户的 Assistant 回复内容——非空文本、图片或未知可见块——并且不含工具调用块时,该步骤才成为最终正文边界。正文保持可见。边界之前的上下文注入、推理、较早 Assistant 内容、工具行与重试行统一进入一条过程 disclosure。系统提示词、用户消息与 steering 消息保持独立,绝不加入过程组。已完成、已取消、已中断、失败和达到最大 token 的轮次使用同一终态投影;错误、最大 token 与 turn-tail 行留在过程组外。关闭时没有最终正文的轮次会保留全部过程证据。

轮次作用域的 turn-process Definition 根据日志事件与步骤 Location data 推导首条模型或工具证据、最近步骤的已定稿正文边界、该正文之前带回复内容的持久 Assistant 消息数和工具调用计数。随产品交付的 subagent 委派名称(subagent 与 subagent_*)只增加 subagent 计数,不增加普通工具调用计数,因此两类不会重叠。上下文注入仍是过程证据但不增加摘要计数;系统提示词保持独立、持续可见,并始终位于开场 User 上方。Definition 把同一份不可变 TurnProcessSpec 直接发布到 Turn Location data 与稳定控制 Chat Node;持续 open stream 的更新在字段不变时复用两份值。Chat target 从首次投影起就把开场 User 或 steering 输入放在过程候选之前,再把合成控制行插入该输入与过程行之间。没有开场人工输入时,控制行从首次出现起就位于最早的过程候选之前。因此正文定稿、Retry、后续步骤、完成状态与手动展开只改变可见性,不改变既有节点的相对顺序,具体规则由稳定的轮次过程排序说明。

ChatTurnProcessProjector 拥有跨 Node 的呈现事实。只有 Node 结构、TurnProcessSpec 或 Turn 状态变化时,它才扫描受影响的 Turn;相等的呈现会按引用保留,且只有变化 Turn 内的 Seat 会收到稳定 process source 的发布。每个 Seat 从共享呈现判断自身的过程成员与正文角色,无需读取全局 Chat snapshot、扫描 Turn 或编码再解码签名。Turn 状态与已加载窗口是否完整共同决定能否折叠:打开中的 Turn 绝不折叠,历史不完整时也既不显示控件又不隐藏成员。控制 Node 从首条过程证据出现起一直存在,但其 Seat 会保持隐藏,直至关闭的 Turn 拥有最终正文且历史完整;显示后,它会省略每个值为 0 的分段,三项全为 0 时使用「已思考」(英文为 Thought for a while),并在摘要下方绘制通栏分隔线。

Chat target 通过共享 settings scope 绑定持久化的 transcript 偏好,并把逐轮交互状态保存在会话作用域的 Chat store 中。ChatView 通过稳定的 keyed ChatNodeSeat 直接渲染每个业务 Node;加入过程控件不会重排既有 key,Compact 模式只改变 Seat wrapper 的 hidden 属性,不会重新挂接或卸载工具、Assistant、上下文或重试 renderer。Seat 通过 ChatNodeOwnerProps 传递同一份过程状态,因此最终 Assistant renderer 会隐藏自身步骤中的推理块,同时保留回复块;wrapper 可见性与行内推理共用一个 UI 状态真源。

收起的过程成员使用 hidden="until-found"。在支持该能力的浏览器中,任一成员触发 beforematch 都会打开共享过程组。由于 hidden-until-found 成员会保留可搜索的零高度 box,Chat 列只在可见的相邻成员之间设置间距;控件分隔线横跨内容宽度,只有中间没有独立输入时,收起的过程控件才与正文相隔 8px,展开后恢复普通的 16px 行间距。收起的 Think 行通过 CSS 跟随最新流式文本行,具有随字号轴变化的单行固定高度,并启用 size 与 layout containment;展开时移除 containment,正文恢复自然高度。在 Compact 模式下,不持久化的会话 store 只保存用户手动展开的「Turn + 正文 Step」generation;没有记录即为收起,不同正文 generation 默认收起。因此,每个合格的已关闭 Turn 都使用相同默认状态,不区分实时完成、在「加载更早」后出现,或在读者离开尾部时结束。这可能在 Turn 关闭或历史变完整时让读者上方的内容重排。若自动收起会隐藏过程成员中的键盘焦点,则改为打开共享过程组并把焦点留在原处;手动收起会先把焦点移到过程控件,再隐藏成员。存在「加载更早」时,每个过程保持展开且控件隐藏;历史加载完整后,合格过程立即使用默认收起状态。页面重新加载会恢复持久化的 Normal 或 Compact 偏好;逐 Turn 手动展开只在同一页面生命周期内的 view remount 之间保留。切换到 Normal 会显示所有过程行,切回 Compact 时会在默认收起状态上重新应用当前页面生命周期内的手动展开记录。

这项展示与 Conversation Node 组装共同成立:Definition 持有确定性的过程事实,Seat 持有共享交互状态,keyed renderer 保持独立。按日志顺序投影的人工 transcript保持完整,因为折叠不改变任何会话事件或模型输入。

曾考虑的替代方案

只折叠较早的 Assistant 回复。 不采用:常见的 Think → Tool → 正文 轮次只有一个回复步骤,不会出现紧凑控件,用户要求收起的过程内容仍会完整展开。

把上下文注入留在过程组外。 不采用:注入的运行时上下文属于正文之前的轨迹,并不是一条新的人类指令;展开过程后,其自身的 disclosure 与标签仍完整保留。系统提示词则留在过程组外,因为移动或隐藏整次请求使用的指令会改变开场 User 周围的可见框架。

把整个轮次重新挂接到一条摘要行下。 不采用:折叠资格会在轮次运行期间变化,而把既有 Chat Node 移过 React 父节点会重挂载有状态工具视图。稳定 Seat 可以提供一个 disclosure,同时不移动其子节点。

把手动展开状态存入轮次 Location data。 不采用:Location data 是会话事件的确定性投影,不存在浏览器动作写入路径。UI 手势属于已声明且不持久化的 store。

复用 DisclosureRow 并卸载收起成员。 不采用:浏览器查找无法发现其文本,重新打开也会重建有状态 renderer 子树。

在 turn/end 前折叠实时正文候选。 不采用:流式文本后仍可能出现工具调用、重试或后续仅推理步骤。等待终态边界可以避免自动收起—展开—再次收起及其造成的布局跳动。

读者离开尾部时暂缓刚获得资格的收起。 不采用:该方案需要瞬时完成检测与 deferred 状态,并使相同的已关闭轮次根据进入视口的路径获得不同初始状态。已关闭轮次统一使用确定性的默认值;滚动锚定负责保持位置,焦点保护负责保留正在进行的交互。

后果

Compact 模式会在轮次正文前只有注入上下文、推理或工具时仍突出最终正文,展开后每条过程行按原顺序恢复;Normal 模式则保留完整 transcript 且不展示轮次过程控件。隐藏的 wrapper 与 Markdown 子树保持挂载,用一定浏览器内存换取稳定工具状态、跨视图重挂载的手动展开状态与浏览器查找恢复。只有 Compact 模式下的普通跨消息选择会排除仍收起的成员;用户可以先展开过程组,或切换到 Normal。不支持 hidden="until-found" 与 beforematch 的浏览器仍可手动展开,却无法通过页内查找揭示收起的过程文本。单元覆盖固定已定稿正文边界、重试与中断、跨 kind 共享展开、最终步骤推理、模式切换、手动展开、历史补全后立即收起、离尾收起、焦点保留与最终分页的纯数据更新;组装后的浏览器快照固定运行中、已取消、已完成、分页历史与持久化设置轨迹。