Files
ycode/docs/assessment-chat-projection-2026-10-15.md
T

13 KiB
Raw Blame History

同会话对话区差距评估(2026-10-15)

当前导入让两端拥有相同的用户问题、助手正文和大部分工具结果,但没有复制原版的完整显示投影。整页差距包含已证实的取消状态误判、工具名规范化缺失和内容块映射缺失,不能继续只靠 CSS token 调整来消除。

本次是只读评估,未修改生产代码、会话数据或原版。所有原版实现依据均来自已保存的 REA exports;实时截图由主上下文通过 REA 采集。本报告不粘贴原始思考文本、工具输出和图片内容。

样本与证据

  • 原版:WorkBuddy 5.8.2。原会话 4653e36f-6b2a-446f-a9c9-3f2d2d04644e,YCode 副本 6c000be8-b0e8-4768-9a7f-1a0d94a35951,标题「开始新会话」。
  • 历史导出:.tmp/rea-workbuddy-session-with-images.json,Evidence ev_3c4593ae51bbee833ca9fcbe3b9ad172d108cc82cfd6783d9c06a1a78794f209,JSONL SHA-256 5311865227e9c278798b458d722cc54ac362aeb78f4eb52cece394d3608a04ed。
  • 原版脚本:.tmp/rea-runtime-scripts.json,Evidence ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb。
  • 当前真实画面:.tmp/rea-assessment-initial/workbuddy.png / layout.json,Evidence ev_d6e6920ff4e47f73a182fac5312c5f02393366a035445d18c8a6733a8c8a11ed,2026-10-15T15:47:25.821Z,视口 1336 × 901。主上下文对照 YCode .tmp/assessment-ycode/panel-closed.png / panel-open.png。
  • 本地导入产物:.tmp/workbuddy-copy-session.json、.tmp/workbuddy-copy-report.json、.tmp/ycode-workbuddy-copy-ui-report.json。

原版截图与 DOM 是先后观察,非原子快照;仅证明该会话当前可见范围。不能由最后一轮推断每个历史失败轮或所有展开状态均已验收。

导入目前真实保留了什么

项目 原可见分支中的记录 YCode 副本
用户轮次 31 个可见用户问题,另 10 个注入通知被隐藏 31
助手文本记录 257 合并为 31 条助手消息中的 257 个 text part
工具调用 / 结果 691 / 688 691 个工具,3 个无终态结果改为 cancelled
reasoning 358 1 个 reasoning part
图片 4 4
助手终态 249 completed、8 incomplete 文本记录 24 done、7 error 消息
富内容 part 来源还有工具 renderer 与 metadata 只有 text 257、tool 691、reasoning 1;无 artifact / plan / task / image part

2 次 resend-fork-notice 共排除 357 条旧分支记录;31 个用户文本已剥离 prompt context。没有未匹配的工具结果。这些保证的是导入完整性与当前分支选择,不等同于显示结构或交互一致。

已证实的优先差距

1. 用户取消被导成红色错误,且取消提示显示两次

src/shared/workbuddy-import.ts:168 的 finishAssistant 优先判断 lastAssistantError,只要存在错误文案便将整轮设为 error。src/shared/workbuddy-import.ts:239 同时把所有 assistant output_text 原样保留为正文。

第 3、5、8、9、23、31 轮均满足:源末记录 status: incomplete,providerData.error.message 为 Interrupted by user,末正文也为 Interrupted by user。导入后两者都保留,形成英文正文和红色错误的重复展示。第 28 轮是 429,不能和用户取消混同处理。

原版 workbuddy-provider-DkH2YFYM.js SHA-256 b588e875c469978f216beec86bdf4b6c33a31c0266f9bf996881b8dbf37b5dc7,AST 方法锚点:

  • isHistoryInterruptedByUserChunk offset 478633:识别精确文本 Interrupted by user 或 [User Cancelled]。
  • projectHistoryAssistantTextMessage offset 475180:命中后设 complete: true 与 buildCancelledMessageExtra,不把该标记追加为普通正文。

第 31 轮已经通过主上下文 REA 画面闭环:原版显示「已取消 17m15s」和「用户已取消」,历史过程闭合;YCode 同一轮展开历史正文并在底部显示重复英文取消和红色 error。其他 5 个取消轮的具体画面仍须逐轮复核,但导入语义错误已有源码和数据证据。

修复应保留真实 429 错误,并把可明确识别的取消标记转换为显示终态;不能把所有 error 都粗暴转成 cancelled。

2. 错误终态未进入完成投影,直接拉长页面

