fix/引用持久化 #365

Closed
k88936 wants to merge 100 commits from fix/ref-persistent into master
Member

close #360

after:
shotmd-1789472209.jpg

close #360 after: ![shotmd-1789472209.jpg](/attachments/143b5bd0-cd46-4082-a496-79c23f34d708)
k88936 added 1 commit 2026-09-15 14:56:38 +08:00
新增 DirectProject 用户 Response item 契约
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m35s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m34s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m36s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m31s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m46s
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m32s
Project CI / Frontend tests (pull_request) Successful in 4m0s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m34s
Project CI / Native shell tests (pull_request) Successful in 6m35s
dfd6fadedf
新增 Rust canonical user item 与 Codex wire 转换模块

增加 ts-rs 绑定目录及生成文件检查边界

更新聊天素材引用规范与里程碑实施计划
k88936 added 2 commits 2026-09-15 15:27:18 +08:00
将 direct_runtime 与 codex_app_server 改为目录模块

拆分 user item 的模型、校验与 wire 投影文件

抽离 DirectProject 历史注入载荷构造 seam
抽离 DirectProject 身份解析模块
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 2m16s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 2m20s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 2m4s
Project CI / Backend tests (pull_request) Failing after 18s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 1m54s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m22s
Project CI / Repository checks (pull_request) Failing after 9s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m20s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m36s
Project CI / Frontend tests (pull_request) Successful in 3m45s
Project CI / Native shell tests (pull_request) Successful in 5m27s
5ec40c8b83
将项目 canonical identity 与 digest 放入独立文件

保持 Codex app-server 线程池调用接口不变
k88936 added a new dependency 2026-09-15 15:51:56 +08:00
k88936 added 7 commits 2026-09-15 16:48:56 +08:00
移除 game-creator-conversation.v1 读取 fallback

历史注入前逐项投影 canonical user item 为 Codex message

无效 item 在持久化前失败关闭
拒绝资源引用额外身份字段与未知 content part

补充历史 item wire 投影边界测试

同步 DirectProject 历史文档为无 fallback 合同
移除 DirectCodexTurnReference 平行 DTO 与渲染路径

将引用数量上限收回 canonical user item 校验模块
覆盖 Lexical 文本与引用交错顺序

验证资源引用只发送稳定 resourceId
标记 canonical、wire 与失败关闭验收项

同步实施计划为进行中状态
按 Lexical 顺序构造 message.content

DirectProject payload 改为发送 userItem

策略重试保留同一 canonical item
收紧历史测试与注释口径
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 2m17s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 2m7s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m7s
Project CI / Backend tests (pull_request) Failing after 19s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 2m19s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 2m17s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m26s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m43s
Project CI / Frontend tests (pull_request) Failing after 4m6s
Project CI / Native shell tests (pull_request) Successful in 7m29s
17716347e2
移除 legacy 投影描述

将历史测试统一为 Response item 合同
Author
Member
  • 1. apps/ai-game-creator-shell/src/App.tsx:6490directTurnInput.userItem 重复赋值

    • 当前实现:对象字面量已经写入 userItem: effectiveUserItem,后面又再次赋同一值。
    • 问题判断:有效但仅属死代码,不改变行为。
    • 处理:已删除重复赋值。提交:2c623bb57(移除 DirectProject 回合输入的重复赋值)。
  • 2. apps/ai-game-creator-shell/src/App.tsx:6070 非 DirectCodex 路径提前创建回合身份

    • 当前实现:handleChatSubmit 无条件创建 DirectCodex 回合 ID 和 user item,随后旧 Supervisor/策划路径也会接收到该可选 ID。
    • 问题判断:有效的轻微一致性问题;会做无用工作,并可能让策划回合使用错误前缀身份。
    • 处理:仅 DirectCodex 产品运行时创建 ID 和 user item,其他路径交给各自执行器生成身份。提交:b3b5d7799(按运行模式创建 DirectProject 回合输入)。
  • 3. direct_project_history.rs:185-190 删除 legacy 行投影导致历史读取失败

    • 当前实现:DirectProject reader 对非 response_item 行失败关闭。
    • 问题判断:review 把旧通用 conversation 行当成了本次必须兼容的输入,但里程碑明确“legacy conversation 行不提供 fallback”;本次不做迁移、不加 fallback 符合设计。
    • 处理:不改代码,保留 fail-closed 边界。
  • 4. codex_app_server/mod.rs:15-16 顶层 sha2 import 未使用

    • 当前实现:该文件后续仍使用 Sha256/Digest 计算输出、认证和配置摘要。
    • 问题判断:过时误报,删除会导致编译失败。
    • 处理:不改代码。
  • 5. ResourceReferenceInput.tsx sameDraft 比较 content 造成反复回写

    • 当前实现:输入区已按 Home 模式改为 Lexical EditorState 单一 authority;文本、引用和 canonical content[] 都从该 state 读出。
    • 问题:原先的 sameDraftValue / sameCanonicalDraft 是旧双状态同步的补偿,会造成重复比较和潜在回写。
    • 处理:删除两层 draft 比较;外部清空/替换走编辑器 handle,普通输入只由 Lexical OnChangePlugin 产生。
  • 6. ResourceReferenceInput.tsx:205-210 资源引用到 content part 的映射重复

    • 当前实现:组件内重复构造 resource/runtime-region 两种 part。
    • 问题判断:有效的低风险维护问题,字段新增时存在漂移风险。
    • 处理:复用 chatReferenceToContentPart。提交:f213987f9(复用资源引用的统一内容映射)。
  • 7. resourceReferences.ts content 缺失时把 text/references 拼成猜测输入

    • 当前实现:DirectProject user item 只接受从 Lexical EditorState 派生的 canonical content[];转换入口不再读取 text + references 猜测顺序。
    • 问题:旧回退会重复表达引用并丢失编辑顺序,也会掩盖调用方没有 canonical content 的错误。
    • 处理:删除 legacy fallback;DirectProject 缺少 user item 时直接失败关闭,首轮使用显式 canonical input_text 构造。
  • 8. resourceReferences.ts:130-132 嵌套三元表达式

    • 当前实现:content 回退优先级用嵌套三元表达。
    • 问题判断:不改变行为的可读性问题。
    • 处理:改成显式 if/else 三分支。提交:a543b75cf(拆开聊天草稿内容分支判断)。
  • 10. wire.rs:43-44 校验与 wire 投影重复读取 manifest

    • 当前实现:wire 投影先校验,再单独读取 manifest;prompt 调用链还会再次进入 wire。
    • 问题判断:有效的低风险性能问题。
    • 处理:校验函数返回已读取的 manifest,wire 投影复用它。提交:f2030a616(复用 DirectProject 用户输入校验读取的 manifest)。
  • 11. model.rs:67-69 未使用的 DirectCodexUserMessageEnvelope

    • 当前实现:类型仅定义/内部 re-export,代码库无调用,生成目录也没有对应绑定。
    • 问题判断:有效的死 API 面;删除不影响现有调用方。
    • 处理:移除类型及 re-export。提交:cd2edd696(移除未使用的 DirectProject 输入信封类型)。
  • 12. direct_runtime/user_input.rs 附件未进入 DirectProject 模型 prompt

    • 当前实现:附件/图片继续使用现有 DirectCodexTurnAttachment sidecar;canonical user item 不新增附件 part。
    • 问题:此前 command 只把附件写入 audit,没有调用既有的有界路径映射渲染,模型收不到附件和图片信息。
    • 处理:DirectProject command 在 canonical item 投影后调用 render_direct_codex_user_prompt;图片、Markdown 和其它文件统一输出原名、项目路径、类型、大小、状态。附件-only 输入允许在 sidecar 渲染前保持空 canonical 文本。
  • 13. direct_runtime/mod.rs:4169 两个互斥分支克隆整个 optional JSON

    • 当前实现:两个分支都对不再使用的 direct_user_item 调用 .clone()
    • 问题判断:有效的低风险性能问题。
    • 处理:在互斥分支中直接移动值。提交:22e830ff9(避免 DirectProject 回合输入的无必要克隆)。
  • 14. ResourceReferenceInput.tsx:192-194 空白 text node 进入 canonical content

    • 当前实现:引用后的空格和换行也会生成 input_text,Rust 校验拒绝 trim 后为空的 part。
    • 问题:带引用的常见提交可能失败,属于高影响输入行为。
    • 处理:编辑器读取时跳过纯空白 part、合并相邻文本。提交:3c7b02b9f(过滤 DirectProject 编辑器的空白内容 part)。
  • 15. direct_project_history_wire.rs:18-21 标准历史 item 被重新投影为错误 wire 形状

    • 当前实现:标准 assistant/tool 等非 user item 原样透传;user canonical item 经过 direct_codex_user_item_to_response_item 后,文本 part 当前明确生成为 type: "input_text"
    • 问题判断:review 依据的是旧中间状态;当前源码和 response_item_projection_uses_input_text_not_turn_input_text 测试已覆盖该口径,不需要迁移或 fallback。
    • 处理:不改代码。
  • 16. codex_app_server/mod.rs:2661-2663 canonical AGC part 写入聊天历史后读取丢失

    • 当前实现:追加原始 canonical item,但聊天历史读取只提取 text content part。
    • 问题:纯引用消息或含引用消息在重载后可能显示为空/被过滤。
    • 建议:扩展 history reader 读取 canonical part,或在写入 chat projection 时明确生成安全文本投影;需先定历史真相边界。
  • 17. App.tsx:6072 chatContent 可能携带空白 input_text

    • 当前实现:前端把 Lexical 原始 content 直接传给 converter,引用分隔空格/换行不会被过滤。
    • 问题:与第 14 条同源,会被 Rust 校验拒绝。
    • 处理:在统一 chatComposerDraftToDirectCodexUserItem 转换入口过滤纯空白 input_text。提交:35733f0e3(过滤 canonical 草稿中的空白输入 part)。
  • 18. App.tsx:743-745 规划 V2 提交后未清理引用草稿

    • 当前实现:planning-v2 分支只清空文本,未清空 references/content。
    • 问题判断:有效的低风险状态残留问题。
    • 处理:提交规划回合时同步清空 chatReferenceschatContent。提交:c266ae7b5(清理策划模式提交后的聊天草稿)。
  • 19. direct_codex_user_item/wire.rs:26-30 response item 使用 text 而非 input_text

    • 当前实现:direct_codex_user_item_to_wire_input 内部确实使用 type: "text",但它只服务 turn/start prompt;历史 response item 走另一个投影函数,并明确改成 type: "input_text"
    • 问题判断:review 把两个不同 wire seam 混为一谈;当前实现已分离,不能据此判定“历史投影使用 text”。
    • 处理:不改代码。
  • 21. direct_runtime/user_input.rs:51-62 显式校验与空 prompt 分支重复/不可达

    • 当前实现:调用 direct_codex_user_item_to_prompt 已包含校验和空 prompt 失败,外层再次校验并检查空字符串。
    • 问题判断:有效的低风险重复逻辑。
    • 处理:复用投影函数的错误收口,删除重复校验和不可达分支。提交:1da106af7(避免重复校验 DirectProject 用户输入)。
