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

+173
View File
@@ -0,0 +1,173 @@
# SOP:WorkBuddy AI 运行时调试与对话区参照采集
> 历史 SOP。YCode 自 2026-10-15 接手起,查看 WorkBuddy 实现统一经 REA;以下直接 CDP、evaluate 和采集脚本不再作为执行入口。当前 REA 已提供 `list_electron_targets` / `inspect_electron_page`,支持原版 file 页面。原始测量只作待复核参照。
验证日期:2026-10-08。已验证环境:Windows、WorkBuddy AI 5.7.6、Node 24.21.0。
项目脚本要求 Node 22+,使用内置 `fetch` 和 `WebSocket`,无需额外 npm 依赖。
目标:通过 WorkBuddy 内置 Chromium DevTools Protocol(CDP)读取实际对话页面的
DOM、computed style 和截图,为 Ygent 对标提供可重复采集的依据。
这套流程不依赖 computer-use 或内存 hook,也不修改 WorkBuddy 安装包。
## 1. 调试入口与适用范围
安装包 `main/index.js` 的 `applyCliCommandLineSwitches` 读取
`WORKBUDDY_REMOTE_DEBUGGING_PORT`,并调用 Chromium 的 `remote-debugging-port` 开关。
此开关仅在启动时生效;WorkBuddy 有单实例锁,启动第二个实例不会给旧实例开启调试。
本次端口为 `9223`,已验证监听地址是 `127.0.0.1`。
端口提供页面调试能力,保持本机使用,不做公网转发。
捕获脚本只读取页面,不发送对话、不执行工具、不读取 cookies 或 localStorage。
## 2. 准备环境
以下命令在 PowerShell 中执行。切换到项目目录,检查 Node 与安装路径:
```powershell
Set-Location 'C:\Users\Administrator\code\ygent'
node --version
Test-Path "$env:LOCALAPPDATA\Programs\WorkBuddyAI\WorkBuddyAI.exe"
```
Node 应为 22+,安装路径应返回 `True`。如果 WorkBuddy 安装在其他位置,替换后续启动路径。
完成正在运行的任务,保存输入框草稿,然后通过应用的“退出”菜单或托盘退出应用。
只关闭窗口可能留在托盘,不能视为进程已退出。
```powershell
Get-Process -Name WorkBuddyAI -ErrorAction SilentlyContinue |
Select-Object Id, MainWindowTitle
Get-NetTCPConnection -LocalPort 9223 -State Listen -ErrorAction SilentlyContinue |
Select-Object LocalAddress, LocalPort, OwningProcess
```
确认主应用已退出且端口可用。若端口已被当前 WorkBuddy 的 CDP 占用,可直接进入第 4 步;
若被其他程序占用,选择其他空闲端口,并同步修改启动环境变量和采集命令。
## 3. 开启调试并启动
环境变量只用于此次启动,不通过 `setx` 永久写入。启动后恢复当前终端原有值:
```powershell
$wbSopPreviousPort = $env:WORKBUDDY_REMOTE_DEBUGGING_PORT
try {
$env:WORKBUDDY_REMOTE_DEBUGGING_PORT = '9223'
Start-Process "$env:LOCALAPPDATA\Programs\WorkBuddyAI\WorkBuddyAI.exe"
} finally {
if ($null -eq $wbSopPreviousPort) {
Remove-Item Env:WORKBUDDY_REMOTE_DEBUGGING_PORT -ErrorAction SilentlyContinue
} else {
$env:WORKBUDDY_REMOTE_DEBUGGING_PORT = $wbSopPreviousPort
}
}
```
等待主窗口完成加载。本次重启后原会话“处理大文件”恢复;若没有自动恢复,手动打开目标会话。
## 4. 验证调试入口
```powershell
Invoke-RestMethod 'http://127.0.0.1:9223/json/version' |
Select-Object Browser, 'Protocol-Version'
Invoke-RestMethod 'http://127.0.0.1:9223/json/list' |
Select-Object id, title, type
Get-NetTCPConnection -LocalPort 9223 -State Listen |
Select-Object LocalAddress, LocalPort, OwningProcess
```
验收条件:版本接口返回 `Browser` 和 `Protocol-Version`;目标列表包含 WorkBuddy 的
`page`;监听地址为本机回环地址。本次返回 `Chrome/138.0.7204.251` 和协议版本 `1.3`。
`/json/list` 的原始 URL 可能包含账号快照,不把完整 URL 输出贴入仓库或报告。
## 5. 采集当前页面
在应用里定位到要比对的正文、表格、代码块或工具行。需要比对工具细节时先展开相关过程。
每次采集使用独立目录,避免后一次覆盖前一次:
```powershell
$wbSopCapture = Join-Path $env:USERPROFILE (
'.ygent\imports\workbuddy-debug-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff')
)
node scripts/wb-cdp.mjs "$wbSopCapture" 9223
Get-ChildItem -LiteralPath $wbSopCapture | Select-Object Name, Length
```
输出应包含 `connected: true`,并生成以下文件:
| 文件 | 内容 |
|---|---|
| `dom-styles.json` | 页面标题、视口和 DPR、已挂载正文、相关类名统计,以及指定选择器的 HTML、坐标和 computed style |
| `workbuddy.png` | 当前视口截图,不是整段会话的长截图 |
脚本自动排除带 `windowKind` 的辅助页面,避免把独立搜索窗口当成主对话页面。
DOM 和截图先后读取,采集稳定内容能减少两者之间的差异。
文件含真实对话,保存在用户私有目录;项目仓库只保存脚本、SOP 和整理后的规格。
## 6. 检查样式并建立对标记录
```powershell
$wbSopSnapshot = Get-Content -LiteralPath (
Join-Path $wbSopCapture 'dom-styles.json'
) -Raw -Encoding utf8 | ConvertFrom-Json
$wbSopSnapshot.viewport
$wbSopSnapshot.samples |
Where-Object count -gt 0 |
Select-Object selector, count
($wbSopSnapshot.samples |
Where-Object selector -eq '.cr-markdown p').samples |
Select-Object text, rect, styles
```
逐项记录“会话与内容位置、截图目录、视口、DPR、主题、应用缩放、选择器、样式值、Ygent 差距”。
两侧使用同一段已导入内容,保持窗口尺度、主题及缩放一致再比较。
需要取得另一处表格或工具行时,在 WorkBuddy 中定位并重新采集。
当前脚本的采集边界:
- 每个指定选择器最多保存前三个节点;单节点文本最多 1500 字符、HTML 最多 18000 字符。
- `visibleText` 最多 40000 字符,来自 `body.innerText`,可能包含已挂载但不在屏幕内的内容。
- 历史列表会按视口挂载,`count` 是当前 DOM 节点数,不能当作全会话数量。
- 默认没有覆盖所有工具行类名。若要采集其他组件,先查看 `classCounts`,定位实际节点,
再扩展 `scripts/wb-cdp.mjs` 中的 `selectors`;使用哈希类名时要注意版本变化。
- computed style 应结合实际节点、继承关系、缩放和截图解释,不能直接作为通用设计 token。
## 7. 关闭调试
通过应用菜单或托盘正常退出 WorkBuddy,然后确认当前终端没有调试变量,再正常启动:
```powershell
Remove-Item Env:WORKBUDDY_REMOTE_DEBUGGING_PORT -ErrorAction SilentlyContinue
Start-Process "$env:LOCALAPPDATA\Programs\WorkBuddyAI\WorkBuddyAI.exe"
Get-NetTCPConnection -LocalPort 9223 -State Listen -ErrorAction SilentlyContinue |
Select-Object LocalAddress, LocalPort, OwningProcess
```
确认 WorkBuddy 不再监听该端口。若仍监听,检查是否旧实例未退出,或变量在用户/系统环境中另有配置。
只删除终端变量不会关闭已经运行的 CDP;必须退出调试实例。
## 8. 常见问题
| 现象 | 处理 |
|---|---|
| 连接拒绝 / 请求超时 | 确认启动时设置了变量、旧实例已退出、主窗口已加载、端口一致 |
| 端口被占用 | 查询 `OwningProcess`,换空闲端口;不结束不明进程 |
| `WorkBuddy renderer target not found` | 检查主窗口是否仍在加载;升级后检查主页面 URL 与脚本筛选条件 |
| `WebSocket is not defined` | 升级到 Node 22+,检查 `Get-Command node` 是否指向预期版本 |
| 选择器 `count` 为 0 | 确认已定位到相关内容,检查 `classCounts`;可能是折叠、虚拟列表或类名变化 |
| 截图显示搜索窗口 | 检查是否使用最新脚本;主页面筛选应排除带 `windowKind` 的辅助目标 |
| 重复采集后旧文件消失 | 同一输出目录会覆盖两个文件;按第 5 步创建带时间戳的新目录 |
| 脚本超时或断连 | 等待页面稳定后重新采集;连接超时为 10 秒,单个 CDP 请求为 20 秒 |
## 9. 本次实测发现与相关资料
当前 WorkBuddy AI 页面实际使用 `.cr-markdown`、`.cr-self-message`、`.cr-input-box`。
已挂载的 DOM 没有旧资料中的 `.cb-markdown` 和 `.cb-task-tool-item-inner`。
在本次 1200 × 762、DPR 1 的快照中,正文段落的 computed style 约为
`15.0001px / 26.2502px`。这是该环境下的实测值,不应概括为所有版本和缩放状态的固定规格。
因此 `lib-chat-ui` 中仍存在的旧样式只作为辅助资料;当前对话区的对标依据是实际 DOM 和 computed style。
本次验证了调试与采集能力,Ygent 的 1:1 对齐需要逐项实现和验收。
- [真实对话数据转换与导入](workbuddy-reference-import.md)
- [历史静态分析与 ASAR 提取方式](reference/workbuddy/chat-tool-fold.md)
- [运行时采集脚本](../scripts/wb-cdp.mjs)
- [对话区对标路线图](ygent-chat-parity.md)
+131
View File
@@ -0,0 +1,131 @@
# WorkBuddy 对话区前端布局实测
> 2026-10-08补充:[最新原生内层文字与布局审计](ygent-workbuddy-render-audit-2026-10-08.md)。下文外层用户气泡13px、输入容器14px不是实际文字字号;本机Slate内层两处实际均15px,应以最新审计为准。
验证对象:WorkBuddy AI 5.7.6、Windows、主窗口 1200 × 762 CSS px、DPR 1。
证据来自真实页面 CDP computed style、元素矩形、内联样式及安装包 CSS。
这是一个窗口与会话下的实测,不代表所有分辨率和用户字号设置。
## 字体规则
对话正文不是每级字号各自写死 `px`。Markdown 先接入根字号和行高 token,再由段落与标题按相对比例排版;运行时显示出来的像素值只是当时 token 的计算结果。输入框属于另一套控件样式,当前 CSS 确实单独声明了 `14px`。
| 元素 | 运行时实测 | CSS 规则 |
|---|---:|---|
| Markdown 根节点 | 当前解析为 17.143px / 30px | `font-size: var(--cr-md-root)`;行高 `var(--cr-md-line-height, 1.75)` |
| Markdown 段落 | 当前解析为 15px / 26.25px | `font-size: .875em`,继承 1.75 行高 |
| Markdown 一级标题 | 由 token 控制 | `font-size: var(--cr-md-h1-font-size, 1.25em)` |
| Markdown 行内代码 | 按父级字号 | `font-size: 1em` |
| Markdown 表头 | 当前解析为 15px / 26.25px,字重 600 | 单元格横向 padding 12px;浅色表头实测 `#f7f7f7` |
| 输入区 | 当前解析为 14px / 21px | `.cr-input-box` 声明 `font-size:14px; line-height:1.5` |
| 输入编辑器 | 高度 64px,padding 横向 16px | `.cr-input-editor-host` `min-height:64px; overflow-y:auto` |
Markdown 组件声明 `--cr-md-root: var(--cb-md-root, 16px)`,当前主题解析为
`--cb-md-root: 17.143px`。HTML 根字体为 16px,页面 zoom 和 visual viewport scale 均为 1。
本次 15px 段落是根字号乘 `.875em` 的计算结果,不能反推为源码把段落固定写成 `15px`,
也不能归因于 viewport 缩放。字号变量的上游已在组件 bundle 中找到,具体的六级调节规则见下节。
实际正文段落间距为 12px;代码块实测使用 monospace、12.857px / 22.5px 行高、
横向 padding 16px,并限制内部滚动。Ygent 当前默认档的 Markdown 根字号、段落比例、
行高与代码字号已按上述规则设置;用户气泡仍单独采用 13px / 19px。
## 全局字号控制
`renderer/assets/ui-docs-viewer-veG3wQhz.js` 中有统一的字号级别管理器,作用超过 Markdown:
正文、标题、说明文字、代码、按钮文字和按钮高度都接入它。
级别保存在 `localStorage` 的 `agent-ui-font-size-level:v2`,并同步到
`config.preference.fontSizeLevel`。有效级别为 1 到 6;没有有效保存值时默认为 2。
每级同时更新根 Markdown 字号和全局偏移量:
| 级别 | 根字号 token `--cb-md-root` | 全局字号偏移 |
|---:|---:|---:|
| 1 | 16px | -1px |
| 2(默认) | 17.143px | 0px |
| 3 | 18.286px | +1px |
| 4 | 20.571px | +2px |
| 5 | 22.857px | +2px |
| 6 | 26.286px | +2px |
`--wb-font-body-size`、`--wb-font-caption-size`、标题和代码等设计 token 用各自的 base size
加全局偏移计算。全局 token 偏移夹在 -1 至 +2px,避免级别 5、6 把紧凑控件撑大过多;
按钮高度再按更新后的行高和垂直 padding 重算。
旧 CSS 中直接写为 `font-size: 13px` 的规则也会参与字号调节。管理器扫描可读的样式表,
按级别注入 `max(8px, calc(13px + var(--cb-font-size-offset) * 1px))` 覆盖规则。
它保留 `@media` 分组,观察后续新增的样式表,并排除 `.cb-font-size-fixed` 及其子孙节点,
以便明确声明固定字号的控件不随全局级别改变。
Windows 上可用 `Ctrl+-` 降一级、`Ctrl++` 升一级、`Ctrl+0` 恢复默认。级别限制在 1 到 6。
切换时派发 `cb-font-size-change` 和 `cb-font-size-level-change` 事件,让组件刷新。
源码会同时出现字体 token、相对 `em` 和少量固定 `px`:全局设置更新设计 token,
并兼容旧组件里的固定字号。
## 宽度与主布局
在当前 1200px 窗口中,左侧栏为 280px,主内容区为 920px。对话历史和输入区各自在主内容区居中,并使用相同的 832px 上限:
- `.cr-message-list__content` 运行时内联 `max-width: 832px`,源码使用 `width:100%; max-width:100%; margin-inline:auto`。
- 对话内容区左右 padding 为主题变量 `--cr-message-list-content-inline-padding:40px`。832px 外框扣除 80px 后,消息正文列为 752px。
- 输入区外框上限同为 832px,外框左右各 padding 24px,输入控件宽度为 784px。
- 小于 832px 的可用主列时,`width:100%` 收缩外框,正文与输入仍分别保留自己的横向 padding。布局跟随内容区宽度,不依靠 viewport 单位设定字体。
- 对话主列是 flex 布局。消息列表 `flex:1; min-height:0; overflow-y:auto`,输入区 `flex-shrink:0` 固定在底部;这样滚动发生在历史列表内部,长内容不会把输入区挤出窗口。
- 输入编辑区设置最小高度,并通过纵向滚动承载增长内容;工具栏单独 flex 布局、`flex-shrink:0`,操作项不会跟着编辑内容收缩。
Ygent 对应使用同一内容列:在 1200 × 762 窗口、280px 侧栏和 10px 消息滚动条下,832px 对话外框居中后,消息正文列落在 `x=359..1111`(752px)。助手头像行、回答正文和用户气泡均对齐这条列;输入框外框落在 `x=348..1132`(784px),其编辑器和工具栏分别保留 64px 与 56px 高度。窗口窄于内容上限时,消息列跟随可用宽度收缩,窄屏左右内边距为 16px。
实测 DOM 层级中,对话列和输入区都受 832px 居中容器约束,但消息、输入和工具栏是独立组件。这个边界让两边 padding 与窄窗收缩策略各自清晰。
## 响应策略
- 主列采用 `width:100% + max-width + margin:auto`;用可用宽度与最大宽度自然收缩。
- `.cr-message-list` 声明 `container-type:inline-size`,具备查询容器的能力。当前对应 CSS 文件没有 `@container` 规则,不能仅凭声明推断对话区已有完整的容器断点体系。
- 对话输入工具栏有 `width <= 320px` 的局部断点,在极窄宽度下隐藏次要 context-usage 标记,给常用操作留空间。
- 主内容 CSS 的另一个欢迎页容器 `.chat-container--welcome` 默认上限 848px,在 viewport 至少 1681px 时扩到 1008px;这是不同容器的规则,不能跟本次运行页面的 832px 对话列混为一谈。
- 组件 CSS 使用 `prefers-reduced-motion` 减少消息列表进出动画。
## 消息气泡、widget 与输入区
同一窗口的当前会话快照实测:
| 元素 | 运行时规格 |
|---|---|
| 助手头部 `.cr-agent__header` | 752px 内容宽;24.5px 高;24px 圆形标识、10px 间距;名称 14px / 24.5px、字重 600;下方间距 12px |
| 完成状态 `.cr-collapse__header` | 文案 `已完成 3m2s`;15px / 26.25px、三级文字色、宽度随内容;12px 箭头与 8px 间距 |
| Markdown 根 `.cr-markdown` | 字号 17.143px / 行高 30.0002px(当前 2 级);段落按 `.875em`,实测 15.0001px / 26.2502px |
| 列表 `.cr-markdown ul` | 15.0001px / 26.2502px;左缩进 21.4502px;列表后间距 16px;列表项间距 4px |
| 表格单元格 `.cr-markdown th/td` | 15.0001px / 26.2502px;padding `8px 12px`;表头底色 `#f7f7f7` |
| 代码块 `.cr-markdown pre` | 12.8573px / 22.5002px;padding `12px 16px` |
| 用户气泡 `.cr-self-bubble` | 13px / 19px;`#f2f2f2`;padding `8px 12px`;圆角 `16px 16px 0`;最小宽 40px、最大宽 100%、最大高 310px,内部滚动 |
| 用户消息工具栏 `.cr-toolbar` | 相对用户气泡框架绝对定位在底部;默认透明;时间 14px / 20px,含复制和编辑按钮 |
| 表格操作 `.cr-message-quote-table-menu` | hover 时显示于表格右上角;菜单 116×38px,按钮 106×28px;点击把原表格 Markdown 加入输入草稿 |
| widget 卡 `.cr-widget-card` | 正文列宽 752px;边框 `1px solid #ebebeb`、圆角 16px、纵向 margin 8px |
| widget 内容 `.cr-widget-body` | padding `12px 16px`;当前 iframe 宽 718px,高度随内容变化 |
| widget iframe | `sandbox="allow-scripts"`,不含 `allow-same-origin`;CSP 允许内联脚本与指定 CDN |
| 输入容器 `.cr-input-container` | `x=348, y=592, 784×134px`;白底、`1px solid #e6e6e6`、24px 圆角、两层轻阴影 |
| 输入编辑区 `.cr-input-editor-host` | `x=349, y=605, 782×64px`;横向 padding 16px;字号 14px / 21px |
| 输入工具栏 `.cr-input-toolbar` | `x=349, y=669, 782×56px`;padding 12px;按钮 32px |
| 禁用发送按钮 | 32px 圆形;图标圆底填充 `rgba(0,0,0,.2)` |
widget 的高度由 iframe 内容决定。SVG 根据自身 viewBox 呈现比例,HTML 图表按内部容器高度扩展;iframe 向父层报告尺寸,宿主验证来源并限制最大值。
## 对 Ygent 的参考价值
1. 给对话消息和输入区一个共享的居中最大宽度,再分别配置内边距。避免消息列与输入框在宽屏各自漂移。
2. 用 `min-width:0`、`min-height:0`、flex shrink 和列表内部 `overflow-y:auto` 明确滚动容器。窄窗或长内容时,输入区仍留在底部。
3. 把 Markdown 基准、段落倍率、行高、输入区字号做成角色明确的 token。Ygent 的默认 Markdown 规则与本次实测一致;用户气泡和输入区按各自控件规格管理。全局字号应明确级别、上下界、持久化、组件更新方式及固定字号例外。Ygent 六档根字号跟随 WorkBuddy,常规控件偏移在第 5、6 档封顶为 +2px。
4. 在真正受限的控件上做局部响应。窄宽时优先收起次要工具标记,别先整体缩小所有字号。
5. 以运行时 computed style 验收主题变量、Electron zoom 和实际像素;只读静态 CSS 很容易漏掉主题宿主注入的 token。computed `px` 是实测结果,不是 token 定义本身。
## 证据与局限
- 运行时快照与截图保存在用户私有目录 `%USERPROFILE%/.ygent/imports/workbuddy-debug-20261008/`,不放进仓库。
- 主要组件 CSS:`renderer/assets/lib-chat-ui-B-axvvx6.css`。
- 字号管理器:`ui-docs-viewer-veG3wQhz.js`,包括级别表、存储键、快捷键和旧式 `px` 样式覆盖。
- 正文段落规则:`.cr-markdown` 使用主题根字号和 1.75 行高,`.cr-markdown p` 使用 `.875em`,标题也使用相对字号 token。
- 输入布局规则:`.cr-input-box` 14px / 1.5;编辑器最小高 64px;输入容器运行时 inline `min-height:96px`。
- 当前会话主体宽度 832px 来自运行时 inline style;CSS 文件里 `.cr-message-list__content` 只声明 `max-width:100%`。具体控制该 inline 值的组件逻辑尚未追踪。
- DOM 是虚拟列表,仅包含当前已挂载部分。离开视口的消息矩形可以是负坐标,不能按快照节点数估算完整会话。
- 点击窗口不同宽度进行重复采样前,先另建输出目录。复测时同时记录 viewport、DPR、Electron zoom、主题与相关主题变量。
采集过程见 [运行时调试 SOP](workbuddy-cdp.md),可续接会话数据见 [对话导入说明](workbuddy-reference-import.md)。
@@ -0,0 +1,70 @@
# WorkBuddy 输入框:添加文件与专家参照
采集日期:2026-10-08。本文记录实际运行界面与安装包源码,不代表 Ygent 已实现附件或专家。
## 证据与范围
通过 WorkBuddy 原生 Electron CDP 9223 获取 DOM、计算样式和矩形,通过 app.asar 读取组件逻辑;未使用 computer-use。实测视口 1334×888、DPR 1。真实对话 DOM 仅保存在用户私有目录 `~/.ygent/imports/hello-layout-20261008/`,不提交。
主要源码:`renderer/assets/wb-status-chips-CEdDJaZl.js`,包含统一添加菜单、文件来源子菜单、专家选择面板。当前专家子菜单实际显示“暂无可用专家”,因此选中后的页面呈现、实际专家执行及附件发送链路尚未实测,不能根据组件源码宣称闭环通过。
## 统一入口
输入框左下角“+”是“更多操作”,不是直接打开文件选择器。当前主菜单:
1. 添加文件。
2. 分隔线。
3. 模式。
4. 专家。
5. 技能。
6. 连接器。
鼠标进入条目即打开二级菜单,支持在主菜单和二级菜单之间移动。源码对子菜单离开采用 120ms 延迟收起,触屏通过 pointer down 选择。关闭主菜单会清空当前子菜单。菜单项是否展示取决于调用方是否提供对应功能;源码还存在引用文件、应用入口,但当前界面未展示。
## 布局测量
以下为当前字号下的实测值,位置仅用于定位此次采集,不应硬编码到 Ygent:
| 元素 | 位置 / 尺寸 | 样式 |
|---|---|---|
| +触发器 | x428、y807,32×32 | 圆形;展开背景 rgb(242,242,242),图标16×16 |
| 主菜单 | x428、y602,200×197 | 内边距8,圆角16,白底 |
| 普通条目 | 宽182、高32 | 水平内边距8,圆角8,14px / 22px |
| 文件子菜单 | x623、y611,200×186 | 内边距8,圆角16 |
| 专家空态子菜单 | x623、y690,240×50 | 内边距8,圆角16 |
条目字体为 `"PingFang SC", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif`。菜单阴影为 `0 6px 24px rgba(0,0,0,.04), 0 4px 6px rgba(0,0,0,.04)`。主菜单向上展开,子菜单向右并沿相应条目定位;不是全屏居中的弹窗。Ygent 应接入现有六档字号管理,不能把此处实测14px作为全局固定字号。
## 添加文件
当前二级菜单实际包含:本地文件、项目资产、腾讯文档、ima、乐享知识库。
源码提供独立来源回调:本地文件、腾讯文档、ima、乐享,另外可由调用方注入额外来源;当前项目资产属于界面提供的额外来源。点击来源调用相应回调,然后关闭添加菜单。来源选择与文件选择/导入分层,云服务不能等同于本地上传。
本轮没有选择真实文件或连接外部服务。文件类型限制、数量/大小上限、导入进度、草稿附件显示与失败重试尚未验收;当前 DOM 没有 `input[type=file]`,不能据此推断不支持多选或没有限制。
Ygent 当前差距:普通对话的 + 仅显示“附件上传:M4 落地”,新建任务显示“附件上传:开发中”。两个入口都没有真正文件选择、草稿附件和发送数据链路,不能只替换弹出菜单就称为上传完成。
建议首期实现本地文件与项目文件引用;腾讯文档等入口在对应连接器真正可用后增加。先明确“上传副本”与“引用现有项目文件”的区别,不因添加到草稿就隐式移动文件或扩大执行目录。
## 专家
当前界面空态为“暂无可用专家”。以下为同一组件源码确认的能力,受调用方配置限制,不保证当前页面全部启用:
- 专家使用 `selectedExpertId` 单选;选中项显示勾选,再选同一专家仅关闭菜单,不重复触发选择。
- 行结构是16px头像、名称与右侧操作。名称优先使用 profession,其次 name、id;不是直接显示原始文件名。
- 可选搜索框支持中文输入法组合事件;搜索具有加载、不可用、无结果等独立状态。
- 普通列表由置顶、最近使用、推荐项合并去重;推荐补足目标5项,超过10项启用滚动。置顶点击阻止冒泡,不触发选择专家。
- 搜索结果走独立召唤回调;回调返回 false 时不关闭菜单。普通列表走选择回调,选择后关闭。
- 调用方可提供“更多专家”入口,也可关闭推荐和搜索。因此当前只有空态不能作为完整专家面板的样式参照。
Ygent 当前差距:专家管理与选择未实现;Skill/MCP 已有能力登记与会话选择,但不是专家本身。专家执行仍按 `ygent-capability-integration-plan.md` 的 P3 处理,不能用角色标签冒充指令、依赖和回合快照已经接入。
## Ygent 后续落地顺序
1. 共用一个 Composer 添加菜单组件,覆盖新建任务、项目内输入及已有对话;将现有技能和连接器选择整合到统一 + 入口,保留其真实能力选择逻辑。
2. 实现本地文件选择、草稿附件移除、提交/失败恢复、对话重载与分支引用,以及后端实际读取/图片输入合同。项目文件引用独立记录来源,不能只有一个显示用标签。
3. 按 P3 实现专家登记、依赖校验、选择和指令注入;非空会话切换专家按既定方案新建分支/聊天,不能静默替换已有历史的角色。
4. 验收菜单的悬停迁移、键盘/Escape、点击外部、边缘避让、六档字号,以及生成中操作对当前回合不产生影响。附件发送与专家执行必须使用私有测试会话验证实际后端链路。
上述为最初参照调查。后续已落地统一添加菜单与本地附件,具体已实现行为和真实验收边界见 [输入框菜单与附件进度](ygent-attachments.md);专家、项目资产和云来源仍未实现。
@@ -0,0 +1,79 @@
# WorkBuddy 无项目归属对话实测(2026-10-08)
## 1. 环境与检查范围
应用为 WorkBuddy.exe 5.7.6,通过原生 Electron CDP 9223 检查真实侧栏、既有独立对话、新建任务页、工作空间选择菜单和“保存到工作空间”弹窗。另只读检查本地 SQLite 与安装包对应处理代码。
未发送消息、执行工具、保存工作空间、移动任务、归档或删除数据。打开的保存弹窗已取消;结论区分实际 UI/数据观察和未执行的代码路径。
## 2. 无项目归属不代表无目录
本地 `sessions` 分别保存:
```text
project_id 项目归属,可为空
cwd 实际本地工作目录
is_playground 区分自动目录的独立任务与工作空间任务
transport 本地/云端执行来源
group_id 另一种分组字段,不能等同于 project_id
```
当前未删除的样本共有 15 条本地会话,10 条 `project_id IS NULL`:
| 类别 | 数量 | 实测结果 |
|---|---:|---|
| 自动目录独立任务 | 9 | is_playground=1;cwd 为用户 WorkBuddy 根目录下的时间戳目录 |
| 已有目录工作空间任务 | 1 | is_playground=0;cwd 为已有本地目录,project_id 仍为空 |
检查的目录均存在;不是靠一个隐藏的项目 ID 为这些任务兜底。当前 Ygent 的独立任务绑定隐藏 task 级项目,与这个本地会话模型不同。
## 3. 侧栏按任务形态展示
- 自动目录独立任务显示在“任务 (9)”分组;当前 DOM 挂载前 5 条,另有“查看更多 (4)”。挂载数不能当作总数。
- 已有目录工作空间任务放在“空间”分组的目录名称下面。
- 两个真正有项目 ID 的项目也显示在“空间”分组中,因此“空间”不是“所有会话都有项目归属”的证据。
- 侧栏没有为无项目归属任务显示一个“未归类项目”。
## 4. 新建任务如何取得目录
新建任务页的输入区默认显示“选择工作空间”。展开后可以选择已登记目录、新建工作空间或打开本地文件夹。
静态代码确认:未选择目录时,前端将 selectedCwd 留空并使用 isPlayground=true;选择目录时使用该目录并设 isPlayground=false。
后端的 `workspaceGenerateDefaultCwd` 解析默认根目录,再创建以 `YYYY-MM-DD-HH-mm-ss` 命名的目录;同名时尝试其他时间戳,确保新目录唯一。默认根目录可来自应用配置,通常位于用户主目录的品牌文件夹下。
这个自动创建路径与现有会话目录吻合。本次没有新发消息触发创建,故不把创建的准确时点、失败交互或工具运行过程记为动态实测通过。
## 5. “保存到工作空间”不是“归入项目”
既有独立任务的右键菜单实测含:置顶、重命名、分享任务、在独立窗口中打开、保存到工作空间、打开文件夹、批量操作、归档和删除任务。
“保存到工作空间”弹窗要求填写工作空间名称,并说明可持续使用对话和文件、同时开展多个任务。
对应代码路径:
1. 校验名称及重名/系统保留名。
2. 调用 conversations.move(taskId, 原 cwd, transport)。
3. 为原 cwd 设置工作空间显示名。
4. 将前端任务 isPlayground 更新为 false,刷新列表。
这里没有传入目标 projectId,也不是选择云端项目的归类弹窗。调用仍传入原 cwd;本次没有点击保存,未实测 move 的所有后端文件副作用。
在当前独立本地任务菜单中没有看到“归入项目”入口,不能据此断言其他来源或版本绝对不存在该能力。
## 6. 持久化与清理边界
独立任务已有本地 SQLite 会话记录,工作目录真实存在,旧任务能重新打开。“未保存到工作空间”不能解释成“不保存聊天”或“关闭立即清除文件”。
清理周期、归档/删除是否清理目录、任务恢复时的全部执行状态、本地任务归入云端项目等路径均未实测。
## 7. 给 Ygent 的参考与后续落地
以下来自调研建议。后续已在 [项目概念约定](ygent-project-space.md) 和 [实施方案](ygent-project-implementation.md) 明确 Ygent 自身规则,包括归属调整保留实际目录;这些实现选择不属于 WorkBuddy 实测结论。
- 无项目归属对话可以保留 projectId=null,显示在“任务”列表,不必制造“未归类”项目或展示隐藏项目。
- 未指定目录时为该任务准备独立托管目录;任务本身持久化,项目归属与实际 cwd 分开记录。
- 以后归入 Ygent 项目时,应单独定义是否沿用原目录、项目指令从何时生效、文件如何处理,不能只改 projectId 就暗中搬文件或切换执行目录。
- 当前不必照搬 WorkBuddy 的“保存到工作空间”产品入口;Ygent 已采用 [项目+工作目录定义](ygent-project-space.md),需要保持术语简单。
原始采集及静态片段位于用户私有 `.ygent/imports/render-audit-20261008/`。参见 [WorkBuddy 项目概念](workbuddy-project-concept-2026-10-08.md)。
@@ -0,0 +1,46 @@
# WorkBuddy 本地对话参照导入
2026-10-08 已确认:WorkBuddy AI 的会话正文保存在本地,并非只能从云端获取。
此前参照文档只检查了 AppData 下的 WorkBuddy 目录,遗漏了 `.workbuddy-ai`。
## 数据位置
- `%USERPROFILE%/.workbuddy-ai/workbuddy.db`:`sessions` 表保存标题、工作目录及会话 ID。
- `%USERPROFILE%/.workbuddy-ai/sessions/<pid>.json`:运行进程对应的会话 ID。
- `%USERPROFILE%/.workbuddy-ai/projects/<目录键>/<sessionId>.jsonl`:正文及工具调用记录。
无需 UI 自动化或内存 hook;读取这些文件不会修改 WorkBuddy。
## 转换
```powershell
python scripts/import-workbuddy.py '<会话 JSONL 完整路径>'
python scripts/import-workbuddy.py '<会话 JSONL 完整路径>' --apply
```
默认只预检。`--apply` 先通过 SQLite backup API 备份 Ygent 数据库,再以事务创建独立任务及消息,逐字段回读验证。
同一 WorkBuddy 会话已有导入任务时跳过,避免重复;此脚本不增量同步。
转换文件和数据库备份放在 `%USERPROFILE%/.ygent/imports/`,不写入代码仓库。
默认标题从 WorkBuddy `sessions` 表读取(优先 `custom_title`);无来源数据库时回退到 JSONL 的 `ai-title`,也可用 `--title` 覆盖。
映射规则:
- 用户消息提取 `<user_query>`,过滤系统注入与纯恢复提示。
- 助手消息保留可见正文,不导入内部推理正文、模型凭据或 provider 元数据。`reasoning`事件仅记录存在及相邻可见消息的位置,写入`render_meta.reasoningBefore`;没有可公开展示的摘要时只呈现事件标题,不提供空的展开按钮。
- 行内代码在消息来源cwd下能识别为真实文件/目录时,保存标签、路径和类型;代码文本不改写,原始正文仍用于搜索/复制。普通新对话由共享路径组件通过真实IPC在所属会话工作目录下识别,不按参照会话ID或标题硬编码。
- 工具按 `callId` 匹配结果,在调用位置插入工具行,保留原参数、输出和可用的 description。
- 保留消息时间;没有结果的调用注明“此调用没有执行结果记录”。
- `show_widget` 的 HTML 保留在工具参数中,并在独立 sandbox iframe 内渲染。
## 当前显示限制
2026-10-08补齐呈现元数据:更新版本首次启动迁移到v10后,运行`python scripts/import-workbuddy.py '<源JSONL完整路径>' --enrich --apply`。仅处理已导入且逐条role/content/fn/result与来源完全一致的参照会话;不匹配即拒绝。先备份数据库,再事务更新render_meta并回读验证,保留消息ID、内容、工具数据及顺序。本次829条已验证,新增374个事件位置标记和7个路径关联。来源文件与推理正文均不改写/导入。
“深度思考”当前仅恢复事件位置标题,未恢复内容展开或真实模型的思考阶段流式事件;仍不能作为动态思考行为对标通过。路径标签已支持键盘/点击打开,原生验收只执行只读路径分类,未自动启动外部文件应用。
这是一份参照快照,不会恢复 WorkBuddy 内核上下文。不要把导入记录当作可续接的原内核会话。
Ygent 已按导入顺序呈现正文、工具和权限事件,并只折叠连续的工具调用;工具结果仍主要显示单行摘要。
本次源会话的五份 HTML 制品已在 sandbox iframe 中渲染;其中一份 SVG 的 iframe 高度仍比 WorkBuddy 少 5px。图片附件、内部推理、审批交互和完整工具结果查看器尚未完整呈现。
本次导入的源会话为 `05c73f5f-e3ac-452e-bfde-fd5be036e588`,当前 WorkBuddy 标题和 Ygent 参照任务标题均为“处理大文件”。
转换结果为 26 条用户消息、254 条助手正文、549 条工具调用,其中一条调用没有结果记录。
+48
View File
@@ -0,0 +1,48 @@
# 输入框菜单与附件进度
2026-10-08:已将技能、连接器从输入框底栏合并到 WorkBuddy 风格的“+”二级菜单。新建任务、普通对话和项目内输入使用相同添加菜单与附件组件。专家仍按能力接入方案 P3 实施,当前菜单不显示未实现的专家操作。
2026-10-09:添加列表进一步统一为12px圆角、36px行高和线条图标;文件来源子菜单收窄至200px,两级菜单间隔4px,首行内容沿父条目对齐。技能/连接器的重复标题移除,勾选控件统一置于行右侧,空态和管理入口采用相同间距。原生9335验证三种子菜单在六档字号下均位于视口内,位置仍随内容尺寸与窗口边界调整;本轮实际列表为空,未新增安装或修改会话能力选择。
## 当前行为
- + → 添加文件 → 本地文件,调用系统多选选择器;也支持拖入输入框。拖到侧栏等输入框以外位置不添加。
- 一次/一条消息最多8个附件,单文件不超过20MB。草稿展示名称、大小和移除按钮;可不填写文字直接发送,使用“请查看附件”作为请求。
- 导入时将原文件复制到 Ygent 数据目录 `attachments/<独立ID>/`,保留文件扩展名,原文件不移动、不修改。相同名称独立保存,源文件随后改变不影响已保存副本。
- 附件元数据由后端按ID解析,与用户消息在同一SQLite事务内保存到 render_meta;正文仍为用户输入,不混入附件路径和文件内容。显示、重载和分支使用此元数据。
- OMP 请求加入附件副本路径;UTF-8文本内联前128KB,超过部分明确标注截取,工具可继续读取副本。图片/其他二进制保留真实扩展名和副本路径,由模型的文件工具读取;不能宣称所有文档格式均已支持。
- 直连模式只支持128KB以内、不含NUL的UTF-8文本附件;不支持的二进制/大文本在发送前明确报错,不产生用户消息。直连后续请求重新从真实副本恢复历史附件上下文。
- 发送后立即清空草稿;失败恢复文字和附件。切换会话/页面清理当前附件草稿,文件选择期间切换页面不会把旧选择落到另一输入框。生成中不改动当前回合附件。
- 技能与连接器仍使用原会话选择逻辑,菜单显示已选数量,生成中不能修改选择;管理入口进入相应的技能/连接器标签页。
## 已验证
环境为真实Tauri WebView2、CDP9335,视口1335×916、DPR1。使用独立临时对话和本地测试文件,未在参照会话发送测试消息。
1. 真实IPC导入UTF-8文本,OMP模型回答附件中的验证口令。
2. 在新建任务页面通过受控Tauri拖入事件触发前端导入,再点击实际发送按钮;模型正确读取,重新载入会话后附件名称/大小仍存在。
3. PNG附件通过真实OMP `read` 工具读取,模型正确回答图片主色;不是仅将图片名称作为文字传入。
4. 真实数据库回复分支包含两条用户消息的附件元数据。
5. 用直连模式发送PNG,消息数不变,前端文字及附件恢复,显示明确限制提示。
6. 1至6档真实原生DOM测量,菜单字号为13/14/15/16/16/16px,子菜单没有内部横向溢出,位于视口内。主菜单的scrollWidth包含向右定位的子菜单,不把此正常外部定位当作内部文字溢出。
7. Rust 33项测试、前端构建、对话回归通过;附件测试覆盖副本独立性、路径越界拒绝、二进制直连拒绝与OMP引用。
证据位于用户私有目录 `~/.ygent/imports/hello-layout-20261008/yg-attachment-*` 和 `yg-add-fonts.json`,不提交真实消息/截图。测试对话已从可见列表删除,恢复原会话5、OMP及字号第2档。
## 验收边界与后续
系统文件选择器使用真实后端Dialog API,但本轮没有自动操作Windows原生文件选择窗口;受控拖入事件验证的是前端处理和真实导入链路,不等同于真实鼠标拖拽验收。项目内输入复用同一组件和发送合同,项目对话附件专项尚未单独发送模型测试。
尚未接入项目资产选择、云文件来源、附件内容预览、图片缩略图、OCR/文档转换及自动清理未发送的副本。二进制解析能力取决于当前OMP工具/模型;本轮明确实测UTF-8文本与PNG,不承诺PDF/Office等类型全部可读。当前副本保留用于历史与分支,移除草稿不会删除源文件或历史副本。
## 调试操作
按 `ygent-debug.md` 启动9335,打开临时对话;使用原生DOM和IPC采集,禁止用浏览器模拟IPC代替桌面验收。日常验证命令:
```powershell
npm run build
npm run check:chat
cargo test --lib --manifest-path src-tauri/Cargo.toml
```
真实模型验收分别发送含唯一口令的文本和具有明确主色的PNG,检查模型响应、工具调用、render_meta、重载及分支;失败路径检查消息未误发送、正文/附件恢复。恢复原会话与字号,清理临时对话,不改用户参考消息。
@@ -0,0 +1,47 @@
# 对话授权与问题回答:实现及验收(2026-10-09)
## 对标依据
读取本机 WorkBuddy 5.7.6 的 app.asar,定位 lib-chat-ui 的 InterceptCard(1n5vt)、QuestionFloating(ggdxn)和 QuestionAnswerDisplay;通过 WorkBuddy 原生 CDP 9223 读取真实主题变量。没有发送 WorkBuddy 消息或更改其会话。当前 WorkBuddy 没有待处理交互卡,因此本次依据为组件源码、原生主题和 Ygent 动态实测,未宣称完成两端同场景动态逐像素验收。
| 位置 | 对齐内容 |
| --- | --- |
| 输入区域:待授权 | 原输入框隐藏但保持挂载,24px 圆角白色卡片;标题 16/25、命令摘要 14/28,超长省略并保留悬停全文;拒绝、本对话允许、允许依次排列 |
| 授权选项 | 40px 行高、12px 圆角、24px 数字底块、8px 间距,选中/悬停灰底,右箭头反馈;默认高亮拒绝,但不自动提交 |
| 输入区域:待回答 | 24px 圆角,最大高度 min(60vh,520px);标题 14/24,页码/关闭入口,描述与选项同排,32px 圆形提交按钮,0.2 秒淡入上移 |
| 回答方式 | 原始选项值回传,支持自由输入、确认问题和明确跳过;自由输入保留原始文字,空白禁用,中文输入法回车不误提交 |
| 消息时间线 | 灰色紧凑入口,回答后显示“提问”;展开为 16px 圆角灰色问答卡,问题 15/25、回答 15/22;授权结果区分允许、拒绝、取消 |
| 助手下方 | 等待回答/等待授权与实时耗时;完全访问不能隐藏实际收到的待处理请求 |
| 中断与异常 | 保留停止生成入口,提交锁防止重复点击,失败提示且可重试;结束/取消后删除待处理请求,迟到回执被拒绝 |
上述字号为基准,文字统一叠加六档全局字号偏移;几何尺寸保留参考组件规则。共享组件适用于普通会话、历史回显和实时生成,不依赖会话身份。主页面继续沿用用户指定的渐变设计。
## 实际执行链路
OMP rpc-ui 的工具授权与问题回答分开管理。工具授权保留原网关、会话白名单和审计;问题由独立 pending_questions 保存会话、运行请求、问题 ID、方法及选项,不能被完全访问或授权白名单自动回答。答案通过真实 stdin extension_ui_response 回传,验证当前运行与选项,写入成功才移除问题。
本机 OMP 18.6.3 的 ask 使用 select;选择 Other 后再次发出 editor。前端将其作为同一道问题,保留消息 ID,允许中间插入工具事件;请求 ID 变化后,旧提交确认不能覆盖新输入状态。问题/答案写入 render_meta,重载恢复;进程已失效的历史 pending 请求仅显示取消记录。
MCP 宿主授权不展示尚不支持的会话放行选项。其他内核未纳入本次问题回答验收。当前 OMP 每次发送一个 select/editor/confirm,页面显示 1/1 并禁用翻页;批量问题、多选、选项 preview 尚未接入,不能把单题实现当作完整批量对标通过。
## 调试与回归 SOP
1. 按 [原生调试 SOP](ygent-debug.md) 停止正常实例,使用独立数据目录与 9336 启动调试构建;绝不使用测试库覆盖用户库。
2. 在隔离数据库设置 interaction_native_test=1,确认真实 WebView2 的 window.__TAURI_INTERNALS__ 和 window.__yg 存在。
3. 执行 `node scripts/chat-interaction-native-check.mjs 9336 <用户私有输出目录>`。脚本拒绝没有隔离标记的数据库,使用受控本地模型服务、真实 Tauri IPC 和真实 OMP;只在隔离库创建测试渠道/会话,命令仅为 echo。
4. 核查 result.json、原生截图、六档字体的 DOM 几何;截图等待入场动画完成。源码/模拟 IPC 回归作为补充,不代替原生验收。
5. 关闭测试实例,移除进程级数据目录变量,以 9335 恢复正常库与原会话。
本次原生 WebView2 视口 1335×916、DPR 1,通过:完全访问下仍等待真实回答、选项回传、数据库重载、Other→editor 自由回答及单条记录、跳过、允许执行、拒绝不执行、取消与迟到回答隔离;六档字号均保持 40px 选项行、24px 卡片圆角,无卡片横向溢出。原生脚本汇总 7 项检查。测试数据与截图位于用户私有 `.ygent/imports/interaction-native-20261009/`,不提交。
辅助验证:`npm run check:chat`、`npm run build`;后端 `cargo test --lib -- --test-threads=1`。新增回归覆盖选项不自动提交、重复提交、失败重试、Other→editor 先于 IPC 确认且插入工具事件、答案持久化及过期问题重载。
## 回答后的展开体验补充
回答记录保留受回合控制的展开状态,内容使用 grid 高度与透明度过渡,收起后高度归零;减弱动态效果时取消动画。箭头常驻淡显并随展开旋转,键盘焦点可见,按钮关联详情区域且收起内容不暴露给读屏。问题浅灰、答案深色,跳过/取消补充明确结果,长文本换行且可选择复制,输入答案保持原始内容。
原生隔离验收在回答落库、重新打开会话、展开完整时间线后展开“提问”,测得卡片圆角 16px、内边距 12px 16px、问题/答案行高 25px/22px,内容宽度与滚动宽度均为 752px;再次收起详情高度为 0。证据为私有目录的 answer-expansion.json 与 question-answered-expanded.png;7 项真实 OMP 交互检查及 check:chat、TypeScript 检查通过。
### 按 Ygent 整体风格调整颜色
按用户后续要求,用户消息与历史问答卡不再使用 WorkBuddy 的实心中性灰底,改为共享聊天表面变量:用户气泡 68% 白色、历史问答 48% 白色,配 64% 白色内描边,透出页面蓝紫渐变。问题/答案分别使用全局 t2/t1,取消/跳过说明用 t3。此项属于用户指定的产品视觉调整,保留前述布局及交互。原生 1335×916、DPR 1 下只读检查真实会话,用户气泡和问答卡宽度/滚动宽度一致,截图位于私有 chat-color-20261009.png。
+16
View File
@@ -0,0 +1,16 @@
# 编辑消息与重新生成
2026-10-10:编辑并重发改为当前对话内重新生成,不创建新的 Ygent 对话。
- 保留 sessionId、项目归属和实际工作目录。编辑位置之前的消息不变;编辑消息及后续可见时间线由新回合替换。编辑提示说明替换范围。
- OMP 先通过真实消息 entryId 回退内核历史,再原子更新当前对话的消息及内核文件指针。内核内部可能产生新的会话文件,该文件继续绑定原 Ygent 对话,不出现在侧栏作为新对话。映射/回退失败保留原时间线和编辑草稿。
- 直连模式从回退后的消息重新组装请求;两种模式都不能把已经替换的消息或回复送给模型。
- 替换前的消息与旧内核文件指针存入本机 `session_edits` 修订记录,当前未提供修订切换 UI。编辑不会撤销此前 Shell、文件、网络等已经产生的实际操作。
- 删除被替换回合的待整理任务,清空过期上下文占用快照。消息 ID 使用持久高水位,避免删除后重复分配导致来源证据/工具事件串到新消息。失去有效证据的自动记忆沿用现有检索过滤规则。
- 前端准备编辑期间禁止并发发送;等待取消屏障和消息写入结束。成功回退后清除本会话的终态回合缓存,再读取真实记录,避免旧回复在重载时复活。
- 如果回退成功而新的发送未被接受,输入草稿保留,继续在原对话发送即可;旧时间线保存在本地修订记录。
- 只有“分支到新聊天”入口才创建新的 Ygent 对话,继续沿用独立的分支逻辑。
验证:构建通过,Rust 83 项通过、1 项官方网络测试跳过;`npm run check:chat` 回归通过。
真实桌面 SOP:使用 `docs/ygent-debug.md` 的隔离数据库启动方式,数据中设置 `activity_test_mode=native-isolated`,运行 `node scripts/chat-edit-native-check.mjs 9336`。该脚本通过实际编辑按钮/输入框/发送按钮发起操作,使用真实 OMP 和直连、受控本机 SSE 上游,校验上游历史已回退、会话数不增加、前缀消息 ID 不变、标题/cwd 不变、重载无旧回复,以及显式分支仍创建新对话。不得对用户日常数据库运行该测试。
@@ -0,0 +1,204 @@
# 对话区动态交互对标与验收
> 阶段状态(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 验收。
+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、积分、敏感保护、媒体生成)。**
@@ -0,0 +1,98 @@
# 对话区对标阶段进度(2026-10-08)
## 2026-10-09:删除对话确认浮层
通过 WorkBuddy 9223 CDP 打开真实会话菜单的「删除任务」,仅采集并取消,未删除会话。参考实际组件为 `wb-popconfirm`:无全屏遮罩,贴会话行右侧、8px 间隔及小箭头;宽 240px、内边距 16px、边框 #dedede、圆角 16px、两层轻阴影;标题 16px/24px、600 字重,说明 14px/22px、黑色 70% 透明度;正文与按钮区间隔 24px,按钮间距 12px、高 32px、圆角 8px,确认按钮 #e85c5c。
Ygent 删除入口改为共享的行锚定浮层,侧栏和项目列表均使用相同组件;空间不足时左右翻转及纵向避让,随滚动/尺寸变化更新定位。文案按真实能力显示「删除对话?」和「删除后,对话记录将被移除,且无法恢复。」,不照搬 WorkBuddy 的所有设备同步承诺;后台删除规则与工作目录保留行为不变。初始焦点放取消,支持 Escape、外部点击关闭、Tab 焦点循环及关闭后焦点恢复;提交期间禁用操作并防重复提交,失败保留浮层与原有错误提示。重命名入口保留原交互。
真实 Ygent WebView2 1335×916、DPR 1 实测浮层 240×166,文字/按钮尺寸、颜色、间距、边框与阴影匹配参考;WorkBuddy 视口为 1334×919、DPR 1,未为采集修改用户窗口。原生验证取消、Escape、焦点循环与恢复,未实际删除用户数据;构建通过。截图保存在用户私有目录 `~/.ygent/imports/session-delete-native.png`。提交中/失败保护通过实现审阅确认,本轮未触发真实删除请求。
## 2026-10-09:工具状态图标补齐
按当前本机 WorkBuddy 前端包的 `ToolHeader`、`ToolExpandable` 和工具图标注册表核对,Ygent 的 ToolCard 改为工具类型图标,不再将普通成功状态统一替换为绿色勾。读取、写入、命令、搜索、目录、网页、技能、计划、Agent、浏览器和通用工具采用核实的向量路径;Ygent 内置任务/浏览器/技能及 OMP 别名映射到对应类别。
图标为 14×14,中性灰;失败/取消使用参考组件的灰色感叹号。命令外层摘要保留终端图标,意图层显示异常标记。执行中普通工具隐藏图标,文字采用参考组件 2.2 秒扫光;写入工具保留图标并以 1.2 秒周期改变透明度,减少动态效果时静态显示。成功、失败、取消的原始数据和输出保留,状态在可访问名称及悬停说明中区分。权限回执移除装饰性勾叉;下拉选中标记和复制反馈不受影响。
验证:构建及对话回归通过;组件矩阵覆盖 14 种工具/别名的完成、运行、失败、取消与手动展开保留。真实 Ygent WebView2 1335×916 下核验当前普通会话的浏览器成功与失败工具:SVG 几何匹配参考包,实际图标 14×14、颜色 rgba(0,0,0,0.5),无逐工具旋转图标。当前 WorkBuddy 页面没有工具行,本轮参考来自已安装源码与此前命令原生采集,未声称完成所有类别的 WorkBuddy 双端实时流式验收。原生证据保存在用户私有 imports 目录。
## 阶段状态
按用户要求,对话区工作在此阶段收尾,暂不继续修改。当前状态为:主要字体规则、工具呈现、折叠状态和流式事件管线已实现并分层验证;**尚未完成 WorkBuddy 双端原生流式 1:1 验收**。本页是恢复工作时的当前进度入口,详细证据与历史基线保留在关联文档中。
目标仍是流式交互效果一致,包括块顺序、工具增量、自动/手动折叠、滚动、完成/失败/取消和重载恢复。所有会话共用呈现规则,不能按会话标题、ID或导入身份修补。产品名称与头像统一为 Ygent;名称字体、头像尺寸和间距参考 WorkBuddy,品牌内容按用户要求保留 Ygent。
## 已完成的实现与验证范围
| 模块 | 当前实现 | 已取得的证据与边界 |
| --- | --- | --- |
| 调试与参照数据 | 原生 Tauri WebView2/CDP 调试、WorkBuddy CDP/打包源码分析、真实本地对话导入及元数据补齐 SOP;规则写入 AGENTS.md | 对话界面修改以真实 DOM、计算样式、几何及状态验收,截图作为补充。原始会话/源码采集保存在私有目录,不入库 |
| 窗口与六档字体 | 对齐窗口基准1335×916;设置滑杆、快捷键和持久化共用六档;正文/UI采用不同缩放规则,名称、Markdown代码、终端代码分别管理字体族 | 两端默认及六档原生测量:108组字号/行高、18组几何对比一致。此为当时指定9个位置的结果,不能外推所有组件;本机系统字库依赖仍存在 |
| 工具基础外观 | 历史、过程、实时回合共用 ToolCard;命令摘要/意图/输出分层,修正颜色、竖线、缩进、滚动条和长命令断行 | 同一失败命令的原生面板文本、换行及尺寸与WB匹配;失败摘要保留灰色终端图标,意图层有失败标记,输出保留非零退出码。其他工具类型状态图标尚未全面验收 |
| 路径与阶段元数据 | 共用行内路径组件;普通会话通过真实IPC识别路径,导入会话补齐来源元数据;只恢复有来源事件的“深度思考”标题 | 参照路径标签几何匹配,普通真实目录可识别、不存在候选不变成链接;增量保留控件。路径实际打开的完整行为、文件图标和公开思考阶段仍待补验;内部推理正文未导入 |
| 正文锚点与整体折叠 | 完成/取消共用“全部并列最长正文+最后正文”;中间短正文进入过程;整体展开显示完整时间线,权限/产物保留专用渲染器,末段后真实事件不挪到前面 | 组件覆盖最长位置、并列、一/两段、空白、混合过程、权限/widget及尾部工具。原生完成/取消3个样本验证完整/摘要互斥和节点/详情状态保留;WB自动折叠资格和时机尚未完整对照 |
| 展开状态与增量稳定性 | 按回合/消息ID持有组、工具、意图状态;单工具升级为组保持边界;完整时间线与摘要首次挂载后隐藏而不卸载;普通增量不重置手动选择 | 运行→完成/取消、最终输出更新、父层往返、明确关闭的详情、代码容器/复制按钮/路径控件均有回归;原生历史样本往返通过。文字选择、面板滚动位置及超长会话性能不能据此算通过 |
| 工具动作摘要 | 40种动作/别名按参数对象、动作组、相邻正文和状态生成标题;运行/等待/未知动作有对应文案,不把命令正文或工具意图任意拼成标题 | 与安装WB纯摘要函数离线对照1760组一致;17个独立语义场景及标题更新不重建节点回归通过;原生3组检查字号/省略与往返。组头图标、推理参与分组、底座命名适配和双端真实流式标题切换待验收 |
| 流式事件与持久化 | 请求/会话/块/工具ID隔离;正文按工具边界分块,工具start/update/end原位合并;按创建顺序串行落库;取消拒绝迟到事件;SSE按完整字节行解码 | 组件/模拟IPC事件回归及先前16项Rust测试通过;YG真实Rust/Tauri/WebView2+隔离受控SSE的6项端到端检查通过。受控HTTP服务不是实际OMP/Codex模型,也不是WB双端动态验收 |
## 阶段末的验证记录
- 最新前端实现通过 `pnpm check:chat`,包含事件隔离、渲染/折叠保留及17个摘要语义场景;`pnpm build`通过,仍有既有大bundle提示。
- `node scripts/fe-check.mjs`在整体折叠统一后通过;先前Rust16项测试和隔离SSE6项记录属于对应批次验证,没有在纯文档收尾时重复运行。
- 原生对话实测以1335×916、DPR1、默认2档为主要条件,普通会话和导入参照会话均有检查。不同尺寸、所有消息类型、所有工具底座并未全面覆盖。
- 正式参照会话没有发送测试请求;未替换真实IPC或向正式会话注入delta。原生历史往返、组件合成事件、离线源码对照和隔离SSE测试分别记录,不能互相替代。
私有证据目录为 `C:/Users/Administrator/.ygent/imports/render-audit-20261008/`,关键记录:`full-turn-fold-native-check.json`、`tool-summary-native-check.json`、`summary-oracle-check.mjs`、`native-stream-check.json`。其中早期`anchor-layout-native-check.json`对应仅展开前段历史的旧入口,当前整体入口已改为完整时间线/摘要切换;不能直接沿用旧选择器和计数验收新实现。
## 剩余工作及优先级
| 优先级 | 未完成项 | 下次验收位置/通过条件 |
| --- | --- | --- |
| P0 | 滚动跟随与阅读锚点(S05) | ChatView的messages/atBottom逻辑,以及展开、字体、图片、公式、widget异步变高;贴底跟随,上翻不拉回,回底恢复,记录scrollTop/scrollHeight及锚点 |
| P0 | 自动折叠时机与活动回合资格(S04) | WorkBuddy活动/非活动回合、后续正文、完成/取消和尾部工具;按事件采集双端时间序列,不能只比较终态截图 |
| P0 | 实际OMP/Codex与WB动态链路(S01/S02/S06) | 隔离会话中真实工具增量、并行、空结果、失败、取消、迟到、切会话、重载;核对正文/工具顺序、完整输出及落库恢复 |
| P1 | 公开思考/等待/错误阶段(S07) | 接入有依据的公开阶段/摘要,检查首字前、工具中和终态的可见元素;不伪造内部推理、模型或消耗元数据 |
| P1 | 组头图标、组成员与局部间距 | 通用摘要头图标、推理事件是否参与分组、非命令工具状态图标;组内gap、reasoning包装与段落间距分别测量,不硬补整段高度 |
| P1 | 回合尾部与更多交互 | 产物入口/操作栏、代码/表格/widget中间态、搜索命中展开、队列、附件与@/技能候选等,区分已有入口和真正接通/验收的行为 |
| P1 | 长会话与跨环境 | 完整/摘要保留DOM的挂载量、829条及更长会话性能,窗口/右栏变化、六档扩大覆盖、系统字库缺失回退 |
原精确差异清单中的40项渲染差异、4项外围差异、5项交互缺口和15个待验收场景是**修复前及指定采集范围的基线**,不是当前剩余数量。部分已修、部分有后续修正、部分未验收,不能据此计算“完成百分比”,也不能把当前所有差异都归为未修代码。
恢复时建议先选择隔离测试会话与同条件双端样本,更新原生基线/展开状态,再处理S05滚动及S04触发时机,随后补真实底座动态验收。任何新结构调整都复测增量、手动展开、取消、顺序和重载;正式参照会话继续保持只读测试原则。
## 文档入口
- [动态实现与逐项验收记录](ygent-chat-interaction-parity.md):S01—S07、各批次实现、原生证据与必测序列。
- [原生渲染差异基线](ygent-workbuddy-render-audit-2026-10-08.md):逐位置坐标、字体、几何及历史D/C/V项。
- [六档字体验收](ygent-font-parity.md):缩放规则、实际字库和测量结果。
- [Ygent调试SOP](ygent-debug.md)、[WorkBuddy调试SOP](workbuddy-cdp.md)、[参照数据导入SOP](workbuddy-reference-import.md)。
- [旧路线图](ygent-chat-parity.md)及[工具折叠源码参考](reference/workbuddy/chat-tool-fold.md):用于追溯设计,不替代本页当前状态和动态验收记录。
## 对话页面背景调整(2026-10-08 补充)
按用户后续要求,对话页面外层采用与侧栏、项目页相同的连续背景:移除 `.main-chat` 的整块白底,工作台区块与分享区移除外层分割线,分享区底色透明。输入框、用户消息气泡和代码块保留内容层级。本次是页面设计语言调整,不计作 WorkBuddy 白底的逐像素一致性验收。
通过真实 Tauri WebView2 / CDP 9335 在 1335×916 视口检查普通对话、工作台展开和分享模式。主区域与分享区 computed background 为透明,工作台分割线与分享区上边框为 0;退出分享后输入框正常恢复。采集保存到私有 `.ygent/imports/chat-surface-20261008/`。
## 与新建任务页统一视觉(2026-10-08 补充)
按用户最新要求,对话页沿用新建任务页的品牌渐变背景;两处输入框共用半透明白色表面、16px 圆角、轻描边、柔和阴影与蓝色聚焦环,发送按钮统一品牌蓝。共享输入表面变量集中于 tokens.css,避免页面分别维护后再次出现差异。停止按钮保留独立语义与危险色悬停反馈。
对话仍采用适合连续阅读的正文宽度和底部输入布局。此次调整为产品视觉选择,不代表 WorkBuddy 静态或动态对标项目全部通过。原生 Tauri WebView2 在 1335×916、DPR 1 下检查新建任务、普通对话、829 条消息的历史会话、输入框聚焦及工作台展开;背景和输入表面计算样式一致,未出现窗口横向溢出。此次没有新增流式执行验收。证据位于用户私有目录 `.ygent/imports/chat-newtask-style-20261008/`。
## 发送输入反馈修复(2026-10-08 补充)
原输入框在 await onSubmit/send 返回后才清空,因内核确认或直连流式 IPC 等待导致已发送正文长时间残留。共享 Composer 与新建任务输入改为提交后立即清空;拒绝或异常时恢复原文,若用户已输入新草稿则同时保留两段,成功回执不清除新草稿。提交中的按钮禁用,与同步锁共同避免重复发送。此次仅调整输入反馈,不缩短内核响应耗时,也不修改请求接受或失败判定。
验证:在原生 WebView2 中额外挂载辅助 Composer,用可控异步回执检查立即清空、成功保留新草稿、失败恢复且不覆盖新草稿、字符串拒绝恢复及重复提交禁用;没有替换真实 IPC,没有发送实际消息,不能视为真实内核端到端验收。证据为私有目录 `chat-newtask-style-20261008/send-check.json`。
## 右侧工作台开始接入(2026-10-08)
以当前 WorkBuddy 的标签工作台重新梳理范围,已接入真实目录、文本预览及 Git 读取,不再把文件变更入口实现为跳回对话。详情、真实原生验收和未完成范围见 [工作台进度](ygent-workbench-parity.md)。内嵌浏览器、富文档、终端、引用来源及完整流式刷新验收仍待完成。
## 对话授权与问题回答(2026-10-09)
输入区浮动卡、紧凑历史问答、真实 OMP 选项/自由输入/跳过回传已接入。修复完全访问隐藏问题、问题被误当授权、Other→editor 重复记录与旧回执覆盖新状态。原生隔离链路 7 项及六档字号检查通过,批量多选与双端同场景动态验收仍待补充。详见 [实现与 SOP](ygent-chat-approval-questions.md)。
+165
View File
@@ -0,0 +1,165 @@
# SOP:Ygent 真实桌面 WebView2 调试与渲染采集
## 隔离动态链路验收
调试构建支持 `scripts/ygent-debug.ps1 -ReuseFrontend -Port 9336 -DataDirectory <绝对路径>`。
独立SQLite和托管项目目录位于该目录;进程变量为YGENT_DEBUG_DATA_DIR,脚本退出恢复原环境,发布构建忽略该变量。安装实例正在执行任务时,可用 `-ReuseFrontend`、独立数据目录与空闲端口并行启动调试实例,不能停止安装实例或共享其数据目录。脚本拒绝重复调试实例与正常数据目录;完成后只关闭本次测试 PID 和测试服务,不用测试库覆盖正常库。
可用本机受控SSE验证真实Rust/Tauri IPC/WebView2并记录DOM时间线。该响应属于测试数据,结果仅表示YG端到端通过,不能称为WB或真实模型对照通过。序列见[动态清单](ygent-chat-interaction-parity.md)。
开发句柄window.__yg包含真实chat/session/settings/channel store和flushChatWrites。隔离测试使用同一运行时句柄;Vite HMR带时间戳模块与不带时间戳的动态import可能产生第二套store,不能误当当前UI。普通采集仍只读,不调用send/abort或修改设置。
辅助回归:`pnpm check:chat`;后端:`cargo test --lib --manifest-path src-tauri/Cargo.toml`。不代替原生验收。
### 原生普通回合的刷新恢复
1. 用真实 `agent_live` 读取普通与协作运行,包括启动预留、冻结模型和原用户消息;`collaboration_live`只覆盖协作,空数组不代表所有工作停止。
2. 只读采集运行requestId、会话、最后持久消息ID与DOM。页面刷新后核对同一requestId、原正文前缀、工具详情及pending授权身份,等待真实新增量;刷新不是重新发送。
3. `agent_replay`返回有序快照及水位,思考活动不进入持久历史。宿主在页面不在场时继续保存正文/工具,页面以hostRunId和稳定块键对齐持久行,不重复写入。
4. 完成/取消后核对真实终态、消息不重复、工具消息ID及展开作用域保持;停止准确绑定requestId。程序退出再启动仅标中断,不能把刷新重接理解为自动重放副作用。
5. 实际员工“继续”同时核对team_user_continuations、原team_dispatches/messageId与当前runId、当前合同版本及经理结果路由;不要用普通手动回合绕过派发。测试不得给正在执行的正常库注入事件或直接SQL改状态。
适用环境:Windows、Tauri 2、WebView2、Node 22+。默认 CDP 端口 9335,前端端口 1420。
本流程连接真实桌面窗口,使用真实 Rust IPC 和数据库,不依赖 computer-use、模拟 IPC 或 fixture。
已于 2026-10-08 在本机验证:WebView2 154.0.4258.62、CDP 9335 回环监听、视口 1335×916、DPR 1;恢复真实会话 5 的 829 条消息,并成功生成 DOM/样式 JSON 与原生截图。Rust `cargo build --no-default-features` 通过。
## 1. 启动前检查
在项目根目录执行。常规同数据调试需保存输入框草稿并退出旧 Ygent;安装实例正在工作时,改用上方独立数据目录方式,禁止为验收停止它。
旧实例启动后不能补开调试端口;如果由 `pnpm tauri dev` 启动,也结束旧开发终端中的命令。
```powershell
Get-Process ygent -ErrorAction SilentlyContinue
Get-NetTCPConnection -LocalPort 9335 -State Listen -ErrorAction SilentlyContinue
```
启动脚本遇到旧实例或占用端口会报错,不会自动结束其他进程。
## 2. 调试模式运行
常规开发(编译 Rust、启动 Vite、打开桌面窗口,终端保持运行):
```powershell
pnpm debug:desktop
# 或指定其他空闲端口
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/ygent-debug.ps1 -Port 9336
```
如果 localhost:1420 的 Vite 已经运行且已有最新调试版可执行文件:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/ygent-debug.ps1 -ReuseFrontend
```
复用模式不会重新编译 Rust;修改 Rust 后先 `cargo build --manifest-path src-tauri/Cargo.toml`,再启动隔离实例,或在无运行任务时使用常规开发模式。
脚本仅对启动子进程设置 `YGENT_DEBUG_PORT=9335`,随后恢复当前终端原值,不使用 setx 或注册表。
Windows debug 构建读取此变量,通过 Tauri 的 `additional_browser_args` 传入 `--remote-debugging-port`,保留默认浏览器参数;release 构建不启用此入口。
本机实测仅设置 `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS` 未开放端口,不能把环境变量设置成功视为已连通。
机制参考:[Tauri 参数接口](https://docs.rs/tauri/latest/tauri/webview/struct.WebviewWindowBuilder.html#method.additional_browser_args)、[Microsoft WebView2 调试说明](https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/debug-visual-studio-code)。
## 3. 确认连接的是原生窗口
```powershell
Invoke-RestMethod http://127.0.0.1:9335/json/version | Select-Object Browser, 'Protocol-Version'
Invoke-RestMethod http://127.0.0.1:9335/json/list | Select-Object id, title, type
Get-NetTCPConnection -LocalPort 9335 -State Listen | Select-Object LocalAddress, OwningProcess
```
验收条件:端口仅回环监听,目标为 localhost:1420 的 page,页面同时具有 `window.__TAURI_INTERNALS__` 和开发调试句柄 `window.__yg`。
仅有 localhost URL 不足以证明是原生窗口;采集脚本会检查两项句柄,不符合时拒绝采集。
9334 的独立 Edge 参照页面与此原生端口不同,不能混用验收结果。
## 4. 采集真实渲染
打开待验收会话,设置对应字号,定位到目标消息,展开待比对的过程行,等内容稳定后执行:
```powershell
$ygSopCapture = Join-Path $env:USERPROFILE ('.ygent\imports\ygent-debug-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff'))
node scripts/ygent-cdp.mjs "$ygSopCapture" 9335
$ygSopSnapshot = Get-Content (Join-Path $ygSopCapture 'dom-styles.json') -Raw -Encoding utf8 | ConvertFrom-Json
$ygSopSnapshot.viewport
$ygSopSnapshot.state
$ygSopSnapshot.samples | Where-Object selector -eq '.thread-content' | ConvertTo-Json -Depth 8
```
输出 `connected: true`、`runtime: native-tauri-webview2`,保存:
| 文件 | 内容 |
| --- | --- |
| dom-styles.json | DOM/HTML、最终计算样式、元素矩形、滚动尺寸、视口/DPR、活动会话与消息数量摘要 |
| ygent.png | 真实 WebView 当前视口截图 |
采集不读取 cookies、存储、密钥或完整 store,不改动页面状态。正文和截图仍包含真实会话,应保存在上述私有目录。
DOM 与截图先后采集,不是原子快照;流式生成期间需注明时间差。
## 5. 深入调试与对标
可在 Edge 的 `edge://inspect` 配置 `localhost:9335`,选择 Ygent page 的 inspect,使用 Elements、Computed、Console、Sources、Network。
Console 中只读查询示例:
```javascript
getComputedStyle(document.querySelector('.thread-content')).maxWidth
document.querySelector('.thread-content').getBoundingClientRect().toJSON()
window.__yg.useSessionStore.getState().activeId
window.__yg.useChatStore.getState().messages.length
```
读取不存在的元素前先检查选择器命中情况;新建任务页面可能没有对话节点。
对标 WorkBuddy 参照 [WorkBuddy CDP SOP](workbuddy-cdp.md)。记录同一会话、字号档位、窗口/视口、DPR、滚动位置及展开状态,先比较结构和计算样式,再检查截图。
不使用 Emulation 修改原生视口来代替真实窗口尺寸,不把模拟 IPC 的页面当作原生验收。
## 6. 退出调试与排错
- 退出 Ygent,再用 `pnpm tauri dev` 普通启动即可关闭本次 CDP。若终端外部本来设置了 `YGENT_DEBUG_PORT`,先移除该变量。
- 端口不响应:检查是否启动了旧实例、WebView2 是否继承启动参数、可执行文件是否存在;不要仅重启 Vite。
- 无目标:确认 Vite 1420 和原生窗口均已加载;本采集脚本针对开发页面,不针对安装版 tauri.localhost。
- 缺少 `__yg`:确认是 Vite 开发版;缺少 Tauri 句柄:确认没有连到独立浏览器。
- 采集无对话节点:先在真实窗口打开目标任务,再采集,不注入数据掩盖问题。
## 7. 对话路径 → 右侧工作台(2026-10-10)
- 对话正文中已识别的目录/文件路径默认在右侧工作台打开,支持点击、Enter 和空格;目录直接定位,文件复用已有标签(统一 Windows 路径分隔符)。收起后再次点击会重新展开。
- 目录浏览、文本与 Markdown 预览沿用当前对话实际工作目录边界,不因项目导航切换扩大范围。目录外路径显示读取拒绝;二进制文件显示不支持文本预览;均不自动调用系统应用。工作台“系统打开”是显式外部入口,目录标签打开当前浏览目录。
- 会话切换清除待打开路径,工作台标签仍按会话挂载隔离,不向新会话重放上个会话的请求。未新增图片/PDF/Office 预览;文本仍限制前 1 MB。
- 本机真实 Tauri WebView2、CDP 9336、视口 1335×916、DPR 1 验证通过:目录定位、两级返回到根目录、JSON 实际内容、重复点击及目录条目/正文路径共用文件标签、Markdown 渲染/源码、Enter/空格、收起重开、外部目录/文件拒绝、二进制预览错误、错误后恢复和跨会话隔离。采集了实际 DOM、计算样式及矩形:工作台 x=809.015625、y=46、宽=525.984375、高=870,display=flex。
- 验收使用独立测试数据库,通过真实宿主 IPC 持久化受控路径消息,再操作真实 DOM;没有模拟/替换 IPC,没有验证真实模型流式输出。截图保存在用户私有目录 `~/.ygent/path-workbench-smoke.png`。未改动已安装客户端,未进行 Mac/Linux 验收,未触发系统打开按钮。
- 类型检查 `node node_modules/typescript/bin/tsc --noEmit` 和 `node node_modules/vite/bin/vite.js build` 通过;构建仍提示大 chunk。本机 pnpm 入口遇到 esbuild 构建脚本审批错误,因此直接执行已安装的本地工具,未调整依赖审批设置。
- 同时运行已安装客户端时,独立调试窗口首次启动出现 WebView2 HRESULT 0x8007139F;为调试子进程临时指定独立 `WEBVIEW2_USER_DATA_FOLDER` 后成功,不修改系统环境变量或发布配置。
## 并行隔离验收的 WebView2 配置(2026-10-10)
调试构建同时设置 `YGENT_DEBUG_PORT` 与绝对路径 `YGENT_DEBUG_DATA_DIR` 时,主界面 WebView2 使用该数据目录下的 `debug-main-webview`。子浏览器仍按项目/对话使用原有独立 profile;发布构建不启用这个分支。
不要用 `WEBVIEW2_USER_DATA_FOLDER` 隔离含内置浏览器的整进程:它会覆盖子 WebView 的目录,主界面与浏览器使用不同启动参数时,WebView2 可能报 `0x8007139F`。本轮已在真实子视图创建时复现。仅修改当前启动命令的环境,不永久设置系统变量。
需要与用户运行窗口并行验收时,使用独立数据目录和未占用端口;回归脚本先校验 `activity_test_mode=native-isolated`。窗口尺寸以实际 DOM 为准;Win32 缩放/恢复前校验窗口 PID、标题和句柄,只操作验收进程。测试结束关闭自身标签、回环服务和进程,保留用户窗口。
## 编译缓存与磁盘占用
开发与测试共用 `Cargo.toml` 的 dev 配置:`debug = 1`、`incremental = false`,第三方依赖 `debug = 0`。保留 Ygent 自身回溯的文件/行号,不保留完整变量调试信息;需要调试第三方 Rust 依赖时临时启用其符号。WebView2 的 CDP、DOM 与流式调试不受影响。release 配置独立。
关闭增量缓存以减少长期磁盘占用,代价是 Rust 代码重编译更慢;依赖编译产物仍由 Cargo 复用。切换 profile 设置后的首次编译会重建受影响的依赖,不代表每次都全量编译。
旧缓存不会随配置变更自动删除。无 cargo/rustc 构建进程时,可清理 `src-tauri/target/debug/` 下的 `incremental`、`deps`、`build`、`.fingerprint`;这些是可重建的中间文件。保留顶部可执行文件、运行资源、sidecar 和 release 分发产物。清理后首次开发编译和测试须重建依赖。若运行中或正在构建,先停止对应任务再清理,不能一边编译一边删除。
## 长历史对话打开卡顿(2026-10-13)
用户反馈从团队打开成员执行对话时整个页面短暂无响应。真实正常库的Rust成员对话约2,000条消息、正文/工具/参数合计约600万字符。通过9335的真实WebView2连接,在执行同一 `openSession` → `showView('chat')` 路径前开启CDP `Profiler.enable/start`,打开后等待首轮渲染,再 `Profiler.stop` 保存CPU profile;同时使用 `PerformanceObserver` 记录 `longtask`。这些探针仅导航、读取和测量,不发送模型消息、替换IPC或注入消息数据。
诊断必须分别记录会话/消息IPC等待、历史合并、Markdown解析、首次布局及滚动恢复,不能把Promise等待当成JavaScript计算。此次既捕捉到首次Markdown/布局的长任务,也出现过打开等待22秒而渲染线程主要空闲的情况。相关同步IPC在原生窗口线程取数据库锁和读取,不适合继续放在UI线程;具体22秒内的持锁方未捕获,不能宣称已经定位到某个后台工具。
实现:
- `HistoryTurn` 仅在历史接近滚动视口时首次挂载正式 `TurnBlock`,挂载后持续保留,滚动离开不重置手动展开。当前生成、未处理问题/授权、搜索、分享和明确定位的历史立即挂载。原始消息仍完整保留,历史不截断、不按会话特殊处理。
- 共用Markdown高亮转换器的语言登记,避免每个段落重复注册全部语言;正文、代码、公式及工具仍使用原组件。已显现历史通过content-visibility跳过离屏布局和绘制。
- 真实消息行按ID/运行建立索引,合并活跃协作和历史不逐消息扫描整个历史。恢复滚动保存消息锚点及相对偏移,历史挂载改变高度时按真实跟随状态处理,用户上滚不会被强行拉回底部。
- 会话/消息读取、团队成员/工作台、协作列表及任务实际运行查询改用 `spawn_blocking`;保持原数据库、项目/运行身份和返回内容,读库等待不占原生窗口线程。运行标记包含真实恢复派发,不能由持久in_progress推断。
验证:TypeScript、Vite构建、聊天增量/渲染/工具摘要回归通过;新增长历史索引、历史可见性切换及工具展开保留、共享高亮跨块不串内容检查通过。运行标记Rust3项、团队恢复9项通过,调试版 `cargo rustc --bin ygent -- -C extra-filename=-chat-read` 编译通过;没有重复旧全量LSP测试来替代员工当前整改验收。
真实1335×916、DPR1下,前一阶段首次打开长任务524ms;按需挂载后同路径长任务60ms、DOM节点约4,848→1,016。滚动历史后重入的锚点偏差0.125px,回到底部间距0;原生复测中没有异常。该原生脚本选中的历史段未包含可展开工具,工具手动展开保留由组件回归证明,不能据空结果宣称原生工具验收通过。最初1.5–1.7秒采样发生在144×19的最小化视口,与正常窗口数据分别保留,不直接作同尺寸提速比例。
前端更新已在现有开发窗口生效。Rust修复已编译,当前PID1964仍为旧调试内核,未重启/替换、未部署安装目录;异步IPC和运行标记需切换新构建后原生复验。用户当前工作及主动取消不因性能修复重新派发。CPU profile、原生DOM/时间和检查日志只保存于私有 `~/.ygent/imports/employee-chat-*`,不提交会话内容。
+47
View File
@@ -0,0 +1,47 @@
# Ygent 字体渲染对齐与验收(2026-10-08)
本轮对齐真实字库、字号继承、六档管理、行高和用户文字行框。两端真实视口1335×916、DPR1;WorkBuddy9223、YG原生WebView2 9335,同一真实会话。通过真实键盘快捷键逐档变化,测试后两端恢复默认2档;没有替换IPC或模拟会话。
## 统一管理
- 六档Markdown根字号:16、17.143、18.286、20.571、22.857、26.286px。
- 普通UI偏移:-1、0、1、2、2、2px;用户文字、输入、折叠标题、取消提示采用15px基准,即14、15、16、17、17、17px。
- 正文通过Markdown根字号的`.875em`缩放;不要用UI封顶规则覆盖Markdown正文。
- `--yg-font-sans`显式加入Noto Sans SC,匹配本机WorkBuddy真实中文字体;Latin仍使用Segoe UI。
- `--yg-font-agent`遵循参照名称栈,本机实际命中Arial Bold。
- `--yg-font-markdown-code`使用SFMono-Regular/Consolas/Liberation Mono/Menlo;终端使用独立`--yg-font-terminal`,本机实际命中Courier New、中文回退NSimSun。
- 本机Noto Sans SC为已安装系统字库,本轮没有把字体文件复制进项目;其他机器若缺少字库会回退,不能声称跨机器字形已经保证一致。
- 字号变化由设置与Ctrl+-/Ctrl++/Ctrl+0共用Zustand/SQLite链路。没有新增运行时样式表扫描,现有组件通过CSS变量显式接入,剩余裸字号已清理;新增组件遵守AGENTS约束。
## 内层文字与行框
用户气泡外壳保持13px基准,内层15px/1.75;p为1.78行高、1.78em最小高度,内容span垂直居中,对齐Slate混合中英文的实际行框。没有为了对标引入Slate或改变消息数据。
输入textarea实际文字15px/1.75;过程/工具组摘要15px/1.75;取消提示15px、固定20px行高。命令与结果拆成两块:命令12px/1.6,stdout/stderr固定18px行高,块间4px。UI偏移只应用字号一次,结果行高不随字号变化,这是参照实测规则。
设置界面只显示字号档位,移除Markdown像素数值。普通行内代码和Markdown代码块保持Consolas族,不能一并换成终端Courier New。
## 原生验证结果
[两端六档原始测量摘要](reference/workbuddy/font-parity-2026-10-08.json)仅含字号、行高、字体族和几何,不含对话正文或凭据。
| 验收项 | 结果 |
| --- | --- |
| 六档根字号 | 两端全部一致 |
| 9个位置×6档×字号/行高 | 108组对比全部一致:助手名称、正文、用户编辑器、用户p、输入、过程标题、取消、命令、输出 |
| 用户文字宽度、p实际高度、名称宽度 | 每项六档均一致,共18组几何对比 |
| 实际命中字库 | 中文Noto Sans SC及Bold、名称Arial Bold、终端Courier New/NSimSun;平台字体接口确认 |
| 默认用户气泡 | 外框355.15625×44.59375,与参照一致,未硬编码宽高 |
| 设置滑杆 | 原生输入ArrowRight:2→3,根17.143→18.286;ArrowLeft恢复2 |
| 调试版桌面重启 | 原会话5、829条消息恢复;默认档从真实设置恢复,窗口1335×916 |
以上不等于整个对话区1:1通过。工具意图独立折叠、reasoning占位、回合尾部操作栏、滚动条等仍以原差异清单为准;第三方widget iframe的自带字体不在本轮9位置验收内。
## 重复验收
按[原生调试SOP](ygent-debug.md)连接两端,确认同一字号和视口。可通过DevTools的Computed查看内层实际文字,DOM/CSS接口读取`CSS.getPlatformFontsForNode`确认字库。先Ctrl+0回默认,Ctrl+-到1档,再连续Ctrl++采集1—6档,最后恢复原档。设置测试使用真实滑杆,不直接写style模拟字号。
测试时保存草稿,不发送对话。先记录原档位,验证后恢复;本轮原档为2。更新差异状态时须保留原测量记录并说明已修范围,不能删除未修的结构问题。
2026-10-08 视觉优化补充:按用户要求,工作台与对话的 Markdown 围栏代码共同使用根字号 0.8125em、行高 1.7,取代原 0.75em;表格使用 0.875em、行高 1.65。六档仍由同一根字号管理,终端字体不受该 Markdown 样式影响。此调整优先可读性,不再代表这两个行高/比例与 WorkBuddy 原始值完全一致。
@@ -0,0 +1,58 @@
# 模型编辑、模型选择与上下文状态
## 对标依据
2026-10-09 通过 WorkBuddy 5.7.6 的真实渲染页 CDP、DOM、计算样式和安装包资源确认,未使用 computer-use。原始会话及采集资源只保存在用户私有目录。
- 模型入口高 32px,图标 16px、箭头 14px;弹层宽 280px、最大高 368px、圆角 16px、内边距 8px。列表按渠道分组,组标题高 28px,模型行基准高 32px;选中标记、悬停、滚动和键盘操作共用一个列表。
- 上下文入口位于模型入口左侧,点击区域 32px,圆环 16px、线宽 2px。用量面板宽 280px、内边距 16px、圆角 16px,包含百分比、token 用量、占用条与分类图例。
- WorkBuddy 的付费、Max 等专有功能没有对应的 Ygent 功能,不能添加无效入口。模型图标采用随包本地 SVG(Lobe Icons 1.95.1,保留 MIT 许可),按 canonicalId 模型归属匹配;未识别元数据时仅按已知模型名前缀回退,未知模型显示通用图形。模型按钮及列表共用组件,客户端不访问图标 CDN。
## 已实现
模型编辑恢复输入上下文、输出上限的选项按钮。输入提供 32K/64K/128K/256K,输出提供 8K/16K/32K/64K;精确模型上限作为独立选项,超出模型上限的预设不可选。默认不展示数字输入框,点击“自定义”后才能输入;保留元数据默认值、逐字段覆盖与恢复自动能力。
补充:两组均提供 128K/256K/1M,token 档位使用十进制 K=1000、M=1000000。模型声明在 1000000–1050000 的窗口归入 1M 显示档,但选中与保存采用模型的精确上限(例如 1050000),悬停显示准确 token 数。128000 对应 128K,不再因按 1024 换算而被误判超限。已有精确数字不重算。
自动输出预算直接使用元数据声明的输出上限(例如 gpt-6-luna 为 128000),不再统一限制为 8192 或上下文的一半;保留每字段手动覆盖,仅元数据未声明输出上限时兜底 8192。配置允许输出上限等于上下文上限,实际请求仍校验输入加输出预留是否超限。
对话模型菜单改为单层渠道分组列表,选择真实模型后关闭;支持方向键、Enter、Escape、外部点击关闭和焦点返回。当前模型的原生思考选项及预算仍可设置,配置入口打开模型设置。新建任务和对话复用同一模型组件。
对话输入区增加上下文圆环、悬停说明及点击详情。切换会话会清空旧显示,生成期间及面板打开时每两秒刷新;查询不启动、不切换、不重启 Agent。
## 用量语义与边界
- OMP 总量:读取已绑定当前会话的 `get_state.data.contextUsage`,标注“内核当前上下文估计”。读取最长等待两秒,操作冲突或失败使用本会话持久化快照。
- 直连:读取实际 SSE 的最近请求输入计数,标注“最近请求的输入用量”。支持 Chat Completions、Responses、Anthropic Messages、Gemini;Anthropic 包含缓存读取与写入输入。
- 不把各轮 token 累加作为上下文占用,不把输出或账单总量当成输入。没有真实计数/窗口时显示“—”,不能用运行时兜底窗口伪装模型实际上限。
- OMP 分类:随包观测扩展读取主 Agent 的实际 `context` 输入与 `before_provider_request` 最终工具声明,通过 OMP 分词器本地计数;不是分类 RPC,也不按内核总量分摊比例。分类与内核当前总量是独立快照,可能不相等。
- 分类包含系统提示词(扣除已识别的技能目录)、工具及子智能体的声明/调用/返回、对话正文、MCP 声明/调用/返回、技能目录及按需读取的正文。只计算当前主 Agent 实际输入中可见的内容,不推断子 Agent 的私有上下文。停用技能或连接器后,仍在输入历史中的调用和返回继续计入原分类。
- 面板显示各类估计 tokens 及其占请求时上下文窗口的比例;悬停可查看精确估计数、快照时间、模型和请求身份。无法识别名称的工具声明列入“未归类”,仅非零时显示;供应商协议封装及未公开的隐藏输入不伪装成已分类内容。
- 精度按真实计数路径标注“模型分词器”、`o200k_base` 或“UTF-8字节估算”。后两者及本地分类都不能当作上游账单实测值;没有请求快照、直连尚无可靠分类来源时继续显示“— / 暂无分类统计”,不以零补齐缺失数据。
- 分类每次实际准备模型请求时替换,不累加;按宿主会话/请求/原生会话文件校验后持久化。取消保留已准备输入,拒绝取消后的迟到帧;重载和总量刷新保留同一分类快照。旧历史不反推分类,更新后的 OMP 进程产生新请求后才会有新统计。
- 快照按会话持久化;直连数值是最近请求观察值,不代表用户编辑历史后已经重新计算;新请求开始清除旧的直连观察值。
## 验收
2026-10-09:后端 `cargo test --lib --quiet` 69 项通过、1 项忽略,包含各协议输入计数、覆盖而非累加、缓存计数、会话隔离和 OMP 字段解析。`npm run build`、`npm run models:check`、`npm run check:chat` 通过。
原生验收使用隔离数据库与真实 Tauri IPC,脚本 `scripts/model-context-native-check.mjs`;上游仅使用本机受控 SSE 服务,不操作用户正常会话,不替换前端 IPC。Windows WebView2 视口 1335×916、DPR 1:编辑器选项/精确上限/自定义/恢复自动、模型列表位置和方向键焦点、上下文面板/Escape、两轮输入 1250→2750 替换而非累加、跨会话隔离及重载恢复均通过;六档字号下两种面板均宽 280px,无横向截断。模型选择使用真实按钮激活验收,未将 CDP 的 Enter 默认行为计为已通过。
截图和 DOM 证据位于用户私有目录 `C:/Users/Administrator/.ygent/imports/model-composer-20261009/native`。OMP 实际返回的窗口可能是内核可用窗口,不能强制等于模型元数据最大窗口;以实际 `contextUsage.contextWindow` 为准。本次只实测 Windows,未声称 Mac/Linux 通过。
### OMP 输入分类验收(2026-10-10)
隔离数据库、真实 Tauri IPC / WebView2、OMP 18.6.3;模型上游为本机受控 SSE,技能通过真实安装及按需读取接入,MCP 通过真实 stdio 握手、工具发现及独立宿主授权调用。未替换 IPC、未注入前端分类数据,不把受控上游当成真实供应商计费验收。Windows 视口 1335×916、DPR 1;其他平台未实测。
八项场景通过:无请求时分类未知;技能与 MCP 调用后五类均有真实输入计数;刷新总量不覆盖分类;六档字号下 280px 面板无横向溢出、Escape 关闭并返回焦点;未启动的第二会话查询不创建内核会话文件且不串分类;下一请求替换而非累加并保留历史技能/MCP 输入;运行及取消保留已准备输入;真实 WebView 重载恢复同一快照且不产生新模型请求。DOM、计算字号/行高、边界及滚动尺寸与截图同时采集。
本次分词路径为 UTF-8 字节估算:首次内核总量 8,935,独立分类合计 9,383;停用扩展后的新请求分类合计 8,857,取消回合 8,878,重载后保持不变。分类没有缩放为内核总量,也没有把旧快照累加到新快照。
后端 `cargo test --lib --quiet --manifest-path src-tauri/Cargo.toml`:119 项通过、1 项忽略,覆盖分类和校验、溢出、会话隔离、旧请求/取消身份拒绝;`npm run build` 与 `npm run check:chat` 通过。构建仍有已有的大 chunk 和 `knowledge::context` 未使用警告,未扩展本轮范围处理。
证据:用户私有目录 `C:/Users/Administrator/.ygent/imports/context-categories-native-C7mOTZ`,含 `result.json`、真实上游请求、六档 DOM/计算样式及第 1/6 档截图。隔离进程与本机服务已关闭;临时验收脚本不留在仓库。
## 本地图标验收
2026-10-09:14 个品牌 SVG 在真实桌面 WebView2 中均完成解码,模型按钮与列表图标为 16×16px,资源均为本地/内联资源。未知归属回退和 GPT 模型名回退已验证;类型检查、构建及 diff 检查通过。截图与 DOM 位于私有目录 `C:/Users/Administrator/.ygent/imports/model-icons-20261009`。
+205
View File
@@ -0,0 +1,205 @@
# Ygent 富内容渲染设计(HTML 制品 / 流程图 / 公式)
> 状态:设计提案,待确认
> 背景:`docs/reference/workbuddy/chat-tool-fold.md` 已摸清 WorkBuddy 的实现与安全边界
> 本文只讨论「对话区要支持哪些内容类型、怎么安全地渲染、分几步做」
---
## 1. 现状盘点
| 内容类型 | WorkBuddy | Ygent 现状 | 差距 |
|---|---|---|---|
| 段落 / 列表 / 引用 | ✓ | ✓(remark-gfm) | — |
| 表格 | ✓ | ✓ | — |
| 代码块高亮 | ✓ Prism | ✓ highlight.js | 可接受 |
| 代码 diff(改文件时) | ✓ `tool-diff` | ✗ | 见 §7 |
| 图片 | ✓ | ✓(react-markdown 默认) | — |
| **流程图 / 图表** | ✓ mermaid | **✗** | 需新增 |
| **数学公式** | ✓ KaTeX | **✗** | 需新增 |
| **HTML 制品** | ✓ sandbox iframe | **✗** | 需新增 |
| 内联 SVG(消毒) | ✓ DOMPurify | ✗ | 低优先 |
Ygent 当前渲染管线:`remarkGfm` + `rehypeHighlight`,**无 `rehype-raw`**(即不渲染 Markdown 里的裸 HTML)——这一点与 WorkBuddy 一致,是安全基线,**不要为了省事打开它**。
---
## 2. 两条进入路径(关键决策)
富内容有两种进入对话的方式,**建议两条都做,但优先级不同**:
### 路径 A:Markdown 内联(模型天然会用)
模型输出 ```mermaid 代码块或 `$$…$$` 公式,由渲染管线识别。
- 优点:**零工具改动**。模型不需要被教会调用新工具,它在别处已经习惯了这套写法。
- 证据:WorkBuddy 的 mermaid 就是这条路径——存在 i18n 键 `markdown.mermaid.rendering`(渲染中占位文案),说明是代码块触发而非工具产出。
- 适用:mermaid、KaTeX
### 路径 B:工具产出制品
专用工具(如 `show_html`)返回一段 HTML,以「制品块」形式呈现,带独立查看器 UI。
- 优点:有明确的类型边界,可以配查看器(切代码 / 复制 / 下载 / 导出图片)与独立的安全边界。
- 证据:WorkBuddy 的 `show_widget` 工具 + `SYn = {show_widget, visualize:show_widget, visualizer:show_widget}`,走 `<iframe sandbox="allow-scripts">`。
- 适用:HTML 制品(交互式页面、可视化)
---
## 3. 各类型的渲染方案与安全边界
### 3.1 mermaid 流程图(路径 A)
```
```mermaid
flowchart LR
A[用户] --> B[内核] --> C[结果]
```
```
渲染:` ```mermaid ` 代码块 → 动态加载 mermaid → `mermaid.render()` → 得到 SVG → **消毒** → 注入。
**消毒是必须的**,直接照抄 WorkBuddy 已验证的配置:
```js
DOMPurify.sanitize(svg, {
USE_PROFILES: { svg: true, svgFilters: true },
FORBID_TAGS: ["script", "foreignObject"],
FORBID_ATTR: ["srcdoc", "formaction"],
});
```
要点:
- **只开 SVG profile**(不含 HTML profile)——消毒结果只能表达图形,带不了 `<a>`/`<form>`
- **禁 `foreignObject`**:它能把 HTML 塞进 SVG 里绕过 SVG profile
- 渲染中显示占位(对应 `markdown.mermaid.rendering` 那种文案),失败时**回退显示原始代码**而不是空白
### 3.2 数学公式(路径 A)
`$inline$` 与 `$$block$$` → remark-math + rehype-katex → KaTeX 产出 HTML。
KaTeX 的输入是公式文本、输出是受控 HTML,**不需要额外消毒**(与 WorkBuddy 一致)。
### 3.3 HTML 制品(路径 B)
```jsx
<iframe sandbox="allow-scripts" srcDoc={html} title="交互制品" />
```
**不带 `allow-same-origin` 是整个方案的核心**:制品里的 JS 能跑(图表要动),但因为源是 opaque origin ——
读不到 `localStorage`、拿不到父窗口 DOM、发不出带 cookie 的请求。
已确认的前提:Ygent 的 `tauri.conf.json` 里 `"csp": null`,**不会拦 iframe srcdoc**。
若将来收紧 CSP,需为 iframe 放行(或在制品 HTML 内自带 `<meta http-equiv="Content-Security-Policy">`)。
查看器能力(参考 WorkBuddy 的 `widget.*` 文案):
显示 UI ⇄ 查看代码、复制代码、下载到本地、导出为图片、加载中态、错误面板。
---
## 4. 数据模型
**不需要新增 `MsgKind`。** 制品就是工具产出,复用现有 `tool` kind:
```ts
export type MsgKind = "user" | "agent" | "tool" | "perm"; // 不变
export interface ChatMessage {
// …现有字段
/** 制品:HTML 内容或落盘路径(见 §4.1) */
artifact?: { kind: "html"; path: string; title?: string };
/** 制品必须 keepVisible —— 折叠时不能被收走(否则制品整个消失) */
keepVisible?: boolean;
}
```
`toolState` 已在本轮补上,制品卡直接复用「运行中 / 完成」两态。
### 4.1 制品内容存哪(待决策)
| 方案 | 优点 | 缺点 |
|---|---|---|
| 存 `messages.result`(TEXT) | 零改动 | 大 HTML 撑大 SQLite;`list_messages` 变重 |
| **落项目工作目录 + DB 只存路径(建议)** | 符合「目录即项目」哲学;可被工具读回;DB 轻 | 需要文件生命周期管理 |
建议第二种:`.agent/artifacts/<message-id>.html`,DB 的 `result` 只存相对路径。
删除会话时一并清理(或按「永不删除项目目录」的铁律只解除登记)。
---
## 5. 与「回合分组 / 折叠」的关系(容易踩坑)
这是 WorkBuddy 用 `isShowWidget` + `keepVisible` + `presentationGroupId` 解决的问题,Ygent 必须一起考虑:
1. **制品不能被折叠掉。** 回合结束时会把连续工具块收成一行摘要——制品必须 `keepVisible`,
否则用户点了折叠,图表就没了。
2. **制品要和它的解释文字绑在一起。** WorkBuddy 的做法是制品块向前找最近的正文块,
共享 `presentationGroupId`。Ygent 目前用「回合」粒度分组(见 `ChatView.tsx` 的 `groupTurns`),
如果制品总是出现在回合末尾,回合粒度暂时够用;一旦出现「文字→制品→文字」的结构,
就需要下沉到块粒度。
3. **制品高度不定**,不能像工具卡那样单行省略。需要 iframe 通过 `postMessage` 上报高度自适应,
或给一个可拖拽/固定高度 + 内部滚动。
---
## 6. 体积代价(必须先决策)
| 依赖 | 体积 | 现状 |
|---|---|---|
| mermaid | **~2.8 MB**(WorkBuddy 的 `vendor-mermaid` chunk) | Ygent 前端 bundle 现在共 563 KB |
| katex | ~300 KB(含字体) | — |
| dompurify | ~45 KB | — |
**结论:一律动态 `import()`,按需加载,首次出现该内容类型时才拉。**
否则只为了偶尔一张流程图,就把首屏 bundle 撑到 3 MB+,冷启动明显变慢——这跟前面查到的「OMP 内核启动 1.31s」是同一类问题。
---
## 7. 顺带:代码 diff 视图(与富内容同级)
工具改文件时显示行级 diff,WorkBuddy 的 `tool-diff` 是现成参考:
- 输入 `oldCode` / `newCode` / `fileName`
- 按扩展名推断语言(`ts/tsx/js/py/rs/go/java/kt/swift/c/cpp/cs/php/css/html/vue/sh/yml/sql/scala`)
- Prism 懒加载该语言 + LRU 缓存,**语言不支持时回退 HTML 转义纯文本**(不要渲染空白)
- 行渲染 `+/−` 号
Ygent 的 `edit` / `write` 卡目前只显示「项目/新增文档.md +15」徽标。
要做 diff 的话,**必须用转义兜底**——文件内容绝不能当 HTML 注入。
---
## 8. 建议的分阶段落地
| 阶段 | 内容 | 成本 | 收益 |
|---|---|---|---|
| **P1** | mermaid 代码块(动态 import + DOMPurify SVG 消毒 + 失败回退原始代码) | 低 | 直观,模型零适配 |
| **P2** | KaTeX 公式(remark-math + rehype-katex,动态 import) | 低 | 技术对话可读性明显提升 |
| **P3** | 代码 diff 视图(`edit`/`write` 卡) | 中 | 直接改善现有工具卡 |
| **P4** | HTML 制品(工具 + iframe 查看器 + 存储策略) | 高 | 能力上限最高,但需要先定 §4.1 和 §5 |
P1 + P2 可以在一个改动里做完(都是 Markdown 管线扩展 + 动态加载),建议作为第一步。
---
## 9. 待决策清单
1. **制品 HTML 存 DB 还是落项目目录?**(建议落目录,见 §4.1)
2. **是否允许制品访问外网(CDN 脚本/字体)?** 现在 `csp: null` 允许;要不要收紧到白名单?
3. **制品高度**:`postMessage` 自适应,还是固定高度 + 内部滚动?
4. **mermaid 之外是否还要别的图表库**(如 ECharts)?WorkBuddy 的 `show_widget` 走的是「生成 HTML」而不是绑定图表库,这条路更通用但要制品能力先就位。
5. **是否给制品加「导出为图片」**?WorkBuddy 有(`widget.downloadImage`),但需要额外依赖做 HTML→图片。
---
## 附:与 WorkBuddy 的差异(有意为之)
| 项 | WorkBuddy | Ygent 建议 |
|---|---|---|
| 高亮库 | Prism | 保持 highlight.js(已用,换库无收益) |
| Markdown 裸 HTML | 未开启 | **同样不开启** |
| 制品渲染 | iframe sandbox | 同 |
| 内联 SVG 消毒 | DOMPurify SVG profile | 同(做 mermaid 时一并引入) |
| 虚拟列表 | 有 | **不做**(Ygent 无此瓶颈) |
| widget 分组 | 有(`presentationGroupId`) | **暂不做**,先用回合粒度;出现「文字→制品→文字」再下沉 |
+13
View File
@@ -0,0 +1,13 @@
# 对话标题规则与验收
2026-10-10:修复侧栏项目中新建空对话后,首条消息未更新默认标题的问题。
- 默认名称为“新对话”;宿主在用户消息落库时,用首条非空用户正文命名。连续空白合并,取前 24 个 Unicode 字符,超长添加省略号;不调用模型生成标题,不影响流式速度。
- 独立对话和项目对话共用规则。前端发送后异步刷新页头、侧栏项目分组及项目详情列表,不等待模型完成。
- `sessions.title_auto` 区分默认自动命名和手动命名。手动重命名关闭自动命名,即使用户主动命名为“新对话”也保留。后续用户、工具、助手消息不改变首条用户正文确定的标题。
- 未被内核接受的首条消息撤回后恢复默认名称;重试使用实际保留的首条用户正文。取消或失败但已经被接受的回合仍保留标题。
- v18 升级仅修复普通、非分支、无导入来源的旧默认名称(“新对话/新建对话/新任务”)。旧版本未记录命名来源,无法区分用户曾手动改为完全相同默认名称的情形;其他已有名称保持原样。新版本记录明确的手动命名来源。
验证:`npm run build`、`npm run check:chat`、`cargo test --no-default-features --manifest-path src-tauri/Cargo.toml --lib` 通过,Rust 82 项通过、1 项官方网络测试跳过。新增测试覆盖两个归属范围、空白消息、首条正文、后续消息、手动默认名称、Unicode 截断、拒绝发送回退及升级幂等。
真实桌面验收:隔离数据库的 WebView2 CDP 下运行 `node scripts/session-title-native-check.mjs 9336`,验证真实 IPC、页头/列表刷新、重载持久化和拒绝发送回退。未发送模型请求、未替换 IPC。主调试窗口重启后确认已有默认名称得到修复,恢复原查看对话;安装版未替换。
+22
View File
@@ -0,0 +1,22 @@
# 设置页风格对齐(2026-10-08)
参照 WorkBuddy 原生设置窗口(CDP 9223,windowKind=settings),通过 DOM、计算样式、元素尺寸采样;Ygent 在真实 Tauri WebView2(CDP 9335)验收。
## 已调整
- 设置区域从 760×600 调整为 900×680,与 WorkBuddy 设置窗口视口一致;小窗口限制最大宽高,内容单独滚动。
- 使用 #f7f7f7 中性浅灰背景、白色 12px 圆角卡片,去掉导航分隔线和通用项逐行边框。颜色令牌仅作用于设置区域。
- 顶部保留 32px 关闭栏;导航列 224px(含左右 12px 留白),导航项 200×34、间隔 2px、字号基准 14、常规字重,选中底色 #e6e6e6。
- 内容区左留白 8px、右留白 30px;分组标题字号基准 14、灰色、常规字重,卡片内边距 12×16。通用分组宽 638px,内部行宽 606px。
- 下拉框 120×32,标签字号基准 14、字重 500,描述使用弱化灰色。
- 字号滑杆宽 224px、高 40px,细线六档刻度、8×16 滑块;“默认”对准第 2 档(20%),删除额外档位数字。沿用现有全局字号及持久化逻辑,所有文字依赖全局字号偏移。
- 模型卡片、权限说明、授权/审计区域和空态使用相同中性卡片规则;导航改为可键盘操作的按钮。
## 验证与边界
- pnpm build、node scripts/fe-check.mjs 通过。
- 原生 Ygent 主视口 1335×916,设置区域 900×680。通用的导航、分组、行高、下拉框尺寸及颜色与 WorkBuddy 采样匹配;通用三行高度为 44/70/52px。
- 六档字号检查:标签实际字号 13/14/15/16/16/16,滑杆值同步,没有设置内容区横向溢出;三页切换及选中态检查通过。
- 原生键盘右方向键使滑杆从第 2 档变为第 3 档;下拉展开、关闭设置检查通过,验证后恢复原字号并显示通用页。
- 原生截图保存在用户私有调试目录,不提交真实会话数据。
- 本次对齐设置的视觉体系和已有控件。WorkBuddy 使用独立原生设置窗口,Ygent 仍使用应用内弹窗;额外功能目录、独立窗口生命周期、所有嵌套编辑表单和小屏实测未列为已完成的 1:1 验收。
+57
View File
@@ -0,0 +1,57 @@
# Agent 命令执行环境
设置 → 通用 → 命令执行环境。当前接入 OMP 命令工具,独立于系统默认终端窗口;不修改 Windows Terminal、系统环境变量或其他软件的配置。
## 使用
1. 选择自动检测、Git Bash、PowerShell 7、Windows PowerShell、CMD 或自定义路径。
2. 自定义模式填写 Shell 可执行文件的绝对路径,也可通过“浏览”选择。接受 bash、sh、zsh、pwsh、powershell、cmd;不接受 Windows Terminal 等窗口启动器。
3. 选择后自动验证并保存;自定义路径在失焦、按 Enter 或浏览选择文件后保存。程序实际执行固定的验证命令,验证成功才持久化;路径不存在、无法启动、执行失败或超时会显示错误,保留原来的已保存配置。界面不显示额外保存按钮、正常状态说明或检测出的路径。
4. 下一次发送消息时应用新的配置。运行中的回合继续使用启动时的 Shell,不因保存设置重启或中断。
自动检测依次尝试 Git Bash → PowerShell 7 → Windows PowerShell → CMD,跳过不存在或验证失败的候选。探测结果显示实际可执行文件路径;每次新回合还会检查是否可用。指定类型不可用时直接提示错误,不悄悄改用其他类型。
## 实现约束
- SQLite 设置键 `execution_shell` 存储模式和自定义路径;保存命令只写偏好,不触碰正在运行的内核配置。
- 在 OMP 回合准备阶段解析 Shell,将实际路径/类型加入内核配置标识,变更时在空闲边界重启并恢复当前会话。
- OMP 启动时加载 Ygent 私有的 `omp-profile/ygent-shell.yml`,追加实际 Shell 和语法的系统指令。关闭登录 Shell/PowerShell profile 加载,使探测与执行使用相同环境。
- 本机 OMP 的普通 `bash` 工具实际使用内置 POSIX 解析器,单独设置 `shellPath` 无法执行 PowerShell 语法。因此显式加载 `ygent-shell-adapter.mjs`,在 `tool_call` 中将原始命令作为单个参数安全引用,再调用所选 Shell。仍走 OMP 原有执行、授权、流式输出、超时与取消链路,不另设绕过授权的执行工具。
- Windows 可执行文件路径统一使用反斜杠,避免 OMP 对 CMD 正斜杠路径的错误解析。CMD 命令写入随机临时目录中的 UTF-8 `.cmd` 脚本,以保留引号、多行和中文;脚本在本次工具结果或会话关闭时清理。
- 具名后台服务(`bash` 的 `name`)自身使用 `shellPath` 启动,不重复包装。其他工具与 Skill/MCP 调用不改写。工具详情可能显示包装后的实际执行命令。
- 当前仅接入 OMP;直连模式及 Codex 底座不应用此选项。
## 验收 SOP
按 [原生调试 SOP](ygent-debug.md) 启动 WebView2 CDP 9335,在临时真实会话验收,完成后恢复原会话与设置。截图/会话输出放用户私有目录,不能提交凭证、真实聊天内容。
1. 在设置页检查六种选择、路径输入、验证反馈与重新打开后的持久化。使用无效路径确认保存失败且旧配置保留。
2. 选择 PowerShell,在真实命令工具中执行 `$PSVersionTable.PSVersion` 和 `(Get-Process -Id $PID).Path`,核对实际版本/路径;不能用设置页“已验证”代替内核调用验收。
3. 执行带等待的命令,在工具仍运行时保存另一种 Shell,确认 OMP PID 不变、当前命令仍返回旧 Shell 的输出。结束后下一回合检查新 Shell 的语法与实际输出。
4. 自定义有效路径与对应预设应产生相同执行环境;自定义不存在的路径必须拒绝。Git Bash 未安装或损坏时显示失败。
5. 检查六档字体的 computedStyle、控件矩形和 scrollWidth;长路径需换行,不得撑宽设置页。
6. 编译前端、执行 Rust 测试并编译桌面程序。更换 OMP 二进制版本后重新验证工具 hook、参数引用及具名后台服务行为。
## 2026-10-09 验收记录
- 真实 Tauri WebView2:六种选项展示、Windows PowerShell 点击保存、无效自定义路径错误及旧偏好保留通过。六档字体无横向溢出。
- 后续简化设置页:移除正常状态说明、路径展示和保存按钮,真实 UI 验证选择 Windows PowerShell 自动持久化、无效自定义路径保留旧偏好并显示错误、恢复自动检测成功。
- 自动检测跳过本机损坏的 Git Bash 启动器,找到 PowerShell 7。真实 OMP 命令返回 PowerShell 7.6.5 的版本及进程路径。
- Windows PowerShell 真实语法执行返回 5.1.26100.9444;等待 12 秒期间保存 CMD,OMP PID 保持不变,当前命令成功以原 Shell 完成。
- 新回合使用 CMD,真实 OMP 工具返回 COMSPEC 和 Windows 版本;命令适配器搭配同版本 OMP 原生 Shell 验证环境变量、双引号、单引号、多行与中文,全部通过。具名服务及其他工具未被该 hook 包装。
- 前端生产编译、TypeScript 检查、Rust 桌面编译及 35 个 Rust 测试通过。
- Git Bash 本机安装缺少 `usr/bin/bash.exe`,未验收实际 Bash 命令;其验证失败路径已确认。具名后台服务不重复包装,但完整后台生命周期尚未单独验收。
## 2026-10-12:重复包装与失败重试修复
真实 bundled OMP 18.6.3 的隔离对照确认:普通 `bash` 仍经内置 POSIX 执行器,不能删除所选 Shell 的适配。原始 PowerShell 脚本经过一层包装可正常执行;把已包装的历史参数重新作为脚本提交会形成嵌套,并产生 `-NoLogo` 等意外标记错误。内存中的下一次模型请求仍保留原始参数,但持久会话恢复后,模型上下文会读到保存的执行包装。两种路径不能混为一谈。
修复入口为 `src-tauri/src/shell-adapter.mjs`,由 `shell::adapter_in` 写入每个隔离 profile,保留实际 Shell、取消、超时、输出和授权链路:
- 在通用 `context` hook 中,仅克隆并还原助手 `bash` 调用中与本回合 Shell/参数精确匹配的完整单参数包装。不修改持久审计文件、工具结果、其他工具或具名后台服务,不依赖渠道协议。
- 工具启动前同样去除可严格验证的重复包装,最多还原八层,然后仅包装一次。不解析任意 Shell 表达式;带其他标志、管道或重定向的脚本不能被当作自身包装去除。
- CMD 的历史包装指向已清理的临时脚本,无法据路径重建原始内容。明确要求重新提供原始 CMD 脚本,不能重放未知临时文件。正常 CMD 的中文、多行和结果后清理仍保留。
- 同回合、同 cwd 的同一原始命令失败两次后,结果保留原错误并补充诊断提示;失败三次后拒绝第四次原样尝试。换用实际不同的诊断/修复命令仍可执行。计数按内核实例及回合隔离,成功清除相应失败计数,迟到和重复结果不累加。
- 限次不代表任务完成、取消或通过,不新增人工授权。缺少前置条件时沿现有员工与经理协作处理。它只约束同一命令的重复失败,不宣称能识别所有等价命令或所有无效诊断循环。
回归入口:`cargo test --lib --manifest-path src-tauri/Cargo.toml shell::tests -- --test-threads=1` 检查实际生成模块;`scripts/shell-adapter-native-check.mjs` 使用隔离 profile、真实 OMP 与本机受控 SSE,验证原始命令、历史包装、上下文恢复、真实输出及非零退出。私有证据不进仓库;本节源码修复不表示已替换正在运行的用户进程。
+24
View File
@@ -0,0 +1,24 @@
# 左侧菜单:侧栏收起/展开对标(2026-10-08)
本轮范围是侧栏切换入口和收起/展开行为;对话区仍按阶段进度收尾,不继续修改其内部实现。
## WorkBuddy 原生参照
真实WorkBuddy 5.7.6、CDP9223、1335×916:入口在左上角,展开和收起时均保留同一个按钮,分别提示“收起侧边栏”/“展开侧边栏”。按钮位置(8,3)、24×24,图标16×16,圆角8px,文字/图标黑70%;使用面板分栏向量,没有方向箭头。hover/active背景#0000000f、图标#000000e6,100ms颜色/背景过渡。
实测展开时当前侧栏宽240px;点击后侧栏完全隐藏,主区宽度扩展到1335px,没有保留图标窄栏。入口仍在原位置,第二次点击恢复侧栏。采集后还原原展开状态。私有原生证据`sidebar-toggle-wb.json`,位于`C:/Users/Administrator/.ygent/imports/render-audit-20261008/`。
## Ygent 本轮修改
- 移除左侧菜单底部的“收起侧栏”文字入口;底部设置保留。
- Titlebar左上固定一个原生button,展开/收起共用,切换提示和aria-expanded;aria-controls关联`ygent-sidebar`。
- 使用WorkBuddy原生SVG的面板路径,位置(8,3)、24×24/16×16、颜色、圆角和hover/active规则按实测接入。
- 侧栏继续通过隐藏容器收起,保留挂载;恢复时保留任务/项目展开状态,不切换会话或页面。切换按钮也不卸载,键盘焦点保留。
代码位置:`src/components/Titlebar.tsx`、`src/components/Sidebar.tsx`、`src/App.tsx`、`src/App.css`。未新增侧栏状态的重启持久化或快捷键,WB相应规则尚未核实。
## 验收与边界
真实Ygent Tauri WebView2、CDP9335、1335×916、DPR1:按钮在两态均为(8,3,24,24)、黑70%、圆角8;收起时host display:none、主区x0/w1335;按钮节点及焦点保持;恢复后侧栏为同一节点、当前会话/页面不变、底部不再出现旧入口。操作后还原原展开状态。私有证据`sidebar-toggle-yg-check.json`。前端编译检查随本轮执行。
本轮对齐的是入口和切换行为,不是整个左栏/标题栏已1:1:YG侧栏仍宽280px,WB当前实测240px;YG标题栏高40px,WB高30px,因此主区顶部分别y40/y30。左栏其他菜单、背景、项目层级、账号区域及窄窗响应另行对标,不能为此次入口修改直接外推。
@@ -0,0 +1,18 @@
# 思考与工具参数增量接入(2026-10-10)
当前 OMP 接入 `assistantMessageEvent.thinking_delta`、`toolcall_start` 与 `toolcall_delta`。真实二进制隔离探针确认:Responses 的 `response.reasoning_summary_text.delta` 转为 `thinking_delta`,`response.function_call_arguments.delta` 转为 `toolcall_delta`;后者 `partial.content[contentIndex]` 提供工具 ID 和名称。不读取 reasoning 的签名、加密内容,也不保证所有渠道/模型都公开思考摘要。
Rust 将这些帧转为 `agent://event` 的 `activity`,保留 delta、messageId/contentIndex、工具 ID/名称;原有会话/回合绑定与取消过滤不变。正文仍是 chunk,实际执行仍是 tool。结束快照不重复播报。
ChatRun 独立维护最近 4000 字符的原始事件播报,按到达顺序包含思考、参数、正文、工具输出和授权文字。已流式收到的工具参数不被执行开始时的完整参数重播。未闭合 JSON 仅用于播报,不解析执行,也不提前创建工具卡或放行授权。
播报是内存临时状态,切换会话隐藏,返回运行中的会话恢复,结束/取消/失败清空。思考不转为 ChatMessage,不写历史数据库,不进入项目记忆整理源;activity 事件不会触发消息落库。头像下的阶段随事件显示“正在思考/生成工具参数中”;实际执行、待授权/回答仍优先显示原有阶段。底部始终使用原有单一“正在思考”扫光与播报动效。
## 验证 SOP
1. `node scripts/omp-activity-probe.mjs <仓库外私有目录>`:独立 OMP、独立 profile、回环 Responses 服务,无用户凭据或远程模型;检查真实帧的 delta、顺序及工具 ID。
2. `cargo test sidecar::tests --lib`、`npm run check:chat`、`npm run build`:检查解码、未完整参数不建卡、快照去重、取消和跨会话隔离、思考不落库,以及原有交互与折叠回归。
3. 按 [原生调试 SOP](ygent-debug.md) 启动独立数据目录的真实 Tauri 调试窗口(9336)。仅在此独立数据库中设置 `activity_test_mode=native-isolated`,不能在用户正常数据库中设置测试标记;有正在使用的窗口时不要停止它。
4. `node scripts/chat-activity-native-check.mjs 9336 <仓库外私有证据目录>`:通过真实 IPC 创建测试渠道和对话,真实 OMP 连接本地受控 Responses SSE。分别检查思考片段、未闭合参数、正常正文在终态前出现在 DOM,同一时间恰好一个播报栏,正常工具完成,思考不在持久化消息中,参数生成时取消后晚到 SSE 不恢复运行。
本机已通过真实 Tauri WebView2、真实 OMP 与受控 Responses SSE 验证。证据保存在用户私有 `~/.ygent/imports/activity-native-evidence-20261010/`,不提交。测试使用受控模型输出,不代表当前远程渠道一定提供增量,也不代表 WorkBuddy 双端流式对标、Mac/Linux 或其他内核已通过。安装版 0.01 不随源码/调试构建自动更新,须重新打包安装。
@@ -0,0 +1,125 @@
# Ygent UI 能否像素级对齐 WorkBuddy —— 可行性结论
日期:2026-10-14
问题:是否可以和 WorkBuddy 的 UI / 交互做像素级对齐?
本文是**可行性结论**,不是实施方案,也不改变任何既有对标承诺。证据来自项目已有的对标记录(`ygent-workbuddy-render-audit-2026-10-08.md`、`ygent-font-parity.md`、`ygent-chat-interaction-parity.md`、`ygent-chat-stage-summary-2026-10-08.md`)与 `AGENTS.md` 的原生渲染调试约束。
---
## 0. 结论
1. **对话区(chat):可以,而且大部分已经做到。** 现有实测已把关键几何收敛到「同视口 / 同字号 / 同展开状态下 ≤1px 取整误差」,含 108 组字号/行高、18 组几何、多个回合成品尺寸完全一致。
2. **外围壳层(侧栏 / 顶栏 / 左下 / 新建页):只能部分对齐。** 一部分是宿主结构差异,一部分是数据模型差异,还有一部分是平台商业入口——后者按项目约定不应复制。
3. **「全局 100% 像素一致」不可能,也不需要。** 三类硬性不可消除:渲染引擎版本差、跨机器字库、数据驱动内容。
4. **有一个前置取舍**:项目已按用户要求做了若干**品牌化偏离**(Ygent 名称/图标、品牌渐变背景、品牌蓝发送按钮、移除邀请卡/账号区),这些与"像素级对齐"直接冲突,需要明确取哪一边。
---
## 1. 技术上可行的前提(已全部具备)
| 前提 | 状态 | 证据 |
|---|---|---|
| 同内核族渲染 | WorkBuddy = Electron/Chromium;Ygent = Tauri/WebView2(Edge Chromium)。CSS 盒模型与亚像素布局算法同源 | `AGENTS.md` 原生渲染调试约束 |
| 双端真实 CDP 对标通道 | 本机回环:WB 9223 / Ygent 9335 | `docs/workbuddy-cdp.md`、`ygent-debug.md` |
| 读真实计算值与字库 | `getComputedStyle`、`getBoundingClientRect`、`CSS.getPlatformFontsForNode` | `ygent-workbuddy-render-audit-2026-10-08.md` §采集条件和坐标 |
| 同条件可比 | 固定窗口/视口、DPR、字号档位、同会话位置、展开状态;用 `dy`(相对头像行)排除历史高度差 | 同上 |
| 误差口径已定义 | 关键几何允许 ≤1px 取整误差;缺失结构/入口**不按像素误差豁免** | 同上 §修复顺序与完成标准 |
| 字库已匹配 | `--yg-font-sans` 显式加入 Noto Sans SC;终端 Courier New;名称 Arial Bold;六档 108 组字号/行高一致 | `ygent-font-parity.md` |
---
## 2. 已经达到像素级的实测样例(不是空谈)
| 元素 | 两端共同值 |
|---|---|
| 正文列 | x359、w752、右边 1111 |
| 命令结果面板 | w752、内容 720、圆角 16、padding 12×16、高 198.75 |
| 用户气泡外壳 | 355.15625×44.59375(未硬编码,由内层文字推出) |
| 输入外框 | (348,592,784,134)、1px #e6e6e6、圆角 24、同双层阴影 |
| 发送按钮外框 | (1087,681,32,32) |
| 头像行 | x359、头像 24×24、名称 x393、gap 10 |
| 六档字号/行高 | 108 组全部一致;18 组几何一致 |
| 删除确认浮层 | 240×166,圆角/边框/双层阴影/按钮尺寸匹配 |
| 路径标签 | 68.25×20、15px/22.5、padding 1px 4px、图标 15×15 |
---
## 3. 不可对齐 / 只能部分对齐清单(按原因分类)
### A. 渲染引擎层(少量,需逐项适配)
- WebView2 的 Edge Chromium 版本与 Electron 内置 Chromium 版本不同 → 默认 UA 样式、原生滚动条伪元素、字体回退顺序可能不同。
- 实证差异:滚动条 D39(WB 宽 6 / thumb 黑 20% vs Ygent 宽 10 / 蓝灰 14%)、D40(滚动条上下端小三角 `pseudo display` 不同)。
- 结论:**绝大多数元素可在 1px 内对齐,少数宿主原生控件需专项处理**,不能机械复制 `display` 值。
### B. 字库层
- 本机已匹配,但 `ygent-font-parity.md` 明确:**字库是本机已安装系统字体,未复制进项目,其他机器缺少会回退** → 跨机器像素一致不成立。
- 要对齐跨机器:可打包 Noto Sans SC(OFL 许可允许再分发);**但 Courier New 属微软系统字体,不可再分发**,只能依赖系统存在。
### C. 宿主结构层(不可消除)
- **X01 顶栏**:WB 菜单+全局图标(主顶栏 y30 h56)vs Ygent 品牌标题栏(y46 h40)——宿主 chrome 不同。但内部对话标题/五按钮坐标已一致,**不应为复制菜单破坏这些坐标**。
- **X03 侧栏项目层级**:WB「项目→子项」vs Ygent 独立任务,同时含层级、导入归属和不同列表数据 → **不能硬移整个侧栏**。
### D. 数据与功能缺失层(必须先有数据,不是调 CSS)
以下不是像素偏移,而是**结构/数据缺失**:
- D25「深度思考」收起行 —— 需要 reasoning 事件数据。
- D29「查看所有产物(5)」入口 —— 需要真实回合产物关联与计数。
- D30 助手操作栏整行(复制/赞/踩/朗读/重试/分享 + 消耗/模型/时间)—— 需要真实消耗与模型元数据。
项目明确"不伪造消耗/模型数据或放无效按钮"。**补齐数据来源后才谈对齐;在此之前任何"像素级"都是假的。**
### E. 平台商业与品牌资产层(按约定不应复制)
- **X04 左下**:WB 邀请卡/账号区 vs Ygent 设置/收起侧栏 → 平台商业体系,不默认复制。
- **品牌偏离(有意为之)**:Ygent 名称与图标、对话页品牌渐变背景、品牌蓝发送按钮 —— 均为用户要求的偏离,`ygent-chat-stage-summary-2026-10-08.md` 明确"不计作 WorkBuddy 白底的逐像素一致性验收"。
- **图标资产**:现有 SVG 路径是逆向取值的 WB 图标(D08 分享箭头、D09 概览、D37 纸飞机仍有图形差),照搬其品牌资产涉及资产许可,建议自绘。
---
## 4. 真正的难点不是像素,而是动态交互
项目已定:**静态画面通过 ≠ 流式通过**(`ygent-chat-interaction-parity.md`)。像素级达标不解决以下问题,未完成项:
| 编号 | 未完成项 | 通过条件 |
|---|---|---|
| S01/S02/S06 | 正文分块、工具 start/update/end、取消与迟到事件 | 真实 OMP 隔离会话双端动态链路 |
| S04 | 自动折叠触发时机与活动回合资格 | 按事件采集双端**时间序列**,不能比终态截图 |
| S05 | 滚动跟随与阅读锚点 | 贴底跟随、上翻不拉回、回底恢复,记录 scrollTop/scrollHeight |
| S07 | 公开思考/等待/错误阶段 | 不伪造内部推理、模型或消耗元数据 |
另:"同输入"无法要求 token 级墙钟一致,只能比较**对应事件后的显示位置、块顺序、更新方式、折叠、滚动和操作反馈**。
---
## 5. 建议的分级目标
| 级别 | 目标 | 可行性 |
|---|---|---|
| L1 几何对齐 | 同视口/同字号/同展开状态下关键锚点与尺寸 ≤1px 取整误差;字库匹配 | ✅ 对话区已基本达成,可继续收敛外围 |
| L2 静态像素对齐 | L1 + 全部可见元素(图标路径、颜色、阴影、滚动条)一致 | ⚠️ 可达 90%+;宿主原生控件与品牌偏离项除外 |
| L3 动态交互一致 | 事件序列、折叠时机、滚动、取消/恢复与 WB 同步 | ⏳ 未完成,**这才是真正目标** |
| L4 全局 100% 像素一致 | 含宿主 chrome、平台入口、跨机器字形 | ❌ 不可能,也不建议 |
---
## 6. 需要明确的一个取舍
项目当前定位是「**对标布局与交互,但保留 Ygent 品牌**」:名称/头像/背景/按钮色已按用户要求偏离 WB。若坚持"像素级",需二选一:
- **选项 A(推荐,即现状方向)**:对齐到 L1 + L2 的**结构与几何**,保留 Ygent 品牌视觉;后续追加收敛图标路径、滚动条、剩余间距与缺失结构。
- **选项 B**:连品牌视觉也照搬 WB(白底、WB 图标、WB 名称)→ 与既有产品决策冲突,且涉及资产许可,需单独确认。
---
## 7. 不做的事
- 不为对齐硬补高度(如 D26 的 45.77px)。
- 不伪造消耗/模型/产物计数以凑齐视觉。
- 不复制平台商业入口与无效操作卡片。
- 不把任一端的绝对 y 差直接当作需要修复的 margin。
- 不把静态像素通过宣称为动态交互通过。
@@ -0,0 +1,165 @@
# Ygent 与 WorkBuddy AI 实现对比及可实施项
日期:2026-10-14
对比对象:[WorkBuddy-AI-实现分析报告](WorkBuddy-AI-实现分析报告.md)(对该报告所述 WorkBuddy 桌面版能力的静态逆向结论)× Ygent 代码库实际实现
状态说明:本文是**差距分析 + 可实施项评估**,不是实施方案,也不改动任何既有交付承诺。文中"已实现"以代码为据(附文件路径);`docs/*.md` 与 `AGENTS.md` 的目标描述不计为已实现。
---
## 0. 结论速览
1. **两者不是同类产品,不能逐项对齐。** WorkBuddy 是「自带 Agent 内核 + 云端多模型网关 + 自研 OS 沙盒」的一体化商业桌面端;Ygent 是「接入外部内核(OMP)+ 用户自带渠道(BYO Key)+ 宿主权限治理」的可控桌面端。**内核不是自己的**,这是最大的结构性差异。
2. **Ygent 在六个方向的实现深度已超过 WorkBuddy**(团队/岗位 80+ 表、项目任务、资料库版本化、A2A 协作预算、LSP 自管、grants+审计),这些**不需要对齐**,属于反向优势。
3. **真正值得补的差距集中在宿主层,且大部分不需要碰内核**:进程治理、删除安全、循环防护、预热、少量高频工具缺口、内置连接器预设。这批属于**低风险可直接做**。
4. **唯一的大工程差距是 OS 级沙盒**(WorkBuddy 的 tsbx + shim 双层),但当前用户取向(2026-10-12「给全部的授权,现阶段不考虑在现实上做这么多工作」)与重型限制机制相反,**不建议现在做**,继续如实声明"规则隔离不是沙盒"。
5. 报告本身是静态逆向,**提示词全文、服务端模型路由、鉴权细节本地不可见**,不能当作实现规格照抄。
---
## 1. 逐层对比
### 1.1 整体架构
| 层 | WorkBuddy(报告) | Ygent(实测) | 判定 |
|---|---|---|---|
| 桌面壳 | Electron + app.asar,含 workbuddy-editor-sdk(Office 编辑)、baas-v2 | Tauri 2 + React 18 + zustand 5(`package.json`) | **等价不同技术**,无需改造 |
| UI↔引擎协议 | ACP(`@agentclientprotocol/sdk`),本地 HTTP `/api/v1/acp` | 自研 NDJSON RPC over stdin/stdout(`src-tauri/src/sidecar.rs:448-489, 667-726`) | 能力等价;除非要接第三方 UI,否则不必换 ACP |
| Agent 内核 | 自带 `@genie/agent-cli`(Claude Code 血统,9.4MB bundle + 66 懒加载分块) | 外部 `omp-*-pc-windows-msvc.exe`,`--mode rpc-ui`(`sidecar.rs:506-544, 647`) | **结构性差异**:内核非自有 |
| 模型接入 | 云端网关 `/plugin` 前缀 + Bearer + `X-User-Id`,服务端路由 | 用户渠道表 + 直连 OpenAI 兼容 / Responses / Anthropic Messages / Gemini(`commands/channel.rs`, `llm.rs`) | **BYO 渠道 vs 服务端托管**,各有取舍 |
### 1.2 内核与循环
| 项 | WorkBuddy | Ygent | 可实施性 |
|---|---|---|---|
| 循环原语 | `@openai/agents` + 自研 genie 工作区包 | 由 OMP 提供,宿主不自建循环 | ❌ 不建议(违反"不创建第二套聊天内核"约定) |
| 死循环防护 | `CBC_LOOP_GUARD_CONSECUTIVE_THRESHOLD` / `_SEQUENCE_REPEATS` / `_DISABLED` | **未见实现** | ✅ 可在宿主对工具名/参数序列做重复检测 |
| 进程守护 | `daemon-supervisor.cjs` + `windows-job.cjs`(Job Object 绑子进程树) | 仅 `buildtest/process_windows.rs:86-290` 用 Job Object(构建进程强杀),OMP 子进程未绑定 | ✅ 低成本高收益 |
| 启动预热 | `cbc-prewarm`、`preload-lazy-chunks` | 有空闲回收 `trim_idle_processes(8)`(`collaboration_runtime.rs:263`),**无启动预热** | ✅ 可补 |
| 低内存模式 | `codebuddy-lowmem`(RSS 阈值触发 heap snapshot) | 无 | ⚠️ 可选,Node 内核才有意义 |
### 1.3 工具系统
Ygent 的工具体系**不是更少,而是不同**:宿主侧有 `ygent_*`、`library_*`、`experience_*`、`collaboration_*`、`project_tasks_*`、以及大批 `team_*`(`team/*.rs`),前端标签字典 `src/lib/toolSummaryRules.ts` 头部注释标明「verified against installed WorkBuddy 5.7.6」——**字典里有 WorkBuddy 工具名,但后端并不产出**。
后端**确证缺失**的 WorkBuddy 侧高频工具:
- 联网:`web_search`、`web_fetch`
- 规划:`enter_plan_mode` / `exit_plan_mode` / `plan_*`
- 待办:`todo_write`
- 交互:`ask_followup_question`(Ygent 有 `questions.rs` 问答机制,但非同名工具体系)
- 可视化:`visualize:show_widget`、`widget_guidelines`(前端 `turnFold.ts:91-95` 能识别 widget 渲染,后端不产出)
- 多媒体:`image_gen`(Ygent 完全无多媒体生成)
- 静态检查:`read_lints`(Ygent 已有 LSP 自管 + `ygent_code_analysis`,基础具备)
- MCP 侧:`mcp_call_tool` / `mcp_get_tool_description` / `fetch_mcp_resource`
- 集成:`call_*_integration`、`automation_update`
文件类工具靠 OMP 原生 `read/write/edit/bash/grep/glob` 替代(`sidecar.rs:596`),**命名与 WorkBuddy 不同**,但功能覆盖。
### 1.4 模型层
| 项 | WorkBuddy | Ygent |
|---|---|---|
| 推理位置 | 云端网关(本地不推理) | 用户渠道直连(`llm.rs` 真流式 SSE) |
| 协议 | OpenAI 兼容 `/chat/completions` + SSE | OpenAI 兼容 + Responses + Anthropic Messages + Gemini(`ygent-model-metadata-plan.md`) |
| 降级/回退 | 有降级标记(如 `deepseek_flash_unavailable`) | 未见渠道级降级/回退路由 |
| 多模态 | ASR(`wb-asr` / `gpt-4o-mini-transcribe`)、图像生成/编辑(`hunyuan-image-*`) | **无多媒体生成** |
### 1.5 沙盒与安全(**最大差距**)
| 层 | WorkBuddy | Ygent | 判定 |
|---|---|---|---|
| 策略/审批 | `@anthropic-ai/sandbox-runtime` + 权限提升桥 | 审批网关:内核恒 `--approval-mode always-ask`,宿主决定放行/弹卡(`sidecar.rs:648-650`) | ✅ 已有 |
| 执行层沙盒 | 腾讯自研 `tsbx.dll` + `sandbox-center.exe` + `betterleaks.exe` + `tsbxldr.dll` | **无 OS 级沙盒**(无 seccomp/AppContainer/文件系统隔离) | ❌ 大工程 |
| Shim 层 | `brokered-fs-shim`(fs 走 broker IPC)、`sitecustomize.py`、**`safe-delete`(删除进回收站 `GENIE_TRASH_DIR` + bulk-guard)**、`brokered-bin` 白名单命令目录 | 无 | ✅ **safe-delete 与命令白名单可移植** |
| 授权模型 | 会话/账号级 | `grants` 表白名单(`fnv1a(method\|title)` 哈希)+ `audit_log` + 完全访问 + 经理只读白名单(`omp.rs:318-341`, `approval.rs:54-118`) | Ygent 更细 |
### 1.6 扩展体系
| 项 | WorkBuddy | Ygent | 缺口 |
|---|---|---|---|
| MCP | `@modelcontextprotocol/sdk` 1.29.0,配置文件驱动 | stdio + Streamable HTTP 自研(`connectors/client.rs`),协议协商 `2025-11-25→2024-11-05`,凭证进 Windows 保险库(`connectors/vault.rs`) | OAuth、SSE、CLI 适配器、resources/prompts、市场 |
| Skills | SKILL.md(兼容 Anthropic Agent Skills) | SKILL.md 按需 `ygent_load_skill(id)`,SHA256 摘要 + 回合冻结快照 | ZIP/Git/市场导入 |
| 专家 Expert | 专家包(plugin.json + agents/*.md)、专家团 | **无独立专家概念**:「专家」tab 实为团队岗位(`TeamRolePane.tsx`, `CapabilityCenter.tsx:41`) | P3 专家闭环待实现(方案 §9 已列) |
| A2A | `@a2a-js/sdk` | 自研 collaboration 体系 + 80+ `team_*` 表,含预算/取消/恢复 | **Ygent 更强** |
| IM 渠道 | `/api/v1/channels/wechat\|wecom` + 客服/群机器人 API | 无(`channels` 表是模型渠道,非 IM) | 可做,依赖连接器可用 |
### 1.7 部署与治理
| 项 | WorkBuddy | Ygent |
|---|---|---|
| 部署变体 | `product.json` 四变体(cloudhosted/selfhosted/ioa/internal),`ACC_PRODUCT_CONFIG_V2/V3` | 无(单机桌面) |
| 认证 | 腾讯云账号 + Bearer + `X-User-Id` | 本机,无账号体系 |
| 可观测 | `@tencent/galileo-node-sdk` + OpenTelemetry `/v1/traces` | `audit_log` 表;无 OTEL |
| 资源分发 | COS 加速桶 | 本地 |
---
## 2. 可实现清单(按成本分档)
### A 档:宿主层、低风险、可直接做(不碰内核协议)
| # | 事项 | 依据/落点 | 收益 | 前置 |
|---|---|---|---|---|
| A1 | **OMP 子进程纳入 Windows Job Object**,进程退出时回收整棵子进程树 | 对标 `windows-job.cjs`;现 `sidecar.rs` 启动 OMP 未绑定 Job | 异常退出/崩溃不再残留 OMP 进程 | 无 |
| A2 | **safe-delete:删除类操作进回收站 + 批量删除 guard** | 对标 shim `safe-delete` + `GENIE_TRASH_DIR` + bulk-guard;Ygent 完全无 | 直接降低误删不可逆损失 | 需用户确认(见 §4) |
| A3 | **危险命令 / 危险路径黑名单拦截**(宿主 Shell 工具包装层) | 对标 `brokered-bin` 白名单;Ygent 有 grants 但无命令级策略 | 挡住高危命令 | 需用户确认 |
| A4 | **工具调用死循环检测**(同名+同参序列阈值告警/中断) | 对标 `CBC_LOOP_GUARD_*`;Ygent 无 | 省 token、防卡死 | 无 |
| A5 | **内核启动预热**(新对话页提前拉起/复用内核) | 对标 `cbc-prewarm`;Ygent 有回收无预热 | 缩短首字延迟 | 无 |
| A6 | 补 **`read_lints`**(复用已有 LSP + `ygent_code_analysis`) | `lsp/*.rs`, `code_analysis.rs` 基础设施已具备 | 近乎白送的工具补齐 | 无 |
| A7 | 补 **`web_fetch` / `web_search`**(可基于内置浏览器或直连 fetch) | 对标 WB 同名工具;Ygent 有 `ygent_browser` 可复用 | 联网研究类任务能力 | 需授权策略 |
| A8 | 内置 **连接器预设扩充**(现仅 GitHub / DeepWiki) | `connectors/presets.rs:17-33` | 降低接入门槛 | 无 |
| A9 | **前后端工具名对齐**:把 `toolSummaryRules.ts` 里已有但后端不产出的名字清点,避免"能渲染但不产出"的错位 | `src/lib/toolSummaryRules.ts` vs `sidecar.rs:973-1004` | 消除认知错位 | 无 |
### B 档:中等成本,需设计与验收
| # | 事项 | 说明 |
|---|---|---|
| B1 | **多媒体生成接入**:文生图 / 图生视频 / 音频转写,走现有渠道体系 | Ygent 目前**零多媒体生成**,是明显功能空白;参考 WB 的 `image_gen`、`AudioTranscribe` |
| B2 | **专家(Expert)闭环 P3** | 方案 §9 已定;导入 WorkBuddy `.codebuddy-plugin/plugin.json` + `agents/*.md` 到 Ygent 模型(映射表见方案 §5)。当前"专家 tab = 团队岗位"需明确区分 |
| B3 | **MCP 增强**:OAuth 授权流、CLI 连接器适配、`resources`/`prompts` 读取、`mcp_get_tool_description` 等价工具 | 现只支持 stdio + Streamable HTTP,无 OAuth/SSE/CLI |
| B4 | **渠道级降级/回退路由** | 对标 WB 的降级标记(如 `deepseek_flash_unavailable`) |
| B5 | **非完全访问时把 `write`/`edit` 纳入 cwd 范围校验** | 目前经理有只读路径校验(`approval.rs:95-118`),普通会话主要靠审批网关 |
| B6 | **结构化 trace / OpenTelemetry 导出** | 在 `audit_log` 与已有渲染性能诊断之上,便于定位渲染长任务 |
| B7 | **IM 渠道接入**(企业微信/微信机器人) | 依赖连接器可用;当前会话企业微信连接器为关闭状态 |
### C 档:大工程 / 不建议现在做
| # | 事项 | 不建议理由 |
|---|---|---|
| C1 | **OS 级沙盒**(tsbx 等价物) | Windows 需文件过滤驱动/内核态组件,成本极高;且与用户 2026-10-12「不做这么多现实工作」的取向相反。建议**保持规则隔离 + 审批 + 审计**,继续如实声明"不是沙盒"(`ygent-team-integration.md:91`) |
| C2 | 自建 agent 循环 / 换自研内核 | 违反"不创建第二套聊天内核"约定,收益低 |
| C3 | 改用 ACP 协议 | 现 NDJSON RPC 已满足;除非要接第三方 UI 或多内核 |
| C4 | 市场 / 云同步 / 多设备 / 云资产 | 方案 §9 已列为后续,不在首期 |
| C5 | 产品四变体配置 | 单机桌面场景价值低 |
| C6 | 遥测上报(galileo 类) | 涉及隐私,桌面版不建议引入 |
---
## 3. 反向优势(Ygent 已超 WorkBuddy,不需要对齐)
- **团队 / 岗位**:80+ `team_*` 表,覆盖成员、岗位、计划、执行、复核、产出、恢复、调度(`team/*.rs`, `TeamOffice.tsx`)。
- **项目任务**:版本化任务、验收/复核/续跑(`project_tasks.rs`, `ProjectTasks.tsx`)。
- **资料库**:版本化物料 + 冻结引用 + 经验沉淀(`library.rs`, `knowledge.rs`);P0/P1 已接入。
- **A2A 协作**:自研调度器 + 因果预算 + 取消归属 + `agent_live`/`agent_replay` 重放(`collaboration_runtime.rs`)。
- **权限治理**:`grants` 白名单 + `audit_log` + 经理只读白名单 + 员工分级冻结,层次比报告所述更细。
- **LSP / 代码分析**:宿主自管 LSP 生命周期,禁用 OMP 原生 LSP(`lib.rs:78-94`)。
---
## 4. 前置条件与冲突提醒
1. **内核范围**:`AGENTS.md` 明确"当前只使用 OMP 内核""Codex 内核适配和验收暂不纳入本轮"。涉及内核的改动只按 OMP 验收。
2. **授权取向冲突(重要)**:用户 2026-10-12 明确"给全部的授权,现阶段不考虑在现实上做这么多工作",取代了逐工具授权方案。⇒ **A2 / A3(删除回收站、命令黑名单)属于新增限制性机制**,与"完全访问不逐次确认"的当前取向存在张力,**实施前必须与用户确认**。A1 / A4 / A5 / A6 / A8 / A9 与授权无关,可直接做。
3. **报告不可当规格**:报告为纯静态逆向,提示词全文、服务端模型路由、鉴权细节本地不可见(报告 §9 自述);tsbx 内部行为、`product.json` 变体语义均无字节级证据。**只参考其架构分层与机制存在性,不照抄实现细节**。
4. **不虚构能力**:本文 A 档各项均为"可实施",**不代表已实现**;落地时仍需按各域既有 SOP 完成真实验收(不支持项继续如实标注)。
5. **不引入 WorkBuddy 数据依赖**:任何导入格式兼容都是配置适配,不写其他软件的配置、不复制其凭证。
---
## 5. 建议的下一步
1. 先确认 §4.2 的授权取向:**是否允许新增删除回收站 / 命令黑名单这类限制机制**。
2. 若允许,按 A1 → A2/A3 → A4 → A5 → A6/A8/A9 顺序落地(A1 无争议可先做)。
3. B 档单独立项:建议先做 **B1(多媒体)** 或 **B2(专家 P3)**,前者是功能空白、用户可感知,后者方案已定稿。
4. C 档维持"不做",在相关文档中继续如实声明现有局限。
@@ -0,0 +1,209 @@
# Ygent ↔ WorkBuddy 原生渲染精确差异清单(2026-10-08)
> 阶段收尾与当前实现状态见[进度汇总](ygent-chat-stage-summary-2026-10-08.md)。下文40项为历史采集基线,不是当前未完成数量;后续通用样式、字体、完整时间线/锚点折叠及动作摘要修复以动态记录为准。
> 对标范围已明确包含真实流式交互。动态P0、必测事件序列和证据分级见 [动态交互对标清单](ygent-chat-interaction-parity.md)。本文件的历史画面通过不等价于流式通过。
> 后续过程修复:真实原生1335×916、DPR1、默认2档下,D11—D13、D16、D18—D20、D28、D31已修复并检查折叠往返;D15的尺寸/位置/颜色及D17文字色已对齐,图标path形状仍需核验。首命令面板dy227.25、752×198.75已匹配,D23通过此状态复测。最终正文仍因缺少reasoning及其包装留白提前48.25px,D25—D26未完成;不能硬补高度。详细结果见动态清单中的“当前已验证的局部交互”。
> 后续字体修复:[字体对齐验收](ygent-font-parity.md)。D01—D05、D14、D21—D24、D27、D32—D33涉及的字体/行高/文字行框已处理;此处40项保留为修复前基线,不能把其他层级、间距和操作栏缺失视为已修复。D23面板总高另需随着后续层级调整复测。
本轮确认 **40项对话区渲染、结构及折叠差异**,另列 **4项外围差异、5项源码交互缺口、15项待验收场景**。这是已检查范围的清单,不是整个产品缺口总数。仅梳理、采集和定位,本轮没有修改对话区实现。P0优先恢复当前同一对话的形态和交互,P1收敛细节,外围与复杂交互后置。
## 采集条件和坐标
- 均为真实原生渲染器:WorkBuddy CDP 9223,Ygent Tauri WebView2 CDP 9335。没有模拟IPC或fixture。
- 同一“处理大文件”对话,锚点为移动项目请求后的最后一个取消回合。YG真实会话5,829条消息。
- WB原视口1200×762,临时调整YG真实窗口到相同视口;DPR均1、scale均1、字号均默认2档。
- A:过程收起;B:过程展开,首个运行命令和意图结果展开。等待动画稳定并贴底后采集。没有发送消息、执行工具、读取或展开深度思考正文。
- `(x,y,w,h)`为页面视口CSS px;`dy`为元素顶部减头像行顶部,用于排除不同历史高度和滚动位置。负y表示在滚动区域上方,不表示CSS错误。
- A头像行:WB y267.98,YG y322.69;B头像行:WB y-40.02,YG y52.69。两端均贴底;不能把绝对y差直接当作需要修复的margin。
- 字体通过`CSS.getPlatformFontsForNode`检查实际命中字库,不只读取font-family。数值保留两位小数,0.1px以内取整不单列缺陷。
- [整理后的几何、样式、字体证据](reference/workbuddy/render-audit-2026-10-08.json)。原始DOM和截图保存在私有目录`C:\Users\Administrator\.ygent\imports\render-audit-20261008`,不入库。
- 主比较为1200×762;YG1335×916已单独采集,但WB1335同条件比较未完成,不将结论外推到所有尺寸。
## 需要纠正的历史判断
WB用户气泡外层声明13px,内部Slate实际文字是15px;输入容器声明14px,内层编辑器实际也是15px。此前仅看外层得到的规格不能继续作为验收目标。YG“过程消息”最终级联命中13px,即便某条源码规则已写参照值也不能算通过。
## D01—D10:字体、用户气泡和顶栏
| ID/优先级 | 具体位置 | WorkBuddy实测 | Ygent实测 | 差异、目标与代码定位 |
| --- | --- | --- | --- | --- |
| D01 P0 | 助手中文正文`.cr-markdown p`↔`.md p`;对话标题 | 实际Noto Sans SC,强调使用Bold | 实际Microsoft YaHei,强调使用Bold | 同字号仍有字形/笔画/行框差。先匹配字库和回退;`src/styles/tokens.css:78` |
| D02 P1 | 头像右侧名称,x393 | Arial Bold,14px/24.5px,宽78.31 | Segoe UI Semibold,14px/24.5px,宽74.67 | 文字短3.64px;头像和10px间距已一致,不能扩大整个头像行;`.assistant-name` |
| D03 P0 | 命令/结果灰面板英文,x375,内容宽720 | Courier New,中文回退NSimSun | Consolas,中文回退NSimSun | 等宽字库不同导致换行字符不同;`src/styles/chat.css:763`、`:775` |
| D04 P0 | 最新用户气泡的内部实际文字 | Slate15px/26.25px,内部p15px/26.7px | `.msg.me .txt`13px/19px | 少2px;不能以WB外层13px为参照;`src/styles/chat.css:436` |
| D05 P0 | 最新用户气泡,右边均x1111 | x755.84、w355.16、h44.59 | x800、w311、h35 | 左边向右缩44.16、高度少9.59;padding8×12、底色/圆角已一致。修内层文字,不写死355.16宽度 |
| D06 P1 | 左上“处理大文件”,(304,46),h24 | 黑色rgb(0,0,0) | rgb(31,35,40) | 坐标/16px字号/24px行高一致,颜色冷灰;`.chat-title` |
| D07 P1 | 顶栏五按钮,x1012/1048/1084/1120/1156,y42,32×32 | 黑70% | #5b6472 | 坐标都一致,颜色偏蓝灰;不能再整体平移按钮组 |
| D08 P1 | 第二个分享按钮,(1048,42) | 弯曲分享箭头 | 从托盘向上导出箭头 | 图形不同,应核对SVG/path;`src/components/ChatView.tsx:464` |
| D09 P1 | 第四个概览按钮,(1120,42) | 纸张/文档轮廓 | 四块网格 | 外框一致,内部图形不同;`ChatView.tsx:485` |
| D10 P1 | 对话标题旁的编辑入口 | 有“编辑标题”按钮,默认隐藏 | h1只有文字,无对应按钮 | 侧栏重命名不等价;已确认DOM缺失,hover后坐标待验收 |
## 路径标签及思考事件位置补齐(2026-10-08)
通用Markdown行内代码组件根据真实路径关联渲染文件/目录标签,其他代码不变。普通会话在自身工作目录下通过IPC只读分类;参照导入保留来源cwd下核实的路径关联。原生YG/WB同一`ygent`标签68.25×20、字号15/行高22.5、padding1px 4px、颜色#1470b4、背景#e9eef2、文件夹图标15×15已匹配;非按名字直接装饰的静态标签。标签键盘/点击接实际opener,未在参照采集中自动打开外部应用。
导入旧规则丢弃全部reasoning事件,现只保存存在和位置标记,不提取内部正文;相邻可见消息前通过通用组件呈现“深度思考”。标题15px/26.25px、灰色、包装padding2px 0。此为D25的数据/标题部分补齐,内容展开、真实思考流式阶段及D26上下层间距尚未通过,不能将标题出现等同于reasoning交互完整。
普通会话和参照会话共用TurnBlock/ToolCard/Markdown;本次工具摘要跨会话原生样式一致。仍需覆盖普通完成、单/多工具、特殊取消的分组标题、默认折叠和块间距,禁止按参照会话名称/ID加样式补丁。
## 失败命令显示规则修正(2026-10-08)
用户补充同一“检查目标位置与源目录”失败命令截图后,真实WorkBuddy CDP确认:外层“运行命令”摘要使用14px灰色终端图标,不因失败替换红叉;下方意图行`.cr-tool-head__icon--error`使用14px灰色圆形感叹号。失败数据与视觉位置独立,不能由Ygent自身的红叉规则推断参考行为。Ygent现保留toolError数据,按这一分层显示;终端图标/失败图标/箭头使用当前原生DOM核实的向量路径。
长结果面板宽752、高300、padding12px 16px,10px滚动条使文本可用宽710。命令12px/19.2px、输出12px/18px,pre-wrap且word-break:break-all。之前Ygent默认滚动条和overflow-wrap:anywhere导致长命令断行不同,现已修正。输出还遗漏非零Exit Code对应的`执行失败 (退出码: 1)`末行,已恢复。真实Ygent/CDP下同一命令高度95.9375、输出756,与WB一致;完整可见输出文本比较相同。
此结果覆盖该失败命令的局部显示,不代表整段完成:截图中的“深度思考”、路径标签及上层布局仍在原有待办中;未伪造推理内容。其他工具类别、运行中/取消/信号终止的图标策略仍须分别验证。此前补验中“失败红叉保留”仅是当时YG状态,以上修正取代该视觉规则。
## 取消历史工具样式补验(2026-10-08)
此前D20等工具样式修复只限定在`.process-fold`,遗漏了“已取消”展开后的`.turn-history`:同一ToolCard上方仍为2px竖线、4px左缩进、摘要负margin和蓝灰文字,下方已使用无边框的中性灰样式。现将共同规则移至基础`.tool`,移除父容器限定覆盖,历史/过程/实时回合共享基础外观;失败红叉与运行中状态独立保留。
真实Ygent WebView2、1335×916下,已核验同一取消回合中的5条历史命令和1条过程命令:边框/左缩进/摘要margin均为0,文字rgba(0,0,0,0.5)、15px/26.25px;逐条展开意图和结果,详情上间距4px,结果面板宽752px、padding12px 16px、左边缘对齐。2条失败命令仍保留红色状态图标。操作后恢复各工具原有展开状态;未发送消息或执行命令。这是Ygent两条渲染路径的一致性补验,未据此新增WorkBuddy失败图标或实时状态验收结论。
## D11—D20:回合间距、过程标题和工具层级
| ID/优先级 | 具体位置 | WorkBuddy | Ygent | 差异与代码定位 |
| --- | --- | --- | --- | --- |
| D11 P0 | 头像行底→取消耗时行顶 | 12px;状态dy36.5 | 16px;状态dy40.5 | 下移4;头像margin12又叠加msg gap4;`.assistant-header`、`.msg` |
| D12 P0 | 状态行底→首段正文顶 | 12px | 8px | 少4,抵消D11,所以首段dy都74.75;不能只看首段坐标;`.turn-body`与WB文本块margin |
| D13 P0 | 首段正文底→过程消息顶 | 12px;过程dy140.25 | 8px;过程dy136.25 | 过程标题相对头像提前4;统一gap不能模拟所有局部间距 |
| D14 P0 | “过程消息”标题 | 15px/26.25px,文字宽60;点击行76×26.25 | 13px/20.8px,文字宽52;点击行80×26.80 | 文字小2px但按钮反而更宽;`src/styles/chat.css:845`、`.mf-label` |
| D15 P1 | 过程标题右侧箭头 | x423,12×12,黑50% | x419,14×14,#8a93a3 | 左移4、变大2,颜色/线形不同;`.mf-arrow`,连同标题字号/gap/padding修复 |
| D16 P0 | 过程标题底→运行命令顶(B) | 2px;命令dy168.50 | 8px;命令dy171.05 | 命令相对头像晚2.55;需process-inner局部padding;`.mf-body` |
| D17 P1 | 运行命令文字、意图和终端图标 | 黑50% | #5b6472 | 整体偏蓝灰;摘要15px/26.25已一致;`.fn`、`.tool-intent`、`.tool-ico.command` |
| D18 P0 | 意图“切换工作目录后重试移动”左侧 | x359有独立14px终端图标,文字x381 | 文字x381,但本层图标缺失 | 不是第一层运行命令图标能代替;`TurnBlock.tsx:190` |
| D19 P0 | 工具意图及邻近右箭头 | 独立可点击/折叠;文字宽154,标题主区192,有箭头 | `.tool-intent`普通div,宽730,无箭头/折叠 | WB“过程→运行命令→意图→结果”,YG少一层;需结构和状态共同补齐 |
| D20 P0 | 展开工具左边x≈359 | 无贯穿意图/面板的竖线 | 旧工具卡border-left仍形成竖线 | 检查`.tool`border-left/padding和`.tool-row`负margin,不能用白色遮盖 |
## D21—D31:命令结果、深度思考和回合尾部
| ID/优先级 | 具体位置 | WorkBuddy | Ygent | 差异与代码定位 |
| --- | --- | --- | --- | --- |
| D21 P0 | 灰面板命令结束→stdout | 独立`__command`与`__output`,块间4px | 一个pre拼接命令/输出 | 缺分块,无法独立设行高;`formatToolResult`、`ToolCard` |
| D22 P0 | stdout正文,WB(x375,y283.98)(B) | 12px/18px,当前5行高90 | 同命令共用12px/19.2px | 每行多1.2;命令本身19.2已一致,不应全部改18 |
| D23 P1 | 命令灰面板(B),x359,w752 | h198.75,dy227.25 | h200.69,dy231.80 | 高多1.94,顶部晚4.55;圆角16、padding12×16、内容宽720已对齐,不写死高度 |
| D24 P1 | bash标签与代码文字 | 黑90% | #1f2328 | 冷灰字色;背景同为#f2f2f2,不再调整背景 |
| D25 P0 | 结果面板后、最终正文前(B) | reasoning外框h30.25、dy440;标题dy442,15px/26.25 | 整段缺失 | 缺“深度思考”收起行;normalized数据未映射该段,需要数据/时间线联合处理。本轮未读取正文 |
| D26 P0 | 过程组底→最终正文(B) | 12px,最终正文dy486.25 | 8px,最终正文dy440.48 | 最终正文提前45.77,含D25及过程高度差;不能硬加45.77margin |
| D27 P0 | “用户已取消” | 15px/20px,内容宽75 | 13px/20.15px,外框拉伸752 | 少2px且渲染类型不同;`chat.css:527`、`TurnBlock.tsx:471` |
| D28 P0 | 最终正文底→取消提示 | 0px | 8px | YG多统一gap;需取消状态局部规则,不能清零所有回合间距 |
| D29 P0 | 取消提示下所有产物入口 | x359;B y504.48,129.83×25,15px/25,“查看所有产物(5)” | 无本回合尾部入口 | 顶栏概览不等价;需真实回合产物关联和计数,不硬编码5 |
| D30 P0 | 所有产物下助手操作栏 | B(359,537.48,547.59,38.25);复制/赞/踩/朗读/重试/分享/更多,消耗/模型/时间 | 助手回合整行缺失;MessageToolbar只用于用户 | 缺整行,不是像素偏移;入口、排列和后台能力分别验收,不伪造消耗/模型数据或放无效按钮 |
| D31 P1 | 关闭过程再重新展开 | 本轮首命令/意图展开状态保留 | ToolCard卸载后open重置false | 相同点击看见不同内容;本轮往返操作与useState/条件挂载已确认;需状态存放策略 |
## D32—D40:输入编辑区、提示和滚动条
| ID/优先级 | 具体位置 | WorkBuddy | Ygent | 差异与代码定位 |
| --- | --- | --- | --- | --- |
| D32 P0 | 输入实际文字,左上(365,605) | Slate15px/26.25;空p高28.38 | textarea14px/21 | 少1px、行高少5.25;外框64px一致不代表文字一致;`chat.css:1105` |
| D33 P1 | 输入占位 | 实体span15px/26.25,黑90%×opacity.5 | ::placeholder14px/21,黑40% | 字号见D32;深浅不同;YG问号与@之间多一个空格;Composer placeholder |
| D34 P1 | 权限项文字及警告图标 | 文字(x429,y687,h20),#b42c3f,13px/20;盾牌感轮廓 | (x430,y688.5,h17),#d5304f,13px/normal;圆圈叹号 | 右移1、下移1.5、行框少3,图形/颜色不同;`Chips.tsx:43` |
| D35 P1 | 右下模型选择 | 品牌图标+模型名+6×3箭头,文字黑90% | 品牌图标缺失、蓝灰文字、15px caret外框 | 当前Deepseek与gpt-6-luna最高是配置差异,不强改模型;对齐真实模型的图标槽/字体/箭头 |
| D36 P1 | 模型项左侧圆环,中心约(885.27,697) | 有上下文/用量类指示控件 | spacer空白 | 控件缺失;准确语义/tooltip待验收,不用常驻loading伪装 |
| D37 P1 | 发送按钮,均(1087,681,32,32) | 白实心纸飞机/上行形状 | 细线向上箭头,路径约8.4×10 | 内部轮廓不一致,外框无需移动;Composer SEND |
| D38 P1 | 框下免责声明 | 外框(348,726,784,36),12px/20,黑30%,内部padding定位 | (348,736,784,14),12px/14,#8a93a3 | 外框含padding,不能把y差10直接当文本偏移;颜色/行高不同,需对内部基线;`.composer-hint` |
| D39 P1 | 历史最右滚动条 | 宽6、thumb黑20%、圆角3 | 宽10、thumb蓝灰14%、圆角4 | 粗4且颜色不同;改宽会影响可用宽度和居中,应联动复测正文;`chat.css:373` |
| D40 P1 | 滚动条上下端小箭头 | 当前截图可见原生小三角,pseudo display inline | 未呈现同样箭头,pseudo display block | 宿主可能影响外观,需匹配可见效果和点击/滚动表现,不机械复制display |
## 精确定位:相对回合头像行
A过程收起,除头像名称x393外,以下锚点x359。
| 锚点 | WB绝对y | YG绝对y | WB dy | YG dy | 说明 |
| --- | ---: | ---: | ---: | ---: | --- |
| 头像行 | 267.98 | 322.69 | 0 | 0 | h24.5一致 |
| 取消耗时 | 304.48 | 363.19 | 36.5 | 40.5 | YG相对晚4 |
| 首段正文 | 342.73 | 397.44 | 74.75 | 74.75 | 上下间距抵消,不能误判 |
| 过程消息 | 408.23 | 458.94 | 140.25 | 136.25 | YG提前4 |
| 最终正文 | 446.48 | 493.73 | 178.5 | 171.05 | YG提前7.45 |
| 用户已取消 | 472.73 | 527.98 | 204.75 | 205.30 | 近似同起点但字号/前间距不同 |
| 所有产物 | 504.73 | 缺失 | 236.75 | — | 实际入口缺失 |
B过程、首命令、意图结果展开。
| 锚点 | x | WB绝对y | YG绝对y | WB dy | YG dy |
| --- | ---: | ---: | ---: | ---: | ---: |
| 头像行 | 359 | -40.02 | 52.69 | 0 | 0 |
| 首段正文 | 359 | 34.73 | 127.44 | 74.75 | 74.75 |
| 过程消息 | 359 | 100.23 | 188.94 | 140.25 | 136.25 |
| 运行命令 | 359 | 128.48 | 223.73 | 168.50 | 171.05 |
| 意图文字 | 381 | 158.73 | 255.98 | 198.75 | 203.30 |
| 灰面板 | 359 | 187.23 | 284.48 | 227.25 | 231.80 |
| bash标签 | 375 | 199.23 | 296.48 | 239.25 | 243.80 |
| 命令文本 | 375 | 222.42 | 319.67 | 262.44 | 266.98 |
| stdout | 375 | 283.98 | 没有独立块 | 324.00 | — |
| 深度思考标题 | 359 | 401.98 | 缺失 | 442.00 | — |
| 最终正文 | 359 | 446.23 | 493.17 | 486.25 | 440.48 |
| 用户已取消 | 359 | 472.48 | 527.42 | 512.50 | 474.73 |
| 所有产物 | 359 | 504.48 | 缺失 | 544.50 | — |
| 助手操作栏 | 359 | 537.48 | 缺失 | 577.50 | — |
## 已对齐的基准,不应继续盲调
| 元素 | 两端共同值(1200×762) |
| --- | --- |
| 主区/历史视口 | 主区x280,w920;滚动视口(280,86,920,506) |
| 正文列 | x359,w752,右边1111 |
| 标题/顶栏按钮 | 标题(304,46),16px/24;五按钮位置和32×32尺寸一致 |
| 头像行 | x359,头像24×24,名称x393,gap10,h24.5 |
| Markdown默认字号 | 根17.143/30.0002;段落15.0001/26.2502;首段h53.5、最终段h26.25 |
| 普通inline code | Device or resource busy宽197.69、高18、字号15.0001 |
| 用户气泡外壳 | #f2f2f2、padding8×12、圆角16且右下直角;实际文字另见D04 |
| 输入外框 | (348,592,784,134),1px #e6e6e6,圆角24,同一双层阴影 |
| 编辑宿主/工具栏 | 宿主(349,605,782,64),左右padding16;工具栏(349,669,782,56),padding12 |
| 发送按钮外框 | (1087,681,32,32),圆形灰底;内部图形未齐 |
| 命令面板壳层 | w752、内容720、圆角16、#f2f2f2、padding12×16 |
## 4项外围壳层差异,另行记录
| ID/位置 | 差异 | 范围说明 |
| --- | --- | --- |
| X01 顶部 | WB菜单与全局图标,主顶栏(280,30,920,56);YG品牌标题栏,主顶栏(280,46,920,40) | 宿主结构不同,但内部对话标题/按钮坐标一致;不应为复制菜单破坏这些坐标 |
| X02 左栏x0—280 | WB中性浅灰;YG冷色背景及顶部渐变 | 整窗视觉仍不同;核心对话优先 |
| X03 当前选中任务 | WB项目ygent下子项,文字约(48,417)、条h31;YG独立任务,文字约(20,240)、条h35 | 同时含层级/导入归属/不同列表数据;不能硬移整个侧栏 |
| X04 左下y626—744 | WB邀请卡、头像账号;YG设置与收起侧栏 | 外围产品入口;不默认复制平台商业体系 |
## 5项源码确认的交互缺口,未发送消息实测
| ID/位置 | YG已确认实现 | 与目标的关系 |
| --- | --- | --- |
| C01 左下+按钮(361,681,32,32) | Composer.tsx:115仅showToast附件上传M4落地 | 不是可用附件入口,需添加/展示/删除/提交链路 |
| C02 编辑器@与/ | 普通textarea onChange/Enter,未接候选菜单 | 占位提示承诺的上下文/技能交互未接通;菜单、chip、键盘导航待做 |
| C03 生成中发送 | Composer.tsx:68 pending直接return,按钮变停止 | 暂无忙时队列UI/编辑删除立即发送;需真实流式测试 |
| C04 字号设置/快捷键 | 六档滑杆与token表已实现;设置旁暴露Markdown px;未找到对应全局Ctrl+-/Ctrl++/Ctrl+0处理 | token参数一致不等于设置形态/快捷键/持久化/全覆盖一致 |
| C05 长会话与系统事件 | 当前全量829消息;分页、回退、队列、模型切换/压缩事件未全部接通 | 旧“几十条消息无需虚拟列表”的规模假设失效;两端DOM总高不能直接推出性能结论 |
## 15项待验收场景,暂不声称一致或确定差异
| 编号 | 精确验收状态/位置 | 需要检查 |
| --- | --- | --- |
| V01 | 两端1335×916 | 正文/输入上限、换行、贴底;本轮仅YG该尺寸已采集 |
| V02 | 窄窗、最小980×640 | padding切换、模型权限挤压、横向溢出、标题省略 |
| V03 | 六档1—6实际设置 | 正文、用户文字、过程、代码、输入、按钮行框;操作后恢复原档 |
| V04 | 设置滑杆 | 轨道刻度thumb颜色、键盘/点击调节、重启持久化 |
| V05 | 用户气泡hover | 时间/复制/编辑坐标、出现时机、hover间隙、键盘焦点 |
| V06 | 顶栏搜索打开/有命中/无命中 | 输入宽高、计数、导航、高亮、折叠命中与滚动定位 |
| V07 | 分享模式 | 选择框、底部操作条、复制导出;与平台分享链接分开 |
| V08 | 最近任务/概览popover | 锚点、行距、最大高、外部关闭、产物计数/跳转 |
| V09 | 右工作台打开 | 两列变化、主列收缩、工具和产物列表、空态 |
| V10 | 真实表格 | 字体、padding、横滚、添加到对话hover位置/引用内容 |
| V11 | Markdown代码块 | 与命令面板分开:语言栏、复制、字库、背景、横滚、最大高 |
| V12 | 真实widget/SVG | iframe高度、前后间距、响应尺寸、产物链接;不沿用模拟页结论 |
| V13 | 流式/失败/取消/重试 | 文案、耗时、按钮状态、错误、重复丢消息、折叠稳定 |
| V14 | 上翻后新消息/展开变高 | 阅读锚点、自动跟随条件、回底按钮位置/appearance |
| V15 | 图片附件引用路径长文本 | tooltip/图标/点击、加载尺寸、复制、310px长气泡、输入增长/IME |
## 修复顺序与完成标准
用户明确动态目标后的优先顺序:先处理 [S01/S02/S06事件管线](ygent-chat-interaction-parity.md),建立增量、折叠、滚动与取消的双端验收,再继续下列静态细节;不能只沿像素微调顺序推进。
1. 先修真实文字和字库:D01—D05、D14、D27、D32。重测六档,不仅核对font-size数值。
2. 恢复过程真实层级:D11—D23、D25—D28、D31。摘要、意图、命令、输出、reasoning应有独立可测间距和状态,移除旧工具卡干扰。
3. 补当前回合尾部:D29—D30。真实产物关联、操作栏及有依据的元数据,分项接通交互。
4. 收敛图标颜色滚动:D06—D10、D24、D33—D40。改尺寸后重新核对正文与输入,避免引入全局偏移。
5. 扩展V01—V15验收矩阵和C项;明确外围X项是否纳入同轮,平台能力不阻塞核心对话区。
每项完成需提供同条件原生采集,记录字库、字号档位、视口/DPR、展开状态、rect/样式及行为结果。字库差先消除;关键几何允许不超过1px取整误差,缺失结构/入口/错误交互不按像素误差豁免。无法获取的元数据和未操作场景明确标记,不伪造数据、不以“组件存在”标记已完成。
@@ -0,0 +1,269 @@
# 岗位与项目团队方案
日期:2026-10-11。版本:方案 v0.6(首版已接入,长期方向继续讨论)。
最新管理设计见 [数字员工项目管理落地方案](ygent-team-management-plan.md),制度依据见 [项目管理调研](project-management-research-2026-10-11.md)。后续责任领域、参与式规划、任务承接与人员交接按新方案讨论和分阶段实施;当前尚未接入这些新增流程。员工实施统一暂停,早期自动承接说明仅保留历史背景;真实行为以 [进度及 SOP](ygent-team-integration.md) 的最新阶段为准。
历史首版状态:按用户要求已接入创建岗位 → 项目入职 → 分配范围 → 自动承接明确任务 → 多轮协作 → 提交验收的 OMP 首版,实际范围与证据见[进度及 SOP](ygent-team-integration.md)。首期采用规则隔离,操作系统沙盒留作后续选项。本文保留后续方向,不代表所有建议已实现;自动承接须用户明确分配任务并启用成员设置,不扩大原有操作权限。
## 1. 目标与已明确的需求
将当前「专家」改名为「岗位」,支持用户按实际需要定义岗位。各岗位有不同职责、技能及默认模型;项目可以分配岗位,通过「入职」确定其负责内容,再承接和推进工作范围内的任务。
希望构建能持续协作的团队,覆盖销售、开发、交付与售后。项目不局限于代码仓库,工作目录也可包含文档、图片及业务材料。成员之间应能多轮提问、补充、交付和返工。
必须防止 Agent 为完成自己的目标而越界代做其他岗位的工作。成员在职责范围内完成交付;依赖其他岗位的工作,通过协作请求、任务依赖和交接推进,不能自行扩大负责范围。
### 讨论状态
| 内容 | 当前状态 |
|---|---|
| 专家改名为岗位,配置职责、技能和模型 | 首版已接入,范围见进度及 SOP |
| 项目分配岗位,通过入职确定负责范围 | 首版已接入,范围见进度及 SOP |
| 形成销售、开发、售后协作团队 | 用户明确提出的目标 |
| 岗位模板与项目成员分开,复用任务和对话 | 已获整体方向认可的建议;细节可调整 |
| 按事件自动承接任务,交付后验收 | 首版按明确负责人及完整条件自动承接,默认关闭;人工验收 |
| 防止越界,表达跨岗位依赖和交接 | 用户明确要求;首期采用规则隔离 |
| 文件、Shell、连接器的强制隔离 | 留作后续增强,首期不依赖沙盒;尚未实现 |
## 2. 概念保持简单
| 概念 | 职责 | 生命周期 |
|---|---|---|
| 岗位 | 可复用的职责、方法、技能、连接器需求和默认模型 | 全局定义,可供多个项目选用 |
| 项目成员 | 某个岗位在一个项目中的具体安排 | 入职后持续存在,可暂停或退出项目 |
| 项目任务 | 目标、负责人、范围、依赖、进展与验收 | 复用现有项目任务,不随一轮对话结束 |
| 执行对话 | 某项工作的讨论、工具调用和执行证据 | 可多轮继续,绑定真实成员、任务和运行 |
| 临时子 Agent | 协助成员处理边界明确的局部工作 | 复用现有协作机制,责任仍归原成员 |
界面主要呈现「岗位」「项目成员」。不新增部门、职级或组织架构。按用户新增要求,每个项目默认一位项目经理,专职审核职责、拆解和分配任务,不参与编码,不具备文件修改权限。经理不出现在全局岗位列表,不能删除或禁用;可在项目内修改名称、职责、模型、推理强度和技能,各项目配置独立。
项目成员不绑定某个发起对话的寿命。关闭一个对话或结束某次委派,不等于成员离职;暂停成员与取消当前执行应有明确区分。具体取消归属还需结合现有子 Agent / 平级对话机制设计,不能直接照搬子 Agent 的父级取消规则。
## 3. 岗位定义
建议包含以下配置:
- 名称、说明与职责:能处理哪些工作,如何判断交付质量。
- 技能引用:从已安装技能中选择,复用稳定组件 ID,不重复复制安装。
- 连接器需求:声明所需服务和工具能力;凭证与实际操作授权独立管理。
- 默认模型:选择已有渠道、模型及其支持的思考配置;渠道决定请求协议。
- 工作要求:输出、验证、交接和需要提出澄清的问题。
同一岗位可以加入多个项目,但项目中的任务、记忆、对话、授权和运行状态不能因此互通。岗位模板调整应记录版本,并在下一回合边界采用;运行中的模型、目录与能力快照保持稳定。项目是否允许覆盖岗位默认模型、模板更新是否需要成员确认,留作下一轮讨论。
长期成员不等于永久运行的模型进程。空闲时保留身份、任务和上下文索引,需要工作时再恢复执行。
## 4. 项目入职
项目详情增加「团队」,用户选择岗位后安排:
1. 负责范围:业务领域、模块、客户群体或明确产物。
2. 参考资料:项目概况、相关资料、工作目录和已有任务。
3. 协作与验收:向谁交付、依赖哪些成员、由谁验收。
4. 接任务方式:人工分配,或自动承接归属明确的任务。
建议入职后进行一次有边界的熟悉工作:读取相关概况与任务,按需检索资料,形成职责理解、可承接任务和待澄清问题。不一次性装入整个仓库、全部资料或所有聊天历史。
入职本身不授权执行所有未完成任务。自动执行依据用户设置的工作范围、接任务方式和操作权限;存在歧义时提出建议,避免自行扩大业务目标。
## 5. 任务分配与自动推进
复用现有任务状态:「待办/进行中/阻塞/待验收/已完成/已取消」。负责人和自动调度是新增能力,不能以已有任务状态代替实际运行。
建议每个任务有一个主要负责人,可有多个协作成员。确定交付责任后,由宿主原子领取和排队,防止重复领取或重复执行。用户调整任务仍使用版本校验,Agent 不能覆盖较新的人工修改。
工作循环:
```text
任务新增 / 依赖解除 / 收到协作消息
→ 检查负责范围、前置条件、暂停状态与执行额度
→ 明确归属的任务领取并排队
→ 执行、记录进展、验证、提交验收
→ 通过后完成;需要修改时继续原任务
```
- 归属不清或多人范围重叠:提出分工建议,不让多个成员竞相处理。
- 任务拆解:围绕已有目标,明确子任务的范围和验收;不按每条工具调用建任务。
- 缺少信息:记录阻塞原因和解除条件,向对应成员或用户提问。
- 任务等待期间:释放运行占用,可处理其他已具备条件的任务;避免反复请求模型询问进度。
- 完成判定:保留交付结果、验证依据和未验证项,遵守子任务与依赖检查。回复结束不是任务完成。
- 用量控制:并发、轮次和预算由宿主执行;具体默认值另行确定,不在本稿直接扩大现有并发。
自动推进由事件触发,事件需要去重和可恢复的工作状态。首版建议以应用运行期间为边界,最小化继续运行。退出应用后的持续执行需要单独的后台服务,不属于现有能力。重启可检查待办队列,但结果不确定的中断操作不能直接重放。
## 6. 多轮协作、上下文与交付
成员使用既有协作消息处理请求、补充、提问、回复、结果和通知,以稳定关系和 replyTo 追踪往来,不为每次回复新建成员。消息处理与任务领取需关联去重,避免一项工作同时经消息和任务触发两次。
任务记录责任、依赖和验收;消息记录交流;执行对话保留完整过程。三者相互关联,不以聊天正文解析结果直接替代任务事实。
成员可调用临时子 Agent,委派范围不能超过成员当前任务范围;结果由原负责人核对。角色说明、协作消息和子 Agent 自报身份均不能扩大权限或代替用户授权。
建议成员保留职责、经确认的项目知识和任务索引,具体任务使用可多轮继续的执行对话,避免所有工作永久堆入一个无限增长的聊天。资料采用已有项目范围及版本机制,运行时冻结引用,后续撤销仍优先;待定判断不得写成已确认事实。
通用业务示例:渠道拓展记录客户需求及来源 → 建立需求任务 → 开发成员澄清并拆解 → 实现和验收 → 售后准备说明并跟进。销售、售后使用各自的技能、连接器和交付条件,不强制依赖代码目录。对外发送、发布和退款等操作依照明确授权范围执行。
## 7. 职责边界与越界处理(首期采用规则隔离)
### 7.1 统一岗位、入职与任务规则
首期以明确规则引导 Agent 分工,配合任务依赖、协作交接与交付检查。暂不接入操作系统沙盒,也不以完成命令隔离研究作为岗位功能的启动条件。规则隔离属于行为约束,不能保证任意 Shell 或脚本在系统层面无法越界;已有授权、项目范围校验和连接器确认继续适用。
建议由宿主从岗位模板、项目入职安排和当前任务组装一份范围说明,在执行对话开始、恢复、上下文压缩后以及新回合使用有效版本;稳定职责保持稳定,不反复塞入全部历史。规则至少包含:
- 负责什么:业务领域、模块、客户范围和交付结果。
- 可以参考什么:资料、交付约定和相关目录;可以读取不代表可以修改。
- 可以修改或创建什么:明确目录、文件或业务对象,必要时列出例外。
- 不负责什么:禁止代做的其他岗位职责与操作。
- 依赖谁:前置交付、协作对象和解除阻塞的条件。
- 怎样完成:可核对的产物、验证方式和验收人。
实际范围由岗位、项目入职安排、本次任务和用户授权共同约束,不能简单相加。成员按范围领取与拆解任务;范围缺失、冲突或归属不清时澄清,不能默认获得整个项目的职责。检查与执行共用当前上下文,不为每次工具调用额外启动一次模型审查。
新文件按创建位置和用途判断是否属于本岗位工作,不采用“只要是自己创建就永久归自己”的规则。公共类型、共享配置和锁文件应明确负责人或修改约定,不能因为编译报错就顺手修改其他成员负责的内容。业务负责范围与工具操作授权分开:配置连接器不等于拥有全部账号操作权限;普通操作确认也不默认扩大职责。
Agent 不得通过改任务负责人、创建子任务、切换模型或调用另一种工具扩大范围。临时子 Agent 继承原成员的限制,再叠加本次委派范围;平级岗位之间发送请求时,接收方仍按自己的职责和任务条件判断。协作消息、技能或文件中的文字均不能自动扩大职责。允许跨范围时,由用户明确调整具体范围并记录版本;已有能力快照仍遵守回合边界约定,撤销不能仅靠下一次提示词提醒。
### 7.2 任务依赖与交接
任务依据实际工作需要配置依赖和交付条件,不预设岗位类型、固定工作阶段或执行顺序。
成员可以独立交付已满足条件的工作;依赖尚未满足的部分保持等待,并记录所需交付和负责成员。等待期间可处理其他职责范围内、具备执行条件的任务,不能代做依赖方的工作。
交接至少要说明需要什么、由谁交付、产物或版本在哪里、如何验证、何时满足条件。收到“已完成”的消息不等于自动证明依赖可用;核对交付后才能解除对应阻塞。交付不符合约定时反馈给负责人,约定变化时通知受影响的任务与成员。
### 7.3 通用越界流程
```text
发现范围外问题
→ 记录事实、影响与所需协助
→ 发送给负责成员,关联任务与约定
→ 需要等待的部分记录阻塞;可独立部分继续
→ 收到可核对交付,检查解除条件
→ 恢复原任务
```
没有负责人、范围冲突或需要扩大范围时交给用户决定。首版不额外设计多级审批组织;是否允许指定协调成员处理部分分工,后续再讨论。
若执行后才发现越界,停止继续扩大改动,报告具体文件或对象、影响与交接建议。不得擅自回退其他成员或用户的修改,也不因为测试通过就隐去越界事实。提交验收时汇总实际改动、验证证据、依赖与未完成项;代码项目可结合 diff 检查,非代码工作按实际交付和操作记录核对。
### 7.4 首期范围与后续增强
| 层次 | 首期建议 | 能力边界 |
|---|---|---|
| 任务元数据 | 负责人、依赖、版本及领取条件由宿主校验 | 职责描述仍需 Agent 理解,不能用关键词匹配证明归属 |
| 文件读写 | 将参考范围和可修改范围写入执行规则 | 不宣称已在文件系统层强制拦截 |
| Shell / 脚本 | 命令的预期副作用也须遵守相同范围规则 | 不增加脆弱的命令字符串黑名单,不宣称沙盒隔离 |
| 连接器 | 规则描述业务对象与允许行为,保留已有确认 | 岗位规则不自动扩展服务端账号权限 |
| 交付 | 核对实际改动、结果、验证和依赖 | 事后检查可以发现问题,不能防止已发生的副作用 |
首期不新增独立权限语言、通用审批引擎或强制每个岗位使用独立工作副本。使用当前任务、消息、对话和授权机制完成分工闭环,并记录发生过的越界与交接问题,作为后续改进依据。
后续如果需要系统层强制限制,再对文件、命令、子进程和宿主连接器逐项选择并验证隔离方式。普通 worktree 与规则字段本身都不构成安全边界;沙盒技术选型暂缓。
## 8. 页面与操作建议
- 全局入口改为「岗位 · 技能 · 连接器」;岗位页用于创建、配置、复制与停用。
- 项目详情增加「团队」,展示成员、负责范围、当前任务与真实状态。
- 入职以渐进表单安排职责、资料、模型和接任务方式,不塞入执行层术语。
- 任务列表及看板增加负责人和筛选;任务详情展示交接条件、依赖和阻塞原因。
- 成员详情可以发要求、看任务与往来、暂停接任务、打开执行对话。
- 执行对话复用现有流式、工具、授权、问题回答和工作台;不另造一套执行界面。
- 范围外请求明确展示“需要谁处理”和影响;缺少职责配置时引导补齐,避免静默失败。
界面沿用现有六档字体和布局语言,具体交互待功能边界确定后设计;真实桌面验收要求仍按项目约束执行。
## 9. 当前基础与待实现能力
截至本稿,已核对现有代码与进度文档:
| 能力 | 现状 |
|---|---|
| 技能、连接器、回合快照 | 已有基础,具体支持范围以原进度文档为准 |
| 项目任务、依赖、历史、验收字段 | 已实现;首版补充成员负责人和明确条件自动承接 |
| 多轮子 Agent / 对话协作、排队、因果关联 | OMP 已实现;首版项目团队复用其多轮、队列与等待机制 |
| 原专家入口 | 已改为岗位,支持真实职责、技能和模型配置 |
| 岗位、项目成员、入职 | OMP 首版已接入;每成员持久执行对话 |
| 任务负责人、领取、事件驱动承接 | 明确分配、自动承接开关、依赖与子任务检查、持久队列已接入;不支持智能抢单 |
| 岗位职责、任务范围与交接规则 | 每回合注入职责规则,子 Agent 继承;任务字段及人工验收由宿主校验,非沙盒 |
| 文件、Shell 等强制隔离 | 后续选项,首期暂不接入 |
| 应用退出后的持续工作 | 尚无后台服务 |
复用现有任务、消息、对话和能力机制。角色与调度合同由宿主管理,首期验证现有 OMP;其他基座另行适配。首版数据库表、IPC 与工具参数见[进度及 SOP](ygent-team-integration.md),不增加第二套聊天内核或通用工作流框架。
## 10. 建议实施顺序与验收
以下为整体演进顺序;用户已授权并实施最小闭环,未落地能力及尚未验证的场景以进度及 SOP 为准:
1. 定清岗位、项目入职和任务规则的组合、继承、变更与越界交接方式。
2. 岗位定义、模型与能力配置、项目入职和成员身份持久化。
3. 任务负责人、领取、依赖交接和成员多轮协作。
4. 在明确的职责和任务条件内加入事件触发、队列、暂停、预算与中断恢复。
5. 使用职责不同的岗位跑通跨岗位协作闭环,验收覆盖代码与非代码工作,不绑定具体岗位组合。
首个完整闭环:创建岗位 → 项目入职 → 指定范围 → 承接明确任务 → 协作和等待依赖 → 实际验证 → 提交验收。
关键验收场景:
- 同一岗位加入两个项目,资料、任务、cwd 和授权不串线。
- 岗位使用实际配置的模型;配置变更在正确回合生效。
- 成员完成职责内交付后不代做依赖方的工作;依赖经核对满足条件后,才恢复对应任务。
- 两个成员不会重复领取;忙碌、暂停、重复事件不会重复执行。
- 跨岗位问题可多轮澄清,交接保持任务与消息来源。
- 普通执行、恢复对话、上下文压缩和子 Agent 委派均保留有效范围规则;协作消息不改变职责。
- 对范围外文件修改、命令副作用、连接器操作及职责外代做的测试请求,成员按规则交接;记录实际表现,不把行为测试通过等同于系统层强制隔离。
- 共享资源职责冲突、撤销范围、交付约定变化均有可见处理结果。
- 取消、异常退出和重启不把未知结果当成成功,也不重复外部操作。
- UI 状态来自真实队列和运行;空闲成员不会为了显示在线而持续调用模型。
## 11. 下一轮待讨论
1. 规则配置如何保持简单:业务描述、参考范围、修改范围和依赖如何安排?
2. 首版由用户明确分配、自动承接默认关闭;后续是否支持范围重叠时的协调分配?
3. 哪类任务允许依据检查自动验收,哪类必须人工验收?
4. 共享资源的责任归属和任务重分配如何处理?
5. 模型覆盖、岗位模板升级、成员长期上下文如何管理?
6. 规则变更、上下文恢复和长期成员如何同步有效职责,避免旧规则继续影响任务?
7. 实际用量如何计费展示与限额,预算耗尽后如何恢复?
讨论后在对应章节原地修订,记录已确定结论和仍待决定的问题,避免把建议自动升级成项目约束。
## 12. 文档维护与关联资料
本文件作为持续讨论的源文件,以文件来源接入「ygent 项目 → 资料库 → 资料」。后续修改同一路径,由资料库刷新生成新版本;必要时手动刷新。修改文件不会直接替换已开始回合冻结的旧版本,已删除或撤销资料仍按现有规则处理。
只关联这一份方案文件,不因此登记整个工作目录。资料库条目 ID 与版本属于本机用户数据,不写入仓库。本文进入项目资料库供讨论引用,不额外写成“已确认”的项目记忆。
- [原专家、技能、连接器方案](ygent-capability-integration-plan.md):技能与连接器基础继续复用,岗位首版与后续方向见本文及进度 SOP。
- [协作方案](ygent-collaboration-plan.md)与[实际进度](ygent-collaboration-progress.md):多轮消息、运行与恢复边界。
- [项目任务方案](ygent-project-tasks.md):任务状态、验收、版本与宿主工具。
- [资料库方案](ygent-library-plan.md)与[接入进度](ygent-library-integration.md):归属、来源与版本规则。
修订记录:
- 2026-10-10,v0.1,整理岗位与项目团队整体方向,补充职责边界和交接规则,标明执行隔离等未决项;仅交付文档。
- 2026-10-11,v0.2,按用户选择改为首期规则隔离,补充范围组合、新文件归属、子 Agent 继承和越界交接;移除沙盒作为首期前置条件,同步实施顺序与验收边界。仅更新方案,功能尚未实现。
- 2026-10-11,v0.3,移除具体岗位分工示例,将目标、依赖交接、实施顺序和验收项统一为通用规则,不将讨论中的例子固化为产品流程。
- 2026-10-11,v0.4,按用户授权实施 OMP 最小闭环:岗位配置、项目入职、职责规则、明确任务自动承接、多轮协作和人工验收;关联实际进度与原生验收 SOP,保留尚未接入的长期建议。
- 2026-10-11,v0.5,按用户要求增加默认项目经理、入职职责审核与任务分配;经理只读协调、普通成员审核通过后执行,最终用户验收。具体交付和证据以进度 SOP 为准。
- 2026-10-11,v0.6,增加普通项目对话向既有岗位成员发要求、持续多轮返回;岗位编辑直接取消,统一模型选择面板;经理配置项目独立且不可删除/禁用。
## 已落地补充:经理自主组队
项目经理可以按用户明确需求复用现有岗位或创建项目专用岗位,办理入职、审核职责范围、分配完整任务并协调交付。新建岗位默认继承经理模型和推理配置,可调整;经理创建成员默认开启自动承接,但审核、范围、验收条件及依赖仍是执行前提。项目岗位只属于本项目,只有用户显式操作才能复制为全局岗位。经理不能扩大自身执行权限或代用户验收。具体工具、界面、边界与本机验收证据见[实施进度及 SOP](ygent-team-integration.md#经理自主组队2026-10-11)。
## 当前执行阶段:入职审核与任务规划
按最新约定,员工暂不执行。入职审核后,经理必须查看现有任务,根据当前岗位和负责范围复用、调整或拆分,明确任务负责人、依赖及验收,再提交完整当前版本规划。规划完成只代表分工确认,不代表开始执行;后续开放执行需单独确定,不加入本轮。
岗位职责或成员范围变化使规划重新待办。经理未完成规划时可显式重试,不由员工主动接任务补齐流程。具体实现与验收见[进度及 SOP](ygent-team-integration.md#入职后任务规划与执行暂停2026-10-11)。
- 2026-10-11,v0.7,增加持久任务规划阶段及完整版本提交;本轮员工执行全局保持暂停,覆盖先前自动执行约定。
- 2026-10-11,v0.8,补充经理移除空闲项目成员工具;先交接未结束任务,保留文件和对话历史,移除使规划失效,退出身份不可继续执行,经理不可移除。见岗位进度 SOP。