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

163 lines
12 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.
# 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、积分、敏感保护、媒体生成)。**