- [x] 1. `apps/ai-game-creator-shell/src/App.tsx:6490` 的 `directTurnInput.userItem` 重复赋值 - 当前实现:对象字面量已经写入 `userItem: effectiveUserItem`,后面又再次赋同一值。 - 问题判断:有效但仅属死代码,不改变行为。 - 处理:已删除重复赋值。提交:`2c623bb57`(移除 DirectProject 回合输入的重复赋值)。 - [x] 2. `apps/ai-game-creator-shell/src/App.tsx:6070` 非 DirectCodex 路径提前创建回合身份 - 当前实现:`handleChatSubmit` 无条件创建 DirectCodex 回合 ID 和 user item,随后旧 Supervisor/策划路径也会接收到该可选 ID。 - 问题判断:有效的轻微一致性问题;会做无用工作,并可能让策划回合使用错误前缀身份。 - 处理:仅 DirectCodex 产品运行时创建 ID 和 user item,其他路径交给各自执行器生成身份。提交:`b3b5d7799`(按运行模式创建 DirectProject 回合输入)。 - [x] 3. `direct_project_history.rs:185-190` 删除 legacy 行投影导致历史读取失败 - 当前实现:DirectProject reader 对非 `response_item` 行失败关闭。 - 问题判断:review 把旧通用 conversation 行当成了本次必须兼容的输入,但里程碑明确“legacy conversation 行不提供 fallback”;本次不做迁移、不加 fallback 符合设计。 - 处理:不改代码,保留 fail-closed 边界。 - [x] 4. `codex_app_server/mod.rs:15-16` 顶层 `sha2` import 未使用 - 当前实现:该文件后续仍使用 `Sha256`/`Digest` 计算输出、认证和配置摘要。 - 问题判断:过时误报,删除会导致编译失败。 - 处理:不改代码。 - [x] 5. `ResourceReferenceInput.tsx` `sameDraft` 比较 content 造成反复回写 - 当前实现:输入区已按 Home 模式改为 Lexical `EditorState` 单一 authority;文本、引用和 canonical `content[]` 都从该 state 读出。 - 问题:原先的 `sameDraftValue` / `sameCanonicalDraft` 是旧双状态同步的补偿,会造成重复比较和潜在回写。 - 处理:删除两层 draft 比较;外部清空/替换走编辑器 handle,普通输入只由 Lexical `OnChangePlugin` 产生。 - [x] 6. `ResourceReferenceInput.tsx:205-210` 资源引用到 content part 的映射重复 - 当前实现:组件内重复构造 resource/runtime-region 两种 part。 - 问题判断:有效的低风险维护问题,字段新增时存在漂移风险。 - 处理:复用 `chatReferenceToContentPart`。提交:`f213987f9`(复用资源引用的统一内容映射)。 - [x] 7. `resourceReferences.ts` content 缺失时把 text/references 拼成猜测输入 - 当前实现:DirectProject user item 只接受从 Lexical `EditorState` 派生的 canonical `content[]`;转换入口不再读取 `text + references` 猜测顺序。 - 问题:旧回退会重复表达引用并丢失编辑顺序,也会掩盖调用方没有 canonical content 的错误。 - 处理:删除 legacy fallback;DirectProject 缺少 user item 时直接失败关闭,首轮使用显式 canonical `input_text` 构造。 - [x] 8. `resourceReferences.ts:130-132` 嵌套三元表达式 - 当前实现:content 回退优先级用嵌套三元表达。 - 问题判断:不改变行为的可读性问题。 - 处理:改成显式 `if/else` 三分支。提交:`a543b75cf`(拆开聊天草稿内容分支判断)。 - [x] 10. `wire.rs:43-44` 校验与 wire 投影重复读取 manifest - 当前实现:wire 投影先校验,再单独读取 manifest;prompt 调用链还会再次进入 wire。 - 问题判断:有效的低风险性能问题。 - 处理:校验函数返回已读取的 manifest,wire 投影复用它。提交:`f2030a616`(复用 DirectProject 用户输入校验读取的 manifest)。 - [x] 11. `model.rs:67-69` 未使用的 `DirectCodexUserMessageEnvelope` - 当前实现:类型仅定义/内部 re-export,代码库无调用,生成目录也没有对应绑定。 - 问题判断:有效的死 API 面;删除不影响现有调用方。 - 处理:移除类型及 re-export。提交:`cd2edd696`(移除未使用的 DirectProject 输入信封类型)。 - [x] 12. `direct_runtime/user_input.rs` 附件未进入 DirectProject 模型 prompt - 当前实现:附件/图片继续使用现有 `DirectCodexTurnAttachment` sidecar;canonical user item 不新增附件 part。 - 问题:此前 command 只把附件写入 audit,没有调用既有的有界路径映射渲染,模型收不到附件和图片信息。 - 处理:DirectProject command 在 canonical item 投影后调用 `render_direct_codex_user_prompt`;图片、Markdown 和其它文件统一输出原名、项目路径、类型、大小、状态。附件-only 输入允许在 sidecar 渲染前保持空 canonical 文本。 - [x] 13. `direct_runtime/mod.rs:4169` 两个互斥分支克隆整个 optional JSON - 当前实现:两个分支都对不再使用的 `direct_user_item` 调用 `.clone()`。 - 问题判断:有效的低风险性能问题。 - 处理:在互斥分支中直接移动值。提交:`22e830ff9`(避免 DirectProject 回合输入的无必要克隆)。 - [x] 14. `ResourceReferenceInput.tsx:192-194` 空白 text node 进入 canonical content - 当前实现:引用后的空格和换行也会生成 `input_text`,Rust 校验拒绝 trim 后为空的 part。 - 问题:带引用的常见提交可能失败,属于高影响输入行为。 - 处理:编辑器读取时跳过纯空白 part、合并相邻文本。提交:`3c7b02b9f`(过滤 DirectProject 编辑器的空白内容 part)。 - [x] 15. `direct_project_history_wire.rs:18-21` 标准历史 item 被重新投影为错误 wire 形状 - 当前实现:标准 assistant/tool 等非 user item 原样透传;user canonical item 经过 `direct_codex_user_item_to_response_item` 后,文本 part 当前明确生成为 `type: "input_text"`。 - 问题判断:review 依据的是旧中间状态;当前源码和 `response_item_projection_uses_input_text_not_turn_input_text` 测试已覆盖该口径,不需要迁移或 fallback。 - 处理:不改代码。 - [x] 16. `codex_app_server/mod.rs:2661-2663` canonical AGC part 写入聊天历史后读取丢失 - 当前实现:追加原始 canonical item,但聊天历史读取只提取 `text` content part。 - 问题:纯引用消息或含引用消息在重载后可能显示为空/被过滤。 - 建议:扩展 history reader 读取 canonical part,或在写入 chat projection 时明确生成安全文本投影;需先定历史真相边界。 - [x] 17. `App.tsx:6072` chatContent 可能携带空白 input_text - 当前实现:前端把 Lexical 原始 content 直接传给 converter,引用分隔空格/换行不会被过滤。 - 问题:与第 14 条同源,会被 Rust 校验拒绝。 - 处理:在统一 `chatComposerDraftToDirectCodexUserItem` 转换入口过滤纯空白 `input_text`。提交:`35733f0e3`(过滤 canonical 草稿中的空白输入 part)。 - [x] 18. `App.tsx:743-745` 规划 V2 提交后未清理引用草稿 - 当前实现:planning-v2 分支只清空文本,未清空 references/content。 - 问题判断:有效的低风险状态残留问题。 - 处理:提交规划回合时同步清空 `chatReferences` 和 `chatContent`。提交:`c266ae7b5`(清理策划模式提交后的聊天草稿)。 - [x] 19. `direct_codex_user_item/wire.rs:26-30` response item 使用 `text` 而非 `input_text` - 当前实现:`direct_codex_user_item_to_wire_input` 内部确实使用 `type: "text"`,但它只服务 turn/start prompt;历史 response item 走另一个投影函数,并明确改成 `type: "input_text"`。 - 问题判断:review 把两个不同 wire seam 混为一谈;当前实现已分离,不能据此判定“历史投影使用 text”。 - 处理:不改代码。 - [x] 21. `direct_runtime/user_input.rs:51-62` 显式校验与空 prompt 分支重复/不可达 - 当前实现:调用 `direct_codex_user_item_to_prompt` 已包含校验和空 prompt 失败,外层再次校验并检查空字符串。 - 问题判断:有效的低风险重复逻辑。 - 处理:复用投影函数的错误收口,删除重复校验和不可达分支。提交:`1da106af7`(避免重复校验 DirectProject 用户输入)。
k88936 added 10 commits 2026-09-15 17:51:07 +08:00
区分 turn/start 的 text 与历史 message 的 input_text

将 AGC 私有引用转换为标准 input_text

新增回归测试避免未知 variant text
删除已在对象初始化时设置的 userItem 重复赋值。
让 Lexical 草稿读取复用 chatReferenceToContentPart,避免引用字段映射分叉。
将资源草稿转换的三种回退路径改为显式分支,保持现有优先级并提升可读性。
规划 V2 提交时同步清空资源引用和 canonical content,避免切回 DirectProject 后复用旧输入。
在互斥的观察器分支中移动 optional user item,避免深层 JSON 克隆。
删除未被调用且未生成到前端绑定的 DirectCodexUserMessageEnvelope,收窄内部 API。
复用 canonical 到 prompt 投影函数中的校验,删除不可达空 prompt 分支。
仅在 DirectCodex 产品运行时生成 direct clientTurnId 和 user item,避免旧 Supervisor 与策划链路复用错误身份。
复用 DirectProject 用户输入校验读取的 manifest
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 1m44s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 2m19s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 2m19s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 2m17s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m17s
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m26s
Project CI / Frontend tests (pull_request) Failing after 3m5s
Project CI / AI game creator shell web tests (pull_request) Failing after 2m51s
Project CI / Native shell tests (pull_request) Successful in 6m21s
f2030a616f
让校验返回已读取的 manifest,wire 投影复用同一份数据,避免一次输入重复读取项目清单。
k88936 added 4 commits 2026-09-15 23:55:39 +08:00
跳过纯空白文本节点并合并相邻文本,避免引用后的分隔空格和换行触发 Rust 空输入校验。
在统一 user item 转换入口移除纯空白 input_text,覆盖恢复草稿和所有提交路径。
新增可复用的 RichTextInput Lexical 输入外壳。

让首页输入与资源引用输入共享编辑器、回车提交和禁用状态。

保留首页附件与图片粘贴节点能力,并移除 DirectProject 草稿 legacy fallback。

统一聊天草稿 canonical content 状态并更新资源引用测试。
收敛输入编辑器单一状态并补齐附件投影
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 2m6s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 1m49s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 1m56s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 2m2s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m19s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m46s
Project CI / Repository checks (pull_request) Failing after 15s
Project CI / Frontend tests (pull_request) Failing after 3m54s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m13s
Project CI / Native shell tests (pull_request) Successful in 7m14s
87b798322e
聊天与快速编辑输入统一由 Lexical 编辑器持有唯一当前状态

App 通过输入句柄读取草稿,移除跨视图 EditorState 和字符串镜像

DirectProject 将附件与图片 sidecar 投影纳入 prompt,支持附件-only 输入

迁移润色测试并更新 DirectProject 里程碑验收记录
kdletters added this to the 陶泥儿gameAgent project 2026-09-16 12:11:45 +08:00
kdletters moved this to 评估中 in 陶泥儿gameAgent on 2026-09-16 12:12:21 +08:00
k88936 added 2 commits 2026-09-16 13:06:39 +08:00
合并主线回合队列、工具流展示与活动回合管理

保留 Lexical 单一输入状态及附件图片 sidecar 投影

收敛 DirectProject user item 校验、历史恢复与图片预算

同步输入链路里程碑和历史异常恢复文档
内联 DirectProject 附件与图片内容
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m30s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m35s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m54s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 6m1s
Project CI / Backend tests (pull_request) Failing after 9s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m52s
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m41s
Project CI / Frontend tests (pull_request) Failing after 3m54s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m41s
Project CI / Native shell tests (pull_request) Successful in 6m9s
46e3cd9744
新增附件与图片 canonical content part 及 ts-rs 绑定

移除 DirectProject Tauri 附件 sidecar 追加路径

修正前端引用字段与生成类型适配

补充附件图片顺序投影测试并同步里程碑文档
k88936 added 9 commits 2026-09-16 16:25:06 +08:00
- 仅在非纯聊天模式清空聊天编辑器

- 保留纯聊天模式恢复的会话草稿
- 准备命令草稿前先清空编辑器

- 避免提交用户上一轮选择的素材引用
- 为快速编辑输入区绑定编辑器句柄

