Files
ycode/docs/reference/ygent-chat-interaction-parity.md

205 lines
36 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 对话区动态交互对标与验收
> 阶段状态(2026-10-08):按用户要求,对话区在本阶段收尾,暂不继续修改。[当前进度汇总与剩余优先项](ygent-chat-stage-summary-2026-10-08.md)作为恢复入口。本文保留各批次证据;历史实现描述以后续修正为准,不能当作双端原生流式1:1已完成。
用户于 2026-10-08 明确:目标包括后续真实流式交互的效果一致,不仅是历史对话静态外观一致。本文件与 [原生渲染差异清单](ygent-workbuddy-render-audit-2026-10-08.md) 同时使用;静态修复不代表动态完成。
## 通用组件路径补查(2026-10-08)
后续品牌统一:按用户要求移除source_app驱动的助手名称/头像切换;所有会话统一显示Ygent及其图标。来源元数据仅用于数据溯源。
新增全会话入口核验:普通会话2(12条消息)与参照会话5(829条)在真实1335×916 WebView2切换比较,工具摘要共同命中15px/26.25px、rgba(0,0,0,.5)、border-left:0。source_app仅用于来源溯源,不选择独立对话渲染器,也不切换助手名称/头像。普通完成/多工具组与特殊取消仍有不同过程容器及间距规则,不据此宣称所有状态已对标完成。
路径标签通过共享Markdown代码组件实现:来源关联元数据用于参照快照,普通对话使用所属会话工作目录下的真实IPC批量分类;不存在的路径保持普通代码,迟到查询不会污染另一个会话/代码标签,增量追加保留路径控件。原生IPC核实普通会话可识别真实`.agent`目录并排除不存在的候选;同一参照标签`ygent`与WB均68.25×20、15px/22.5px、padding1px 4px,图标15×15。内部推理正文未导入,仅恢复有来源事件的“深度思考”标题;无内容不提供假的折叠交互。未来模型的公开思考摘要/阶段事件仍未接入。
“运行命令”上下样式遗漏修复后,继续检查同一组件在不同容器/阶段的路径。新增确认并修复4项:
| 位置/触发 | 问题 | 修复及验证 |
| --- | --- | --- |
| `TurnBlock`取消状态按钮 → `.turn-history` | 收起父层直接卸载历史,工具/意图展开状态和结果节点丢失;下方ProcessGroup已保留 | 历史首次展开后保持挂载,hidden隐藏。组件回归和真实1335×916 WebView2均验证结果节点与两级展开状态保留;还原操作前展开状态 |
| `renderSegment`单工具 → 同段第二条工具增量 | ToolCard变成FoldGroup,第一条工具被重挂载,已打开详情关闭 | 单工具与多工具共用稳定FoldGroup边界,单条不显示组标题。组件回归检查节点身份和意图展开状态;未新增真实模型/WB流式验收结论 |
| `FoldGroup`多个独立工具组 | 每组标题使用全回合toolCallCount,两个2条组均显示4 | 摘要仅计本组seg.items.length;两个工具组的组件回归通过 |
| `getCancelledTurnLayout`含show_widget的末段 | 特殊取消布局把可视化工具传入ToolCard,绕过WidgetArtifact | 初次修复回退正常时间线;后续锚点分段保留产物/权限为独立visible段,不进入普通工具过程折叠;正常→取消及锚点布局回归确认iframe和权限操作仍存在 |
后续取消布局修复:工具摘要、意图/结果和工具组展开状态改由TurnBlock所属回合持有,以回合ID、消息ID及层级作为键;ToolCard/FoldGroup/ProcessGroup共享状态入口,跨父容器重新挂载时恢复原选择。自动折叠依据的上一次shouldFold/processExpanded也随组保存,普通增量或重新挂载不会再次覆盖手动选择;真正触发条件变化仍遵循现有自动折叠逻辑。回归覆盖多工具历史组和末段工具从流式→取消、手动打开组/详情、明确关闭另一条详情、取消后结果更新;全部通过。真实1335×916 WebView2的历史收起/重开仍通过。跨取消布局迁移的验证来自组件回归,没有向参考会话发送请求或注入状态,不声称双端原生动态验收完成。状态限定于当前回合组件生命周期,不写入数据库;迁移会重新创建DOM,此次未保证文字选择或结果面板滚动位置保持。
残留项:通用工具组与“过程消息”组的语义和箭头显示规则不同,不能直接统一所有行为。通用组的色彩、箭头方向及标题到内容的留白已按下节修正;摘要分类、子项间距、非命令工具取消时的图标语义仍待核实。
验证:`pnpm check:chat`、`node scripts/fe-check.mjs`、`pnpm build`通过。以上是路径一致性修复,未表示S04完整通过。
## 第一批动态P0实现结果(2026-10-08)
### 共用折叠样式与源码分组补查(2026-10-08)
依据当前安装的WorkBuddy产物`renderer/assets/lib-chat-ui-BAUBpUwu.js`中的`UJ`、`$Jn`、`tYn`及`lib-chat-ui-B-axvvx6.css`中的`_metaFold*_9ymy5_*`,仅分析渲染规则,没有读取或展开内部推理正文。以下明确区分源码证据和原生验收。
| 位置 | 本轮结果 / 下一步 |
| --- | --- |
| 通用多工具组标题`.mf-head` | 从蓝灰改为黑50%,字号仍使用六档统一变量,默认15px/26.25px。 |
| 标题末尾`.mf-arrow` | 原来收起时向下、展开时向上且离开鼠标隐藏;现在收起向右,展开向下并保持可见。通用组SVG16×16、margin-left:-4px;“过程消息”保留自身12×12及始终向下规则。 |
| 标题底→首个工具`.meta-fold > .mf-body` | 外层gap由8px改0,折叠体上下padding各2px。子项gap8px及相邻工具margin尚未对标,不将整个工具组间距标为完成。 |
| 折叠后的可见正文`getTurnFoldLayout` | **完成/取消已共用锚点规则**:按trim后正文长度保留所有并列最长非空正文及最后正文,首个锚点前归历史、锚点之间归过程。不再要求至少三段或恰好两段可见正文;规则不依赖会话身份。双端动态折叠时机尚未完整验收。 |
| 通用组摘要`FoldGroup` | **动作摘要文字已接入**:按动作分类、参数对象、相邻正文及状态生成摘要;离线与当前安装WB纯函数1760组对照一致。组头图标、推理事件参与分组及双端原生流式标题切换仍待补验;不把任意工具意图直接拼成摘要。 |
原生Ygent9335、1335×916、DPR1:会话5检测到130个通用组,本轮对首个组实测收起opacity0/rotate(-90deg),展开opacity1/transform:none,16×16、组gap0、body padding2px 0px,随后恢复展开状态及原会话。普通会话2没有通用多工具组,仅验证入口,不能算多工具验收通过。WorkBuddy9223当前可见区域没有通用MetaFold;展开两条已完成状态仍未出现该组件并已还原,此处通用组样式目标依据当前安装源码,尚缺同一通用组双端运行时对照。
验证:`pnpm check:chat`通过,覆盖增量、单→多工具、结束折叠、取消迁移及手动展开保留;没有向真实会话发送请求。原始源码和运行时记录保存在私有目录`.ygent/imports/render-audit-20261008`。
### 正文锚点分段实现与验收(2026-10-08)
本节记录最初取消回合实现;下节“完整时间线/摘要统一”取代仅打开前段历史的入口行为。
`CancelledTurnLayout`由固定firstReply/process/lastReply改为anchor/process/visible段序列;中间短正文与普通工具可共同进入过程折叠,多个最长锚点可产生多个过程组。权限和widget保留专用渲染器,位于过程之间时在原顺序显示,不当普通工具处理;历史首次展开后保留挂载。没有历史内容时显示静态取消状态,避免提供空历史折叠按钮。工具/意图展开选择仍由所属回合按稳定消息ID保存。
最后正文之后的真实工具保留在正文之后,不移到正文之前或丢失。WB源码`tYn`仅枚举锚点之前/之间的内容,本轮没有真实WB晚到工具事件对照,因此尾部事件策略仍待动态验收。既有导入快照中没有执行结果的占位调用保持不冒充已执行命令;数据库原消息不删除。权限/widget的折叠位置也需双端补验。
组件回归新增:最长在最前、并列最长(含前后空白)、单正文之前有工具、两正文之间有工具、空白正文、短正文夹在过程、widget/权限控件、末段之后真实工具顺序及导入无结果占位。原有运行→完成、运行→取消的组/工具/意图手动展开保留回归全部通过。
原生YG WebView2/CDP9335,1335×916、DPR1,真实参照会话5:目标取消回合保持2段可见正文、1个过程组;历史5段正文/5条工具、过程1条工具。父过程关闭隐藏结果面板、重开保留相同面板节点与意图展开状态、历史关闭保持挂载,3项通过,操作后恢复原会话及展开状态。记录为私有`anchor-layout-native-check.json`。未发送模型请求、未注入假数据;其他锚点排列来自组件回归,不能宣称已完成WorkBuddy双端流式验收。
### 完整时间线/摘要统一(2026-10-08)
`getTurnFoldLayout`不再限定取消状态。`TurnBlock`在回合结束后使用共用分段,运行中持续显示完整时间线;完成/取消状态按钮均切换完整时间线和锚点摘要,展开时不再只是补前段历史或强制打开所有工具组。无隐藏历史/过程时不提供无意义的整体展开按钮。待确认权限仍在时跳过整体折叠,保持操作可见。
依据当前WB源码`D5n`:整体折叠时渲染anchor/process,展开后恢复通常的内容/MetaFold段;不能把整体展开理解为每条工具详情都展开。Ygent完整时间线`.turn-history`和摘要`.turn-folded`互斥显示,首次挂载后以hidden保留节点;已在流式阶段挂载的时间线在完成后仍保留同一结果面板。两种呈现的工具/意图状态共享稳定消息ID;完成后的最终输出增量不会重置手动整体展开,摘要中的过程组选择也在整体往返后保留。新增`.folded-layout`统一终态布局样式,原`.cancelled-layout`不再作为专用呈现分支。
组件回归新增运行→完成的整体自动收起、完整时间线/结果节点身份、工具详情状态、最终输出更新、摘要过程展开及整体往返,完成/取消纯分段结果一致。`pnpm check:chat`及`pnpm build`通过。
原生YG9335、1335×916、DPR1:普通会话2的完成回合、会话5的完成/取消回合共3项样本,分别验证摘要与完整时间线互斥、关闭隐藏完整时间线、重开同一时间线与结果节点、意图状态保留,全部通过。会话5完成样本摘要1段/完整3段,取消样本摘要2段/完整7段;普通样本摘要/完整均1段,隐藏的是工具历史。证据私有`full-turn-fold-native-check.json`。WB9223同视口对“已完成11m33s”及“已取消4m28s”状态按钮往返,collapsed类正确切换并还原;本轮未获得可排除祖先裁剪/推理标记的可见正文计数,不据此宣称两端计数相等。
剩余:WorkBuddy活动回合资格/自动整体折叠触发时刻、模型底座真实流式终态、末段后事件策略、组头图标、组内间距及滚动锚点。工具动作摘要见下节。当前保留两种呈现的DOM会增加历史展开后的挂载量,超长会话性能待专门验收;不把节点保留直接等同于文字选择/滚动位置已通过。
### 工具动作摘要(2026-10-08)
`src/lib/toolSummary.ts`实现已安装WB的`mJn/IJn/VJn`规则,`toolSummaryRules.ts`记录40种动作及别名/简体中文词汇。对象按字段优先级在参数、嵌套结果、结果中查找;路径缩为末级名称、URL缩为主机名、中日文最多16字符、其他语言最多6词。命令不采用command内容作为摘要对象;同组动作聚合,混合组按数量取主要两阶段,有对象时优先对象、没有时使用经过前缀/后缀及泛词过滤的相邻正文主题;超过3类且没有主题时显示操作类别数量。未知工具使用“继续处理任务过程”,空摘要才走统计兜底。
运行中给可修饰摘要加“正在”,计划退出/提问按实际工具状态显示等待;全部取消保留取消状态。失败不再给动作标题追加“几个错误”,原toolError、失败图标、退出码和输出仍保留在工具层。`computeTurnFold`把本组摘要及后/前相邻正文交给通用`FoldGroup`;不同会话使用同一规则。标题单行,最大520px并以省略号裁剪,默认15px/26.25px且继续跟随六档字号。
验证分层:私有`summary-oracle-check.mjs`在离线隔离VM中仅执行安装产物的纯摘要函数(不执行整包、不读取内部推理),40种动作/别名、混合组合、完成/运行/取消、前后主题共1760组,与Ygent结果逐项一致。仓库`tool-summary-check.mjs`另覆盖命令正文排除、失败保留、未知动作、等待、URL、结果回退、非法增量JSON等17个场景;已纳入`pnpm check:chat`。组件回归确认“正在运行命令”→“运行命令”更新保留同一组头、手动展开及同一结果面板。
原生YG9335,1335×916、DPR1,真实会话5展开一条完整时间线后取3个组:6/5/18条工具对应README.md/App.tsx/lib.rs主题;实测15px/26.25px、max-width520px、ellipsis。折叠往返组头节点保留,通过;操作后还原原会话及状态。私有证据`tool-summary-native-check.json`。没有向参照会话发送请求或注入delta。纯函数一致不等同于真实WB原生流式标题切换通过,推理事件的组成员、组头图标、当前模型底座工具命名适配仍需单独补验。
S01、S02、S06的主链路已修改。以下为实现与验证状态,不表示双端WorkBuddy动态对照完成。
- `src/lib/chatRun.ts`按请求/稳定块ID管理正文;工具切开正文,后续文字创建新块。工具start/update/end原位合并,并行工具按创建顺序排列,空结果进入完成态。
- SQLite先按块创建顺序插入,再原位更新;写队列合并尚未写出的增量。v9增加tool_state,保存完成/取消;启动时恢复中断工具。切会话缓存保留未落库的块,重载依据行顺序。保存失败提示用户并保留内存。
- OMP用messageId:contentIndex定位正文,独立消费工具更新、保留完整输出;prompt_result.id关联提交命令。sessionSettled:false时保留绑定直到session_settled;同步本地命令依据agentInvoked:false结束。依据为项目内docs/reference/omp/rpc.md;旧版缺字段时使用单请求串行回退。
- Codex用thread/turn/item ID定位,outputDelta追加、aggregatedOutput替换最终快照。记录已完成turn和OMP message归属,拒绝旧通知;进程代次隔离旧reader。
- 两种底座和直连统一携带request_id/session;取消保留正文、终结工具及授权,关闭请求拒绝所有迟到事件。新请求等待取消IPC返回,OMP还须等待旧请求settled。ack超时不等于拒绝,保留绑定直到终态;没有终态时需恢复内核,不允许混叠发送。
- 直连SSE按字节缓存完整行后解UTF-8,中文/emoji跨HTTP包不再被逐包lossy解码损坏。
验证:pnpm check:chat通过(组件/模拟IPC事件回归);cargo test --lib共16项通过(含完整输出、块ID、未settled阶段、数据库交错完成顺序、请求写入前取消)。pnpm build通过,既有bundle大小提示仍存在。
原生YG端到端:真实Rust/Tauri IPC/WebView2,1335×916、DPR1,独立数据目录、本机受控SSE。跨包中文/emoji、代码容器身份、内容落库、取消标记、新请求不混旧流、重载内容一致,6项通过。时间线记录时刻、pending、文字长度和滚动尺寸;私有证据在 `.ygent/imports/render-audit-20261008/native-stream-check.json`。HTTP模型服务是受控测试服务,未替换IPC;不声称真实OMP/Codex或WB动态过程通过。
[不含会话正文的验收结果与时间线](reference/workbuddy/stream-p0-2026-10-08.json)。
正式会话5(829条)未发送测试请求。隔离实例与SSE服务关闭,正常YG调试实例恢复9335。
剩余:WB的阶段序列/动画/自动展开策略,真实OMP/Codex原生验收,reasoning、单工具升级成组的双端原生动态验收、异步高度/滚动锚点、队列和操作栏。单工具升级的组件节点/展开状态回归已通过,不再列为未实现。崩溃恢复完整请求、保存失败自动重试、超大OMP分片协议尚未实现。
## 验收对象
同一输入、相同视口/字号/展开状态,比较两端从提交到结束的状态序列。模型输出内容和网络速度不同,不能据此要求每个 token 的墙钟时间一致;比较对应事件后的显示位置、块顺序、更新方式、折叠、滚动和操作反馈。具体动画时长、节流频率、自动展开策略须从当前 WorkBuddy 原生运行时取得,不凭旧产物或猜测设定。
不在参考历史会话内发送测试消息或执行工具。自动化回放应使用隔离测试会话和限定事件序列;组件回归及模拟事件只验证实现,不能作为两端真实流式验收。验收报告区分:源码确认、组件回归、YG原生实测、WB原生实测、双端对照通过。
## P0:先解决事件和渲染状态
| ID | 位置及触发序列 | 当前确认的问题/状态 | 通过条件 |
| --- | --- | --- | --- |
| S01 | `src/stores/chat.ts`,正文A → 工具开始 → 工具结束 → 正文B | `chunk` 都追加至 `streamingId` 的同一节点,未按正文块边界创建后续节点;旧快照的多个正文块不证明真实流式正确 | A、工具、B保持事件顺序,各块ID稳定;持久化/重载保持该顺序,无复制或丢字 |
| S02 | `src-tauri/src/sidecar/omp.rs` → `src/stores/chat.ts`,工具 start → 多次 update → end | OMP update 被归为 start/done,没有独立 update 映射;前端类型虽有 update,分支未消费;可能创建重复卡或过早完成。OMP结果还截为300字符 | 相同工具ID原位更新;进度更新不表示结束、不新增卡;完整输出保留,成功/失败/空输出正确 |
| S03 | `src/components/Markdown.tsx`,未闭合代码块持续追加,最后闭合 | 已去除随文本长度变化的key,并更新表格引用闭包依赖;组件回归通过。当前WB增量解析、动画、节流仍待实测 | 增量不重挂载稳定容器;复制/选择/横滚不被清空;未闭合围栏、表格、公式、mermaid的中间态按WB逐项验收 |
| S04 | `src/lib/turnFold.ts`、`TurnBlock.tsx`,工具1 → 工具2 → 后续正文 → 回合结束 | 单→多工具、终态折叠、完整/摘要往返、手动展开及节点保留已有回归;动作摘要纯函数1760组对照一致。组头图标、DOM选择/横滚、WB自动折叠时机及双端原生流式摘要仍待核实 | 自动折叠触发与WB一致;用户手动展开不被无关delta打回;组形态变化不丢内部状态;统计仅算本组,不用全回合计数 |
| S05 | `ChatView.tsx:269`附近,贴底 → 增量变高、上翻 → 增量变高 | 仅监听messages/atBottom;异步公式、widget及子组件展开引起的高度变化未统一处理,40px跟随阈值未与当前WB核对 | 贴底跟随;主动上翻不被拉回;回底重新跟随;展开/图片加载/字体变化不误判用户离底;记录scrollTop、scrollHeight、阅读锚点 |
| S06 | `chat.ts`的事件监听与全局streamSid/streamingId,取消 → 迟到事件 → 新请求 | chunk/done/error缺少一致的请求身份过滤;工具事件未在取消后统一终结;任务切换时只有单套全局缓冲 | 取消即时停止,已有内容保留;迟到事件不污染新回合;未完成工具有明确终态;切会话不混流;恢复历史与即时显示一致 |
| S07 | 思考、首字等待、耗时、停止按钮及错误入口 | YG有等待动效、光标和pending按钮,但未取得WB对应动态序列;reasoning数据类型未接入 | 首字前、思考中、文字中、工具中、完成、错误、取消每一阶段的可见元素与参考一致;不伪造推理正文/模型/消耗 |
S01、S02、S06先于进一步像素微调;上表保留修复前基线,主链路结果见本文开头,双端动态证据尚未取得的部分仍未完成。
## 当前已验证的局部交互
- `ProcessGroup`:过程、运行命令、意图、结果四层。意图独立折叠;关闭工具或过程再打开,保留意图和结果状态;第一次打开前不创建结果DOM,打开后隐藏而不卸载。
- 真实YG WebView2 CDP9335、1335×916、DPR1、默认2档、真实会话5:意图关闭仅隐藏结果、工具往返保留意图、父过程关闭隐藏子层、父过程往返保留子层、结果节点身份稳定,5项均通过。
- 当前WB参考回合:同条件的状态dy36.5、过程dy140.25、运行命令dy168.5、意图dy198.75、面板dy227.25,与YG一致;面板752×198.75。此处只验证已有回合和折叠交互,不代表生成中策略一致。
- `node scripts/chat-render-check.mjs`:增量Markdown保留代码容器和复制按钮;嵌套折叠往返;结果更新原位保留;多工具组运行→结束自动折叠→手动重开保留状态。脚本为组件测试,使用合成数据、无CSS、不调用后端。jsdom优先读取项目安装,未安装时沿用现有fe-check的本机workspace回退路径;跨机器需自行提供jsdom。
## 执行顺序
1. 获取当前WB流式事件到DOM的映射及时间序列,补齐未知策略;同时修YG的正文分块、工具update和请求身份过滤。实现需以稳定turn/block/tool ID为依据,不能靠历史样本最后两段的排列模拟实时状态。
2. 建立隔离、可重复的事件回放回归:逐字与批量delta、交错工具、并行工具、空输出、错误、取消、迟到事件、切会话和重载;验证内存和数据库都保持顺序、内容和终态。
3. 用真实原生YG与WB执行受控交互,采集MutationObserver时间线、节点身份/rect、折叠状态、滚动量及必要的短录屏。比较事件后的阶段效果,组件回放通过后仍须原生验收。
4. 再收敛动画、图标、回合操作栏和布局细节;每次结构调整复测流式/滚动/取消,避免为历史静态画面破坏实时行为。
## 必测序列
| 序列 | 必须记录的阶段与位置 |
| --- | --- |
| 发送与首字 | 输入草稿清理、用户气泡出现、助手等待、停止按钮、首字替换等待 |
| 正文流式 | 短delta、跨行、代码围栏半截、表格半行、公式、mermaid;正文尾部光标、布局跳动与已完成块节点身份 |
| 工具流式 | start/update/end、空结果、失败、两工具交错;摘要/意图/结果每层可见性、图标状态及输出累计方式 |
| 折叠 | 单工具升级为组、出现后续正文、done自动收起、手动展开后继续delta、父层关闭再打开 |
| 滚动 | 底部跟随、上翻不跟随、回底、展开变高、图片/widget/字体异步变高 |
| 结束与恢复 | 正常完成、停止、失败、重试、切会话、应用重启;耗时、操作栏、按钮终态、消息数量/顺序/内容 |
完成定义:这些序列获得双端原生对照证据,未验证项为零;当前静态清单中已修复项目不计作动态验收通过。
## 2026-10-08:生成过程工具列表刷屏修复
真实原生 Ygent 的 hello 会话在生成时连续展示 45 次 read/grep/todo 调用,正文尚未出现时工具组一直展开。用户确认优先问题是生成过程被工具列表刷屏。本次将连续两个及以上工具调用默认收成动作摘要和数量;生成中额外显示正在执行的工具动作,没有运行工具时显示“正在思考”。这行提示不带转圈图标,“正在思考”文字使用从左到右的扫光,减少动态效果设置下使用静态文字。单个工具不增加分组层级。已知工具使用共享中文动作/对象摘要,长标签省略显示。
组和工具详情仍使用所属回合的稳定消息 ID 保存展开选择。手动展开、收起不会被普通增量或完成事件重置;单工具升级为组时,用户已打开的结果也保留。消息数据和结果没有删除,点击摘要可查看全部调用。
活动提示进一步统一:原首字等待的三个圆点和“正在思考…”已移除。首字等待与工具间隙共用回合底部的 Thinking 组件,每回合最多一处活动提示,且不依赖工具组是否展开。“正在思考”四字使用 2.2 秒循环的逐字扫光/上浮,每字错开 0.14 秒,上浮最大 1px;执行工具时短动作前缀扫光(命令显示“正在执行命令”),对象文字静态。正文正在流式输出时沿用尾部光标,权限待确认时不显示思考提示,完成/取消/失败终态移除活动提示。减少动态效果下取消动画。
此次新增回归覆盖空正文与工具同时存在时提示去重、单工具执行、组展开保留活动提示、正文/授权/终态切换。原生 WebView2 辅助挂载组件检查实际字号、动画关键帧、逐字延迟、静态文件名、展开状态与提示数量,结果通过;未修改真实会话/IPC,也没有发送新的模型请求。证据为私有 activity-check.json。完整 check:chat、类型检查和构建通过;不将辅助挂载结果当作真实 OMP 流式端到端验收。
随后修复单工具升级为多工具组时的瞬时展开:原实现沿用单工具 open 状态渲染组头及列表,再由 useEffect 自动收起;现在分组策略变化时在本次渲染直接计算正确 open,effect 只同步持久状态。用户主动展开及已打开的子详情仍保留。组件与原生 WebView2 辅助 MutationObserver 回归检查升级过程没有出现组头 aria-expanded=true 后又自动收回的瞬态;真实用户刚才的瞬态没有录制,不能断言只存在这一种原因。私有证据为 flash-check.json。
按用户对动效质感的反馈,活动提示最终改为稳定文字和柔和整行扫光:取消逐字拆分、上浮和蓝色高光,使用次级灰色到弱化灰色的渐变,3秒一轮;12%前和72%后保持静止,光带连续从左到右经过整段动作文字。思考和工具动作共用同一效果,对象仍静态。原生 WebView2 辅助样式采样确认整个周期文字坐标、宽高稳定、无 transform,动画时长3秒且保留停顿;证据为私有 soft-shimmer.json。组件回归、类型检查和差异检查通过,未发送真实模型请求。
用户继续反馈思考上方闪出工具行/列表,补齐另一处切换策略:第一条实时工具原先直接展示 ToolCard,第二条才升级摘要。现生成中的单工具也直接使用摘要入口,后续增量复用同一组头节点,避免独立工具行先出现又被收回;本次运行中建立的摘要在完成后保留。已存在且未经过实时显示的历史单工具仍使用原来的直接工具卡。手动展开和取消布局迁移保持原行为。组件及原生 WebView2 辅助检查验证首条工具无独立工具行、1→2组头节点稳定、没有瞬时展开;未发送新真实模型请求。临时只读 flash audit 仅记录当前页面的状态/尺寸/类型,保存在页面内存,不采集正文。
首字衔接试验(已撤回,以下仅保留阶段记录):空的最新流式回复在自己的 ReplyText 容器中显示“正在思考”,首字到达后同一容器立即渲染原始 Markdown,同时进行120ms交叉淡入淡出;思考残影绝对定位、对辅助技术隐藏、不占第二行。后续 delta 不重新入场、不延迟正文、不模拟逐字播放。无空回复占位的等待及执行工具仍沿用原活动提示,工具分组/状态/存储/滚动代码未修改;历史已存在正文不新增入场动画,减少动态效果时直接切换。
组件回归验证首字前后容器稳定、增量代码节点保留、残影清理、后续增量不重播;既有发送/权限/工具分组/完成/取消回归通过。原生 WebView2 辅助采样确认等待与首段正文起点同为y=156.5,首段文字立即可读,后续段落节点稳定且动画停止;证据为私有 reply-handoff.json。没有发送新的真实模型请求,真实长回合滚动及双端动态对照仍待验收。
### 当前有效规则:整个生成期间固定播报
用户明确期望是“正在思考”后面像字幕一样过流式内容,并在整个生成期间保留。已撤回 ReplyText 淡出替换及相关 CSS,恢复原来的正文 Markdown 渲染。新增独立 StreamingActivity 展示层,放在助手回合正文上方;左侧固定思考扫光,右侧将该回合正文纯文本及工具动作按消息顺序组合为单行播报,隐藏代码围栏正文/表格行及 Markdown 标记。短内容直接显示,超长内容左移,达到已收内容末尾后停止且保留,新增内容继续推进;展开工具、正文输出和等待授权都不移除栏,授权提示在右侧说明。结束后移除栏,沿用原来的完成/取消/失败呈现。
播报只保留最近4000字符作为视觉缓冲,速度80~320px/s,过多积压跳到距末尾约两屏的位置;截掉旧内容时继续靠近新内容。减少动态效果下直接显示末尾;尺寸变化重新检查溢出,组件卸载清理 RAF/ResizeObserver/媒体监听。右侧不加入逐字辅助技术播报,避免与正常正文重复。工具分组和展开状态、发送/事件/数据库、正文流式速度与滚动逻辑未改动。
完整 check:chat 和类型检查通过;组件回归验证左侧持续挂载、正文增量独立更新、间隙保留内容、工具展开和授权不消失、终态移除。原生 WebView2 辅助播报测试验证 scrollLeft 连续增长、追到末尾后保持不动、新增内容恢复移动、栏和正文节点保留以及正文立即完整显示;证据为私有 broadcast-check.json。没有发送新的真实模型请求,真实长回合的阅读/滚动体验与双端动态对照仍待验收。
用户指出上述动作/文件名摘要仍经过整理,现播报数据源改为当前消息事件的原始字段:agent.text、工具 fn/toolArgs/toolIntent/result、权限 text,按消息顺序以换行连接。撤掉 summarizeTools、文件名缩短、Markdown 清理和代码/表格替代文字;显示区域仍为单行,所以换行仅作为视觉空白,DOM文本保留原始换行。最近4000字符的视觉缓冲、固定思考标签、暂停/续播机制和正常正文/工具卡均不变。“原始”限于现有接入事件的内容字段,不宣称接入网络协议帧或模型隐藏推理。组件回归及原生 WebView2 辅助检查确认代码围栏、完整路径、JSON参数和工具输出逐字保留,证据为私有 raw-broadcast-check.json;没有发送新的模型请求。
随后按用户要求缩短可见播报窗口:最大18em(当前字号实测270px),滚动速度改为240~720px/s,仅提高视觉播放速度,不改变模型输出速度或原始内容。原生辅助检查300ms内scrollLeft推进144px,完整参数仍保留;私有证据为 fast-broadcast-check.json,类型及差异检查通过。
位置及运行耗时修正:播报栏已从回合顶部移回正常正文/工具时间线下方,生成期间持续保留。助手头像/名称下方的既有状态位置新增“进行中+耗时”,使用本回合 startedAt(缺失时使用首条事件时间),独立组件每秒更新,流式暂停也计时;终态卸载定时器并保留原有完成/取消耗时逻辑。组件回归验证无delta时计时推进、播报位于时间线之后、终态不残留计时器组件;原生 WebView2 辅助检查确认status位于头像下方、播报位于history下方、25s→26s推进以及取消后保持“已取消25s”,私有证据为 live-time-check.json。未发送新的真实模型请求。
### 运行状态文案参考 WorkBuddy
当前安装的 WorkBuddy 5.7.6 产物 zh-cn-CEs_4LQ3.js 的 progress.phase.* 定义了“准备中”“等待模型响应”“生成回复中”“处理结果中”“调用工具中”及分工具动作、“等待授权”“等待回复”“重试中”等。workbuddy-provider-cuZEv46I.js 的 nu 根据 phase/toolName/streamingToolName/pendingInputKind 选择对应文案;这些状态来自事件,而不是耗时阈值。原生当前页面只处于终态“已完成6s”,未发送WorkBuddy请求采集这些阶段的实时序列。
Ygent 新增 liveTurnStatus,共享同一耗时位置,根据可观测消息状态切换:空回复或工具结束后等待后续事件为“等待模型响应”,最新正文正在streaming为“生成回复中”,running工具优先显示“正在读取文件/列出目录/写入文件/编辑文件/搜索文件/搜索内容/执行命令”,未知工具为“调用工具中”,pending权限优先为“等待授权”。文案参考WorkBuddy,但分类映射使用Ygent/OMP工具别名。耗时仍为本回合总耗时,不因阶段变化清零;底部固定思考/原始播报规则不变。
目前没有可靠事件区分准备、模型工具参数生成、重试、模型结束后的处理/快照同步,故没有伪造这些状态。用户问题/计划退出工具采用“等待用户确认”,更细的授权类型需额外事件字段;不能仅由参数文字猜测。组件回归与原生 WebView2 辅助检查覆盖等待→正文→读取→命令→再次等待→授权、同一播报节点和耗时保留;证据为私有 status-phases-check.json 和本机 asar 源码片段,check:chat与类型检查通过。尚不宣称双端原生状态序列已完成1:1验收。
验收:真实 Tauri WebView2 CDP 9335、1335×916、DPR 1,会话 7 的 45 次工具调用在完成后折叠为 26.25px 高的摘要行;展开后显示中文动作,再收起正常。组件回归覆盖 45→46 次调用、当前动作、节点身份、详情保留、手动收起与终态;npm run check:chat 和 npm run build 通过。此次没有发送新的真实 OMP 请求,生成中策略由组件增量回归验证,不能据此宣称双端原生流式对标全部完成。真实截图和 DOM 证据保存在用户私有 .ygent/imports/hello-layout-20261008/,不提交会话内容。
## 回复操作栏(2026-10-08)
已结束的助手回合底部统一显示复制、分支到新聊天和回复模型。复制整个回合的回复正文,沿用已复制/复制失败反馈。分支包含所选回合最后一条助手回复及其之前的上下文,不包含后续消息;OMP 使用原生 fork 和真实会话文件,直连使用数据库上下文。生成期间不显示该操作栏,生成中禁用其他回复的分支操作。
模型在请求开始时记录并随消息持久化,历史未记录的模型显示“模型未记录”,不使用当前选择冒充。回复时间紧跟模型名称,间距 10px;悬停助手回复区域或键盘聚焦操作栏时显示,提示中包含完整日期时间。
验证:组件回归覆盖整回合复制、复制反馈、末条回复分支、历史模型缺失和生成期间隐藏;Rust 回归覆盖包含助手回复的分支边界、元数据保留、重复文本与活动路径映射。类型检查、check:chat、Rust 25 项测试与前后端构建通过。真实 Tauri WebView2 9335(1335×916)使用临时受控 OMP 转录文件验证原生 fork、数据库前缀复制、模型元数据读写、时间位置和显隐;测试会话已删除,原会话未发送模型请求。这是原生分支/渲染验收,不代表真实模型流式或 WorkBuddy 双端对照已完成。
## UI 优化回归补充(2026-10-10)
原生受控 Responses 回归发现等待空块在 text-end 被移除、首个工具事件尚未到达时,回合会短暂消失;首条消息 ID 随之变化也会重建整个回合。展示 key 现使用前置用户消息 ID;运行中最后一行只有用户消息时保留同一空回合,工具/正文按实际事件到达,展开作用域也使用稳定回合身份。无用户消息的历史回合仍使用原事件 ID。
真实 WebView2 + 实际 OMP 验证思考、参数、工具和正文之间播报节点保持身份、26.25px 状态行高稳定;原生滚轮上滚后不抢回阅读位置。完成、取消、HTTP 400 失败均清除播报;思考增量不写入历史。脚本 `scripts/chat-activity-native-check.mjs`,私有证据 `.ygent/imports/ui-final-20261010/stream-final/`。本轮也验证了问题选项键盘移动不提交、Enter 回传精确选项、回答重载/展开及授权拒绝/取消;不是 WorkBuddy 双端实时序列的全量 1:1 验收。