ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Hermes WebUI 稳定助手回合锚点:统一流式渲染与终态结算的前端归属模型

Hermes WebUI 稳定助手回合锚点:统一流式渲染与终态结算的前端归属模型 Hermes WebUI 稳定助手回合锚点统一流式渲染与终态结算的前端归属模型【免费下载链接】hermes-webuiHermes WebUI: The best way to use Hermes Agent from the web or from your phone!项目地址: https://gitcode.com/GitHub_Trending/he/hermes-webui本篇围绕 Hermes WebUI 的设计 RFC《Stable Assistant Turn Anchors for Live-to-Final Rendering》展开解析它如何用助手回合锚点Assistant Turn Anchor这一前端呈现/协调原语把流式输出、回放重放、结算终态与两种显示模式统一到同一个事件模型之下。读完你能掌握该锚点的身份模型、事件归一化与去重机制、结算/重建流程以及当前仓库中static/assistant_turn_anchors.js对 RFC 各条款的落地方式。问题背景流式态与结算态之间的接缝Live-to-Final流式到终态的产品模型已经确立一个 live 的助手回合展示进行中的工作支撑性活动工具、Thinking、生命周期状态归入 Worklog工作日志最终答案成为主要的、已结算settled的结果当没有产出正常最终答案时终态应被显式表达。但这个产品模型之下隐藏着一个架构问题live 助手回合与结算后的转录transcript由不同的层表示。在浏览器路径中live 输出由流局部变量、INFLIGHT快照、live DOM 节点和 SSE 回调拼装而成当流完成时浏览器用服务端会话数据替换或协调S.messages并调用renderMessages()重建转录。也就是说UI 必须在结算时刻跨越这条边界live stream state DOM INFLIGHT snapshot ! settled transcript messages围绕回放、重连、会话切换、空白恢复回合、thinking 占位符、流结束恢复、流中重建等问题项目已经做过多轮针对性修复RFC 中列举了 #3401/#3741、#3707/#3763、#3869/#3876、#3875、#3877、#3885 等修复轨迹。这些修复有用但都指向同一个缺失的可用原语一个在最终答案存在之前就已存在、能够拥有 live 活动、结算、回放、恢复与显示模式渲染的稳定助手回合锚点。RFC 特别强调这个锚点首先是呈现层归属presentation ownership原语其次才是身份或回放原语——持久事件身份与基于游标的回放其实已经存在见下文 Event Envelope。真正的故障模式是当 live 状态与结算转录相遇时哪一层拥有一张工具卡片、一行 thinking、一个已结算答案没有答案。同时这也承接了 WebUI Run State Consistency Contract见 webui-run-state-consistency-contract.md那份契约用不变式清单防止 N 个每回合状态层漂移而本 RFC 的目标是把不变式收敛到一个拥有者对象上让规则有家可归。相应的风险也写得很直白只有当锚点把其他每回合存储S.messages、INFLIGHT、流局部闭包状态、live DOM降级为缓存和渲染器时锚点才有价值。如果它只是并排加在它们旁边而不接管归属就会变成第 N1 个存储层让接缝更糟。RFC 要求每一个实现切片都按是否移动了归属权而不是是否新增了结构来评判。当前架构形态六个重叠的状态层RFC 对当前浏览器中同一个活跃回合的存储层做了盘点层当前角色对 Live-to-Final 的问题S.messages已结算渲染的规范可见转录live 助手回复没有在回合开始时作为稳定规范锚点插入INFLIGHT活跃工作与恢复的浏览器快照是有用的恢复缓存但不是结算转录模型流局部闭包状态跟踪assistantText、reasoningText、live 工具卡片、分段计数器、解析器目标适合热路径流式写入但不能是唯一排序来源live DOM持有当前 live 助手回合、Worklog 行、解析器目标、瞬态卡片渲染快但在renderMessages()重建转录时很脆弱run journal持久化的已发事件源用于回放有用但前端仍需在其上建立归一化呈现模型settled session messages服务端返回的最终转录到达得晚当前会强制一次从 live 表达到结算表达式的桥接最脆弱的时刻就是终态结算流发出done→ 浏览器收到结算会话载荷 →S.messages被服务端事实替换/协调 →renderMessages()重建转录 → 辅助代码尝试把仅 live 的字段、工具元数据、滚动状态、Thinking 元数据和 DOM 连续性搬运过去。需要澄清的是renderMessages()不只是终态函数它是当前转录面板的通用渲染器会话加载、会话切换、用户消息回显、命令输出、错误/取消恢复、最终结算都要走它热路径流式时 token/reasoning/tool 监听器大多是增量更新 live DOM。但任何流中重建都可能擦除并重建消息面板所以现有代码对 live 助手 DOM 节点有专门保护。RFC 的结论是目标不是删除renderMessages()而是让它从live 与 settled 之间的语义边界退化为稳定呈现状态之上的渲染器。真相源分层锚点必须坐在正确的层上。RFC 给出的权限表也是实现中STATE_LAYERS常量的设计依据层权限服务端会话与结算转录持久最终消息、最终答案、持久元数据、累计用量Run journal / 可回放事件live 流事件及其顺序的持久证据发出 Artifact 1 信封run_id:seq注意与记录已提交回合生命周期的 turn journal 区分SSE live 流最低延迟的活跃工作观测路径Assistant Turn Anchor单个助手回合的前端呈现/协调拥有者INFLIGHT、localStorage、HTML 快照仅用于浏览器恢复加速与容错DOM一次性渲染输出RuntimeAdapter未来的执行/事件源边界不由本 RFC 拥有关键约束DOM 不得被当作语义事实——live DOM 节点可以为了连续性保留但事实必须来自 SSE、journal 事件、结算转录载荷和锚点状态INFLIGHT可以加速恢复但绝不能凌驾于 journal 或结算转录证据之上。核心提案AssistantTurnAnchor 概念模型引入一个内部 WebUI 呈现原语——稳定助手回合锚点概念结构如下AssistantTurnAnchor identity session_id turn_id run_id stream_id source_message_refs lifecycle status terminal_state started_at completed_at content final_answer final_message_ref activity_events[] process_prose reasoning tool_started tool_updated tool_completed lifecycle_status control_boundary artifact_reference terminal_status artifacts[] side_effects[] usage锚点不是后端 schema 要求而是让浏览器能够回答这些问题的前端模型这条 live 事件属于哪个助手回合它应该出现在哪里这条事件是否已经被重放过这个回合的最终答案是什么它到达了什么终态哪些工件、副作用和用量元数据属于这个回合哪种显示模式应该渲染这同一串事件序列目标状态可以概括为Current: live DOM ! settled data model Target: live events attach to an assistant-turn anchor settlement updates that same anchor renderers consume the anchor在目标模型中流done不再需要制造另一个回合它只是完成已有回合。同时仅渲染器的偏好Compact Worklog 展开、Transparent Stream 展开、复制按钮可见性、滚动跟随偏好被刻意排除在语义锚点之外——它们可以放在渲染器状态或每会话 UI 偏好存储里但回放与结算不得把这些选择持久化为助手回合事实。锚点创建与身份模型正常创建路径有四步用户提交消息/api/chat/start成功响应返回stream_idWebUI 创建一个绑定到活跃session_id、已提交用户回合和stream_id的锚点。这个时机早于第一条助手拥有的 SSE 事件——第一条事件可能是 token、中间进度、reasoning、工具开始、压缩生命周期行或控制边界等待其中某类事件会让早期排序和归属取决于传输时序。重建路径是另一回事在刷新、重连、会话切换或本地锚点丢失时WebUI 可以从 run journal 事件、结算转录消息和INFLIGHT快照重建锚点但这不应被描述为正常创建策略。Event Envelope身份来源不重新发明锚点消费的是 RuntimeAdapter 契约hermes-run-adapter-contract.md的Artifact 1 Event Envelope作为身份来源event_id run_id:seq、单调seq、run_id、Last-Event-ID/after_seq重连、按run_id seq或event_id去重。这一信封当前已经由 WebUI run journal 真实发出——可以在 api/run_journal.py 中看到写入逻辑event_id: f{run_id}:{assigned_seq}回放侧的after_seq过滤api/run_journal.py和after_event_id游标解析api/run_journal.py也一一对应。run_id是持久键stream_id是run_id预期会超越它的遗留传输键。未来若出现持久run.started事件只是升级这些键的来源锚点的身份模型不变。身份优先级从高到低Event Envelope 的event_id/run_id seq当前run journal将来runner/runtime有持久 turn 键时的turn_id传输层回退session_id stream_id 本地回合序号重建已完成回合时的结算助手消息引用老数据没有更强身份时的浏览器本地回退 ID。锚点不得把身份硬绑到stream_id上因为适配层迁移会替换 WebUI 拥有的流路径而保持 Event Envelope 稳定。可见文本与时间戳不是身份来源只能是载荷与诊断数据。活动事件模型与源事件映射归一化事件模型刻意做得小而稳定不需要镜像每个后端字段但必须保留源载荷或源元数据以便调试和未来迁移{ event_id: optional stable event id, local_id: browser fallback id, session_id: session id, turn_id: assistant turn id, run_id: optional runtime run id, stream_id: optional stream id, seq: 12, kind: tool_started, source_event_type: tool, created_at: 1778750000.0, status: running, payload: {} }必须满足的语义event_id或run_id seq是可得的时优先作为去重键local_id只能作为浏览器回退存在turn_id必须把事件绑定到一个助手回合kind控制渲染策略而非运行时执行source_event_type保留传输或派生来源payload渲染前必须消毒。事件 kind 与两种显示模式的渲染策略Kind含义默认 Compact Worklog 渲染Transparent Stream 渲染process_prose用户可见的助手进度文本Worklog 主散文项时间线转录项reasoning提供方的 reasoning/thinking 载荷折叠的 Thinking 卡片时间线 Thinking 事件tool_started工具调用开始工具卡片或分组工具行一等工具行tool_updated工具输出/进度更新更新现有卡片/分组更新同一工具行tool_completed工具调用结束定稿卡片/分组定稿同一工具行lifecycle_status压缩、重连、恢复中、降级、警告等用户可见时的安静生命周期行时间线生命周期行control_boundary停止、中断、排队/steer、clarify/approval 或延续边界可见时的专用控制/状态行时间线控制行artifact_reference产出的文件、工作区变更、保存输出或交接引用实现后的工件/引用条目时间线工件事件terminal_status完成、取消、中断、无响应、限额、连接丢失或错误终态卡片或最终状态时间线终态行当前源事件到锚点归属的映射现有事件名应被映射进归一化模型而不是自己成为长期模型当前源锚点归属tokenprocess_prose活动事件interim_assistantprocess_prose活动事件常带活动边界reasoningreasoning活动事件toolevent_typetool.startedtool_started活动事件tool_completetool_completed活动事件未来部分工具输出有稳定源时tool_updated活动事件compressinglive 时lifecycle_statuscompressedlive 时lifecycle_status结算渲染可丢弃或折叠approval回合内可见时control_boundary审批 UI 仍是控制面clarify回合内可见时control_boundaryclarify UI 仍是控制面pending_steer_leftovercontrol_boundary和/或下一回合队列元数据goal_continue调度延续时control_boundary加下一回合队列元数据done结算触发加terminal_status/ 用量 / 最终转录合并stream_end传输关闭与恢复触发不等同于completedcancel带cancelled或interrupted语义的terminal_statuserror/apperror带错误元数据的terminal_statuswarning用户可见时lifecycle_status否则诊断元数据state_saved视是否用户有意义持久输出而定artifact_reference或副作用bg_task_complete会话/后台任务副作用仅在启动或解释可见助手回合时可成为control_boundary非活动源的分类并非每个源事件都应成为可读活动事件metering是锚点/会话上的用量与实时吞吐元数据todo_state是侧面板状态快照title是会话元数据title_status是诊断/会话元数据context_status是 composer/会话上下文元数据goal是 composer/状态元数据除非它产生可见回合边界会话列表刷新是会话元数据live DOM 快照只是恢复缓存。这套分类是模型的一部分新增任何 SSE 或回放事件都必须把它归类为 activity、artifact、side effect、metadata、transport 或显式排除。这份分类在实现中被固化为 static/assistant_turn_anchors.js 的SOURCE_EVENT_CLASSIFICATION常量表分类顺序为activity / artifact / side_effect / metadata / transport / excludedCLASSIFICATION_ORDERstatic/assistant_turn_anchors.js未知源类型默认归入excluded见classifyAssistantTurnAnchorSourceEventstatic/assistant_turn_anchors.js——新事件必须被分类从文档约定变成了代码默认行为。身份规则身份是把 Event Envelope 应用到事件粒度。RFC 要求身份必须保守优先使用 run journal 或 runtime 事件的稳定事件 ID两者都有时优先run_id seq同一工具卡片更新优先tool_call_id/tid不得仅按可见文本去重不得仅按时间戳去重不得用模糊或语义相似度丢弃事件身份缺失时优先追加一个归属清晰的事件而不是丢弃一个可能是真实的重复事件。这很重要因为真实 agent 会发出重复文本、重复工具调用、重复状态消息稳健的呈现层不应把它们当作意外重复除非身份能证明。实现核对归一化、去重与事件路由RFC 的状态标记为 Implemented。仓库中的 static/assistant_turn_anchors.js1700 行暴露为window.HermesAssistantTurnAnchors与 RFC 条款逐一对应1. 事件归一化。normalizeAssistantTurnAnchorSourceEventstatic/assistant_turn_anchors.js把任意输入源事件转成 RFC 中定义的归一化结构从event_id/lastEventId提取稳定 ID从event_id run_id:seq反解run_id与seq_eventIdRunId/_eventIdSeqstatic/assistant_turn_anchors.js按SOURCE_EVENT_CLASSIFICATION分类payload经_sanitizePayload消毒限制深度为 6、剔除__proto__/constructor/prototype等危险键static/assistant_turn_anchors.js。2. 去重键。assistantTurnAnchorEventDedupeKeystatic/assistant_turn_anchors.js严格实现了身份优先级优先event_id其次run_id seq最后是session_id local_id source_type seq的本地回退注意本地回退明确要求seq ! pending即身份弱时宁可追加。3. 注册表与事件应用。createAssistantTurnAnchorSeedstatic/assistant_turn_anchors.js创建的种子结构与 RFC 概念模型完全同形identitysession_id/turn_id/run_id/stream_id/source_message_refs、lifecyclestatus/terminal_state/started_at/completed_at、contentfinal_answer/final_message_ref、activity_events/artifacts/side_effects/metadata_events/transport_events、usage缺少turn_id时自动合成local:session:run|stream|pending:local_id作为回退身份。applyAssistantTurnAnchorNormalizedEventstatic/assistant_turn_anchors.js在应用每个事件时依次执行四道闸门无事件 →excluded事件与锚点身份不匹配session/turn/run 任一冲突→mismatched_anchor去重键已见 →duplicate通过则按分类路由到activity_events/artifacts/side_effects/metadata_events/transport_events_routeAnchorEventstatic/assistant_turn_anchors.js并维护applied/skipped_duplicate/skipped_excluded/skipped_mismatched统计——统计字段本身就是回放幂等性的可观测证据。4. 状态层权威序。static/assistant_turn_anchors.js 的STATE_LAYERS把 RFC 的真相源分层表编码为带authorityRank1Event Envelope 最权威7live DOM 最末位与anchorPolicy策略文本的常量例如 DOM 层策略是 DOM continuity is useful, but DOM is never semantic truth。5. 影子快照。createAssistantTurnAnchorShadowSnapshotstatic/assistant_turn_anchors.js按 live → replay → settled → inflight 顺序把四路事件灌进同一注册表是回放与结算顺序无关order-invariance验收标准的直接支撑同一 run 先 live 后 replay、或先 replay 后 settled去重索引保证最终锚点一致。6. 活动场景投影。projectAssistantTurnAnchorActivityScenestatic/assistant_turn_anchors.js把锚点投影为activity_scene_v1每行活动事件生成row_id优先event_id其次run_id:seq再退local_id:source:idx、roleprose/thinking/tool/lifecycle/control/terminal、以及compact_worklog与transparent_stream两套display_hintsstatic/assistant_turn_anchors.js——这正是 RFC两种显示模式读同一归一化输入的实现形态。配套的reconcileAssistantTurnAnchorActivityScenestatic/assistant_turn_anchors.js与reconcileAssistantTurnAnchorRendererSnapshot则负责逐行核对锚点期望的行与渲染器实际输出的行行数、顺序、重复、字段级 mismatch使呈现层与锚点是否一致成为可测试断言。前端消费点可见于 static/messages.js 与 static/ui.js会话恢复路径、static/ui.js、static/ui.js配套测试包括 test_anchor_scene_persistence.py、test_anchor_fallback_ownership.py、test_5749_anchor_scene_client_prefix_dedupe.py、test_5552_viewport_anchor_surrogate.py。结算Settlementdone 是更新不是新回合结算是运行中助手回合获得持久最终事实的时刻不是第二个助手回合。当done到达时WebUI 应把最终会话载荷协调进现有锚点校验session_id、run_id或stream_id仍属于该锚点把anchor.content.final_message_ref绑定到结算助手消息并把anchor.content.final_answer写成派生的渲染快照附加终态与用量元数据把结算的 reasoning/tool/artifact 元数据合并进既有活动事件把仅 live 的事件标记为已结算或丢弃纯瞬态事件从锚点渲染所选显示模式。renderMessages()在早期实现阶段仍可做整转录重建重要的语义变化是重建应渲染一个已经拥有 live 活动与结算答案的锚点done不应依赖另造一个仅结算的 Worklog来解释同一个回合。终态与最终答案文本是分离的一个回合可以带着部分过程散文、工具卡片、reasoning、工件或用量元数据却依然没有产出正常最终答案。content.final_message_ref在有结算消息身份时是持久的转录引用content.final_answer不是独立语义拥有者它是从结算助手消息拷贝的投影缓存让早期渲染器不必每次绘制都追S.messages——若结算之后转录消息被改写锚点必须从那条消息刷新而不是允许两份拷贝静默漂移。这一侧在实现中由projectAssistantTurnAnchorSettledMessageFinalAnswerstatic/assistant_turn_anchors.js完成非 assistant 角色直接拒绝non_assistant缺 session 拒绝missing_session成功时经注册表应用settled_message事件并回填final_answer与final_message_ref_updateContentFromMetadatastatic/assistant_turn_anchors.js同时处理usage与_turnUsage元数据。回放、刷新与重建回放/刷新应当从持久证据重建同一个锚点而不是另建一条仅回放的 UI 路径。来源优先级run journal / 回放事件——live 活动顺序结算转录——最终答案与持久化消息元数据INFLIGHT/ 本地恢复快照——快速本地恢复与回退。概念步骤判断会话是否有活跃或近期终态的流 → 按session_id加流/回合身份找现有锚点或创建重建锚点 → 把持久事件重放进锚点 → 合并结算转录元数据 → 用INFLIGHT填补兼容缺口 → 从重建锚点渲染 Compact Worklog 或 Transparent Stream → 证据不全时显示restoring或degraded。迁移期INFLIGHT仍是恢复缓存直到锚点拥有的字段接管。RFC 给出了逐族的移交顺序当前INFLIGHT字段族锚点目的地回退规则lastRunJournalSeq/ 回放游标锚点事件去重索引加 run journal 游标元数据优先 run journal 回放INFLIGHT只用于恢复缺失的浏览器游标activityBurstAnchors/ live 行锚点activity_events[]身份与分组元数据DOM 提示保留为渲染器缓存不得凌驾归一化事件currentLiveSegmentSeq/ 本地 live 顺序无 Event Envelope 时的锚点本地源顺序仅作浏览器回退身份绝不按可见文本去重streamId/ 活跃传输键identity.stream_id位于run_id之下的回退知道run_id后不得把归属硬绑到stream_id缓存的助手文本/reasoning/工具状态activity_events[]与派生渲染行仅在 journal 与结算转录证据之后用于重建缺口stream_end需要特别小心它是传输关闭信号可能触发恢复绝不能被当作回合已完成的证明。渲染策略一个锚点两个投影锚点把事件存储与显示策略分开AssistantTurnAnchor - Compact Worklog renderer - Transparent Stream rendererCompact Worklog默认模式过程散文是主阅读面Thinking 与工具是辅助 Worklog 项工具运行可分组摘要结算后的 Worklog 详情默认折叠或跟随用户偏好仅 live 的生命周期行不污染最终答案最终答案保持视觉主位。Transparent Stream可选开启过程散文、Thinking、工具、结果、生命周期行、控制边界与终态行都是按时间线排列的一等活动事件工具调用不被聚合摘要掩盖最终答案与执行轨迹保持分离live、settled、reload、replay 使用同一事件顺序。Transparent Stream 不取代 Compact Worklog它是同一锚点与活动事件的另一个投影。两个渲染器都必须保持助手回合归属、事件顺序、终态诚实性、回放幂等、最终答案分离、用户展开状态在可行范围内、刷新或会话切换后的稳定行为。切换显示模式不应触发后端回放、重跑 agent 或改变哪些事实属于这个回合。与 Transparent Stream RFCtransparent-stream-activity-mode.md的关系被显式对账过那边的normalizeToEvents()与本 RFC 的anchor.activity_events是同一条归一化接缝在三个来源路径live、journal 回放、settled上的同一个东西renderActivityEvent()只是锚点的渲染器之一——两侧不允许出现两个独立归一器谁先落地谁定义共享事件形状另一方消费它。终态显式常量而非散落的字符串锚点应显式承载终态终态含义completed产出了最终助手答案并正常结算cancelled用户停止了该回合interrupted运行时/控制流在正常完成前打断了回合no_response没有产出可用的助手最终内容tool_limit_reached工具/重试/迭代上限结束了回合compression_exhausted压缩无法腾出足够空间安全继续connection_lost浏览器传输丢失WebUI 无法确认结算状态degradedWebUI 有部分证据但无法完整重建回合error提供方、后端或回退失败状态终态与最终答案文本分离tool_limit_reached回合不得通过渲染一个合成的控制提示当作用户消息来表达被取消的回合不同于提供方错误stream_end帧不同于completed。Compact Worklog 可以在没有最终答案时把终态显示为状态卡片或最终答案的替代Transparent Stream 应把同一终态真相显示为最后的时间线事件——两种模式不得对结果不一致。实现上终态被固化为常量TERMINAL_STATES9 态齐全static/assistant_turn_anchors.js源别名经TERMINAL_STATE_ALIASES归一done/complete→completedcancel/canceled→cancelledapperror/failed→errormax_iterations→tool_limit_reached等static/assistant_turn_anchors.jsnormalizeAssistantTurnAnchorTerminalState负责归一化——正是 RFC 要求的源别名在渲染器消费前归一到枚举。工件与副作用agent 回合产出的不止散文和工具行它可能创建文件、变更工作区、保存持久状态、更新侧面板、改变用量元数据或调度延续。这些结果即使不该全部出现在可读活动时间线里也需要归属不是每个副作用都是活动事件但每个副作用都必须有 Assistant Turn Anchor 拥有者或一个刻意的会话级拥有者。工件与输出引用生成的文件、工作区变更、导出、截图、报告、保存状态引用与交接输出在归属已知时应挂到产出它们的助手回合元数据缺失时渲染器应降级为链接、文件路径引用或工作区引用而不是空白输出。侧面板与会话状态todo_state更新 Todos 面板默认保持侧面板状态快照metering更新用量与实时吞吐title更新会话元数据context_status更新 composer/上下文状态。它们不应为了证明完整性被塞进 Worklog而应作为副作用或元数据被拥有并通过各自的自然 UI 面恢复。控制与安全边界approval、clarify、steer、interrupt、Stop-and-send 与延续投递会影响用户对回合的理解可见时可挂为control_boundary事件。Pending-intent 控制 RFCwebui-pending-intent-controls.md仍拥有这些用户意图的语义本 RFC 只拥有它们可见边界的挂载、结算与回放位置。与 RuntimeAdapter 的关系缓冲层而非运行时RuntimeAdapter 回答谁拥有活跃执行、控制、持久运行时状态与可回放运行时事件本 RFC 回答WebUI 观测或派生出助手活动后浏览器如何把它挂到一个助手回合上、渲染、结算、回放并切换显示模式而不改变产品模型。锚点不能决定是否让 agent 继续运行、不能成为审批/取消权威、不能凭空发明运行时状态——它只表达 WebUI 已观测、已派生、可展示、可重建的事实。这种隔离是现在就建锚点的积极理由而不只是要尊重的边界live 渲染的底层基座正在通过默认关闭的 adapter 与 runner 接缝活跃迁移#1925。如果呈现层持续直接读基座每一步迁移都冒着再来一轮 live/settled 修复的风险如果它读锚点、锚点读 Artifact 1 信封那么从 WebUI 运行路径切换到 runner 或 Hermes 运行时只改变锚点的输入来源渲染器保持不动。锚点就是让运行时迁移能在 UI 之下落地而不重写 UI 的缓冲。灰度计划与验收标准RFC 把实施拆成七个阶段顺序约束而非每阶段一个 PR结算、重建与显示模式变更应保持独立可评审Phase 0RFC 与盘点落地本 RFC 作为设计指引盘点static/messages.js消费的 SSE 事件形状、static/ui.js消费的结算消息元数据、run journal 回放数据与既有event_id/seq信封把每个源事件分类。Phase 1内部锚点脚手架为活跃会话建立内部锚点注册表在/api/chat/start成功并返回stream_id后创建锚点从当前流/会话信号注水可见 UI 保持不变为身份、归属、陈旧流忽略、重连不重复建锚加测试。Phase 2归一化活动事件加 live 事件归一化助手与结算消息元数据派生助手把回放注水进同一锚点模型Compact Worklog 保持唯一可见渲染器加覆盖证明所有当前事件名都有显式分类。Phase 2.5锚点契约加固渲染器呈现状态不进入语义锚点种子导出终态常量并在 Phase 3 写入结算结果前归一源别名文档化哪些INFLIGHT字段转为锚点所有、哪些保持回退缓存、哪些只是渲染器提示定义final_message_ref为结算转录权威、final_answer为派生渲染快照加 live replay settlement 对同一 run 的顺序无关覆盖。Phase 3经锚点结算把done协调进现有锚点在锚点上保留最终答案、reasoning、工具元数据、终态与用量减少对整转录重建作为活跃回合语义边界的依赖保留安全的回退全渲染路径。Phase 4回放/刷新重建从 run journal、结算转录与INFLIGHT重建锚点让会话切换、硬刷新与重连收敛到同一回合模型证据不全时显示restoring/degraded而非空壳运行界面。Phase 5共享渲染策略接缝Compact Worklog 与 Transparent Stream 都从归一化活动事件渲染保证 live、settled、reload、replay 路径使用同一事件顺序。Phase 6工件与副作用工件引用挂到锚点state_saved、工作区变更、todo、用量元数据获得刻意归属加固当前需要特判渲染的终态仅当锚点/事件模型稳定后再考虑超长透明流的性能工作。RFC 明确记录截至 2026-07-16核心 Phase 0–5 路径已落地Phase 6 与下列加固项是后续工作仍追踪于父 issue用出处或事件身份替换呈现层的文本/前缀去回声启发式同时不删除合法重复的模型输出让更新的 journal/回放证据显式超越陈旧的INFLIGHT首绘状态完成稳定run_id与传输stream_id的分离完成 Phase 6 工件/副作用归属路径只有在历史转录形状能够可靠注水锚点之后才移除每个遗留回退。实现侧应当最终满足的验收标准同一助手回合在 live、settled、reload、会话切换与重连中拥有相同归属done更新现有回合而不是另造仅结算回合两种显示模式读同一归一化输入最终答案与终态分离仅 live 的生命周期行不污染结算最终答案工具/reasoning/控制/工件归属不依赖 DOM 存活不完整重建显示restoring/degraded而非空运行壳每个新事件都被分类同一 run 的 replay/reconnect 在既有(session_id, event_id)去重环上幂等——live 与 replay 先后观测同一 run 时活动事件不丢不重replay/reconnect 与结算对同一 run 顺序无关——无论回放事件先于还是后于结算助手消息到达锚点收敛到同一最终答案引用、终态、用量元数据与活动事件列表。实现 PR 评审清单RFC 最后给实现 PR 留了一份评审清单本质上把归属权是否移动了这一判据变成了可执行的检查项这个 PR 改动了哪个状态层事件源、锚点注册表、活动事件列表、S.messages、INFLIGHT、live DOM、run journal、结算会话元数据、侧面板还是渲染器变更后的真相源是什么是否引入或消费了新事件若是它如何分类进入活动时间线、工件归属、副作用归属、元数据、传输处理还是显式排除刷新/重连/会话切换能否重建同一个助手回合回放会不会复制或丢失真实事件陈旧流能否更新更新的可见回合变更是否依赖 DOM 存在、可见文本、时间戳或模糊相似度作为语义事实done合并最终答案、用量与终态时是否避免了 Worklog/工具行重复Compact Worklog 与 Transparent Stream 对最终答案、终态、工具结果与控制边界是否仍然一致工件与副作用即使不出现在 Worklog 里是否也有拥有者是否影响 RuntimeAdapter 归属什么测试或手工不变式能证明该行为结语这份 RFC 的价值不在于新增一个数据结构而在于把live 与 settled 之间的接缝从一个反复修补的 UI 问题改写为一个有明确拥有者、可测试、可灰度的呈现层契约Event Envelope 提供身份run journal 提供回放证据结算转录提供最终事实INFLIGHT与 DOM 降级为缓存与渲染器而锚点是让这五者不再互相打架的那个对象。仓库中 static/assistant_turn_anchors.js 的常量表、归一化函数、activity_scene_v1投影与对账器以及 api/run_journal.py 的run_id:seq事件信封共同构成了从 RFC 条款到可运行代码的完整证据链也留下了 Phase 6 与身份/工件加固这些明确的后续切面。【免费下载链接】hermes-webuiHermes WebUI: The best way to use Hermes Agent from the web or from your phone!项目地址: https://gitcode.com/GitHub_Trending/he/hermes-webui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表