From e46983154321c761957692d16abbd02779706cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 16 Sep 2026 21:26:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BF=AB=E9=80=9F=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8F=90=E7=A4=BA=E8=AF=8D=E6=8A=8A=20@=20=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E5=86=99=E6=88=90=E5=86=85=E9=83=A8=20id=EF=BC=88revi?= =?UTF-8?q?ew=20=E7=AC=AC=203=E3=80=814=20=E6=9D=A1=EF=BC=89=20-=20applyRe?= =?UTF-8?q?sourceQuickEditPrompt=20=E4=B8=8E=20applyResourceQuickEditDraft?= =?UTF-8?q?=20=E6=94=B9=E7=94=A8=20directCodexContentToPromptText(content,?= =?UTF-8?q?=20manifest.assets)=EF=BC=8C=E5=B9=B6=E5=9C=A8=20useCallback=20?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E9=87=8C=E5=8A=A0=E4=B8=8A=20manifest.assets?= =?UTF-8?q?=20-=20=E4=B8=A4=E5=A4=84=E5=BF=85=E9=A1=BB=E5=90=8C=E5=8F=A3?= =?UTF-8?q?=E5=BE=84=EF=BC=9A=E6=AF=94=E8=BE=83=E7=94=A8=E7=9A=84=E8=8D=89?= =?UTF-8?q?=E7=A8=BF=E6=96=87=E6=9C=AC=E4=B8=8E=E8=90=BD=E8=BF=9B=20quickE?= =?UTF-8?q?ditPanel.prompt=20=E7=9A=84=E6=96=87=E6=9C=AC=E9=83=BD=E6=8C=89?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=90=8D=E5=B1=95=E5=BC=80=EF=BC=8C=E5=87=BA?= =?UTF-8?q?=E7=AB=99=20derive=5Flocal=5Fproject=5Fresource=20=E7=9A=84=20p?= =?UTF-8?q?rompt=20=E4=B8=8E=E8=81=8A=E5=A4=A9=20@=20=E9=80=90=E5=AD=97?= =?UTF-8?q?=E4=B8=80=E8=87=B4=EF=BC=8C=E4=B9=9F=E4=B8=8D=E4=BC=9A=E6=AF=8F?= =?UTF-8?q?=E6=AC=A1=E8=BE=93=E5=85=A5=E9=83=BD=E9=87=8D=E8=B7=91=20replac?= =?UTF-8?q?eText=20-=20=E8=A1=A5=E5=85=85=E4=B8=A4=E5=A4=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E8=AF=B4=E6=98=8E=E7=B4=A0=E6=9D=90=E6=B8=85=E5=8D=95?= =?UTF-8?q?=E5=8F=A3=E5=BE=84=EF=BC=8Cshared-memory/pitfalls=20=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E3=80=8C=E6=B4=BE=E7=94=9F=E6=96=87=E6=9C=AC=E6=BC=8F?= =?UTF-8?q?=E4=BC=A0=20manifest.assets=E3=80=8D=E7=9A=84=E7=8E=B0=E8=B1=A1?= =?UTF-8?q?=E3=80=81=E5=8E=9F=E5=9B=A0=E3=80=81=E5=A4=84=E7=90=86=E4=B8=8E?= =?UTF-8?q?=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/view/project-development/index.tsx | 56 +++++++++++-------- docs/project-memory/shared-memory/pitfalls.md | 8 +++ 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/apps/ai-game-creator-shell/src/view/project-development/index.tsx b/apps/ai-game-creator-shell/src/view/project-development/index.tsx index 38146ff4a..13cb25887 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/index.tsx +++ b/apps/ai-game-creator-shell/src/view/project-development/index.tsx @@ -6489,41 +6489,51 @@ export default function ProjectDevelopmentView({ * * 与共享 composer 的 `resetFailedDialogStatus` 同口径:提示词变了就不再是上一次 * 失败的那份请求,状态回到 idle、错误清空——同时提交侧会按新提示词重铸请求身份。 + * 比较用的草稿文本必须和输入区自己读草稿的口径一致(都带 `manifest.assets`): + * 少传素材清单会把 chip 读成 `@内部 id`,与真正写进面板的 `@显示名` 永远不等, + * 于是每次改写都再 `replaceText` 一次。 */ - const applyResourceQuickEditPrompt = useCallback((text: string) => { - const currentDraft = quickEditPromptInputRef.current?.getDraft(); - if ( - currentDraft && - directCodexContentToPromptText(currentDraft.content) !== text - ) { - quickEditPromptInputRef.current?.replaceText(text); - } - setQuickEditPanel((current) => - current - ? { - ...current, - prompt: text, - status: current.status === 'failed' ? 'idle' : current.status, - errorMessage: - current.status === 'failed' ? undefined : current.errorMessage, - } - : current, - ); - }, []); + const applyResourceQuickEditPrompt = useCallback( + (text: string) => { + const currentDraft = quickEditPromptInputRef.current?.getDraft(); + if ( + currentDraft && + directCodexContentToPromptText( + currentDraft.content, + manifest.assets, + ) !== text + ) { + quickEditPromptInputRef.current?.replaceText(text); + } + setQuickEditPanel((current) => + current + ? { + ...current, + prompt: text, + status: current.status === 'failed' ? 'idle' : current.status, + errorMessage: + current.status === 'failed' ? undefined : current.errorMessage, + } + : current, + ); + }, + [manifest.assets], + ); /** * 快速编辑提示词输入区的整体草稿(文本 + `@` 引用)。 * * 文本仍走 `applyResourceQuickEditPrompt`(失败态重置口径不变),引用单独收下来供 - * 输入区回填 chip。提交时的出站 payload 就是这份文本:与聊天 `@` 同源、同字面量。 + * 输入区回填 chip。提交时的出站 payload 就是这份文本:与聊天 `@` 同源、同字面量, + * 所以 `@` 引用必须带上 `manifest.assets` 按显示名展开。 */ const applyResourceQuickEditDraft = useCallback( (draft: ChatComposerDraft) => { applyResourceQuickEditPrompt( - directCodexContentToPromptText(draft.content), + directCodexContentToPromptText(draft.content, manifest.assets), ); }, - [applyResourceQuickEditPrompt], + [applyResourceQuickEditPrompt, manifest.assets], ); /** diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 26eacc4ae..a2fa70792 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -5624,3 +5624,11 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **处理**:投影层改成「向前合并」——待写文本先攒在 `pendingText` 上,下一个文本到来时合并成同一个 `input_text`(`\n` 因此落在 `\n把这一版改成夜景` 里);攒到最后仍只有空白的(以换行结尾、两个 chip 之间只隔一个换行)不入 content,因为 Rust `validate_direct_codex_user_item` 会拒绝空 `input_text`,直接按 review 的 `text.includes('\n')` 落 part 会让「chip 换行 chip」这种输入整轮发不出去。 - **验证**:`apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx` 新增「引用后面的段落分隔不会被吞掉」,断言 chip 后一段的 part 为 `{ type: 'input_text', text: '\n把这一版改成夜景' }`、派生文本逐字一致、且不出现纯空白 part;去掉修复后该用例变红(比对失败在 content 相等那一行)。 - **关联**:`apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx`(`DraftContentCollector` / `appendInputText`)、`docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md`。 + +## 2026-09-16 派生文本漏传 `manifest.assets`:`@引用` 从显示名退化成内部 id + +- **现象**:快速编辑面板里 `@` 插了素材再点「修改」,出站 `derive_local_project_resource` 的 `prompt` 是 `把夜色改成星空@source-rules`,而界面 chip 与聊天输入区显示的是 `@rules`;仓库自带的 `projectResourceLiveIntegration` 用例因此长期是红的(`expected '把夜色改成星空@rules' to be '把夜色改成星空@source-rules'`)。同一根因还让排队消息 chip 显示 `@asset:…`。 +- **原因**:`directCodexContentToPromptText(content, assets)` 的 `assets` 有默认值 `[]`,漏传不报错、只是把 `agc_resource_reference` 退化成 `${resourceId}`。`ResourceReferenceInput` 自己读草稿的四处都带了 `manifest.assets`,而它的三个消费方漏传:`chatComposerQueue.queuedChatTurnLabel`(宿主 `ComposerTurnQueue` 也没接素材清单)、`project-development/index.tsx` 的 `applyResourceQuickEditPrompt` 与 `applyResourceQuickEditDraft`;后两个的 `useCallback` 依赖里同样没有 `manifest.assets`,改完还会读到旧清单。 +- **处理**:三个消费方全部补上素材清单并进依赖数组——`queuedChatTurnLabel(turn, assets)` + `ComposerTurnQueue` 新增 `assets` 属性(由 `ProjectSupervisorView` 传 `chatProjectAssets`)、快速编辑的两处改用 `manifest.assets`。改「比较用的草稿文本」与「落进面板的文本」必须同一个口径,否则 `replaceText` 会每次输入都重跑一遍。 +- **验证**:`apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx` 的「快速编辑提示词里能 @ 出资源选择器」由红转绿(该文件 29 passed);`tests/appSurface/chat-composer.suite.ts` 新增「队列 chip 的 @ 引用按 manifest 显示名展开」;`appSurface.test.ts` 467 passed、定向 51 passed、`npm run ai-game-creator-shell:typecheck`、`npm run check:encoding` 通过。 +- **关联**:`apps/ai-game-creator-shell/src/features/project-workspace/chatComposerQueue.ts`、`ComposerControls.tsx`、`ProjectSupervisorView.tsx`、`apps/ai-game-creator-shell/src/view/project-development/index.tsx`、`apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx`。