合并最新主分支变更
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled

合入 origin/master 的 Direct、资源画布、工具展示和运行时更新
保留策划 Agent V1/V2 退役删除结果
冲突文件继续采用当前分支的策划退役边界
This commit is contained in:
2026-09-18 08:32:03 +00:00
92 changed files with 15553 additions and 834 deletions
@@ -60,7 +60,10 @@
#### 3.3.2 本体化资源卡交互与性能合同
- 卡片默认可视区域不再显示文件名、资源名称、来源、路径、任务和媒体类型等详细文本。这些字段继续进入搜索索引和中央详情;卡片“打开详情”入口的可访问名称必须包含稳定可辨识的资源名与类别。
- 所有资源卡在卡面显示正式资源名称,沿用生成命名和用户重命名后的资源投影;长名称单行省略,实际可交互的卡片入口提供完整名称提示。来源、完整路径、任务和媒体类型等详细字段继续进入搜索索引和中央详情;卡片入口的可访问名称必须包含稳定可辨识的资源名与类别。文档卡仅展示居中文档图标和名称,正文在独立预览中展示,不把正文摘要铺在卡面。
- 显式“整理画布”重排当前栏目全部资源(包含手动坐标和被筛选隐藏的资源),其他栏目不变;“所有资源”页作用于全部可展示资源。重排可一次撤销,恢复原坐标及手动标记。自动协调仍保留手动坐标,不因新增素材自行重排。
- 当前画布可见资源框选后可成组移动,保持相对位置;松手统一保存且一次撤销。取消手势还原拖动前布局,切项目清理选择,不将隐藏或跨栏目残留选择带入操作。
- 多选已登记素材后,可从选中工具栏“编辑标签”或资源面板“批量标签”入口统一追加标签。面板明确实际目标数量,保存对象在打开时冻结,保留每项原标签及素材类型;不把已有标签并集覆盖到每项。混合未登记资源、超过 200 项、任何一项标签越界或项目版本冲突时整批拒绝,不静默跳过。一次保存更新整批素材,失败保留待追加标签;切项目不将迟到结果写入新项目。单素材编辑保留原有增删标签行为。
- 卡片外层是非交互容器;“打开详情”与“播放 / 暂停”必须是可分别键盘聚焦的同级按钮,禁止在 `<button>` 中嵌套 `<button>`。播放键不选择资源、不打开详情。
- 同一时间最多播放一个卡片音频或视频。打开详情、切换布局模式、切换项目、进入运行视图、搜索 / 筛选隐藏当前资源、当前资源被删除或资源身份 / 路径变化时,必须暂停旧媒体并收口待播放意图;卡片卸载还必须执行防御性暂停。同资源 ID 的无关 manifest 更新不得重建控件或抢走焦点。
- 图片、视频首帧和项目文档只在卡片进入资源画布可见区及小幅预取边界后读取;音频只在用户点击播放后读取。前端逻辑调度器必须使用有界并发、同身份去重、有界 LRU 淘汰,不允许按全部投影同步启动读取。`play > detail > visible` 是固定调度优先级;可见性预取不得占满全部队列容量或静默丢弃播放 / 详情请求,主动请求进入硬上限队列时必须替换最低优先级的排队预取并优先执行。终态预览缓存同时受 `48` 项和 `64 MiB` 总载荷双重上限约束,媒体按解码后的 Blob 字节、文档按 UTF-8 字节计入;Tauri 返回的 data URL 只允许作为 IPC 临时载体,进入 React 状态前必须转换为可撤销的 Blob URL。LRU 淘汰、资源删除、项目 / mode 切换和卸载都必须 `revokeObjectURL`,不能让 base64 字符串或失效 Blob 长期占用 WebView。
@@ -0,0 +1,34 @@
# 【实施计划】多选素材批量标签
| 字段 | 值 |
| --- | --- |
| Milestone | docs/project-memory/plans/【里程碑】多选素材批量标签-2026-09-17.md |
| Status | implemented-awaiting-runtime-acceptance |
| Owner | 主 Agent 集成;deepseek-flash 实现和独立 review |
## 修改边界
- 原生:`project/manifest` 标签批量追加函数和 DTO、`commands.rs` 权限门面、`main.rs` 注册、分类测试。沿用项目写锁、manifest mutation、审计和 revision,不新建状态系统。
- 前端:扩展现有 `ResourceClassificationPanel` 为单/批量模式,复用已有字段与 pill;`ResourceCanvasPanelView` 增加可选批量标签动作;工作台冻结选择并用完整返回条目更新。前端不得逐素材循环写回。
- 并行采用不重叠文件集:原生 agent 只写 Rust,前端 agent 只写 TS/TSX/CSS/前端测试;主 Agent 负责文档与集成,禁止跨区提交别人文件。
## 顺序与检查点
规范经独立 deepseek-flash 评审通过;批量输入仅追加草稿,面板动作行直接增加入口,返回顺序、去重上限、no-op revision 和未知字段拒绝已在主规范明确。
1. 规范独立评审,确定命令与错误语义。
2. 前后端并行实现,均在明确工作区局部修改、自审和定向验证。
3. 集成后独立 review,再按有效发现返修;不因测试方便而扩产品范围。
4. 本地中文提交、报告已验证和待真机事项;远程操作留待用户后续确认。
## 验证
`npm test -- <相关测试>`、AGC 类型检查、目标文件 ESLint、原生 classification 相关测试、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check`。依赖复用时使用本工作树忽略目录的隔离配置,避免修改主目录依赖。
## 风险与回滚
批量写不能掩盖部分失败;类型字段不能借标签保存被读时自愈值覆盖。单素材编辑与多素材追加保留明确分支,不重构其它菜单动作;本地独立提交可回退新需求,保留主线合并及既有画布工作。
## 下一验收入口
在已登记素材上分别从画布多选工具栏与资源面板进入批量标签,确认新增标签、原标签保留、刷新后持久化与跨项目切换。真实客户端验收通过后,将持久行为保留在主规范,删除本实施计划与里程碑;远程推送与 CI 等用户恢复安排,不自行启动。
@@ -0,0 +1,51 @@
# 【实施计划】对话总耗时与动态工具计时
| 字段 | 值 |
| --- | --- |
| Status | implemented-awaiting-runtime-acceptance |
| Milestone | docs/project-memory/plans/【里程碑】对话总耗时与动态工具计时-2026-09-18.md |
## 修改边界与顺序
1. 独立评审主规范与里程碑后进入实现。当前问题是工具组窗口、整轮范围和运行快照混用;不能只把 setInterval 从 1000 改成 100。
2. 原生在现有生命周期事件上提供阶段时间:`turn.started` / `turn.completed` 的事件级 `at`,以及 `item.started` / `item.completed` 的事件级 `at`,不是更改条目嵌套的 `item.at`。工具计时只消费阶段事件时间,嵌套 `item.at` 继续承载条目展示时间,不当作真实开始/完成。开始/完成事件优先读取对应上游阶段字段或时长,缺失时在宿主事件产生时取钟。TypeScript 可选数值字段处理既有历史/无时间夹具,真实宿主始终提供时间;ts-rs 生成绑定,按仓库 u64→number 约定处理,不手改。
3. 前端事件 reducer 保留工具开始、完成边界以及本轮终态时间;完成边界可附在本轮聊天条目展示元数据上,沿用现有用户条目划分回合,不新增 turnId 或第二套生命周期。无时间旧历史不编造准确总耗时。
- 整轮起点:该轮用户消息的实际发送时间优先,缺失才取 `turn.started.at`;与用户要求的“发送到完成”一致,不能改为第一条工具的起点。终点只取明确终态事件,不能取最后一条正文的创建时间或最后工具更新时间。
- 只有完成没有开始事件的工具隐藏未知耗时;缺失、0、非有限或倒序边界隐藏,正常运行的零时长显示 `0.0`。
4. 回合状态/小结消费整轮起止时间,各工具块仅消费本组工具阶段时间,以局部有界的 100ms 时钟驱动展示,不把整棵 App 状态每 100ms 重建。只在该层有运行中计时目标时订阅,结束/切项目/卸载清理。
5. 测试先覆盖静止事件输入下推进时钟、工具完成但回合仍运行、终态与重复事件;补阶段字段与回放时间测试。独立 review 后主 Agent 核对并返修。
6. 同视图的追加局部修复:初始消息占位判定应读取实际 Direct 用户条目/乐观用户条目和分页状态,不只检查旧 conversationMessages;增加正式气泡只出现一次、合法同文消息不被去重的回归。
## 并行写入边界
- 原生实现者:`src-tauri/src/agent/direct_thread_wire.rs`、`codex_app_server/mod.rs`、必要的 `direct_thread_manager.rs` 模式匹配/测试及 ts-rs 生成绑定。
- 前端实现者:`directThreadChat.ts`、`directThreadItemProjection.ts`、`directTurnPresentation.ts`、`ToolCallGroup.tsx`、`toolCallGroupPresentation.ts`、`ProjectSupervisorView.tsx`、必要的 App 接线与对应测试。不得修改原生或生成绑定。
- 主 Agent:文档、集成验证、独立 review 决策与浏览器 smoke;不得覆盖其他人的未提交文件。
## 验证与风险
前端使用已有 `.app/merge-deps` 隔离配置,不修改共享 node_modules。运行定向 Vitest、AGC 类型/skill/config 检查、Rust wire/manager 相关测试与 all-targets offline check、编码/文档索引/diff 检查。历史缺少完整时间时隐藏无法证明的用时,不迁移历史文件。原生协议变更需重新启动客户端才能生效,不擅自重启用户正在运行的回合。
回滚点为本次改动前的 `1bd153d7f`;若失败只回退本次文件变更,不动用户锁文件和其它分支。
## 收口
已完成本轮实现、独立 review 返修与自动化/模拟浏览器验证,证据见对应里程碑。用户已授权更新 Issue/PR 并推送当前功能分支;不得据此合并 PR、发布或恢复定时任务。真实客户端端到端验收尚待完成,因此保留计划,卡片全面重设计和画布内任务浮层不计入本轮已交付内容。
## PR 补审返修(2026-09-18)
### 用户截图澄清:工具组必须独立计时
上一版把整轮总耗时复用到各组,导致已完成的前组仍显示进行中并与后组同步增长。按最新主规范返修:整轮总耗时留在回合状态/小结一处;ToolCallGroup 只消费自身 calls 的阶段边界,显示“本组用时”,完成组停止 ticker,运行组与内部运行工具按 100ms 更新。删除不再使用的回合时间 props,更新原先锁定“各组相同总耗时”的错误测试,补前组已完成/后组运行、LLM 仍运行、并行、缺失/倒序边界与独立冻结回归。此为用户明确修正表现语义,不改变原生生命周期或真实发送时间修复。
已完成并经独立复核:组内每条原始时间边界先校验再聚合,防止单条倒序被其他工具或舍入掩盖。Edge 真实浏览器中前组固定 5.0 秒且无进行中,后组从 2.1 秒增长至 3.0 秒、完成后固定;整轮总耗时仅在回合状态/小结显示。合入主线 `b137f1759` 后 appSurface 463 项通过、17 项跳过,聊天/插件 45 项及发布构建脚本 27 项通过,Rust all-targets check 通过。全量中曾有一条精确用时断言依赖等待 IPC 后重新取 Date.now,已改为读取同身份用户气泡真实发送时间,单独回归通过,不放宽断言。
用户确认修复补审发现:保留同身份乐观消息的真实发送时间;live 为空时仍向明确的本轮用户条目保存终态边界。先补失败回归,再最小修改原 reducer/回合投影与必要的 App 接线,不新增持久化 schema 或平行回合状态源。取消后迟到终态只补可验证测试,不能仅凭时间大小改变现役事件顺序合同。独立复核后运行定向与集成验证。本次 fix 不自动授权新的远程写入。
补审返修中已复现 bootstrap 只有生命周期事件、用户消息经 history slice 回读且 live 恒为空的缺口。前端无法证明归属,因此批准原生在 turn.started/turn.completed 上透传现有用户条目 userItemId;沿用原事件与已有消息身份,不另造 turnId。前端按精确 itemId 补时间边界,移除按历史尾项或时间戳相等猜测用户归属的兜底;完成先于历史到达时,在历史回读后同样按该身份补齐。原生与 TypeScript 绑定同批更新并验证重放。
### 返修结果
已完成同身份发送时间保留、原生 userItemId 关联、live 为空或终态先于历史时的精确回填;旧回合终态及取消回包不能关闭另一条已知身份的新请求。计时 40 项定向、appSurface 462 项(17 跳过)通过,原生身份序列化/重放/取消用例 3 项及原阶段时间序列化 1 项通过;绑定由 ts-rs 导出,Rust all-targets locked offline check 通过。
Edge 真实浏览器使用生产 reducer/组件和模拟原生事件,确认发送后的 8 秒启动等待计入总耗时、100ms 递增及终态冻结;仅历史恢复、live 为空的回合显示正确的 2.0 秒。真实 Provider 与原生客户端端到端尚未验证,不据本地通过宣称远程 CI 或发布通过。
@@ -0,0 +1,50 @@
# 【实施计划】画布验收问题统一修复
## PR 补审返修(2026-09-18)
用户确认修复:生成面板按 draftId 隔离且切换保留各草稿;失败重试保留失效参考身份并在提交前明确拒绝,不改变原付费请求;不同栏目整理意图分别排队;多选拖动预览和写回统一使用按下时起点。每项先加失败回归,再最小修复、独立复核与集成验证。共用 index.tsx 时限定不重叠区域,禁止整文件重写。卡片重设计、任务浮层和远程写入不在这次 fix 范围。
返修已完成:生成占位实例与草稿隔离、失效参考及原请求输入修改阻断、队尾同范围整理合并、场景预览与局部写回分别冻结同一按下时基准。生成/布局/计时合计 17 文件 213 项定向通过;appSurface 462 项通过、17 项跳过。音频失败后切换导致草稿丢失的集成回归也已修复并重跑通过,没有删断言或加任意等待。
独立交叉 review 无新增阻断;浏览器使用真实工作台和模拟原生接口确认 BGM/音效以及同类图片的不同占位输入隔离、切回恢复原输入。未发起真实付费生成、未运行真实 IPC 端到端;不同栏目排队整理的乐观中间态仍可能短暂回退,最终落盘范围与顺序正确,该既有表现未纳入本次返修。
| 字段 | 值 |
| --- | --- |
| Milestone | docs/project-memory/plans/【里程碑】画布验收问题统一修复-2026-09-17.md |
| Status | implemented-awaiting-runtime-acceptance |
| Owner | 主 Agent 集成,deepseek-flash 实现与独立评审 |
## 修改边界与顺序
1. 规范独立评审通过后,在同一里程碑内并行四个 worktree。
2. 生成工作区负责生成面板、任务占位、引用和工作台入口接线;原生引用工作区独立负责 Rust 入参、账号绑定、生成请求与恢复校验。两者以可选 `referenceAssetIds` / `reference_asset_ids`(当前 manifest 的 asset.id 列表)作为接缝,避免 UI 等待原生实现。
3. 展示工作区负责卡片名称/文档图标、预览表现与对应测试,不修改工作台入口及画布手势。
4. 布局工作区负责共享画布多选拖动、布局保存/整理/撤销及测试;工作台入口仅允许布局接线局部变更,集成时人工检查与生成工作区的冲突。
5. 每个实现者先自审、运行定向验证、本地中文提交并报告文件列表;主 Agent 逐项核对后集成,再由独立 Agent 先写评审计划、理解全流程、由局部到整体只读 review。
6. 主 Agent 复核问题并指派有效问题返修,重新验证后交付。远程写入另行确认。
## 评审补充与接缝所有权
- 参考选择复用当前资源引用选择组件,原生命令新增可选引用 ID 列表,解析为当前项目已登记图片,复用当前账号 external editor binding;平台请求消费现有 `referenceImageSrcs`,不修改远端 API 合同。复用 durable 已有引用快照及指纹,核对并修复仍硬编码为空或单引用的恢复校验,不无端扩展账本 schema,补 Rust 测试;对账复用 `list_local_project_asset_generations`(以源码实际命名为准)及 manifest,不新造账本。
- 主规范已固定草稿/任务身份、切换恢复、整理集合、历史粒度、手动标记及名称字段来源。真实 Provider smoke 有费用与环境前置,不默认触发付费生成。
- index.tsx 的 ResourceCard 组件体、名称/图标相关 import 属展示实现者;生成 action/draft/task/settlement 与占位 state 属生成实现者;selectedResourceIds、resourceCanvasHistory、drag handlers 和整理 handler 属布局实现者。不得整文件格式化或跨界重构;共享 import 冲突由主 Agent 集成。
- 布局实现者提供支持批量坐标及手动标记的保存入口;生成实现者仅使用现有单位置保存接口做完成落点,避免同时修改布局 hook。
## 验证命令
- `npm test -- <相关测试文件>`
- `npm run typecheck --workspace @genarrative/ai-game-creator-shell`
- `npm run check:encoding`
- `npm run check:doc-index`
- `git diff --check`
- 原生契约变更时补对应 Rust 定向测试;真实 Provider 调用前单独核对费用和环境。
## 风险与回滚点
生成结果登记、持久化布局及手势共享组件是主要交叉风险;独立分支保留可回滚提交,不覆盖原有工作区。依赖复用需避免 workspace 包指向旧工作区;不能因测试通过而跳过实际解析路径核对。文档临时计划在全部验收后清理。
## 剩余执行入口
1. 真实客户端复验末版生成浮层可见性,以及图片/音频结果接管占位;真实 Provider 验证需先确认环境与费用。
2. 用户确认远程写入后再创建/更新 Issue、PR、推送与需求记录;本地 worktree 和提交均保留。
3. 运行时验收通过后融合持久结论并删除这两份临时计划。appSurface 异步轮询用例收尾及全量复验已经完成,证据见里程碑。
@@ -0,0 +1,43 @@
# 【里程碑】多选素材批量标签
| 字段 | 值 |
| --- | --- |
| Version | 1.0 |
| Status | implemented-awaiting-runtime-acceptance |
| Date | 2026-09-17 |
| Parent Spec | docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md |
## 目标与范围
多选已登记素材后一次追加标签,保留每项原有标签和类型。复用主线菜单与现有标签面板,画布和资源面板均可进入,原生一次校验与保存。
## 非目标
不处理动画失败、资源面板卡死与未完成编辑恢复;不做聊天引用扩展、批量类型修改、既有标签批量删除或 AI 自动分类。不推送、不触发或监视 CI、不写飞书。
## 前置
主线菜单 PR #410 已合入;保留本分支前六项画布功能。主规范及本里程碑通过独立评审后进入实现。
## 验收
- [x] 两个入口均按完整冻结选择集编辑,不只修改首项。
- [x] 原有标签、正式分类和无关素材不变。
- [x] 权限/身份/CAS/任意项上限失败时无部分写入;成功一次 revision。
- [x] 空操作、重复标签和重复 ID 不重复写入;最大 200 项有界。
- [x] 保存锁定、失败草稿保留、切项目迟到响应正确处理。
- [x] 单素材标签、菜单角标和画布布局回归通过。
- [ ] 真实客户端点击、原生 IPC 写盘与跨窗口操作验收。
## 证据
前端组件与宿主整合测试、Rust 原生定向测试、AGC 类型检查、ESLint、编码/文档索引/diff 检查;真实客户端验证单独报告。
## 本地验证与审查
- 原生 `classification_tests` 22 项通过(保留既有 10 项并补批量写入、原子失败、no-op、权限、上限和审计测试)。
- 真实工作台组件的批量标签集成用例 9 项通过,包括画布和资源面板入口、两种混合选择顺序、完整目标集、回读期间切项目以及已保存但刷新失败。
- 单/批量面板、目标模型、资源面板、类型、重命名和标签统计等 9 文件、68 项定向回归通过;AGC 类型检查、目标 ESLint、编码与文档索引检查通过。
- 主线合并态 appSurface 450 项通过、20 项跳过;前端实现者完成批量接线后的同套回归,仍为 450 项通过、20 项跳过。
- 独立 review 的有效问题已落实:空白素材 ID 整批拒绝、超限错误定位到素材、批量锁操作名称、保存中输入锁、项目代次校验及首项为版本卡时入口原因可达。
- 浏览器工具当前无法连接,未将 jsdom 矩形/事件模拟称为真实客户端验收。没有推送、没有 CI 轮询、没有修改飞书。
@@ -0,0 +1,37 @@
# 【里程碑】对话总耗时与动态工具计时
| 字段 | 值 |
| --- | --- |
| Version | 1.0 |
| Status | implemented-awaiting-runtime-acceptance |
| Date | 2026-09-18 |
| Parent Spec | docs/technical/【技术方案】GameAgent对话工具调用卡片-2026-09-14.md |
## 目标与边界
整轮总耗时只在回合状态/小结显示一次,工具组显示本组历时,单条显示自身调用耗时;运行中均以 100 毫秒粒度动态增长并保留一位小数,各自完成后固定。沿用 Thread Manager,不新增业务状态源或计时账本。保留既有画布功能和本地未提交锁文件;不自动合并 PR、发布、写飞书或调用真实付费 Provider。
## 验收
前置独立评审已完成:事件级时间与条目展示时间分离、缺失/倒序判据、章节结构及格式示例已明确。主 Agent 决定整轮起点以用户发送为优先、原生 turn.started 为缺失兜底,不采用会排除发送后准备时间的起点替换。
- [x] 总耗时从用户发送到回合终态,仅显示一次并包含无工具运行时的 LLM 等待;各工具组单独计时,前组完成后不得跟随后组增长(组件回归与 Edge 模拟事件验证)。
- [x] 工具运行中无事件亦增长,已完成工具与完成回合均冻结,失败/终止通过既有明确收口路径冻结。
- [x] 原生开始/完成时间不混用,事件重放不重新取当前时间。
- [x] 重复、迟到条目不抬高已冻结用时;缺失/倒序时间不伪造耗时。同秒新回合仍按事件顺序正常开始。
- [x] 一位小数、分钟进位、并行调用与卸载清理有定向/浏览器证据。
- [x] 类型检查、Rust 定向测试与 all-targets check、编码/文档索引及 diff 检查通过。
- [x] 模拟事件的实际浏览器验证动态增长与终态冻结;未调用真实 Provider。
- [x] 正式 Direct 用户条目或本地乐观条目出现后撤下初始占位,真实同文重复发送仍保留。
- [ ] 真实客户端切项目、取消后立即重发、重开历史及真实 Provider 通知链路验收。
## 验证与剩余风险
补审返修已保留同身份真实发送时间,并为生命周期事件补 userItemId,使 live 为空时也能精确关联历史回合;独立 review 与新增恢复、迟到终态和取消回包回归通过。最终证据见对应实施计划,真实客户端验收项仍不勾选。
- appSurface 与 reducer/回合投影三文件合计 493 项通过、17 项跳过;最终初始占位与计时边界补丁另跑 5 项通过。
- 隔离依赖配置下 AGC TypeScript、skill/config、ESLint、编码与文档索引检查通过;Rust all-targets locked offline check 通过。
- 原生实现者执行 direct_thread 35 项、direct_ 312 项(1 跳过)、codex_app_server 58 项(1 跳过)及系统工程提示定向用例通过,过滤集合有重叠,不能相加作为独立用例总数。
- Edge 无头真实浏览器使用生产组件与 reducer、模拟生命周期事件:无新事件仍每 100ms 增长,单工具完成后冻结,另一工具与整轮继续增长,回合完成及重复完成事件不改变最终值。
- 无上游精确阶段时间时使用宿主观测毫秒,不宣称测得模型内部物理耗时;旧历史缺少完整生命周期时间时隐藏未知用时。
- 此证据不代表远程 CI 全绿。此前 PR 当前已推送提交的 run 2473 有两条 Rust shard 2 失败,仍需单独排查及后续 SHA 的远程结果。
@@ -0,0 +1,46 @@
# 【里程碑】画布验收问题统一修复
| 字段 | 值 |
| --- | --- |
| Version | 1.0 |
| Status | implemented-awaiting-runtime-acceptance |
| Date | 2026-09-17 |
| Parent Spec | docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md |
## 目标与范围
作为一个里程碑统一交付:生成参考、占位生成、资源名称、文档卡、多选移动、当前栏目整理及撤销。内部可用独立 worktree 并行,统一集成验收。
## 非目标
不做拖拽对话引用、聊天复制、远程写入和无关重构。不修改数据库 schema。
## 前置条件
主规范“资源画布生成、展示与布局合同”通过独立评审;保留原工作区已有未提交文件。以当前分支 d85622069 为实现基线。
## 验收标准
- [x] 空素材项目可打开生成占位和面板,必要规范前置在提交时验证(组件及宿主测试)。
- [x] 图片引用传递真实资源身份;任务失败可重试,成功回写最新占位位置(引用、队列、宿主和原生测试)。
- [x] 名称统一显示,文档卡无无效正文,详情与 UI JSON 能力无回归(定向测试及模拟原生浏览器)。
- [x] 当前栏目全部整理且可撤销,其他栏目和筛选集合语义正确(含在途写回/系统重算并发测试)。
- [x] 多选移动保持相对位置,保存与撤销为一次操作(定向测试及 141% 缩放浏览器操作)。
- [x] 独立 review 的有效阻断问题已返修并复审:引用弹层焦点、SVG 预检、音频占位身份、结果归类、整理并发及撤销作用域。
- [x] 普通生成总参考不超过 5 张,图集不接受额外参考;重试复用占位,重开不恢复未持久化占位位置。
- [ ] 最后一版浮层高度和横向居中在真实客户端复验;浏览器连接中断前已确认引用点选和插入正常,末版只有真实矩形宿主测试及独立代码复核。
- [ ] 真实 Provider 生成与 Tauri IPC 全流程(涉及账号、费用,不默认执行)。
## 证据要求
定向测试、AGC 类型检查、编码/文档索引及 diff 检查;尽可能运行 UI smoke。真实客户端/Provider 未验证必须单独列出。
## 当前证据与剩余边界
- 集成工作树的 37 个画布/引用/布局相关测试文件:424 项通过;AGC 类型检查、编码与文档索引检查通过。
- 集成工作树 `cargo check --all-targets --offline` 与 17 项 `reference_` Rust 测试通过;原生实现工作树已通过生成、登记、任务账本与 Direct 专项测试。
- appSurface 两条异步轮询泄漏相关失败已通过用例内部等待后端阶段合并、任务终态及轮询退出修复,未修改生产逻辑或全局 harness。子 Agent 在集成工作树全量复验:450 项通过、20 项跳过、0 失败。
- 画布名称沿用正式落盘文件名,生成素材可能带时间戳前缀与扩展名;未新增另一套显示名状态。
- 在途落点失败且整理无变化时可能留下一个空撤销步骤,失败提示仍可见,不导致正式素材数据丢失;低优后续事项。
- 已按确认创建 Issue #411、PR #412,并推送 `feat/agc-canvas-acceptance`;飞书未写回。用户另已授权合入 master、修复 CI 并持续推送到检查通过,不授权合并 PR 本身。
- 合入 master 后的 CI 2439 暴露五类检查偏差:图集 mock 缺少显式切分参数、工具目录断言未包含新增切分字段、更新插件迁移后的 HTTP 白名单期望过期、窗口空快照稳定化后的发布次数期望过期、测试文件末尾多空行。修复保持现行生产合同和权限范围,补齐参数/边界断言;两个 Rust 失败用例、原生合同门禁及窗口/落点四项前端用例已定向通过,仍需新提交的远程 CI 全量结果。
@@ -24,6 +24,8 @@
## 开始前
- worktree 复用 `node_modules` 时,测试与构建的 workspace alias 必须指向当前工作树源码,不能经依赖软链接读取另一工作树的共享包。遇到仅 worktree 出现的 JSX 编译错误时先核对解析路径,不用给组件补全局变量来掩盖错误来源。
- 运行 `git status --short`,保留用户已有的未提交修改;不要在共享工作树中使用破坏性 Git 命令。
- 复杂任务先读 `AGENTS.md`、`docs/【协作规范】Agent工作入口与执行准则-2026-06-22.md`、`docs/README.md` 和对应专题。
- 需要完整 SDD 的任务先确认主规范位置和验收证据,再创建 `docs/project-memory/plans/` 下的里程碑规范与实现计划;计划完成、取消或合并后删除。
@@ -1,5 +1,17 @@
# 踩坑与排障记录
## 生成草稿与异步展示边界必须按身份隔离
非模态生成浮层切换占位时按 draftId 分实例,卸载保留未提交/失败草稿,成功提交不再复活草稿;旧项目占位不存在时丢弃其保存回调。失败重试保留原请求输入和引用身份,引用失效不能静默过滤;修改已绑定输入须明确另起请求,不伪装成原请求重试。
聊天真实发送时间按相同用户 itemId 与正式条目合并,不能被启动应答后的观测时间覆盖。Thread Manager 生命周期事件透传已有 userItemId,使仅历史回读、live 为空的回合仍可精确补终态时间;不得按历史尾项或时间近似猜归属。布局整理仅可合并队尾同范围意图,不能越过中间手动写入;拖动预览和保存均冻结按下时的相应坐标基准。
## Phaser 与 CSS 双重居中导致游戏画面偏移
Phaser `Scale.FIT` 与 `autoCenter: CENTER_BOTH` 会给 canvas 计算定位外边距。若 canvas 的直接父容器同时使用 `display: grid; place-items: center` 或另一套 CSS 居中,浏览器再次定位带 margin 的元素,竖屏游戏会相对预览区域偏右。应只保留一个居中责任方:Phaser 居中时直接父容器使用尺寸明确的普通块布局;CSS 居中时设置 `autoCenter: NO_CENTER`。不禁止外围页面的 Grid/Flex 布局,不通过修改 AGC iframe 的固定偏移掩盖项目 CSS 问题。
开发 Agent 的实际系统工程提示和 `agc-web-game-development` Skill 均包含此规则。布局修改后重新构建 dist,分别在桌面、移动与 resize 后测量 canvas 相对游戏父容器的中心误差(预期居中时不超过 1 CSS px),同时检查无溢出和意外滚动条;构建成功不等于视觉验收通过。
## 发布目标与原生能力必须贯穿完整入口
显式 `--target` 不能只改变 Tauri 命令参数;AGC 发布入口必须把同一解析结果传给版本高水位、更新端点、产物目录/后缀和清单平台键,否则 macOS 构建可能错误使用 Windows 渠道。插件文件存在也不代表 native 能力可用:Cocos 在宿主注册表缺少适配器时应隐藏并拒绝启动,前端自动启动消费后端列表投影,不能仅凭项目类型推断能力。发布策略以客户端更新权威文档为准,单架构资源不能登记成双架构产物。
@@ -16,6 +16,12 @@
## 开发中
- AGC 思考与执行入口共用共享单行摘要骨架;Markdown 只在展开正文走既有安全渲染,折叠预览只取纯文本,不在 summary 嵌套链接或按钮。耗时统一复用中文时分秒格式(不足一分钟一位小数,达到分钟后整数秒),格式化与各层计时边界分离。过程行在运行中和完成后的折叠层内保持同一紧凑间距;失败状态按明确终态与非零退出码呈现红色,不由自然语言输出猜测。
- Direct 对话计时区分条目展示时间与生命周期事件时间:整轮用用户发送到明确终态的跨度,工具用各自开始/完成边界;运行时用 100ms 叶子时钟刷新一位小数,终态冻结,旧历史缺边界不推测。不得用整秒时间的大小比较取代 Thread Manager 的事件顺序判定新回合。
- AGC 批量追加素材标签由原生在一次项目写锁与 revision CAS 下合并各项原标签,先校验全批再写 manifest;前端不能循环单素材分类命令,不回传展示层推导的分类或旧标签全集,以免部分写入或覆盖未编辑字段。
- 画布卡片类型与信息角标共用 `CanvasCardCornerActions`;菜单收纳共用 `OverflowActions`,宿主决定展示数量和资源命令。AGC 选中菜单前 5 项直显,Web 默认不折叠;浮层 portal 继续接入现有画布关闭与滚轮归属判据。
- 修改范围保持聚焦;优先扩展现有系统、页面、组件、DTO 和脚本,不新建平行入口或业务真相。
- UI 开发优先复用现有公共组件;跨页面或跨端重复的视觉/交互模式应沉淀到 `packages/shared`,由现有页面迁移使用,禁止在业务页复制同类 UI。共享组件只承载通用表现与交互,不下沉领域规则、后端副作用或正式业务状态。
@@ -1,5 +1,45 @@
# AI 游戏创作智能体 App 实施计划
## 游戏画布居中指引
开发 Agent 的系统工程提示与 `agc-web-game-development` Skill 明确约束同一 canvas 的居中只能由一方负责:Phaser `FIT + CENTER_BOTH` 配合尺寸明确的普通块级父容器,不叠加同一父容器的 Grid/Flex 居中、自动外边距或居中 transform;如由 CSS 居中则设置 Phaser `NO_CENTER`,外围页面的 Grid/Flex 不受此限制。布局修改后构建实际 dist,并在桌面、移动和 resize 下核对 canvas 对游戏父容器中心偏差不超过 1 CSS px、无溢出与意外滚动条。出现偏移先检查游戏项目的 CSS/scale,不修改 AGC 预览固定偏移掩盖问题;这些要求通过 Agent 指引执行,不新增运行时门禁或平行校验系统。
## 画布验收返修边界
- 生成浮层的实例、输入、失败状态与请求身份必须按占位草稿身份隔离;切换到另一张占位时不能沿用上一张的工具类型、输入或 operation。切换未提交草稿仍须保留各自输入,回到原占位可继续编辑。
- 失败任务重试必须保留原请求的完整参考资产 ID 集合。参考资产失效时明确提示并阻止旧请求提交,不得静默过滤后用改变的参考集恢复原 operation,也不得自动创建新的付费请求。
- 显式整理的待写意图不能因切换栏目而覆盖其他栏目的排队范围。每个受影响范围与撤销步骤保持一致;拖动预览和最终写回使用同一份按下时冻结的起点快照,即使拖动期间布局收到异步更新也不跳位。
## 多选素材批量标签
- 画布与资源面板共用选中集合。选择至少两项同项目已登记素材后,从已有“编辑标签”入口或资源面板的“批量标签”动作打开同一标签编辑器的批量模式;入口遵循既有“常用操作 + 更多”收纳,不新增平行资源管理页。
- 批量模式只将用户填写的标签追加到整组选中素材。输入按既有中英文逗号、顿号、换行拆分,trim、去空及去重;每份素材原有标签、正式分类、类型、路径、来源、版本关系均保留。批量删除/替换既有标签、批量改素材类型及 AI 自动分类不在本次范围。
- 操作对象在打开面板时冻结为去重后的素材 ID 列表,不随后续选择变化扩散;项目切换关闭面板并忽略迟到响应。混合选择含虚拟版本、未登记附件或已删除资源时,不允许只对其中一部分静默保存,入口禁用并给出原因。
- 批量范围为当前入口展示的完整选中集合:资源面板保留跨筛选的选择时,也必须显示实际目标数量;不得仅修改第一项或仅修改当前可见项。每批最多 200 个不同素材,超过上限要求缩小选择。
- 原生新增局部命令 `add_local_project_resource_tags`,参数 `input: { projectPath, expectedProjectId, expectedProjectRevision, assetIds, tags }`;仅消费当前 manifest 素材 ID。响应 `{ assets, committedProjectRevision }` 返回整组选中素材最新条目。沿用 `asset.register` 权限、项目身份、写锁及 revision CAS;不新建 manifest schema、数据库字段或外部 API。
- 原生按锁内最新 manifest 为每项合并标签,沿用现有单标签长度与标签总量限制,先校验全部目标及合并后上限,再一次写 manifest;非法 ID、标签、项目身份或版本冲突不写入任何一项。重复标签重试不重复追加;整批无变化时不推进 revision、不追加修改审计。已写 manifest 后的审计或 revision 异常必须明确返回“已写入”状态信息,沿用既有单资源写入错误语义,不能谎称回滚。
- 保存期间禁用重复提交及关闭;失败保留待追加标签,CAS 冲突需明确报错而非自动覆盖。成功用原生返回条目刷新宿主 manifest 与筛选统计,不循环调用单素材保存、不按旧闭包覆盖最新其他素材。
- 单素材标签编辑仍保持既有增删标签行为;菜单信息/类型入口、批量移动、文档与引擎资源预览不得回退。验收覆盖不同原始标签与分类、资源面板/画布多选入口、重复标签、超限及混合选择、批次失败零部分写、一次 revision、项目切换迟到回包和单素材回归。
- 批量模式的标签输入仅显示待追加草稿,不把各素材已有标签并集作为提交值。资源面板入口放入现有动作行,画布入口沿用选中工具栏的收纳。响应条目按去重后请求 ID 的首次出现顺序返回,无变化时返回当前 revision;DTO 使用 camelCase 并拒绝未知字段,批次上限按去重后数量计算。
## 资源画布生成、展示与布局合同
- 生成工具点击后先在当前栏目创建临时占位卡,并以卡片为锚点展示独立生成浮层;占位不登记为正式素材、不进入 Agent 可引用资源集。上传仍沿用文件选择,不创建虚假生成任务。关闭编辑浮层不应丢失正在执行的任务;切换项目不得将旧项目结果或草稿写入新项目。
- 图片生成支持从现有素材选择器添加真实参考;引用携带稳定资源身份并经既有原生权限、归属与类型校验传至生成链路,不能仅拼接名称。缺少规范图不阻止打开面板;确有规范前置的操作必须在提交前满足要求,不能绕过后端校验。用户可通过现有工具栏先生成规范图。
- 占位可移动。提交复用正式生成任务、幂等与结果登记链路;成功结果使用占位最新位置,失败保留输入与引用供重试。已受理但响应不确定时先对账,不能无条件再次发起付费生成。关闭、删除占位和后台任务的行为需保持既有任务所有权,不把隐藏展示当作取消任务。
- 所有资源卡显示正式素材名称(Agent 生成的 assetName 或用户重命名),没有名称时才使用既有文件名兜底;长名称省略但可查看完整名称。文档卡以居中图标呈现,不显示无效正文片段;独立详情保留原文预览、UI JSON 识别、权限及读取预算。
- “整理画布”显式重排当前栏目全部素材,包括手动坐标;筛选不缩小整理集合,其他栏目不变。重排作为一次可撤销操作保存,失败继续使用现有写队列及冲突处理,不伪报保存成功。
- 框选多个素材后拖动任一已选卡,按统一位移移动整个选择集并保持相对位置;拖动未选卡保留单选语义。松手统一提交,整次操作可一次撤销;缩放坐标、指针取消、窗口失焦、保存失败和项目切换不得导致选择丢失或布局串写。
- 本合同不包含拖入对话批量 @、复制聊天引用、历史替换交互、SpacetimeDB schema 或新的远程公开 API。共享表现与交互优先扩展公共组件,正式资源状态仍由宿主/原生链路维护。
- 参考选择范围为同一项目已登记图片,可跨栏目、多选,无规范前置时最多 5 张,有规范前置时最多 4 张用户参考(总计最多 5 张);复用资源引用选择组件,不允许文档、音视频、占位或跨项目素材。本地生成命令补最小引用 ID 参数并转换为当前账号绑定下的远端资源 ID,沿用图片生成 API 已有 `referenceImageSrcs`。需要规范图的普通图片请求合并并去重规范引用,总数不超过现有 API 限制;只接受单规范引用的图集操作不显示用户参考选择器,原生提交拒绝额外参考而非静默丢弃。不得降级成纯提示词。
- 占位由宿主按项目与独立草稿 ID 管理,提交后关联任务 ID;失败重试使用同一占位。切项目清理未提交草稿与界面位置,已提交任务继续沿用账本恢复,重开后不承诺恢复未持久化的占位位置。迟到结果先核对项目和任务归属;只有本会话仍存在的占位才应用最新位置。删除占位只隐藏展示,不取消后台任务或丢弃正式结果。
- 参考必须是原生可解码的栅格图片,SVG 不进入参考候选;原生在上传任何引用前预校验整组素材的归属、受控路径、文件及解码,失败不静默丢图。需要重新上传当前账号绑定的参考遵循 `asset.upload` 权限。manifest 读侧的引用形状检查不证明远端账号归属,实际生成始终通过当前账号 binding 解析,不凭历史来源 ID 发起请求。
- 图片类 GUI 生成通过可选 `targetCategory` 在原生登记时写入入口栏目,使用既有 manifest `category` 字段及合法分类词表;不传时保留按 kind 派生的行为,Agent 不传。该值不改变远端生成内容及计费幂等槽,仅决定本地生成结果分类;重试保持原占位栏目。同路径重新生成时,主产物按本次入口栏目更新分类(包含覆盖此前手动分类),图集附属切片保持既有独立分类规则。
- 生成面板打开后,占位和面板需处于当前画布标题栏与底部工具栏之间;面板复用公共外观,空间不足时面板内部滚动,提交按钮可达。音频/BGM 占位绑定原有 operation/idempotency 身份,进行中不允许换身份重复提交;失败可用原身份重试,成功结果与图片一样接管占位。关闭未提交浮层保留可继续编辑的草稿,删除占位才丢弃该草稿。
- 整理范围为当前栏目页全部资源;“所有资源”页为当前项目所有可展示资源,总览不新增整理行为。重排结果成为自动坐标,可撤销恢复原坐标与手动标记;历史仅保留当前会话,切项目清空。多选仅作用于当前画布可见选中资源,不携带筛选隐藏或跨栏目残留选择;取消手势恢复拖动前坐标,切项目清空选择。
- 当前素材名以现有正式命名链路为准:生成时 assetName 参与落盘名称,重命名更新文件名;卡片消费正式资源 label,不从临时输入或历史任务名覆盖后续重命名,不新增平行显示名持久化。若原有命名链路丢失 assetName,则修复原链路,而非只在卡片本地伪造。文档卡不显示任何正文摘要,但详情原文与 JSON 识别读取不变。
- 验收覆盖空素材项目进入工具、真实引用入参、成功/失败/重试与迟到响应、占位移动后落点、全类型名称、文档详情、当前栏目重排/撤销、不同缩放的多选移动/撤销以及其他栏目不变。自动化、真实客户端和真实 Provider 验证分别报告;未实际运行的路径不得标为通过。
## 策划 Agent 批量局部修改
`patch_file` 的所有 edits 均匹配同一份原文件,参数顺序不影响结果。完成唯一匹配与不重叠校验后,按原文起点升序拼接未修改片段与替换文本,最后一次性写入;任一校验失败时不写文件。回归用例覆盖乱序 edits、中文内容与替换长度增减,并核对完整落盘内容。此行为仅属于策划 Agent 文件工具。
@@ -11,7 +11,38 @@
## 一句话交付
把 GameAgent 右侧对话面板里的「执行命令 / 写文件 / 调工具」从一行中文进度文本,改成 Codex 桌面客户端那样的**可折叠卡片**(折叠态一行摘要,展开态看命令与文件明细),并且在**刷新页面、重开项目后仍然存在**。
把 GameAgent 右侧对话面板里的「执行命令 / 写文件 / 调工具」改成可折叠卡片,整轮总耗时只在回合状态/完成小结显示一处,工具组与内部工具分别显示各自耗时;运行中的计时动态增长,不足一分钟保留一位小数,达到分钟后显示整数秒。
## 总耗时与动态工具计时
### 紧凑过程入口与 Markdown
- 思考过程、执行过程和工具组统一为无大块底色的单行折叠入口:左侧小图标/简短预览,最右侧展开箭头;长文本省略,不把箭头挤出窄聊天列。沿用共享过程色和 12px 层级,键盘可展开、有可见焦点。
- 思考折叠态直接显示浅色的内容预览,而不是只有“思考过程”标题;预览不显示 Markdown 控制符、原始 HTML 或链接地址。展开后复用现有安全 Markdown 渲染链路,支持段落、强调、列表、链接、代码块等,不开启原始 HTML 执行。实时与历史、当前 Agent 与策划 Agent 使用同一呈现。
- 思考入口使用灯泡图标;展开后入口文字切换为“思考过程”,原内容仅在 Markdown 正文显示一份,不同时保留相同摘要。收起后恢复浅色内容预览;键盘开合与鼠标开合行为一致。
- 回合结束后最外层“执行了 N 个操作,耗时 XXX”使用正文颜色;收进该折叠层的内部过程保持运行中原有颜色、行高和块间距,不能因额外 Grid gap 与子元素 margin 叠加而拉大间距。
- 思考与工具组按紧凑连续列表呈现,相邻过程块间距 4px,内部工具行使用紧凑的 2px 上下内边距;运行与完成后的容器使用同一口径。失败工具的名称、图标、状态及耗时使用错误红色,所属组摘要有“有操作失败”提示且标红;同组其它工具仍运行时也不能吞掉失败标识,成功行不得被连带染红。
- 工具组摘要只统计本组工具条目总数,显示“执行了 N 个操作,耗时 XXX”;运行中另有状态提示,不把操作数称作成功数,失败仍保留明确状态。回合外层执行过程统计所有工具块的操作数,不把思考段落或文本消息当工具操作;缺失耗时不伪造。
- 所有 AGC 耗时统一用中文时分秒:不足一分钟显示 `5.2秒`,达到分钟后显示整数秒,如 `2分05秒`、`1时02分05秒`。省略前导零单位,带小时则保留两位分钟,带分钟则秒补齐两位整数;先整体舍入再拆分单位,避免出现 60 秒/60 分。工具行、组、整轮、生成任务及策划耗时共用一个纯格式化函数,不改变各自计时来源和动态刷新。
- Direct 对话发送后、本轮首个可见思考/文字/工具响应到达前,在消息列表内、工具调用块外临时显示“思考中…”。收到首个响应后移除,失败、取消和空闲时同样不显示;直接从现有忙碌状态与本轮投影派生,不新增原生事件、定时器或持久化消息。工具间等待不在本次轻量实现范围内。
- 独立计时保持不变,组状态/用时在单行中作为次要信息,空间不足可移至展开内容,不能占第二行破坏紧凑入口;整轮总耗时仍只显示一次。工具输入/输出、失败信息与操作明细不因样式变更丢失。
- 只改展示与对应测试,不改变消息身份、分组顺序、生成或原生执行语义。验证覆盖 Markdown 安全与语义、预览省略、准确计数、展开/键盘操作、窄屏布局及原有计时冻结。
- “总耗时”表示同一轮用户请求从发送到回合终态的墙钟跨度,包含 LLM 推理、工具调用和等待;只在本轮运行状态或完成小结显示,不重复放进各工具组。
- 工具组顶部“执行了 N 个操作,耗时 XXX”中的耗时范围是本组首个工具开始到最后一个工具完成,包含组内等待但不是工具耗时之和。不同工具组独立计时;本组全部终态后立即固定,即使本轮或后面的工具组仍运行,也不能显示“进行中”或继续增加。组头不展示发送/结束时刻,不沿用用户发送时间计算本组。
- 回合仍运行但全部工具暂时结束时,只增长本轮总耗时。成功、失败或终止到达后整轮按实际终态时间固定;随后打开折叠块、翻页或其它回合的新事件不得改变已完成的组或回合用时。
- 单条工具从其实际开始到完成计时。运行中的工具按当前时间持续增长,不能把最近一次快照更新时间当作当前时间;已经结束的工具必须立即固定,即使同组其它工具或 LLM 仍在运行。
- 对话的组、工具及整轮耗时运行中均每 100 毫秒刷新,统一使用上述中文时分秒格式。以时间戳计算而不是按 tick 累加,避免后台节流后的累计漂移;缺失或倒序边界不伪造 `0.0`。非对话场景只统一文本格式,不改变原有刷新或后端累计时间语义。
- 各层时间范围与对应耗时使用相同的起止边界。运行标记也按本层状态判定;完成后如果展示起止时间,其精度不得造成范围差与用时矛盾。组内存在缺失或倒序的工具边界时,不能用其他组或整轮的时间补造本组耗时。
- 原生事件保留各阶段的时间语义:开始与完成不能都优先折叠成开始时间。优先采用上游明确提供的阶段时间或实际调用时长,缺失时使用宿主观察该阶段的时间;重放沿用原事件时间,不能在前端收到或重放时重新取当前时间。
- 工具开始/完成的权威边界是事件级 `at`,不是条目展示字段 `item.at`。整轮起点优先采用该轮实际用户消息的发送时间(与气泡一致,不取所有条目的最小时间),缺失时采用原生 `turn.started.at`;终点只采用 `turn.completed.at` 或明确的终止/失败收口事件。首次补到更早的真实发送时间可以校正起点,但旧历史或重复事件不能覆盖已经固定的终点。
- 回合阶段使用宿主观测阶段的毫秒时间,或上游明确的毫秒边界/可靠时长;不把上游已截断的整秒时间冒充十分之一秒精度。回合是否开始以 Thread Manager 的事件顺序为准,不能用时间戳大小拒绝取消后同一秒内的新请求。回合完成的展示时间在当前会话中冻结;重新打开后若历史未保存完整生命周期边界,则隐藏未知用时而非补造。
- 无效边界包括缺字段、非有限值、时间戳为 0、结束早于开始;这些情况隐藏不能证明的耗时。合法开始时刻的运行中 `0.0秒` / `0.0s` 则正常显示。只有完成快照而没有开始事件的工具不猜测开始时间。
- 沿用 Thread Manager 的生命周期与条目身份,不引入第二套回合状态源、计时账本、远程 API 或数据库字段。前端仅保存原事件的展示时间边界;旧历史缺少完整边界时不声称知道精确总耗时或工具耗时,不为补齐计时启动模型请求。
- 必须覆盖:前组已完成而后组运行时各自时间独立、整轮总耗时仅出现一次、无新事件仍增长、工具完成后 LLM 继续、并行工具分别计时、完成/失败/终止冻结、同身份重放不改终态时间、切项目与卸载停止计时、缺失与倒序时间、0.0 / 59.9 / 60.0 秒边界。真实 Provider 验证与模拟事件的客户端验证分开报告。
- Direct 对话的初始消息占位仅在正式用户消息尚未进入当前显示链路时显示;正式条目或乐观用户条目出现后撤下占位,不在消息列表外额外保留一份。只控制占位是否显示,不按文本合并或删除用户真实重复发送的消息;分页已有更早历史时不把初始占位补到当前页。
- 同一用户消息从本地发送转为正式条目时必须保留原发送时间,不能因去重丢掉该时间而改用启动应答后的观测时间。回合明确结束时,即使当前 live 集合为空,也应将终态边界关联到已知的本轮用户条目;不得仅按“历史最后一项”猜测或向无关旧回合补时间。
- 生命周期事件可携带已有用户条目的 `userItemId`,用于把时间边界精确关联到同一条历史消息(不产生新的回合 ID 或持久化字段)。恢复时该关联随 Thread Manager 原事件重放;带旧用户身份的终态不能收口另一条新请求。缺少身份的旧事件不据时间猜测归属。
## 背景与现状(已核实)
@@ -74,21 +105,20 @@ DirectRuntime 写 `<projectRoot>/.agent/conversations/tool-calls.jsonl`;回读
```html
<section class="agent-tool-call-group" data-testid="agent-tool-call-group" data-status="completed">
<button type="button" class="agent-tool-call-group-head" aria-expanded="false" aria-controls="…"
aria-label="已执行 2 个命令、1 个文件变更,用时 42秒">
aria-label="执行了 3 个操作,耗时 42.0秒">
<span class="agent-tool-call-group-icon" aria-hidden="true"></span>
<span class="agent-tool-call-group-summary">已执行 2 个命令、1 个文件变更</span>
<span class="agent-tool-call-group-time">14:20:05 → 14:21:02</span>
<span class="agent-tool-call-group-duration">用时 42秒</span>
<span class="agent-process-summary-preview">执行了 3 个操作</span>
<span class="agent-process-summary-meta">,耗时 42.0秒</span>
<svg class="agent-tool-call-group-chevron" aria-hidden="true"></svg>
</button>
<div class="agent-tool-call-group-body" hidden>
<ul class="agent-tool-call-group-rows">
<li class="agent-tool-call-group-row" data-testid="agent-tool-call-row" data-kind="command" data-duration-ms="12300">
<button type="button" class="agent-tool-call-row-head" aria-expanded="false" aria-controls="…"
aria-label="已运行 npm run build,耗时 12.3s">
aria-label="已运行 npm run build,耗时 12.3秒">
<span class="agent-tool-call-row-icon" aria-hidden="true"></span>
<span class="agent-tool-call-row-text">已运行 npm run build</span>
<span class="agent-tool-call-row-duration">12.3s</span>
<span class="agent-tool-call-row-duration">12.3秒</span>
<svg class="agent-tool-call-row-chevron" aria-hidden="true"></svg>
</button>
<div class="agent-tool-call-row-detail" hidden>
@@ -103,10 +133,10 @@ DirectRuntime 写 `<projectRoot>/.agent/conversations/tool-calls.jsonl`;回读
```
- 文案规则(按 kind,不允许自由发挥):
- 块头汇总按 kind 计数、顺序固定 `command → file_change → mcp_tool → web_search → context_compaction → other`,标签 `命令`/`文件变更`/`工具调用`/`联网搜索`/`上下文整理`/`其他操作`,形如 `已执行 5 个命令、2 个文件变更`;空集合不渲染块。
- 块头按实际工具条目计总数,形如 `执行了 7 个操作,耗时 1分05秒`;空集合不渲染块。操作数不是成功数,失败与运行状态仍单独可见。
- 行文案:展示工具摘要,不重复添加动词前缀;`context_compaction` 固定为“整理上下文”。状态单独放在行尾(执行中 / 已执行 / 失败),`failed` 使用现有 `--platform-*` 错误色;已结束回合不因残留 `running` 快照显示“执行中”。
- 耗时:单条工具 = `startedAt` → `updatedAt`,块头总用时 = 该回合所有工具的 `min(startedAt)` → `max(updatedAt)`。单条格式:`<1s` → `0.4s`、`<60s` → `12.3s`(整秒省略小数)、`≥60s` → `2m 5s`;块头格式:`42秒` / `4分钟` / `5分钟 45秒`。`startedAt` 为 0 或 `updatedAt < startedAt` 时不显示耗时(不显示 `0s` / 负数),耗时为 0 时同样不显示 `0s`。
- 时间:块头显示该回合结束时间(`max(updatedAt)` 的本地 `HH:mm:ss`);同一回合能拿到用户消息时间(`updatedAt > 0`)时显示 `HH:mm:ss → HH:mm:ss`(发送 → 结束),取不到就只显示结束时间,不编造。
- 耗时:执行“总耗时与动态工具计时”合同。块头是本组用时,单条是该工具独立耗时,整轮总耗时只在本轮状态/小结显示;不足一分钟显示一位小数,达到分钟后显示整数秒,运行中每 100 毫秒刷新,各自终态固定。
- 时间:范围与对应层级用时采用同一边界,不把用户发送起点与局部工具组终点混搭。缺失的历史时间不编造。
- 回合结束时间与耗时在正文下方右对齐;Direct 对话输入框提示统一为“描述你的想法,或 @ 引用素材”,引用按钮保留输入盒的 12px 内边距,不使用负边距贴边。
- 当前 Agent 与策划 Agent 共用 `packages/shared` 的 `AgentMessageContent` 表现组件:正文为 14px / `--platform-text-strong`,思考、中间输出和工具调用为 12px / `--platform-text-soft`。实时与历史思考共用同一个折叠入口;工具输入输出继承过程色,失败状态保留错误色。Markdown 标题、表格及代码高亮在过程区同步弱化,最终回复和文档预览仍保留正常排版,不按 Agent 类型复制样式。输入提示与禁用状态保持原有反馈。
- Windows 命令展示:仅 `command` 卡片识别 `pwsh` / `powershell`(含完整路径、`.exe`、常见启动选项)的 `-Command` / `-c` 外层包装,摘要和展开输入只展示脚本正文,并解开单个 shell 参数的引用拼接。摘要优先读取已脱敏的 `detail.command`,再按首行 120 字符截断,避免历史摘要被可执行文件路径占满。无法识别的启动方式、`-File`、`-EncodedCommand`、普通命令和 MCP 输入原样展示;执行参数、持久化原文、脱敏和输出均不改变。