chore: establish YCode replication baseline and TODO

This commit is contained in:
xiaohan.yuan committed 2026-10-17 02:43:49 +08:00
commit 6dc59f89ba
1118 files changed
+196002

No files matched your search

+162
View File
@@ -0,0 +1,162 @@
# Ygent ↔ WorkBuddy 对话区对标清单
> 对话区于2026-10-08按用户要求阶段收尾。[最新阶段进度](ygent-chat-stage-summary-2026-10-08.md)汇总已实现、证据边界及剩余工作;本文路线图中的历史状态不能替代当前实现和双端动态验收。
> 用户要求包含后续流式交互效果一致。当前优先处理 [动态交互P0](ygent-chat-interaction-parity.md):正文分块、工具增量和取消/迟到事件。旧静态分析及下文路线图不能代替当前版本的双端动态验收。
> 最新原生验收依据:[2026-10-08精确渲染差异清单](ygent-workbuddy-render-audit-2026-10-08.md)。下文“已实现/可1:1”是路线图状态,不等于真实窗口验收通过;当前真实样本829条消息,不再适用“几十条消息”的规模假设。
> 状态:路线图与实现状态(2026-10-08)
> 依据:WorkBuddy `lib-chat-ui` 静态分析(2070 个 i18n 键 + 组件 props)、OMP 协议文档
> 口径:对标可见对话区及 Ygent 已有数据能支撑的交互;平台级分享服务、朗读和消耗体系不复制
---
## 结论先说
**能做到接近 1:1,但「1:1」要分开看两层:**
| 层 | 判断 |
|---|---|
| **渲染与交互层** | 待双端动态验收;需要前端与事件协议/持久化共同调整,当前数据缺reasoning、工具增量映射等,不能认定纯前端即可完成 |
| **能力语义层**(消息编辑/回退/排队/压缩/分页) | 🔧 **OMP 已提供核心协议,Ygent 按交互逐项接入;编辑重发已接通** |
| **产品体系层**(敏感保护/IM/插件/积分/媒体生成) | ❌ 不对标,需要 WorkBuddy 那种平台规模 |
**最重要的一个判断**:高级对话交互并非不可对标,OMP 已提供多项底层能力,差别在 Ygent 是否完成接线与状态建模;本轮已接通消息编辑后的分支重发。
---
## A. ✅ 可 1:1(纯渲染层,Ygent 数据已够)
| 能力 | WorkBuddy 证据 | Ygent 现状 |
|---|---|---|
| **对话顶栏与工作台** | 搜索、分享、最近任务、任务概览、右侧工作台 | 顶栏入口已实现;工作台正在按当前 WorkBuddy 的标签容器接入真实目录、文本预览和 Git 变更。内嵌浏览器、终端、富文档与来源区尚未完成,详见 [工作台进度](ygent-workbench-parity.md) |
| Markdown 段落/列表/引用/表格 | `markdown.*` | ✅ 已有 |
| 表格悬浮「添加到对话」 | `.cr-message-quote-table-menu` | ✅ 悬停菜单按 116×38px 规格实现;点击后将原始 Markdown 放入输入草稿 |
| 代码块:语言标签 + 复制 | `markdown.copy/copied` | ✅ 本轮已做 |
| 图片渲染 | — | ✅ 已有 |
| **mermaid 流程图** | `mermaid.*`(12 键) | ✅ 已有按需渲染和源码回退 |
| **KaTeX 公式** | `markdown` 域 | ✅ 已有按需加载 |
| **交互式 widget** | `show_widget` / `widget.*` | ⚠️ 已加入 sandbox iframe、尺寸上报、CDN 白名单与独立时间线段;1200×762 实窗核对后,卡片宽度与时间线一致,参照 SVG 的 iframe 仍有 5px 高差 |
| **代码 diff(改文件时)** | `tool-diff` 组件 | ✅ write/edit 参数可展开查看 |
| 消息悬浮工具栏 | `message.*` | ⚠️ 用户气泡下方支持时间、复制、编辑;OMP/直连支持编辑后分支重发,Codex 仍只保留草稿 |
| 助手身份与回合完成耗时 | `.cr-agent__header` / `metaFold.turnCompletedWithDuration` | ✅ 导入参照会话按来源显示 WorkBuddy 名称与头像;普通会话显示 Ygent;含工具的已完成回合默认收起过程,可展开 |
| 全局字号 | 六档字号级别 / WorkBuddy 字号滑杆 | ✅ 设置中提供 1–6 级离散滑杆;Markdown 根字号逐档匹配,常规控件偏移在第 5、6 档封顶为 +2px |
| 消息状态:思考中 | `message.loading.thinking` | ✅ 本轮已做 |
| 消息状态:已中断 | `message.interrupted` / `userCancelled` | ⚠️ 有「已停止生成」,可对齐文案 |
| 消息状态:未发送 | `message.notSent` / `notSentFailed` | ⚠️ 同步接收失败时保留输入并回滚用户记录;已接收后的异步服务错误仍显示在时间线 |
| 消息时间 | `message.time.*` | ⚠️ 用户消息悬浮时显示时分;相对日期待做 |
| 空会话占位 | `message.empty` | ✅ 本轮已做 |
| 滚动到底部 | `action.scrollToBottom` | ✅ 自动跟随 + 手动回底按钮 |
| 加载更多(历史分页) | `message.loadingMore` + `get_messages_page` | ❌ 见 B 类 |
| 工具卡状态 + 回合折叠 | `metaFold.*`(132 键) | ✅ 连续工具组按正文/回合结束折叠;回合完成行可收起/展开过程;`show_widget` 独立保序 |
| 结构化错误 | `errorBanner.*`(16 键) | ⚠️ 有简易错误占位,可增强 |
---
## B. 🔧 可对标 —— 高阶交互与接通状态
**这一组是重点:OMP 协议提供基础能力,Ygent 正在逐项接入。**
| 能力 | OMP 命令(已存在) | Ygent 要做的 |
|---|---|---|
| **编辑用户消息并重发** | `branch { entryId }` | ✅ OMP 持久 entryId + 独立子会话;直连按选中消息前的历史重放;Codex 暂不支持 |
| **回退到某条消息** | `fork { entryId }` | 仍待实现:任意历史点回退及分支切换 |
| **忙时消息排队** | `steer` / `follow_up` / `set_follow_up_mode` | 输入框在 `pending` 时允许发送并排队;队列 UI(`messageQueue.*` 11 键可参考) |
| **队列项操作**(编辑/删除/立即发送) | `remove_queued_message` / `promote_queued_message` | 队列条 UI |
| **上下文压缩提示** | `compact` / `set_auto_compaction` | 对话内系统事件流(`conversationEvent.contextCompaction.*`) |
| **历史分页(加载更多)** | `get_messages_page`(游标 + `session_busy`/`stale_cursor`) | `list_messages` 改分页 |
| **模型切换提示** | 已有 `set_model` | 对话内事件条(`conversationEvent.modelChange.*`) |
| **权限能力清单**(文件/互联网/终端三档确认) | — | Ygent 已有 `grants` / `audit_log`,扩展成能力清单即可 |
> `conversationEvent` 这一组(12 键)揭示了一个 Ygent 完全没有的概念:**对话内的「系统事件流」**——压缩、历史更新、模型切换、会话边界都作为一类非消息事件渲染在时间线里。这是个值得单独设计的东西。
---
## C. ❌ 不对标(Ygent 无对应能力 / 平台级)
| 能力 | 为什么不列 |
|---|---|
| 平台分享链接、朗读(TTS)、消耗/积分 | Ygent 提供本地选择、复制和 Markdown 导出;不接 WorkBuddy 的外部分享服务与平台权益体系 |
| IM 接入(`im.*` 159 键) | WorkBuddy 是 IM 客户端,Ygent 不是 |
| 插件系统(`plugins.*` 109 键)、MCP(`mcp.*` 68 键) | 平台规模能力 |
| 企业版标识、模型积分速度(`model.badge.enterprise` / `credits.*`) | 商业化体系 |
| 敏感内容保护(`sensitiveProtection.*` 15 键) | 需要凭据检测 + 出入站拦截,是平台级安全能力 |
| 媒体生成(`mediaGeneration.*` 11 键) | Ygent 无此能力 |
| 计划编辑器的设计配置(`planEditor.designConfig.*`) | 面向建站/设计场景,Ygent 无 |
| 沙箱相关(`sandbox.*` 35 键) | Ygent 用项目工作目录做边界,模型不同 |
---
## D. ⚠️ 不建议对标(Ygent 规模不需要)
| 能力 | 原因 |
|---|---|
| 虚拟列表 | Ygent 消息量是「几十条」量级;已有块级 memo 缓存 |
| widget 分组(`presentationGroupId`) | widget 已独立渲染并保序;把解释正文与 widget 绑定成组仍待实现 |
| mermaid 完整查看器(缩放/平移/明暗主题切换/下载 SVG·PNG) | 先做「能渲染 + 失败回退代码」;查看器后置 |
| 队列上限/超时/升级提示(`queue.banner.*`) | 商业化限流逻辑 |
---
## 建议的推进顺序
按「投入产出比」排(✅ = 已完成):
1. ✅ **工具折叠与时间线保序** —— 普通工具折叠,widget 作为独立段保持原位
2. ✅ **mermaid + KaTeX** —— 均按需动态加载
3. ✅ **工具改动 diff**(write/edit 卡)—— 使用工具帧 `args`
4. ⚠️ **消息工具栏与 widget** —— 编辑后分支重发已接;仍需真实窗口截图核对 widget
5. ⚠️ **消息编辑 + 回退**(接 `branch`/`fork`)—— 编辑重发已接;任意历史点回退与分支切换待做
6. ⬜ **忙时排队**(接 `steer`/`follow_up`)—— **内核已验证可用,但前端有前置依赖,见下**
7. ⬜ **对话内系统事件流**(压缩 / 模型切换 / 会话边界)—— 需要新概念,建议单独设计
### 第 6 项的前置依赖(实测发现)
内核侧**已经可用**。探测结果:流式进行中再发一条
```json
{ "id":"p2", "type":"prompt", "message":"再说一句:收到", "streamingBehavior":"followUp" }
```
→ `success: true`,随后收到 `queue_update` 帧,且第二条的 `prompt_result.status = "completed"`。
**但前端不能只加一个参数就接。** OMP 把排队的 follow-up 视为**同一次 run 的延续**(在下一次 yield 时汇报),
而 Ygent 现在只有「一条用户消息 → 一个 agent 气泡」的模型,没有回合边界概念 ——
直接接会导致**两条回答被合并进同一个气泡**。
所以第 6 项的真实依赖是:**先补回合边界处理**(映射 OMP 的 `agent_start` / `agent_end` 事件来切分气泡),
再接 `streamingBehavior`,最后才是队列 UI(排队标记 / 编辑 / 立即发送)。
建议与第 7 项(系统事件流)一起做 —— 两者都需要「对话内事件」这条通道。
### 落地时的关键发现(实测)
**工具帧里有大量此前被丢弃的信息。** 探测 `omp --mode rpc-ui` 的原始帧:
```json
// tool_execution_start —— 带完整参数与意图
{ "type":"tool_execution_start", "toolCallId":"call_…", "toolName":"write",
"args": { "path":"note.txt", "content":"alpha\nbeta\ngamma\n" },
"intent":"Creating requested note" }
// tool_execution_end —— 带显式失败标记(start 帧没有 args,end 帧没有 args)
{ "type":"tool_execution_end", "toolCallId":"call_…", "toolName":"write",
"result": { "content":[…], "details": { "resolvedPath":"…" } }, "isError": false }
```
由此得到三条:
1. **`args` 可做代码 diff** —— `write` 有 `content`(整份新增),`edit` 有 `old_string`/`new_string`
2. **`isError` 可准确区分成功/失败** —— 之前靠「result 是否为空」推断是错的(见 `toolState` 那次修复)
3. **`intent` 可作工具卡副标题** —— 模型自己说明这次调用要干什么
注意 `args` **只在 start 帧下发**,end 帧没有 —— 前端必须记住并在落库时用回来(`stores/chat.ts` 的 `toolCards` map)。
**mermaid 必须关掉 `htmlLabels`。** mermaid 默认用 `<foreignObject>` 承载节点文字,而消毒配置禁掉了 `foreignObject`(它能把 HTML 塞进 SVG 绕过 SVG profile),结果是「框画出来了但文字全丢」。设 `htmlLabels: false`(顶层 + `flowchart` + `class`)改用原生 SVG `<text>`,两全其美。
剩余纯渲染层的工作可继续推进;消息编辑已建立独立子会话与持久内核 entry 映射,任意历史回退仍需单独补充分支选择与恢复界面。
---
## 一句话
> **渲染层能 1:1;高级交互也能 1:1,因为 OMP 内核已经支持 `branch`/`fork`/`steer`/`compact`/`get_messages_page`,缺的是 Ygent 侧的接线;真正不能对标的是 WorkBuddy 的产品体系(IM、插件、MCP、积分、敏感保护、媒体生成)。**