- 润色回调同时更新面板状态与编辑器文本
- 用 React 状态同步编辑器当前文本

- 让按钮禁用态随用户输入即时更新
- 仅在初始内容实际非空时跳过初始化回调

- 保证快速编辑首次输入同步到宿主状态
- 在编辑器发出空草稿时重置润色结果

- 清除本轮发送提醒确认标记
- 编辑器尚未恢复时跳过空草稿持久化

- 保留已有会话草稿等待输入区完成恢复
- 回填前比较编辑器当前文本

- 防止输入区 onChange 与宿主回调形成循环
补充DirectProject canonical内容严格边界计划
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 / Backend tests (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 2/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 shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
f4b496caca
- 明确 content-only 输入与最终空内容校验

- 规划删除 userItem 兜底并修正 Direct caller
Author
Member

Review 复核与处理结果

以下结论以当前代码为准;review.txt 只是临时清单,不纳入任何提交。

  • 1. apps/ai-game-creator-shell/src/App.tsx:4375-4377 总控纯聊天草稿恢复后被立即清空(high)

    • 当前实现:打开项目后先恢复草稿,随后无条件清空编辑器。
    • 问题:清空触发 OnChangePlugin,空文本覆盖刚恢复的草稿。
    • 处理:纯聊天模式只恢复草稿;非纯聊天模式才清空。已提交 b60750191(修复总控草稿恢复后被清空)。
    • 建议:保留总控草稿恢复测试覆盖导航/重载。
  • 2. apps/ai-game-creator-shell/src/App.tsx:4618 准备建议命令时残留旧引用(medium)

    • 当前实现:replaceText() 按设计保留当前编辑器中的引用节点。
    • 问题:建议命令应从干净草稿开始,否则上一轮素材引用会随命令提交。
    • 处理:准备命令前先 clear()replaceText()。已提交 30e27abc6(修复建议命令草稿残留引用)。
    • 建议:需要保留引用时新增明确的整体草稿替换 API。
  • 3. apps/ai-game-creator-shell/src/view/project-development/index.tsx:8127-8130 快速编辑润色结果未进入编辑器(medium)

    • 当前实现:输入区只在首次挂载应用 initialDraft;润色回调只更新 panel 状态。
    • 问题:Lexical 仍显示旧文本,下一次编辑会把旧文本写回父状态。
    • 处理:绑定 ResourceReferenceInputHandle,润色时幂等回写编辑器文本。已提交 d5c4e0e78fc0fd846f
    • 建议:继续保持编辑器为唯一输入真相,回填前比较文本。
  • 4. apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:1010-1012 润色按钮不会随输入启用(high)

    • 当前实现:渲染读取只在 OnChangePlugin 中变更的 ref。
    • 问题:ref 变更不触发 React 重渲染,按钮可能一直禁用。
    • 处理:新增 draftText state,编辑器变更时同步,按钮改读 state。已提交 0b9d16e8f(修复润色按钮无法感知输入)。
    • 建议:ref 用于事件闭包,state 仅用于渲染派生状态。
  • 5. apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:644-645 空初始草稿吞掉首次编辑(medium)

    • 当前实现:无论初始草稿是否产生变化都设置跳过初始化回调。
    • 问题:空初始化不触发 Lexical 变更,第一次真实输入被误吞。
    • 处理:仅初始文本非空或有引用时跳过。已提交 645d806fe(修复空初始草稿吞掉首次编辑)。
    • 建议:保留空草稿首次输入回归测试。
  • 6. apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:867-868 清空草稿后润色状态残留(medium)

    • 当前实现:重置 effect 只在挂载时执行,后续 ref 变化不会触发。
    • 问题:“恢复原文”按钮和发送确认标记可能残留到下一轮。
    • 处理:空草稿由 OnChangePlugin 同步重置润色结果和确认标记。已提交 64a52005f(修复清空草稿后润色状态残留)。
    • 建议:文本与引用都为空才视为新一轮。
  • 7. apps/ai-game-creator-shell/src/App.tsx:3083-3084 初始化阶段空持久化覆盖总控草稿(high)

    • 当前实现:effect 读取尚未恢复的编辑器并立即持久化。
    • 问题:空写入删除 sessionStorage 中的已有草稿。
    • 处理:空草稿时跳过该 effect;用户真实清空仍由输入变更回调处理。已提交 fa99d9ad6(避免总控草稿初始化误删)。
    • 建议:以后用显式 seeded 状态表达恢复时序。
  • 8. apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts:121-123 canonical content 为空时丢失文本/引用(high)

    • 这里的“转换函数”是 chatComposerDraftToDirectCodexUserItem(draft, id):把输入框的 ChatComposerDraft 转成 Rust/Direct Codex 接收的 DirectCodexUserItem,其中 content 是唯一 canonical 消息内容。
    • 它为什么过滤:原实现把纯空白 input_text(引用后的分隔空格、段落换行)在转换函数里又过滤了一遍。这个过滤其实已经由 Lexical 投影层做过(Rust validate_direct_codex_user_item 会拒绝空 input_text),属于重复过滤,只会让人误以为“转换函数在替用户改写内容”。
    • “回退调用”具体指 App.tsxuserItem ?? chatComposerDraftToDirectCodexUserItem(...)?? 左边没传 userItem 时才执行右边的兜底构造,而兜底传的是 { text: prompt, references, content: [] }。首页首轮创建也走这条兜底。此时 prompt/references 有值、content 却是空数组,最终 user message 的文本与引用被静默丢掉。
    • 处理:按「修调用方、保持 canonical 契约严格」落地——转换函数原样传递 draft.content,不再做二次过滤;ChatComposerDraft 删掉 text / references,只保留 content;删除 executeChatAgentReplyuserItem 兜底分支,首页首轮、普通聊天提交、运行中队列出队、策略确认重试全部显式构造 canonical user item;发送前只在最终 content 上判断是否全空(hasMeaningfulDirectCodexContent),不做预过滤;旧 Planner / legacy Supervisor caller 显式构造纯文本 item 并留迁移 TODO。已提交 41366dd71
    • 建议:新入口统一走 directCodexUserItemFromContent(content, id);需要文本的地方(草稿持久化、队列 chip、润色判据)用 directCodexContentToPromptText(content, assets) 从 content 派生,不要再引入并行的文本字段。
  • 9. apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:641-643 快速编辑 initialDraft 单次应用导致润色后显示旧文本(high,和第 3 条重复)

    • 当前实现/问题:与第 3 条同一根因,编辑器与宿主 prompt 脱节。
    • 处理:已由第 3 条的 editor handle 回填覆盖,无额外代码变更;详见 d5c4e0e78fc0fd846f
    • 建议:后续评审将本条与第 3 条合并。
# Review 复核与处理结果 以下结论以当前代码为准;`review.txt` 只是临时清单,不纳入任何提交。 - [x] 1. `apps/ai-game-creator-shell/src/App.tsx:4375-4377` 总控纯聊天草稿恢复后被立即清空(high) - 当前实现:打开项目后先恢复草稿,随后无条件清空编辑器。 - 问题:清空触发 `OnChangePlugin`,空文本覆盖刚恢复的草稿。 - 处理:纯聊天模式只恢复草稿;非纯聊天模式才清空。已提交 `b60750191`(修复总控草稿恢复后被清空)。 - 建议:保留总控草稿恢复测试覆盖导航/重载。 - [x] 2. `apps/ai-game-creator-shell/src/App.tsx:4618` 准备建议命令时残留旧引用(medium) - 当前实现:`replaceText()` 按设计保留当前编辑器中的引用节点。 - 问题:建议命令应从干净草稿开始,否则上一轮素材引用会随命令提交。 - 处理:准备命令前先 `clear()` 再 `replaceText()`。已提交 `30e27abc6`(修复建议命令草稿残留引用)。 - 建议:需要保留引用时新增明确的整体草稿替换 API。 - [x] 3. `apps/ai-game-creator-shell/src/view/project-development/index.tsx:8127-8130` 快速编辑润色结果未进入编辑器(medium) - 当前实现:输入区只在首次挂载应用 `initialDraft`;润色回调只更新 panel 状态。 - 问题:Lexical 仍显示旧文本,下一次编辑会把旧文本写回父状态。 - 处理:绑定 `ResourceReferenceInputHandle`,润色时幂等回写编辑器文本。已提交 `d5c4e0e78`、`fc0fd846f`。 - 建议:继续保持编辑器为唯一输入真相,回填前比较文本。 - [x] 4. `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:1010-1012` 润色按钮不会随输入启用(high) - 当前实现:渲染读取只在 `OnChangePlugin` 中变更的 ref。 - 问题:ref 变更不触发 React 重渲染,按钮可能一直禁用。 - 处理:新增 `draftText` state,编辑器变更时同步,按钮改读 state。已提交 `0b9d16e8f`(修复润色按钮无法感知输入)。 - 建议:ref 用于事件闭包,state 仅用于渲染派生状态。 - [x] 5. `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:644-645` 空初始草稿吞掉首次编辑(medium) - 当前实现:无论初始草稿是否产生变化都设置跳过初始化回调。 - 问题:空初始化不触发 Lexical 变更,第一次真实输入被误吞。 - 处理:仅初始文本非空或有引用时跳过。已提交 `645d806fe`(修复空初始草稿吞掉首次编辑)。 - 建议:保留空草稿首次输入回归测试。 - [x] 6. `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:867-868` 清空草稿后润色状态残留(medium) - 当前实现:重置 effect 只在挂载时执行,后续 ref 变化不会触发。 - 问题:“恢复原文”按钮和发送确认标记可能残留到下一轮。 - 处理:空草稿由 `OnChangePlugin` 同步重置润色结果和确认标记。已提交 `64a52005f`(修复清空草稿后润色状态残留)。 - 建议:文本与引用都为空才视为新一轮。 - [x] 7. `apps/ai-game-creator-shell/src/App.tsx:3083-3084` 初始化阶段空持久化覆盖总控草稿(high) - 当前实现:effect 读取尚未恢复的编辑器并立即持久化。 - 问题:空写入删除 sessionStorage 中的已有草稿。 - 处理:空草稿时跳过该 effect;用户真实清空仍由输入变更回调处理。已提交 `fa99d9ad6`(避免总控草稿初始化误删)。 - 建议:以后用显式 seeded 状态表达恢复时序。 - [x] 8. `apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts:121-123` canonical `content` 为空时丢失文本/引用(high) - 这里的“转换函数”是 `chatComposerDraftToDirectCodexUserItem(draft, id)`:把输入框的 `ChatComposerDraft` 转成 Rust/Direct Codex 接收的 `DirectCodexUserItem`,其中 `content` 是唯一 canonical 消息内容。 - 它为什么过滤:原实现把纯空白 `input_text`(引用后的分隔空格、段落换行)在转换函数里又过滤了一遍。这个过滤其实已经由 Lexical 投影层做过(Rust `validate_direct_codex_user_item` 会拒绝空 `input_text`),属于重复过滤,只会让人误以为“转换函数在替用户改写内容”。 - “回退调用”具体指 `App.tsx` 的 `userItem ?? chatComposerDraftToDirectCodexUserItem(...)`:`??` 左边没传 `userItem` 时才执行右边的兜底构造,而兜底传的是 `{ text: prompt, references, content: [] }`。首页首轮创建也走这条兜底。此时 `prompt`/`references` 有值、`content` 却是空数组,最终 user message 的文本与引用被静默丢掉。 - 处理:按「修调用方、保持 canonical 契约严格」落地——转换函数原样传递 `draft.content`,不再做二次过滤;`ChatComposerDraft` 删掉 `text` / `references`,只保留 `content`;删除 `executeChatAgentReply` 的 `userItem` 兜底分支,首页首轮、普通聊天提交、运行中队列出队、策略确认重试全部显式构造 canonical user item;发送前只在最终 content 上判断是否全空(`hasMeaningfulDirectCodexContent`),不做预过滤;旧 Planner / legacy Supervisor caller 显式构造纯文本 item 并留迁移 TODO。已提交 `41366dd71`。 - 建议:新入口统一走 `directCodexUserItemFromContent(content, id)`;需要文本的地方(草稿持久化、队列 chip、润色判据)用 `directCodexContentToPromptText(content, assets)` 从 content 派生,不要再引入并行的文本字段。 - [x] 9. `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:641-643` 快速编辑 `initialDraft` 单次应用导致润色后显示旧文本(high,和第 3 条重复) - 当前实现/问题:与第 3 条同一根因,编辑器与宿主 prompt 脱节。 - 处理:已由第 3 条的 editor handle 回填覆盖,无额外代码变更;详见 `d5c4e0e78`、`fc0fd846f`。 - 建议:后续评审将本条与第 3 条合并。
k88936 added 4 commits 2026-09-16 18:55:02 +08:00
- 移除 chatComposerDraftToDirectCodexUserItem 对纯空白 input_text 的预过滤,原样传递 draft.content
- ChatComposerDraft 只保留 canonical content,删除 text / references 旧字段
- 新增 directCodexContentToPromptText、hasMeaningfulDirectCodexContent、directCodexUserItemFromContent 供 caller 与展示派生
- 删除 executeChatAgentReply 的 userItem 兜底分支,首页首轮、队列出队、普通提交与策略重试显式构造 canonical user item
- QueuedChatTurn 只保存 clientTurnId 与 userItem,队列 chip 文案由 content 派生
- 旧 Planner / legacy Supervisor caller 显式构造纯文本 item 并留下迁移 TODO
- 资源输入区对外只暴露 canonical content,内部文本草稿改为文本 → content 重建
- 迁移草稿、润色、队列与 appSurface 测试 fixture 到 content-only
- 更新 canonical content 里程碑与实施计划文档结论
- 移除 DirectCodexUserContentPart 的 agc_image_reference 分支与对应 ts-rs 绑定
- Rust 校验与 Codex wire 投影只保留 agc_attachment_reference
- 更新附件顺序投影测试的用例名、输入与断言
- 同步聊天素材功能说明、用户 Response item 里程碑与实施计划
- 在决策日志记录上传文件统一走附件 part、不保留图片兼容分支
- App.tsx 增加 supervisorChatDraftHydratedRef 守卫的挂载水合:独立总控聊天窗口挂载走 loadProjectConversation,不经过 openWorkspace,此前 sessionStorage 里的草稿只写不读,重载后为空
- 仅在 supervisorChatOnly、存在持久化草稿且输入框已挂载时回填一次,避免覆盖用户后续输入
修正 Godot 直接回合用例对 canonical content 的断言
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 / Backend tests (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 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (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
edfd1f9143
- appSurface Godot 用例不再断言被裁剪过的纯文本,改为断言编辑器实际提交的 canonical content(Shift+Enter 与组合态 Enter 插入的换行原样保留)
k88936 added 3 commits 2026-09-17 13:07:39 +08:00
- ResourceReferenceInput 的草稿投影改为「向前合并」:上一 part 是引用 chip 时先把待写文本攒在 pendingText 上,等下一个文本 part 到来再合并,段落分隔符与软换行不再被 trim() 丢掉
- 攒到最后仍只有空白的文本不入 content,避免产出 Rust validate_direct_codex_user_item 会拒绝的空 input_text
- 新增 resourceReferenceInput 用例「引用后面的段落分隔不会被吞掉」,钉住 chip 后一段的 content part、派生文本与「不产生纯空白 part」
- 同步更新 canonical content 严格边界里程碑的实现结论与证据,并在 shared-memory/pitfalls 记录该缺陷的现象、原因、处理与验证
- queuedChatTurnLabel 增加 assets 入参并透传给 directCodexContentToPromptText,@ 引用按 manifest 显示名展开,与聊天输入区文案口径一致
- ComposerTurnQueue 增加 assets 属性,ProjectSupervisorView 把 chatProjectAssets 传下去
- chat-composer 用例新增「队列 chip 的 @ 引用按 manifest 显示名展开」,钉住显示名文案与不传清单时的稳定 id 兜底
修复快速编辑提示词把 @ 引用写成内部 id(review 第 3、4 条)
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m39s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m18s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m8s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m55s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m11s
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m45s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m10s
Project CI / Native shell tests (pull_request) Successful in 8m37s
Project CI / Frontend tests (pull_request) Successful in 8m46s
e469831543
- applyResourceQuickEditPrompt 与 applyResourceQuickEditDraft 改用 directCodexContentToPromptText(content, manifest.assets),并在 useCallback 依赖里加上 manifest.assets
- 两处必须同口径:比较用的草稿文本与落进 quickEditPanel.prompt 的文本都按显示名展开,出站 derive_local_project_resource 的 prompt 与聊天 @ 逐字一致,也不会每次输入都重跑 replaceText
- 补充两处注释说明素材清单口径,shared-memory/pitfalls 记录「派生文本漏传 manifest.assets」的现象、原因、处理与验证
Author
Member
    1. ResourceReferenceInput.tsx 引用后换行被丢 → 已修,提交 280a2dc5d
    1. chatComposerQueue.ts 队列 chip 露出内部 resourceId → 已修,提交 869abad87
    1. project-development/index.tsx 快速编辑比较口径漏 manifest.assets → 已修,提交 e46983154
    1. project-development/index.tsx 快速编辑出站 prompt 漏 manifest.assets → 已修,提交 e46983154
      (第 3、4 条同一根因、必须同一次提交:只改比较或只改落盘,都会让 replaceText 每次输入重跑一遍)
  • 附带:仓库里原本就是红的 tests/projectResourceLiveIntegration.test.tsx > 快速编辑提示词里能 @ 出资源选择器
    随第 3、4 条一起转绿(期望 把夜色改成星空@rules,此前实际 把夜色改成星空@source-rules)。

    1. 引用后的「尾随」换行 / 两枚 chip 之间的换行仍然不保留(要保留就得动 Rust 契约)
    • 当前实现:前端草稿投影(ResourceReferenceInputDraftContentCollector)只会把待写文本「向前合并」到下一个文本 part 上。所以 @素材 + 换行 + 文字 = [reference, {text:'\n文字'}](已修),但 @素材 + 换行 + 后面没有文字、或 @素材 + 换行 + @另一个素材 时,这段纯空白无处可挂,仍然被丢掉,读出来是 @素材 / @素材@另一个素材
    • 问题:canonical content 里没有「分隔符 part」这种表示,而 Rust validate_direct_codex_user_item 明确拒绝 text.trim().is_empty()input_text(错误信息「DirectProject input_text 不能为空」)。因此只要前一个 part 不是文本、后面又跟的是引用,分隔符在契约层就没有合法落点。
    • 建议修法(三选一,都属于 breaking,需要你定):① 放宽 Rust 校验,允许纯空白 input_text,前端照原样投影(最贴近编辑器真相,但放宽了 canonical 输入白名单);② 新增显式分隔 part(例如 input_text 之外的 separator),wire 投影时再翻译成 \n(契约变更 + 历史重放要一起考虑);③ 接受现状,把「引用后必须跟文字才有换行」写进文档当作既定语义。
    • 另外提示:原始 review 建议的补丁形式 if (text.trim() || text.includes('\n')) content.push({type:'input_text', text}) 不能直接用——它会把 @素材\n@素材 变成 [ref, {text:'\n'}, ref],被上面那条 Rust 校验拒绝,整轮消息发不出去(用户看到「DirectProject input_text 不能为空」)。Agent 采用的是「向前合并」口径,请你确认这个口径就是你要的。
    1. queuedChatTurnLabelassets 默认值是否要收掉
    • 当前实现:签名是 queuedChatTurnLabel(turn, assets = []),不传时退回 @resourceId(保留旧调用方与既有单测的可编译性)。唯一的产品调用点(ComposerTurnQueue)已由 ProjectSupervisorView 传入 chatProjectAssets
    • 问题:默认值把「漏传素材清单」从编译期错误降级成运行期文案退化,正是本次第 2 条的成因;将来新增调用方还会再犯。
    • 建议修法:把 assets 改成必填(assets: readonly GameCreationAppAssetManifestEntry[]),并把 tests/appSurface/chat-composer.suite.ts 里那条「不传清单退回稳定 id」的断言删掉。属于 API 口径收紧,会影响该 helper 的其它调用方(目前只有测试),要不要做由你定。
    1. 快速编辑面板的 initialContent 仍然只用 quickEditPanel.prompt 文本回填
    • 当前实现:面板每次打开(key={quickEditSourceLayer?.id})时把 prompt 作为单个 input_text part 塞进输入区,引用 chip 靠 buildDraftSegments@显示名 token 反查重建。
    • 问题:只有「文本里存在 @显示名 token 且 manifest 里能找到同名素材」时 chip 才能复原;如果提示词里的 token 被用户删掉/改名,chip 就退化成普通文字。第 3、4 条修好之后,出站 prompt 的显示名口径已经统一,但「面板重开 → chip 复原」这条链路仍依赖 token 文本匹配。
    • 建议修法:把快速编辑的引用也存成结构化状态(ChatReference[])随 quickEditPanel 一起保存,重开面板时直接回填 content 而不是重建。这会改面板状态结构(QuickEditPanelState)与其持久化/恢复口径,属于跨模块改动,建议单独立里程碑再做。
- 1. `ResourceReferenceInput.tsx` 引用后换行被丢 → 已修,提交 `280a2dc5d` - 2. `chatComposerQueue.ts` 队列 chip 露出内部 resourceId → 已修,提交 `869abad87` - 3. `project-development/index.tsx` 快速编辑比较口径漏 `manifest.assets` → 已修,提交 `e46983154` - 4. `project-development/index.tsx` 快速编辑出站 prompt 漏 `manifest.assets` → 已修,提交 `e46983154` (第 3、4 条同一根因、必须同一次提交:只改比较或只改落盘,都会让 `replaceText` 每次输入重跑一遍) - 附带:仓库里原本就是红的 `tests/projectResourceLiveIntegration.test.tsx > 快速编辑提示词里能 @ 出资源选择器` 随第 3、4 条一起转绿(期望 `把夜色改成星空@rules`,此前实际 `把夜色改成星空@source-rules`)。 - 1. 引用后的「尾随」换行 / 两枚 chip 之间的换行仍然不保留(要保留就得动 Rust 契约) - 当前实现:前端草稿投影(`ResourceReferenceInput` 的 `DraftContentCollector`)只会把待写文本「向前合并」到下一个文本 part 上。所以 `@素材` + 换行 + 文字 = `[reference, {text:'\n文字'}]`(已修),但 `@素材` + 换行 + 后面没有文字、或 `@素材` + 换行 + `@另一个素材` 时,这段纯空白无处可挂,仍然被丢掉,读出来是 `@素材` / `@素材@另一个素材`。 - 问题:canonical content 里没有「分隔符 part」这种表示,而 Rust `validate_direct_codex_user_item` 明确拒绝 `text.trim().is_empty()` 的 `input_text`(错误信息「DirectProject input_text 不能为空」)。因此只要前一个 part 不是文本、后面又跟的是引用,分隔符在契约层就没有合法落点。 - 建议修法(三选一,都属于 breaking,需要你定):① 放宽 Rust 校验,允许纯空白 `input_text`,前端照原样投影(最贴近编辑器真相,但放宽了 canonical 输入白名单);② 新增显式分隔 part(例如 `input_text` 之外的 `separator`),wire 投影时再翻译成 `\n`(契约变更 + 历史重放要一起考虑);③ 接受现状,把「引用后必须跟文字才有换行」写进文档当作既定语义。 - 另外提示:原始 review 建议的补丁形式 `if (text.trim() || text.includes('\n')) content.push({type:'input_text', text})` **不能直接用**——它会把 `@素材\n@素材` 变成 `[ref, {text:'\n'}, ref]`,被上面那条 Rust 校验拒绝,整轮消息发不出去(用户看到「DirectProject input_text 不能为空」)。Agent 采用的是「向前合并」口径,请你确认这个口径就是你要的。 - 2. `queuedChatTurnLabel` 的 `assets` 默认值是否要收掉 - 当前实现:签名是 `queuedChatTurnLabel(turn, assets = [])`,不传时退回 `@resourceId`(保留旧调用方与既有单测的可编译性)。唯一的产品调用点(`ComposerTurnQueue`)已由 `ProjectSupervisorView` 传入 `chatProjectAssets`。 - 问题:默认值把「漏传素材清单」从编译期错误降级成运行期文案退化,正是本次第 2 条的成因;将来新增调用方还会再犯。 - 建议修法:把 `assets` 改成必填(`assets: readonly GameCreationAppAssetManifestEntry[]`),并把 `tests/appSurface/chat-composer.suite.ts` 里那条「不传清单退回稳定 id」的断言删掉。属于 API 口径收紧,会影响该 helper 的其它调用方(目前只有测试),要不要做由你定。 - 3. 快速编辑面板的 `initialContent` 仍然只用 `quickEditPanel.prompt` 文本回填 - 当前实现:面板每次打开(`key={quickEditSourceLayer?.id}`)时把 `prompt` 作为单个 `input_text` part 塞进输入区,引用 chip 靠 `buildDraftSegments` 用 `@显示名` token 反查重建。 - 问题:只有「文本里存在 `@显示名` token 且 manifest 里能找到同名素材」时 chip 才能复原;如果提示词里的 token 被用户删掉/改名,chip 就退化成普通文字。第 3、4 条修好之后,出站 prompt 的显示名口径已经统一,但「面板重开 → chip 复原」这条链路仍依赖 token 文本匹配。 - 建议修法:把快速编辑的引用也存成结构化状态(`ChatReference[]`)随 `quickEditPanel` 一起保存,重开面板时直接回填 content 而不是重建。这会改面板状态结构(`QuickEditPanelState`)与其持久化/恢复口径,属于跨模块改动,建议单独立里程碑再做。
k88936 added 2 commits 2026-09-17 14:03:49 +08:00
- Rust validate_direct_codex_user_item 改为只判整条 content:有一段非空白文本或任意非文本 part 即有效,单个纯空白 input_text(段落分隔 / 软换行 / chip 后的分隔空格)合法,不再逐个 part 拒绝空文本
- 新增 content_has_meaningful_input,并与前端 hasMeaningfulDirectCodexContent 同口径;wire.rs 的「不能转换为空 prompt」只作兜底
- ResourceReferenceInput 的投影层原样透传编辑器节点:不做空白过滤、也不与相邻 part 合并,删掉 appendInputText 与中间版本的「向前合并」收集器
- 按逐字投影更新资源输入、Godot 回合用例的 canonical content 断言
- 同步里程碑实现结论与证据、pitfalls 条目;Rust validation/wire 新增「单个纯空白 part 通过、整条全空白拒绝」用例
收敛 content→可读文本为单一口径并强制传 manifest(review 第 2、3 条)
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m10s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m43s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m28s
Project CI / Backend tests (pull_request) Failing after 15s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m13s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m0s
Project CI / Repository checks (pull_request) Failing after 12s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m58s
Project CI / Frontend tests (pull_request) Failing after 4m24s
Project CI / AI game creator shell web tests (pull_request) Failing after 4m2s
Project CI / Native shell tests (pull_request) Successful in 8m31s
6eed6bd13f
- directCodexContentToPromptText 的 assets 改为必填,去掉 = [] 默认值:漏传素材清单从运行期文案退化变回编译期错误
- queuedChatTurnLabel 的 assets 与 ComposerTurnQueue 的 assets 属性同样必填,队列 chip 与消息正文共用同一个派生(chip 只多做压单行与限长)
- 断言改为显式传 [] 或 manifest:resourceReferences、chat-composer 用例按新签名收敛
- 更新 pitfalls 条目与 decision-log(canonical content 有效性只判整条 content、投影逐字透传、可读文本单一口径必填 assets)
k88936 removed a dependency 2026-09-17 16:56:03 +08:00
k88936 added 42 commits 2026-09-18 10:57:05 +08:00
- Thread Manager 事件新增 callId,条目身份统一为 callId 优先、其次 itemId
- 工具条目按 callId 归并 started/completed,不再留下永远收不到完成事件的幽灵活跃条目
- 历史锚点仍取 response item id,保证分页锚点能在 project.jsonl 中命中
- 补充跨 id 空间归并的单元测试
- 新增 direct_chat_entry 深模块,把原始 response item 与 app-server item 投影成同一聊天条目
- item.started/item.completed 载荷改为完整条目,前端不再需要按 itemId 取快照
- 原始 function_call 与 function_call_output 按 callId 并成一张卡片,文本与明细统一脱敏截断
- 历史切片新增 entries 与 first_item_id,分页锚点不再依赖是否出现可显示条目
- directThreadChat 把运行态事件与历史切片归并成同一份聊天条目,活动回合只由 turn.started/turn.completed 判定
- item.delta 载荷补 kind,reducer 不再靠 itemId 猜条目类型
- bootstrap 原子替换运行态并保留历史窗口,历史与运行态按 callId ?? itemId 去重合并
- 新增 5 条 reducer 单测
- 主规范新增首屏锚点、生命周期锚点必进 bootstrap、事件自足与不提供单点快照四条契约
- 新增 ADR 记录单一事实源取舍、删除清单与待验证的 id 空间风险
- 新增里程碑与实施计划,CONTEXT.md 补项目对话历史/运行态事件/聊天投影词条
- 目标文档合同与文档索引同步
- 唤醒只由 notify 驱动,bootstrap 后立刻 consume 一次补齐竞态窗口
- 定时 tick 无法自举:判断活动回合本身依赖事件,唤醒丢失时定时器不会启动
- 主规范、ADR 与实施计划同步删除该条款
新增 agent/direct_thread_raw_item.rs:把 Codex 原始 response item 与 app-server item 收敛成同一形状的脱敏原始条目,只做挑字段、脱敏、截断,不再生成卡片的 kind / 标题 / 折叠摘要
删除 agent/direct_chat_entry.rs:工具卡片形状不再由 Rust 生产
历史切片改为返回脱敏原始条目列表,不再在 Rust 侧合并 function_call 与 function_call_output
新增前端 directThreadItemProjection.ts:工具卡片 kind / 标题 / 摘要 / 状态与可见性判定全部在前端完成
directThreadChat reducer 改用同一投影函数处理运行态事件,新增 mergeDirectHistoryItems 走同一份投影与合并规则
DirectThreadHistorySlice 去掉 entries 与 itemTimestamps,改为 items + firstItemId
里程碑与实施计划改定边界:Thread Manager 只搬运脱敏原始条目,不生成卡片形状与可见性
条目身份归一为 call_id ?? id,Thread Manager 与前端不再暴露第二个 id 概念,分页锚点仍取文件里的原始 item id
合并规则收敛为"先到定形、后到补空白",删除逐字段优先级表
主规范补充条目形状三条职责边界,并说明思考正文流式下发不放宽可见范围
ADR 同步:DirectRuntime 自己的进度事件与投影文件保留,前端删除的是 DirectProject 的读路径
失败与中止说明只在运行期显示;历史切片改为从文件尾反向扫描;未知 item 类型透传并加 TODO
修正 DirectProject 订阅语义:bootstrap 事件就是当前要处理的事件
Project CI / AI game creator shell Rust shard 2/4 (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 / Backend tests (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
09ad0073fe
subscribe 已在同一边界把游标钉在队尾,因此前端直接 reduce bootstrap 事件,不再补一次 consume
主规范、ADR 与实施计划同步删除"竞态窗口"说法,notify 仍是唯一唤醒来源
DirectProject 聊天事件改用 ts-rs 导出的 tagged enum 并删掉 turn id
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 5m11s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m51s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m57s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m50s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m2s
Project CI / Repository checks (pull_request) Failing after 15s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m14s
Project CI / Native shell tests (pull_request) Failing after 2m13s
Project CI / AI game creator shell web tests (pull_request) Failing after 46s
Project CI / Frontend tests (pull_request) Failing after 3m32s
2748468d12
- 新增 direct_thread_wire.rs:DirectThreadItem / DirectThreadEvent / 订阅与历史切片全部改成 ts-rs 导出的 tagged enum,取代原大而全的可空结构体
- 删除 direct_thread_raw_item.rs,模块注册与直通引用改到 direct_thread_wire
- 条目身份只看一个 itemId:工具条目的第二个 id 在 Rust 边界归一,不再对外暴露
- 删除 DirectProject 聊天事件里的 turn id:生命周期用无载荷的 turn.started / turn.completed{status} 表示
- append 直接接收 DirectThreadEvent 并返回同一事件,队列内部自算 seq
- 请求事件改为携带 DirectThreadRequestKind,去掉字符串中转
- 思考增量走 ReasoningDelta 通道,与正文增量共用 item.delta
- at 用 #[ts(as = "f64")] 对齐 Tauri JSON 通道的 number
- 用 cargo test export_bindings 重新生成 project-workspace/generated 绑定
- directThreadItemProjection.ts 直接消费生成的 DirectThreadItem,工具卡片 kind / 标题 / 摘要 / 状态与可见性判定都在这里
- directThreadChat.ts 聊天条目只留一个 itemId:去掉 callId 概念,去掉 deltaText 缓冲,增量直接追加到运行态条目正文
- 合并规则收成先到者赢、后到只补空:正文只增不减、工具状态允许从 running 升级到终态
- 回合结束把运行态条目并入历史并清空 live,条目既不消失也不重复
- directThreadEvents.ts 改为转发 ts-rs 绑定,只保留历史条目转消息的过渡函数
- ToolCallGroup 与 toolCallGroupPresentation 改用去掉回合身份的 DirectChatToolCard
- generated/index.ts 补上 DirectThread* 绑定导出
- 回退本仓库其它模块仍在改的 DirectCodexUser* 绑定重新生成(避免误改他人进行中的契约)
- 两个 vitest 用例文件按新 API 重写,11 条用例通过
文档先行:把 DirectProject 聊天真相源收敛的文档改到当前实现状态
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 5m13s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m30s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m39s
Project CI / Backend tests (pull_request) Failing after 12s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m43s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m8s
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m10s
Project CI / Frontend tests (pull_request) Failing after 3m24s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m7s
Project CI / Native shell tests (pull_request) Successful in 6m8s
ed3369a494
- 主规范把事件模型写成 ts-rs 导出的 tagged enum,说明 seq 不下发、事件不带回合身份,并补上 ts 绑定生成与 f64 时间戳约定
- ADR 补上 tagged enum 绑定、turn id 删除、正文只增不减与回合回收、前端卡片去掉 turnId、未知类型前端丢弃
- 里程碑与实施计划同步:文件改名到 direct_thread_wire.rs,新增删回合身份与生成绑定两步,验证命令加上 export_bindings
- 工具卡片技术方案在文首加修订段:数据来源层作废,表现层契约仍然有效,DirectRuntime 的 tool-calls.jsonl 写入保留
- 对话回合唯一投影里程碑改为 superseded,列出仍然有效与已作废的分界
- 新增 DirectProjectHistoryReverseLines:按块从文件尾逐行回读 project.jsonl
- 幂等回扫与"读一屏"共用这一套尾部回读,不再各自从文件头读到尾
- read_direct_project_history_items_slice_at 语义不变仍返回元组,新增第四项为本屏最老的 itemId 作分页锚点
- 分页锚点只按归一身份 itemId 匹配,不再接受第二个 id
- read_direct_project_last_item_id_at 改为尾部回扫读一行,不再读整份历史
- 删除只服务聊天框回读的 read_direct_tool_calls / read_direct_turn_stream 命令与注册
- 保留 list_game_creator_direct_active_turns:它服务首页跨页面"运行中的项目",不是聊天框读路径
- 补历史切片尾部回扫与分页锚点两条用例
- 新增 direct_thread_id_for_project:订阅、回合事件写入与兜底释放共用一个线程身份
- 订阅命令改用同一个身份函数,删掉命令层自己那套路径归一
- 用户消息落盘后立刻作为 item.completed 下发,前端用同一个 itemId 合并乐观气泡与历史条目
- 采集终态事件是否已经下发,缺失时按成功 / 失败补一条 turn.completed,避免前端永远停在运行中
- 取消回合的 Stale 分支补一条 turn.completed(aborted)
- App.tsx 删除 Direct 回合事件订阅、turn-stream/tool-calls 读取、活动回合快照接管与瞬时应答文本
- 新增 game-creator-direct-thread-notify 唤醒的 subscribe/consume 单飞循环,过期时重订一次
- 通知先于订阅回执到达时记一笔欠账,回执到达后补一次 consume,避免回合尾部事件卡在队列里
- 历史切片并入同一个 reducer,聊天条目只由 selectDirectChatEntries 投影
- ProjectSupervisorView 改为渲染用户气泡 / 执行过程折叠区 / 最终回复,运行态只保留一个 turnRunning
- directTurnPresentation 重写为条目分区:连续工具合块、本地运行期说明只作最终提示
- 测试改按订阅事件与历史条目断言,补回执竞态、持久化工具卡片、空对话首轮三条用例
- 主规范:运行态事件改为下发与历史切片同形的脱敏原始条目,不再只给类型与身份
- 主规范与 ADR 写清回执竞态:回执前到达的通知只能记欠账,回执到达后必须补一次 consume
- ADR 与实施计划说明 list_game_creator_direct_active_turns 有意保留,服务首页运行中项目列表
- 里程碑验收标准按自动化证据勾选,运行时验收与已知环境缺口单独标注
- 实施计划补 export_bindings 后需 prettier 生成目录、测试文件更名与竞态风险项
- pitfalls 记录:Node 26 的实验性 globalThis.localStorage 会顶掉 jsdom 的 Storage,导致只声明 jsdom 的用例读到 undefined
- 给出跑法:NODE_OPTIONS=--localstorage-file=… 后 clientApi 与 chatPromptPolish 共 26 项转绿
- 里程碑证据更新为全量结果:125 files / 1676 passed / 17 skipped,tsc exit 0
- App.tsx 不再绑定 chat_with_game_creator_direct_codex 的返回值,删掉 void reply
- 保留说明:回复正文按条目身份从线程事件 / 历史切片进聊天,本地不再补第二条
- harness.ts 记录运行态"最新回合是否在跑",emitDirectThreadEvents 只在生命周期事件上更新
- completeDirectThreadTurn 仅在回合没在跑时补 turn.started,避免与用例先发的事件重叠
- harness.ts 记录未完成条目集合、事件序号与最新生命周期锚点
- subscribe 只回放未完成条目与最新生命周期锚点,已完成条目与增量正文不再补发
- 去掉已下发事件的序号记录,避免序号表无限增长
- harness.ts 的 read_direct_project_history_slice 按生产口径从队尾取一屏、锚点条目不进窗口
- 按本屏最老一条算 firstItemId,收满一屏后再有条目才算 hasMore
- project-development.suite.ts 补一条用例:26 条历史只显示尾部 20 条,点「显示更早的对话」按锚点取回前 6 条后按钮消失
- loadProjectConversation 不再在 read_direct_project_history_slice 的 then 回调里直接写 directThreadChat
- 切片先暂存,等 loadVersion / localProjectPathRef 守卫通过后再与 hasMore、锚点一起落到状态
- 现有 launcher 按项目路径 key 重挂载 App,跨项目污染暂不可复现;本次只是让这条写入与其它状态写入的时序一致
- buildDirectChatTurns 先攒住第一个用户条目之前的过程条目,交给后面那个回合
- 不再渲染没有用户气泡的孤儿回合;整份历史都没有用户条目时仍保留一个回合
- directTurnPresentation 单测补一条分页切片从半截回合开头的情形
- DirectThreadChatState 去掉 subscriptionId 与 lastCompletedItemId 两个只写不读的字段
- resolveDirectThreadBootstrap 只把 bootstrap 事件 reduce 进状态,不再顺带写入这两个字段
- directThreadChat 单测改成断言聊天状态里不再出现这两个字段(bootstrap 载荷本身不变)
- handleCancelDirectCodexTurn 的守卫改用 supervisorChatBusy,与「终止」按钮的可见条件对齐
- 刚提交、turn.started 还没到达的窗口里点击终止不再回"当前没有正在运行的回合"
- chat-composer 用例补一条:生命周期事件缺席时也能发出 cancel_direct_codex_turn
- DirectProjectHistoryReverseLines 增记 saw_delimiter,第一段按"文件是否以换行结尾"判定,之后的行按已切掉的分隔符判定
- 尾部残行(上一行完整、这一行没有换行)解析失败时改为跳过继续回扫,不再报错、也不再就地结束丢掉更早的完整历史
- 换行结尾的坏行(含文件第一段)与顺序读取保持一致地失败关闭
- 补两条回扫用例:尾部残行不丢更早条目、坏掉的第一段必须失败关闭(都按旧实现变异验证过)
分页锚点改用文件里的原始 item id
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 6m22s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m34s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m49s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m49s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m7s
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m19s
Project CI / Frontend tests (pull_request) Failing after 6m15s
Project CI / AI game creator shell web tests (pull_request) Failing after 5m47s
Project CI / Native shell tests (pull_request) Successful in 12m22s
da2ad83c3b
- 新增 direct_project_history_anchor_id:优先取 project.jsonl 原始 id,缺 id 时退回归一身份兜底
- read_direct_project_history_items_slice_at 的锚点匹配与 first_item_id 都改用原始 id
- 工具条目的调用与输出共用 call_id,按归一身份当锚点会先跳过 output 再把上一屏的 function_call 带回来
- 原分页用例更名 history_window_paginates_upwards_by_item_id_anchor
- 新增 pagination_anchor_uses_raw_item_id_for_tool_call_pairs,旧实现下会返回 call-1 而非 fc-1(已做变异验证)
- 新增 direct_codex_reasoning_delta_event,两条 reasoning 增量通知只在这一处分类
- 生产 stdout 读取器改用该函数,并跳过「preparing 活动」的降级与活动节流(活动节流会按类别吃掉逐段正文)
- 旧分类函数 direct_codex_notification_event 同步改用它,避免两份实现再次分叉
- 单测 direct_reasoning_deltas_stream_text_while_plan_and_command_output_stay_activity 取代原先断言 Activity 的旧用例
- 新增 E2E codex_app_server_streams_reasoning_deltas_without_activity_fallback:把读取器的路由关掉即转红(已做变异验证)
- direct_thread_id_for_project 改用 resolve_direct_codex_project_authority(存在/是目录/canonicalize)
- 不再读 .agent/manifest.json:那次读取是连接池权威身份的要求,线程 id 只是路径 key
- 否则 manifest 在订阅时读失败、跑回合时读成功,会让符号链接等非 canonical 调用方路径算出两个线程 id,订阅绑到空线程
- 新增 direct_project_thread_id_ignores_manifest_readability,旧实现下会退回调用方原始字符串(已做变异验证)
- direct_codex_notification_event 收编 resolution / request / item / rawItem / Terminal 全部分支,并接收 turnId
- 读取器删掉自己那份内联分类,只保留「必须有 turnId 才处理」与活动/正文节流
- agentMessage 缺 itemId 的告警与 direct-missing-item:{turnId} 兜底身份原样保留,避免行为变化
- 新增 direct_notification_classification_covers_the_reader_branches 钉住各分支;E2E 假 app-server 用例继续覆盖读取器
重新生成 ts-rs 前端绑定并让前端按 null 语义构造运行时区段
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m35s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m31s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m15s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m47s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m15s
Project CI / Repository checks (pull_request) Failing after 19s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m15s
Project CI / Frontend tests (pull_request) Failing after 5m44s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m49s
Project CI / Native shell tests (pull_request) Successful in 10m42s
0caf998227
- 跑 export_bindings 后 prettier 格式化:DirectCodexUser* 5 个文件内容更新,新增 DirectCodexUserMessageEnvelope.ts 与 ui-editor 的 BindingChange/BindingDTO
- DirectCodexUserRuntimeRegionPart 的可选字段由 `?:` 变成 `T | null`(Rust Option 会显式序列化成 null,不是省略键)
- chatReferenceToContentPart 改用 `?? null`,消息条目的 satisfies 目标改为 DirectCodexUserItem(type:'message' 归到信封类型)
- ResourceReferenceInput 不再复制一份区段字面量,改为复用 chatReferenceToContentPart
- 验证:tsc --noEmit 通过;resourceReferences 等 5 个用例集 81 passed;appSurface 452 passed / 17 skipped(连跑两次)
This reverts commit 036395c6c9.
This reverts commit 1b010fb1f8.
- 运行态条目投影新增回显过滤 direct_thread_visible_item,item/started 与 rawResponseItem/completed 两条路径共用
- is_direct_project_codex_user_item 提升为 pub(crate),落盘侧与运行态侧共用同一判据
- 新增 E2E direct_project_turn_does_not_forward_codex_user_echo_as_chat_items:修复前事件流会多出两条同文本用户条目(已做变异验证)
- 同步 ADR 与 shared-memory decision-log:回显过滤必须同时覆盖落盘与运行态两侧
把「可显示」判据明确为合并后聊天投影出现新回合,并写清每操作 5 页上限与锚点不前进即停
里程碑把原第 56 条按后端锚点回扫与前端连拉拆成两条独立验收项,前端那条先留待补证据
实施计划第 6 步同步口径,并把新分页单测加入验证命令
决策记录新增 2026-09-17 条目,记下落点、上限粒度、失败与竞态边界
directHistoryPaging 按「合并后聊天投影回合数增加」判断可见反馈,出现新回合或 hasMore=false 即停
连拉上限 DIRECT_HISTORY_MAX_PAGES_PER_ACTION 放进 app/constants,每个操作最多 5 次请求
锚点未推进(items 为空 / firstItemId 为 null 或原地打转)时立即停手并收口 hasMore
某页读取失败不丢已取到的页,返回 error 交给调用方报错
directThreadChat 抽出 projectDirectHistoryItems,让分页判据与视图共用同一份投影
首屏与「显示更早」共用 readDirectHistoryPages,不再各自单发一页
首屏基线取空并在守卫后一次性并入聊天 reducer,失败仍按原有语义抛出
「显示更早」按当前视图条目判断新回合,取到多页一次性并入并推进锚点
连拉中途失败保留已取到的页,报错统一走同一个出口
用 51 条历史复现用户报的现象:20 条工具条目整屏落进同一个折叠的执行过程
断言一次点击连拉两页拿到新用户气泡,并按 process-31 / process-11 两次锚点推进
断言连拉插入旧内容后视口仍停在原处,不被拉回列表底部
里程碑前端连拉那条转成已验收,证据指向新单测与跨页同回合集成用例
证据要求补上本轮实跑结果与变异验证现象,避免再出现打勾但只覆盖一半
决策记录把验证口径写成具体条数与变异验证结论
Merge branch 'master' into fix/chat-status-lost
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (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 / Backend tests (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
cb840c6e8c
# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
#	docs/project-memory/shared-memory/pitfalls.md
Merge remote-tracking branch 'origin/master' into fix/chat-status-lost
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/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 / Backend tests (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 2/4 (pull_request) Has been cancelled
b7622f4a24
# Conflicts:
#	docs/project-memory/shared-memory/pitfalls.md
- 统一历史切片与 Thread Manager 事件投影,保留 DirectProject 单一聊天事实源

- 保留 canonical content 严格校验、资源显示名派生、附件引用与队列语义

- 修复首页首轮缺失 canonical user item 的真实回归并完成定向验证
解决 DirectProject 合并冲突
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m2s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m54s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m20s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m31s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m3s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m49s
Project CI / Frontend tests (pull_request) Failing after 6m56s
Project CI / Repository checks (pull_request) Failing after 6m23s
Project CI / Native shell tests (pull_request) Successful in 10m17s
Project CI / Backend tests (pull_request) Successful in 11m8s
Project CI / AI game creator shell web tests (pull_request) Failing after 6m0s
ecea7b4ad3
合并双方 DirectProject 历史分页、锚点闸门与订阅竞态处理。

保留 canonical content 输入、聊天 reducer、附件发送和历史分页行为。

合并 Codex 用户回显过滤、增量脱敏及 Direct 回合完成状态处理。

补齐历史截断、损坏行 fail-closed、首屏 anchor 与 appSurface 定向测试。

同步合并应用壳层、后端绑定和项目文档变更。
k88936 marked the pull request as ready for review 2026-09-18 10:57:42 +08:00
k88936 added 8 commits 2026-09-18 13:30:10 +08:00
移除相同结果的死三元分支。

保持资源与运行区域引用均使用统一的 @标签 文本。
使用不含附件的文本输入判断 /history 命令。

避免待发送附件把 canonical prompt 拼成长文本后绕过历史记录加载。
队列标签统一复用 canonical content 的文本派生。

删除不会被现有引用类型触发的附件和素材兜底文案。
避免初始编辑器挂载时 assetsById 为空导致资源引用永久丢失。

保留 Lexical 节点自行解析资产名称的后续 TODO。
DirectProject 继续以 project.jsonl 作为完整回合记录。

入口不再创建 DirectCodexTurnAudit,保留底层可选审计接口供独立测试和其它路径使用。
为 agc_attachment_reference 增加 Lexical 附件节点与可移除 chip。

恢复初始 canonical content 时不再静默丢弃附件,并让编辑器读回完整附件 part。
将 ChatComposerDraft.content 设为必填的 canonical 唯一来源。

删除 text 与 references 重建 DirectCodexUserItem 的兼容分支及其无效空值兜底。
Merge remote-tracking branch 'refs/remotes/origin/master' into fix/ref-persistent
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m18s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m22s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m30s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m41s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m56s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m25s
Project CI / Repository checks (pull_request) Failing after 4m0s
Project CI / Frontend tests (pull_request) Failing after 4m50s
Project CI / Native shell tests (pull_request) Successful in 8m29s
Project CI / Backend tests (pull_request) Successful in 11m23s
Project CI / AI game creator shell web tests (pull_request) Failing after 5m16s
2e78cbf152
Author
Member

Review 复核结果

以下结论基于当前工作区代码重新核对。 表示已自动修复并单独提交; 表示问题仍成立,但涉及输入/提示词/审计/UI 契约或可能改变现有行为,按要求留给你; 表示不是可直接修复的代码问题。

  • 1. apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs:103-120(安全,中):当前 wire 摘要会先复用附件清洗函数,再输出给模型;名称会去控制字符并提取 basename,媒体类型会去控制字符并按允许格式清洗,本地路径也会归一化为项目相对路径,避免换行、绝对路径或反斜杠破坏摘要结构。已补充清洗后的摘要测试;提交 70fa16081

  • 2. apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:41-50(安全,中):资源引用、运行区域引用和 inline 附件现在分别计数;inline 附件使用独立的 MAX_DIRECT_CODEX_ATTACHMENTS 上限(8),不能再通过 agc_attachment_reference 绕过引用数量门禁放大 prompt。已补充超限拒绝测试;提交 50204ff7a

  • 3. apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:54-67(缺陷,中):校验现在要求 status=imported 必须提供非空、有效的项目相对路径;failed 可以没有路径,但如果带路径仍必须通过路径校验。这样不会再把“已导入但无项目路径”或未归一化路径交给后续 wire 投影;已补充对应测试。提交 bc1dc868a

  • 4. apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/user_input.rs:45(重复记录):DirectProject 已经把完整回合写入 .agent/conversations/project.jsonl,额外创建 DirectCodexTurnAudit 只会再写一份 .agent/runtime/direct-codex/turns/*.jsonl,而且原调用还传了空附件列表。已移除 DirectProject 入口的审计器创建、结束和传递,提交 faed0ec25;底层可选参数与独立审计测试保留。

  • 5. apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:204-438(缺陷,中):referenceFromContentPart 原本没有处理 agc_attachment_referenceapplyContentToRoot 会静默丢弃初始草稿附件。已新增 Lexical AttachmentReferenceNode 与可移除 chip,初始化时插入附件节点,读回时重新生成完整 agc_attachment_reference part,并注册到编辑器节点列表;提交 d8af0fa88

  • 6. apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts:51-166(兼容残留):当前生产调用均已提供 content,没有实际的“旧调用者”需要这条 fallback。已将 ChatComposerDraft.content 设为必填 canonical 唯一来源,删除 text + references 重建分支,并移除调用方无效的 ?? [] 兜底;提交 840baf208

  • 7. apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:239-241(可维护性,低):资源与运行区域两条三元分支都返回同一个 @${reference.label},条件没有行为意义。已改为直接使用统一表达式,提交 06004bfee(清理资源引用标签的重复分支)。

  • 8. apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:724-749(缺陷,中):初始草稿 effect 现在会在包含资源引用且 assetsById 为空时先返回,不提前设置 applied guard;manifest 到达后 effect 会重试并恢复资源引用。提交 6e63a118e,并留下 TODO:未来可以让 Lexical 资源节点自己通过 manifest/context 解析资产名称。

  • 9. apps/ai-game-creator-shell/src/App.tsx:12306(缺陷,低):历史命令原先改用含附件派生的 canonicalPrompt 判断,待发送附件会把 /history 变成 /history@文件名,导致命令被当作普通消息发送。已改为使用不含附件的文本输入 prompt 判断,提交 b73a329b2(修复附件场景下历史命令识别)。

  • 10. apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs:103-109(原报告表述过度):PROJECT_ATTACHMENT_HEADER 是旧的 render_direct_codex_user_prompt(prompt, attachments) 文本提示,目前该函数只被首页回合调用;当前项目 DirectProject 走 inline user_item wire 投影,并没有证据证明这里发生了“旧项目 header 被移除”的回归。inline 摘要确实没有这句额外指引,但是否补上属于提示词一致性选择,不应直接定为中等级缺陷。

  • 11. apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:41-53(可维护性,低):inline 附件现在复用附件参数路径的元数据约束:名称拒绝控制字符并限制为 160 个字符,媒体类型拒绝空值、非法字符并限制为 96 个字符;清洗上限常量也已共享,避免异常元数据进入 canonical item 和模型 prompt。已补充拒绝测试;提交 75ec3361d

  • 12. LLM retry report summary(报告元信息):原报告中的两次请求因 core review/comment filtering 超时而失败,没有对应的源代码定位或可验证修复项。这是 review 运行失败记录,不是当前代码问题;如需结论,应在相关文件范围重新运行 review。

# Review 复核结果 以下结论基于当前工作区代码重新核对。`✅` 表示已自动修复并单独提交;`⏸` 表示问题仍成立,但涉及输入/提示词/审计/UI 契约或可能改变现有行为,按要求留给你;`⚪` 表示不是可直接修复的代码问题。 - ✅ 1. `apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs:103-120`(安全,中):当前 wire 摘要会先复用附件清洗函数,再输出给模型;名称会去控制字符并提取 basename,媒体类型会去控制字符并按允许格式清洗,本地路径也会归一化为项目相对路径,避免换行、绝对路径或反斜杠破坏摘要结构。已补充清洗后的摘要测试;提交 `70fa16081`。 - ✅ 2. `apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:41-50`(安全,中):资源引用、运行区域引用和 inline 附件现在分别计数;inline 附件使用独立的 `MAX_DIRECT_CODEX_ATTACHMENTS` 上限(8),不能再通过 `agc_attachment_reference` 绕过引用数量门禁放大 prompt。已补充超限拒绝测试;提交 `50204ff7a`。 - ✅ 3. `apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:54-67`(缺陷,中):校验现在要求 `status=imported` 必须提供非空、有效的项目相对路径;`failed` 可以没有路径,但如果带路径仍必须通过路径校验。这样不会再把“已导入但无项目路径”或未归一化路径交给后续 wire 投影;已补充对应测试。提交 `bc1dc868a`。 - ✅ 4. `apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/user_input.rs:45`(重复记录):DirectProject 已经把完整回合写入 `.agent/conversations/project.jsonl`,额外创建 `DirectCodexTurnAudit` 只会再写一份 `.agent/runtime/direct-codex/turns/*.jsonl`,而且原调用还传了空附件列表。已移除 DirectProject 入口的审计器创建、结束和传递,提交 `faed0ec25`;底层可选参数与独立审计测试保留。 - ✅ 5. `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:204-438`(缺陷,中):`referenceFromContentPart` 原本没有处理 `agc_attachment_reference`,`applyContentToRoot` 会静默丢弃初始草稿附件。已新增 Lexical `AttachmentReferenceNode` 与可移除 chip,初始化时插入附件节点,读回时重新生成完整 `agc_attachment_reference` part,并注册到编辑器节点列表;提交 `d8af0fa88`。 - ✅ 6. `apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts:51-166`(兼容残留):当前生产调用均已提供 `content`,没有实际的“旧调用者”需要这条 fallback。已将 `ChatComposerDraft.content` 设为必填 canonical 唯一来源,删除 `text + references` 重建分支,并移除调用方无效的 `?? []` 兜底;提交 `840baf208`。 - ✅ 7. `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:239-241`(可维护性,低):资源与运行区域两条三元分支都返回同一个 ``@${reference.label}``,条件没有行为意义。已改为直接使用统一表达式,提交 `06004bfee`(清理资源引用标签的重复分支)。 - ✅ 8. `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:724-749`(缺陷,中):初始草稿 effect 现在会在包含资源引用且 `assetsById` 为空时先返回,不提前设置 applied guard;manifest 到达后 effect 会重试并恢复资源引用。提交 `6e63a118e`,并留下 TODO:未来可以让 Lexical 资源节点自己通过 manifest/context 解析资产名称。 - ✅ 9. `apps/ai-game-creator-shell/src/App.tsx:12306`(缺陷,低):历史命令原先改用含附件派生的 `canonicalPrompt` 判断,待发送附件会把 `/history` 变成 `/history@文件名`,导致命令被当作普通消息发送。已改为使用不含附件的文本输入 `prompt` 判断,提交 `b73a329b2`(修复附件场景下历史命令识别)。 - ⚪ 10. `apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs:103-109`(原报告表述过度):`PROJECT_ATTACHMENT_HEADER` 是旧的 `render_direct_codex_user_prompt(prompt, attachments)` 文本提示,目前该函数只被首页回合调用;当前项目 DirectProject 走 inline `user_item` wire 投影,并没有证据证明这里发生了“旧项目 header 被移除”的回归。inline 摘要确实没有这句额外指引,但是否补上属于提示词一致性选择,不应直接定为中等级缺陷。 - ✅ 11. `apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:41-53`(可维护性,低):inline 附件现在复用附件参数路径的元数据约束:名称拒绝控制字符并限制为 160 个字符,媒体类型拒绝空值、非法字符并限制为 96 个字符;清洗上限常量也已共享,避免异常元数据进入 canonical item 和模型 prompt。已补充拒绝测试;提交 `75ec3361d`。 - ⚪ 12. LLM retry report summary(报告元信息):原报告中的两次请求因 core review/comment filtering 超时而失败,没有对应的源代码定位或可验证修复项。这是 review 运行失败记录,不是当前代码问题;如需结论,应在相关文件范围重新运行 review。
lhk229 added 1 commit 2026-09-18 14:25:42 +08:00
Merge branch 'master' into fix/ref-persistent
Project CI / Backend tests (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 / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (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 / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
d5eca8cce6
k88936 added 4 commits 2026-09-18 14:29:51 +08:00
wire 投影复用附件名称与媒体类型的安全清洗。

附件项目路径输出归一化结果,避免原始控制字符进入模型提示。
为 canonical 附件增加独立的八个条目上限。

补充超限附件拒绝测试,避免绕过素材引用数量门禁。
imported 附件必须携带有效非空的项目相对路径。

failed 附件仍允许无路径,并补充状态路径组合测试。
限制附件元数据格式与长度
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m52s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m0s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 6m20s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m41s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m48s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m13s
Project CI / Frontend tests (pull_request) Failing after 5m34s
Project CI / Repository checks (pull_request) Failing after 7m3s
Project CI / AI game creator shell web tests (pull_request) Failing after 5m31s
Project CI / Backend tests (pull_request) Successful in 11m38s
Project CI / Native shell tests (pull_request) Successful in 14m7s
9fa05eccaf
校验 inline 附件名称和媒体类型的控制字符、格式与长度。

共享附件清洗上限常量并补充异常元数据拒绝测试。
k88936 requested review from lhk229 2026-09-18 14:55:36 +08:00
lhk229 added 1 commit 2026-09-18 14:58:57 +08:00
Merge branch 'master' into fix/ref-persistent
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m3s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m44s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m44s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m11s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m28s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m53s
Project CI / Frontend tests (pull_request) Failing after 7m14s
Project CI / Repository checks (pull_request) Failing after 11m30s
Project CI / Backend tests (pull_request) Successful in 15m32s
Project CI / AI game creator shell web tests (pull_request) Failing after 6m26s
Project CI / Native shell tests (pull_request) Successful in 17m50s
d1fa973d25
lhk229 requested changes 2026-09-18 15:37:31 +08:00
lhk229 left a comment
Owner

审查结论

要求修改。

DirectProject 提交、历史和 Rust 校验这条主路径已经收敛到 canonical content[],附件也走 inline agc_attachment_referenceuserItem 不再从 text/references 猜测重建。生产聊天输入区却仍把 value + references 回写进 Lexical,和 content-first 草稿不一致:同一素材插两次会循环重建,素材从 manifest 消失时会先拆掉结构化 chip,绕过 fail-closed。

问题统计

  • 缺陷:2
  • 建议:2
  • nit:1

必须先修两个缺陷。建议和 nit 不阻塞,但测试缺口和受控回写是同一根因,最好一起收。

已核对、本轮不重提

  • 作者前几轮列出的已修项,当前 HEAD 对得上。
  • queuedChatTurnLabelassets 默认值已修。
  • 引用后尾随换行:当前 Rust 允许空白 input_text;chip 之间没有后续文字时换行仍可能丢掉,按作者说明暂不作为本轮阻塞项。
  • 快速编辑仍从 @显示名 token 重建 chip:作者已声明后续里程碑,本轮不阻塞。
## 审查结论 要求修改。 DirectProject 提交、历史和 Rust 校验这条主路径已经收敛到 canonical `content[]`,附件也走 inline `agc_attachment_reference`,`userItem` 不再从 `text`/`references` 猜测重建。生产聊天输入区却仍把 `value` + `references` 回写进 Lexical,和 content-first 草稿不一致:同一素材插两次会循环重建,素材从 manifest 消失时会先拆掉结构化 chip,绕过 fail-closed。 ## 问题统计 - 缺陷:2 - 建议:2 - nit:1 必须先修两个缺陷。建议和 nit 不阻塞,但测试缺口和受控回写是同一根因,最好一起收。 ## 已核对、本轮不重提 - 作者前几轮列出的已修项,当前 HEAD 对得上。 - `queuedChatTurnLabel` 的 `assets` 默认值已修。 - 引用后尾随换行:当前 Rust 允许空白 `input_text`;chip 之间没有后续文字时换行仍可能丢掉,按作者说明暂不作为本轮阻塞项。 - 快速编辑仍从 `@显示名` token 重建 chip:作者已声明后续里程碑,本轮不阻塞。
@@ -31,10 +31,9 @@ pub(crate) fn normalize_direct_client_turn_id(
pub(crate) async fn chat_with_game_creator_direct_codex(
project_path: String,
prompt: String,
Owner

[nit] prompt 参数现在完全没用,真正进模型的是 direct_codex_user_item_to_prompt(&user_item)。前端仍会传带 @显示名prompt,后人很容易再把它接回 Codex。

建议: 改成 _prompt 保留 IPC 字段,或在前端停止发送的同一次变更里删掉。不要重新使用客户端 prompt

**[nit]** `prompt` 参数现在完全没用,真正进模型的是 `direct_codex_user_item_to_prompt(&user_item)`。前端仍会传带 `@显示名` 的 `prompt`,后人很容易再把它接回 Codex。 **建议:** 改成 `_prompt` 保留 IPC 字段,或在前端停止发送的同一次变更里删掉。不要重新使用客户端 `prompt`。
@@ -4078,0 +4087,4 @@
);
return asset
? [resourceReferenceFromAsset(asset, 'asset-picker')]
: [];
Owner

[缺陷] 素材在 manifest.assets 里找不到时这里返回 []。受控 effect 看到更短的 desiredRefs,就会 applyDraftToRoot(desiredValue, desiredRefs),把还在编辑器里的结构化 chip 拆掉。用户最后只剩普通 @resourceId 文本;Rust 本应 fail-closed「引用的素材已不存在,请移除后重新选择」,但这条路径在提交前就把引用弄没了。画布删掉 composer 里还挂着的素材,或 lookup 暂时为空时都会触发。

建议: 提交前不要把未解析的 resourceId 从编辑器里删掉。让 Rust 校验拒绝这一轮;若 UI 要提前警告,把 chip 标成失效,而不是删除 part。

**[缺陷]** 素材在 `manifest.assets` 里找不到时这里返回 `[]`。受控 effect 看到更短的 `desiredRefs`,就会 `applyDraftToRoot(desiredValue, desiredRefs)`,把还在编辑器里的结构化 chip 拆掉。用户最后只剩普通 `@resourceId` 文本;Rust 本应 fail-closed「引用的素材已不存在,请移除后重新选择」,但这条路径在提交前就把引用弄没了。画布删掉 composer 里还挂着的素材,或 lookup 暂时为空时都会触发。 **建议:** 提交前不要把未解析的 `resourceId` 从编辑器里删掉。让 Rust 校验拒绝这一轮;若 UI 要提前警告,把 chip 标成失效,而不是删除 part。
@@ -633,2 +739,4 @@
if (initialDraftAppliedRef.current || !initialContent) {
return;
}
// Manifest assets can arrive after the initial editor mount. Do not mark the
Owner

[建议] 这几处英文注释在复述改动或设计历史(manifest 晚到、Lexical 自己解析 label 的 TODO、The pure projection is exported…AttachmentReferenceNode 的英文 class 注释)。中文主模块里不要堆实现过程。

建议: 删掉叙事/TODO。只有「assetsById 为空时先不要把 initial draft 标成已应用」这条不变量需要一行中文说明。

**[建议]** 这几处英文注释在复述改动或设计历史(manifest 晚到、Lexical 自己解析 label 的 TODO、`The pure projection is exported…`、`AttachmentReferenceNode` 的英文 class 注释)。中文主模块里不要堆实现过程。 **建议:** 删掉叙事/TODO。只有「`assetsById` 为空时先不要把 initial draft 标成已应用」这条不变量需要一行中文说明。
@@ -642,0 +780,4 @@
`${reference.type}:${reference.type === 'resource' ? reference.resourceId : reference.label}`,
)
.join('|');
if (current.text === desiredValue && currentRefKey === desiredRefKey)
Owner

[缺陷] 生产聊天仍把 value/references 回写进 Lexical。readResourceReferenceDraft 会走 dedupeChatReferenceshandleChatComposerChange 不会。同一素材两个 chip 时,currentRefKeyresource:herodesiredRefKeyresource:hero|resource:hero,每次 onChange 都会 applyDraftToRoot + $getRoot().selectEnd()。这是更新循环:光标被拽到末尾,React 可能打到 maximum update depth。applyDraftToRoot 也不能 round-trip agc_attachment_reference,重建时会丢掉 inline 附件。同一素材插两次是编辑器支持的操作。

建议: 清空/恢复/建议命令走 composerRef.clear() / applyContentToRoot / replaceText,比较用 canonical content[](或能保留重复 part 的指纹)。如果受控 props 还要留一阵,父级和编辑器必须用同一套引用身份,且相等判断必须基于 content;applyDraftToRoot(text, refs) 不是 collectDraftParts 的无损逆运算。

**[缺陷]** 生产聊天仍把 `value`/`references` 回写进 Lexical。`readResourceReferenceDraft` 会走 `dedupeChatReferences`,`handleChatComposerChange` 不会。同一素材两个 chip 时,`currentRefKey` 是 `resource:hero`,`desiredRefKey` 是 `resource:hero|resource:hero`,每次 `onChange` 都会 `applyDraftToRoot` + `$getRoot().selectEnd()`。这是更新循环:光标被拽到末尾,React 可能打到 maximum update depth。`applyDraftToRoot` 也不能 round-trip `agc_attachment_reference`,重建时会丢掉 inline 附件。同一素材插两次是编辑器支持的操作。 **建议:** 清空/恢复/建议命令走 `composerRef.clear()` / `applyContentToRoot` / `replaceText`,比较用 canonical `content[]`(或能保留重复 part 的指纹)。如果受控 props 还要留一阵,父级和编辑器必须用同一套引用身份,且相等判断必须基于 content;`applyDraftToRoot(text, refs)` 不是 `collectDraftParts` 的无损逆运算。
@@ -789,2 +831,2 @@
/>,
);
// 切换 / 重开会话:通过输入区 handle 替换 Lexical 唯一状态。
composerRef.current?.replaceText('恢复出来的草稿');
Owner

[建议] 测试现在用 initialContent + getDraft() / replaceText,但生产 Direct Codex 聊天不是这条路:它仍用 value + references 控制编辑器,提交读的是 React chatContent,不是 composerRef.getDraft()。上面两个缺陷因此没有覆盖。

建议: 留一个生产形态 fixture(value + references + onChange 写回父状态,提交读父状态),覆盖同一素材插两次、以及 composer 里的素材从 assets/manifest 删除。断言不要额外 applyDraftToRoot / 光标跳动,结构化 agc_resource_reference 要活到 fail-closed 校验。

**[建议]** 测试现在用 `initialContent` + `getDraft()` / `replaceText`,但生产 Direct Codex 聊天不是这条路:它仍用 `value` + `references` 控制编辑器,提交读的是 React `chatContent`,不是 `composerRef.getDraft()`。上面两个缺陷因此没有覆盖。 **建议:** 留一个生产形态 fixture(`value` + `references` + `onChange` 写回父状态,提交读父状态),覆盖同一素材插两次、以及 composer 里的素材从 `assets`/`manifest` 删除。断言不要额外 `applyDraftToRoot` / 光标跳动,结构化 `agc_resource_reference` 要活到 fail-closed 校验。
Author
Member

必须要和supervisior路径做明确的切割, 不然这类问题没完没了了 转向 #420

必须要和supervisior路径做明确的切割, 不然这类问题没完没了了 转向 #420
k88936 closed this pull request 2026-09-18 17:09:29 +08:00
Owner

supervisor马上要删除了

supervisor马上要删除了
Some checks are pending
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m3s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m44s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m44s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m11s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m28s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m53s
Project CI / Frontend tests (pull_request) Failing after 7m14s
Project CI / Repository checks (pull_request) Failing after 11m30s
Project CI / Backend tests (pull_request) Successful in 15m32s
Project CI / AI game creator shell web tests (pull_request) Failing after 6m26s
Project CI / Native shell tests (pull_request) Successful in 17m50s

Pull request closed

Sign in to join this conversation.