src/renderer/src/components/MessageBubble.tsx:124 仅在 done 或 cancelled 时传 turnFinished: true。上述 7 个 error 因此被投影为仍未完成;摘要组的 isRunning 也成为 true。原版现代 computeTurnFinished(src-DbE1_mgM.js offset 975305)依据最后分组、request terminal、会话 busy 等信号计算结束,并不等同于这个两个状态的枚举判断。

对当前 completed-fold.ts 做内存 bundle 后直接调用纯模型,未改会话数据,结果如下。右列是把相同 parts 按终态投影的诊断结果,不能冒充每一轮原版截图。

轮次 当前状态 当前根渲染单元 按终态投影的根正文锚点 当前完成 / 过程折叠 终态诊断折叠
3 error 11 2 0 2
5 error 17 2 0 2
8 error 13 2 0 2
9 error 3 2 0 2
23 error 3(模型为 null,原 parts 直接渲染) 2 0 2
28 error / 429 13 2 0 2
31 error / 用户取消 21 2 0 2

第 31 轮原版已确认闭合,其差距首先是状态与消息投影。取消语义修复会自然修复这 6 轮的主折叠门控;真实 error 轮还需明确原版终态契约。

3. 原版 provider 做了工具规范化,副本直接使用原始工具名

原版 provider 的 Bi alias 表 offset 190005、canonicalizeToolName offset 191155,以及 normalizeWorkbuddyNotification offset 290986,会在 UI 前规范化工具名和字段;unwrapDeferExecuteTool offset 287955 将延迟调用展开为目标工具并改用 params。

YCode 导入 src/shared/workbuddy-import.ts:261 直接保存 record.name。ToolCallRenderer.tsx:102 的有限 alias 表不能替代 provider 全流程;MessageBubble.tsx:65 的分类又另有一份不完整名单。

本会话原工具名 次数 原版规范化或专门路径 当前 YCode
TaskCreate / TaskUpdate 10 / 14 todo_write,provider 还调用 todoManager.ensureNormalized 无 alias,走通用卡片
DeferExecuteTool 12 解包目标 mcp__rea__* 工具及 params 通用 DeferExecuteTool 卡片
present_files 10 存在专门 compact view 与产物来源识别 通用卡片,未生成 artifact part
AskUserQuestion 1 askuserquestion,inline question 分类、回答恢复 大写名称未命中 question renderer,也未命中 MessageBubble inline 分类

这 47 / 691 次调用确定进入现有通用兜底。另 644 次虽然命中某个已实现 renderer,并不代表已完成内容、展开默认值、预览和像素验收。

present_files 的 10 个调用含 21 条文件引用(可能重复),副本没有 artifact part;原版当前画面有「13 产物」入口。文件引用不是 13 个独立产物的等价计数,必须恢复原版产物提取、过滤、去重、归属与入口,而非直接将数字设为 13。

4. 正文 spacing 还没有消费原版的排列结论

原版 src-DbE1_mgM.js SHA-256 6c6ce63c93854783270e855572797d75e536e3b8d4548410e31fe9d147e1feb4,markBodyTextSpacing offset 946304,按最后正文、前一个非空块是否工具、回合是否结束,分别输出 both / top / bottom spacing。

YCode MessageBubble.tsx:172 仍只按 index > 0 添加 cr-text-block--spaced-top,其适配 CSS 只有 margin-top: 12px(source-adapters.css:15)。CompletedFold 已返回 render context,但这里没有使用它恢复原版 spacing。即使相同文本和字体,混排正文与工具、折叠前后相邻关系仍会产生系统性间距差异。具体像素影响需在相同展开状态截图上测量。

已知信息损失及验证边界

reasoning:有源字节,但还不能凭 JSONL 直接认定全部应显示

可见分支中 357 个 reasoning 的 content: [],但 rawContent 是 [{ type: 'reasoning_text', text: ... }] 形状,另 1 个有显式 content。导入器 workbuddy-import.ts:254 明确排除 rawContent,所以当前只保留 1 个 reasoning。

已经证明数据在导出中存在,不是无法取得源码或缺少字节。仍未证明原版历史回放会把这 357 个 raw reasoning 全部投影为可见思考块:已保存 renderer/provider 脚本不含 JSONL 的 reasoning_text 处理入口,该环节可能在 daemon/replay producer。必须通过 REA 查回放转换或选定展开状态观察后,按原版显示契约转换,不能仅因存在 text 就展示全部 raw reasoning。

若需要显示,缺失 reasoning 会改变连续 foldable 段、工具摘要中的消息数及展开内容;只恢复字体无助于此。

模型信息、消息身份与合并

