feat: add conversation search and usage dashboard

This commit is contained in:
shiyue
2026-08-03 18:20:33 +08:00
parent cc600bdf31
commit 58d5f816c2
30 changed files with 6316 additions and 22 deletions

View File

@@ -0,0 +1,102 @@
# 调研结论:cc-web 使用统计看板
## 用户要求
- 当前只需要可执行计划,不实施产品代码。
- 看板必须不影响现有聊天、会话、检索和工具调用功能。
- 指标必须有明确口径,不能使用含糊的“活跃会话”。
- Skill 只统计显式 `$skill` 使用,不宣称能够监控实际读取或执行。
- 用户已授权开始实施,并要求先完成整体功能,再适配所有现有主题。
- 用户指定统计入口位于侧栏底部:会话列表下方、现有 `CC-Web` 设置入口同一区域,而不是会话列表内部。
- 入口参考图为 `sessions/_attachments/750cb7a2-a109-44a9-ae3d-6ca352d4aba0.jpg`;图中底部操作区在会话列表滚动区域之外。
## 现有数据能力
- 会话数据保存在 `sessions/*.json`。
- 用户消息可持久化 `composerMentions`,可识别显式 `$skill` mention。
- Codex App 的 MCP 调用会规范化到 assistant message 的 `toolCalls[]`,包含 `server`、`tool`、`status`。
- 现存 MCP 工具调用没有独立时间戳;历史统计只能暂时使用所属 assistant 消息完成时间。
- 会话持久化有消息数和每条消息工具调用数上限,因此看板只能统计“当前保留数据”,不能声称是永久全量审计。
- 当前会话主创建字段为 `created`;134 个会话均有 `created/updated`,当前 2,226 条保留消息均有 `timestamp`。
- 当前扫描得到 1,745 次 MCP 调用,`completed=1645`、`failed=100`;失败调用同样可能 `done=true`,失败口径必须读取 `meta.status`。
- 显式 Skill mention 的稳定判定是 `composerMentions[].kind === 'skill'`,不能扫描消息正文中的 `$xxx`。
- `crossConversation` 可区分跨会话自动消息;界面使用“直接发送消息”和“跨会话消息”,避免把前者绝对命名为人工消息。
## 已有数据扫描结果
- 134 个会话 JSON,总量约 82 MB。
- 1,678 次 MCP 调用,`server/tool` 解析率 100%。
- MCP 状态:`completed=1578`,`failed=100`。
- 显式 Skill mention 共 7 次。
- 一次全量扫描约 0.93 秒,峰值 RSS 约 116 MB。
## 架构判断
- 82 MB 数据量下,全量扫描可以用于一次性回填或维护操作。
- 不应让每次看板刷新都全量解析所有会话文件,否则数据增长后会和聊天服务争用 CPU、内存和磁盘 IO。
- 最稳妥的结构是:独立索引文件、异步更新、独立查询协议、独立前端工作区。
- 统计是旁路只读能力,不进入消息发送和会话写入的同步关键路径。
- 统计索引采用懒加载:第一次打开看板才加载/回填,未使用看板时不增加服务启动成本。
- 索引初始化后可防抖增量更新;调度与删除必须内层 `try/catch`,不能让统计异常进入 `saveSession` 或删除会话的主错误分支。
- 统计响应只返回聚合值、工具名、Skill 名和会话元数据,不返回消息正文、MCP 参数或工具结果。
## 页面范围
- 顶部:时间范围、本周、本月、自定义范围、刷新。
- 首行指标:新建会话、发送消息、MCP 调用、MCP 失败、Skill 显式使用。
- 中部:按日趋势;MCP 工具使用明细。
- 下部:MCP 状态分布;Skill 显式使用排行;最近会话明细。
- MCP 工具明细行可进入该工具的调用明细;该交互属于网页实现,不需要在生图提示词中逐字描述。
- 看板作为 `.chat-main` 内局部覆盖工作区,聊天 DOM 保持挂载;高级检索与看板互斥打开。
- 入口必须使用独立 `.usage-dashboard-open`,不能复用 `.settings-btn`,否则 Wasteland 的齿轮伪元素会污染统计按钮。
- 当前共有 11 个主题 ID;基础样式使用语义 token,专属修正只需要 coolvibe、共享暗色组、gilded 和 wasteland。
## 代码落点依据
- `public/index.html` 已有 sidebar 与 `main.chat-main`,看板可以作为 chat-main 内独立工作区,而不必重做应用外壳。
- `server.js` WebSocket 分发已有独立消息类型模式,可新增统计查询类型而不改变现有协议。
- `scripts/regression.js` 已覆盖高级检索的独立入口和独立状态模式,统计看板可沿用相同隔离策略。
- codebase-memory 项目 `home-cc-web` 索引状态为 ready(4,455 nodes / 9,320 edges)。
- `saveSession()` 是高入度核心写入函数,统计逻辑不得直接接入其同步调用链;旁路索引应在看板查询或独立后台任务中刷新。
- 用户和 assistant 消息均有 `timestamp`;Codex App steer 用户消息也会持久化 `composerMentions`。
- MCP 调用继续从 assistant message 的 `toolCalls` 读取,`ensureToolCall()` 负责归一化名称、kind、meta 和状态更新。
## 风险与控制
| 风险 | 控制方式 |
|---|---|
| 看板查询拖慢聊天服务 | 使用增量索引;请求限时;禁止请求时全量扫描 |
| 索引与会话数据不一致 | 保存源文件指纹;可重建;界面显示统计更新时间 |
| 历史 MCP 时间不准确 | 明示按 assistant 消息时间归属;不展示伪精确耗时 |
| Skill 指标被误解 | 指标名称固定为“Skill 显式使用” |
| 前端状态污染聊天 | 独立状态对象、DOM 根节点、样式命名空间和关闭恢复流程 |
| 新功能引入回归 | 功能开关、合同测试、现有完整回归、灰度启用 |
| 现有文件已有未提交修改 | 只在精确区块追加,不重排或覆盖高级会话检索改动;以任务开始时 diff 为基线 |
## 计划审查记录
- 第一次审查发现原计划缺少“全部现有主题逐一适配”的独立阶段。
- 已新增 Phase 5 和硬性主题验收门槛,第二次审查通过。
- 复审确认现有会话主创建字段为 `created`;实施以此为主,`createdAt` 只作历史兼容兜底。
- 统计响应需携带 `schemaVersion`,性能验收已补充明确阈值。
## 资源
- 参考图:`sessions/_attachments/67a5f5ae-ea62-4c12-b723-deb9adb98c2f.png`
- 会话存储与 WebSocket:`server.js`
- Codex App 工具调用归一化:`lib/codex-app-runtime.js`
- 页面外壳:`public/index.html`
- 现有前端状态与交互:`public/app.js`
- 回归测试:`scripts/regression.js`
## 实施与验收结论
- 统计索引在第一次打开看板时才构建;未初始化时保存会话不会安排统计更新。
- 查询响应包含 `schemaVersion` 和 `[from,to)` 语义,不包含消息正文、MCP 参数或结果。
- `usage_stats_query` 使用独立 requestId,真实协议回归确认不会新增 `session_list`。
- `CC_WEB_USAGE_STATISTICS=0` 会关闭鉴权 feature flag,并让查询返回 `disabled`,不影响服务其他能力。
- 真实数据最终性能:83,335,652 字节、134 个会话,回填 1,146.68 ms,查询 P95 51.79 ms,峰值 RSS 119,476 KB,缓存 394,629 字节。
- 浏览器验收:Chrome Headless 151.0.7922.71,视口为 1440×900、1024×768、768×1024、390×844、360×800;11 个主题共 55 组。
- 页面级横向溢出均为 0;窄屏 MCP 表格按设计在 `.usage-dashboard__table-wrap` 内局部滚动。
- Wasteland 的 `.usage-dashboard-open` 没有继承 `.settings-btn::before`;移动端入口为 44×44,桌面为 34×34。
- 浏览器动态状态已覆盖 loading、MCP 明细、空态和错误态;Wasteland 根看板使用实色背景,避免下层聊天视觉透出。