Message fork actions require a completed turn tail
消息 fork 操作要求消息位于已完成轮次尾部
The Web conversation attached branch to the last assistant node with nonempty text in each turn. A later tool result, interrupted reasoning node, or terminal error did not take ownership because those rows have no content-text IconActions. The branch icon could therefore appear beneath an assistant response while more rows from the same turn remained below it. The Host correctly expanded that message anchor through t
English
Problem
The Web conversation attached branch to the last assistant node with nonempty text in each turn. A later tool result, interrupted reasoning node, or terminal error did not take ownership because those rows have no content-text IconActions. The branch icon could therefore appear beneath an assistant response while more rows from the same turn remained below it. The Host correctly expanded that message anchor through the containing turn/end, but the placement made the action look like a message-level cut and the child visibly inherited the same-turn suffix.
Decision
ConversationSnapshot.turnEnds retains the completed turn boundaries present in the raw event window. The conversation view walks transcript nodes through each boundary and enables branch only when the boundary's last node is a user message, a durable steering message, or a content-bearing assistant message. Open turns have no eligible message, and a later tool result, reasoning-only interruption, turn error, or other transcript node leaves branch unavailable on earlier messages. The unavailable control stays visible, focusable, and hoverable; aria-disabled, a tooltip, and aria-describedby explain the completed-tail requirement without sending a Host request. Copy and clock remain available under their existing message chrome, and the Host's completed-turn fork semantics remain unchanged.
The message-bubble half of this eligibility is superseded by the user-bubble branch removal: user and steering bubbles no longer render the control at all, so only content-assistant tails may fork; the assistant-side gate and its visible-but-unavailable presentation stand.
This narrows the message eligibility established by the earlier Web session fork action decision. Session-row forking still selects the latest completed turn, and eligible message actions still pass their event seq through the shared client runtime operation.
Alternatives considered
Cut the event log at the clicked assistant message. Rejected because an assistant message can sit inside an open step and can contain tool calls whose results occur later. A raw prefix at that seq is not a balanced turn and may not be a valid provider transcript.
Infer completion from running or the next user message. Rejected because retry and steering turns need not align with the next visible user bubble, and a paged window may omit that later bubble. The durable turn/end event is the authoritative completion fact.
Hide branch from every interrupted turn. Rejected because an aborted turn is durably closed and its final interrupted text can be the true transcript tail. Eligibility depends on the completed boundary and node order, not the outcome kind.
Hide ineligible message controls. Rejected because a disappearing control does not explain the boundary requirement and shifts otherwise stable message chrome. A focusable unavailable control preserves the affordance while preventing the request.
Consequences
An enabled branch icon denotes the same completed-turn boundary that the Host will copy. In the reported response → tool → interrupted Think shape, the response keeps copy, clock, and a disabled branch control that explains why it cannot act. This change deliberately does not provide same-turn transcript editing or a retry-before-turn operation; the Session-row action remains available when a reader wants to copy the latest completed turn in full. Runtime tests pin boundary projection and reference stability, while conversation tests cover assistant, user-only, and durable-steering tails plus unavailable controls caused by later tool and interrupted reasoning rows.
中文
问题
Web 会话把分支操作挂到每个轮次中最后一个文本非空的 assistant 节点上。如果后面还有工具结果、被中断的推理(reasoning)节点或终态错误,这些行也不会接管操作,因为它们没有内容文本 IconActions。因此,分支图标可能出现在 assistant 响应下方,而同一轮次的更多行仍位于其后。Host 会正确地把该消息锚点扩展到其所在的 turn/end,但图标位置使操作看起来像在消息级截断,子会话又会明显继承同轮次的后缀。
决策
ConversationSnapshot.turnEnds 保留原始事件窗口中的已完成轮次边界。会话视图按各边界遍历 transcript(文本记录)节点,仅当边界的最后一个节点是用户消息、持久 steering(中途引导)消息或含内容的 assistant 消息时才启用分支操作。开放轮次没有符合条件的消息;如果后面还有工具结果、只有推理内容的中断、轮次错误或其他 transcript 节点,较早消息上的分支操作会保持不可用。不可用的控件仍然可见、可聚焦、可悬停;aria-disabled、tooltip 与 aria-describedby 会说明已完成尾部这一要求,且不会发送 Host 请求。复制和时钟仍可在既有消息 chrome 下使用,Host 按已完成轮次 fork 的语义保持不变。
本资格判定中消息气泡的那一半已被 user 气泡分支移除决策取代:user 与 steering 气泡不再渲染该控件,因此只有含内容的 assistant 尾部可以 fork;assistant 侧门禁及其可见但不可用的呈现保持有效。
本决策收紧了较早的 Web 会话 fork 操作决策所定义的消息资格。Session 行 fork 仍选择最新的已完成轮次;符合条件的消息操作仍通过共享 client 运行时操作传递其事件 seq。
考虑过的替代方案
在点击的 assistant 消息处截断事件日志。 不予采纳:assistant 消息可能位于尚未结束的步骤内,也可能包含结果随后才出现的工具调用。以该 seq 截取的原始前缀并不是结构完整的轮次,也可能不是有效的提供方 transcript。
从 running 或下一条用户消息推断完成状态。 不予采纳:重试轮次与 steering 轮次不一定和下一个可见用户气泡对齐,分页窗口也可能省略该气泡。持久 turn/end 事件才是权威的完成事实。
对每个被中断轮次隐藏分支。 不予采纳:已中止的轮次会持久关闭,其最终的中断文本可能正是真正的 transcript 尾部。资格取决于已完成边界与节点顺序,而非结果类别。
隐藏不符合条件的消息控件。 不予采纳:消失的控件无法说明边界要求,还会让本应稳定的消息 chrome 发生位移。保留可聚焦但不可用的控件,既能维持操作提示,也能阻止请求。
后果
启用的分支图标现在表示的已完成轮次边界与 Host 实际复制的边界一致。在所报告的「响应 → 工具 → 被中断的 Think」形态中,响应仍保留复制、时钟,以及一个说明无法操作原因的禁用分支控件。本变更刻意不提供同轮次 transcript 编辑,也不提供轮次前重试操作;当读者希望完整复制最新的已完成轮次时,仍可使用 Session 行操作。运行时测试固定边界投影和引用稳定性,会话测试则覆盖 assistant 尾部、纯用户消息尾部、持久 steering 尾部,以及后续工具行和被中断推理行导致的不可用控件。