原可见 assistant 记录含 requestModelId/requestModelName/model;222 条来自 deepseek-v4.1-flash,28 条来自 glm-5.3-flash,7 条取消/失败末记录没有模型字段。副本 assistant 只保留 id、role、content、createdAt、status、parts、tools、turnDurationMs,缺少模型显示、request 身份和原消息边界。

导入将每个可见用户问题后的全部助手记录合为一条;原版 provider 按 messageId/requestId 累积再交给上层分组。projectHistoryAssistantTextMessage 对同一 message 的相邻同类型 text/reasoning 会直接连接;YCode 每条 assistant source record 单独成为 text part,content 再用两个换行连接。

当前样本存在 257 个文本记录、约 250 个非空 provider messageId。合为 31 条并不必然错误(原版也有 turn grouping),但不能仅用 31/31 消息数证明分组等价。须比较按 turn 的有序「显示块树」,包括同类型连续连接、去重、正文锚点、source ID 到显示节点的映射。恢复模型显示可以保留纯展示 metadata,无需接入原服务端模型。

工具结果与 metadata

当前 688 个结果的 renderer 类型:text 336、list 1、code 101、diff 188、todo 24、无 renderer 38。导入保留 title/content/renderer/rawResponse/error/acpV2PlanSnapshot,并把 rawResponse 放入当前专用视图会读取的 namespace,不能笼统声称 rawResponse 全丢了。

丢弃字段中有 10 个 terminalId 和 12 个 mcpMeta。历史副本不应恢复可执行原 terminal/session,但可以根据原版显示需要保留经白名单转换的静态展示字段。需要区分「为了避免恢复执行态而不导入 native ID」与「因此连静态显示内容也缺失」。todo renderer 的 24 份计划/任务快照已有字节,主要先解决规范化和对应 view 接入。

耗时

当前 turnDurationMs 取该用户 timestamp 到本轮已接收的最后助手/工具结果 timestamp;原版 computeTurnDurationMs(src-0FGg1seX.js offset 757590)取分组内用户 createTime 与 assistantEndTime,并跨连续助手组查找。现代 renderer 也消费 extra.turnDurationMs/assistantEndTime/processingStartedAt。

第 31 轮导入值 1,035,822 ms 格式化为 17m15s,恰与当前原版截图相同,因此这一轮耗时不构成已证实差异。其他轮、跨请求或后台工具结束晚于助手的情况仍应逐轮比较,不能直接换一个估算公式就宣称修复。

长任务应先处理的顺序与验收

  1. 建立本会话按 source record/provenance 回溯的显示块树基线,分清取消、真实失败与正常完成;先修 6 个明确取消轮及最后一轮闭合效果。
  2. 恢复 provider 展示规范化层:alias、defer 解包、question 回答/分类、todo snapshot 与 present_files 产物归属;执行层继续使用自己的实现。
  3. 完成原版 spacing、模型显示 metadata、附件/产物入口和历史工具默认展开状态,再做 CSS/图标/尺寸修正。
  4. 对同一会话至少覆盖首轮、带图片轮、工具密集轮、提问轮、todo 轮、取消轮、429 轮、最后一轮;每个点记录原版 REA Evidence、原窗口尺寸、主题、左右面板状态、滚动锚点和每层折叠状态。
  5. 验收先比较显示块树与可见文本/状态,再比布局矩形、字体、截图像素及操作结果。整页差异不能用少数通用 fixture 通过代替。

阻碍目前主要是数据到 UI 的转换契约和真实状态覆盖,已有脚本、历史字节和 REA 画面足以开始修复。reasoning 的历史显示契约及部分原版回放 metadata 是明确未知项,需要 REA 补证;不需要为上述已证实问题先接入云端服务或子代理调度。

本次验证与修改范围

  • 只读统计 REA JSONL,按已存在 resend-fork-notice 规则选择当前分支,再和副本数据计数比较。
  • 使用 @babel/parser / @babel/traverse 只解析 REA 保存的脚本文本,记录上述 AST 方法与字符 offset、脚本 SHA。
  • 使用 esbuild write: false 将本地 completed-fold.ts 内存打包,直接调用纯模型复现 7 个 error 轮的门控差异;没有修改生产代码或生成替代会话。
  • 主上下文提供最后一轮原版 REA 与 YCode 真实画面对照。没有自行重复 live 采集。
  • 本子任务唯一新增文件:本报告。未运行构建或回归,因为无实现变更;纯模型诊断及数据审计均成功。AST 首次遍历遇到无名称 class method,补充空值判断后完成,只读操作未留下文件改动。