记录 DirectProject 未消费用户上传权威文档问题
Project CI / Repository checks (pull_request) Successful in 3m29s
Project CI / Frontend tests (pull_request) Successful in 4m9s
Project CI / Backend tests (pull_request) Failing after 4m24s
Project CI / Native shell tests (pull_request) Failing after 6m34s

新增可直接用于 Issue 的技术说明文档

补充源码、Direct run 产物与持久化取证证据

明确排除审批引用、全量正文注入和全附件硬门禁等修复方向

改用共享 run ID 与项目相对路径,避免依赖本机绝对路径
This commit is contained in:
2026-08-30 11:59:37 +00:00
parent fb5b5d585c
commit 54ec3ef14f
@@ -0,0 +1,216 @@
# 【技术说明】DirectProject 未消费用户上传权威文档
- 首次记录:2026-08-30
- 问题类型:DirectProject 上下文消费缺陷 / 可审计性缺陷
- 影响范围:用户上传文档并在正文中明确指定其为本次建造依据的“做游戏”链路
- 当前状态:待排期,本文只用于提 Issue,暂不修复
## 0. Issue 摘要
当用户在正文中明确说明“我上传了一份 GDD,里面包含某些具体内容,请按照这份 GDD 做游戏”时,做游戏 Agent 没有可靠地把该附件当作本轮权威规格来检索、读取和消费。
这不是“上传附件功能失败”:附件已经成功复制到新项目并登记。问题在于,DirectProject 只收到用户正文和项目路径,没有收到“用户上传了哪些附件、附件的真实项目路径、哪个附件被正文指认为权威参考”这类一等上下文;Agent 只能自行猜测并搜索项目文件。
当前实现虽然存在条件性的 native 文件检索路径,但该路径既不是稳定的应用层契约,也没有对应的 Direct 读取审计记录。因此一次 run 结束后无法可靠回答:Agent 是否发现了附件、是否读取了附件、读取结果是否进入了后续设计和代码决策。
## 1. 预期行为
本 Issue 讨论的预期行为有一个重要前提:**不是所有上传文档都自动视为 GDD,也不是所有附件都必须被读取。**
只有当用户在正文或交互中明确表达类似以下意图时,相关文档才应被视为本轮权威参考:
> 我上传了一份 GDD,里面有探测艇、脉冲射击、敌方弹幕、模块选择和棱镜母体,请按照这份 GDD 做游戏。
在这一前提下,Agent 应能够:
1. 知道本轮存在用户上传的参考文档;
2. 找到该文档在当前项目中的真实路径;
3. 读取文档内容;
4. 将文档内容用于后续游戏设计、代码和资源决策;
5. 在可共享、可复核的审计信息中留下足以判断上述行为是否发生的记录。
用户手写 GDD、通过外部功能生成后导入的 GDD、普通上传的 GDD,以及“做成游戏”入口带入的 GDD,在这里都属于同一个用户意图场景。是否来自“做方案”审批链路不是必要前提。
## 2. 实际现象
`gameagent-77b5aa31` 这次 2026-08-30 的 Direct run 中:
- 用户正文明确要求先阅读附件中的 `fast_gdd.md`,并以其作为主要依据;
- 文件成功复制到新项目:
```text
assets/uploads/upload-1788083777445-fast_gdd.md
```
- 原策划项目文件与上传副本大小均为 `7944` 字节,SHA-256 一致,说明复制没有损坏;
- 最终游戏却生成了《星光收集者》:星星收集、荆棘碰撞、左右移动、生命值;
- 原 GDD 的核心实体和循环(探测艇、脉冲射击、敌人、弹幕、模块、风险岔路、棱镜母体)没有体现在最终游戏中;
- 最终美术生成 prompt 只有“轻量、明快、暖色纸张质感背景、可爱的主角、可收集物、障碍物和简洁 HUD”等泛化描述;
- 浏览器验收的 `expectedText` 为空,没有对 GDD 语义做断言。
因此最终产物表现为一个内部自洽、但与用户指定 GDD 不同类型的通用收集类小游戏。
## 3. 代码层证据
### 3.1 附件不进入 Direct turn 的结构化输入
首页正文和附件在前端被分开处理;附件节点不会进入正文 prompt,而是作为单独的附件集合保存。
[richTextToPrompt.tsx](../../apps/ai-game-creator-shell/src/view/home/components/RichInputArea/richTextToPrompt.tsx:21)
进入项目工作台后,`ProjectSupervisor` 只收到项目路径、manifest、初始消息和创作类型,没有附件字段。
[WorkspaceLauncher.tsx](../../apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx:335)
[model.ts](../../apps/ai-game-creator-shell/src/features/app-shell/model.ts:29)
Direct Codex 调用的输入也只有:
```ts
{
projectPath,
prompt,
clientTurnId,
creationType
}
```
[App.tsx](../../apps/ai-game-creator-shell/src/App.tsx:5484)
其中没有附件列表、附件路径、附件 hash 或附件正文。
### 3.2 上传后路径被重写,Agent 不会自动得到真实路径
上传实现会把文件写入 `assets/uploads/upload-<timestamp>-<原文件名>`,例如 `fast_gdd.md` 会变成 `upload-...-fast_gdd.md`。
[assets.rs](../../apps/ai-game-creator-shell/src-tauri/src/assets.rs:460)
上传结果会写入项目的 `.agent/manifest.json` 和 `.agent/agent.db`,但这些是项目持久化产物,不是自动注入到 Direct LLM 请求的上下文;`.agent` 还是 Direct 的控制面边界,不能作为普通项目文档让 Agent 读取。
### 3.3 代码中存在条件性的主动检索路径,但不是稳定契约
DirectProject 的 app-server 使用项目根作为 `cwd`,并在可用配置下保留 native shell / 命令能力,因此 Agent 理论上可以:
```text
搜索 fast_gdd
→ 找到 assets/uploads/upload-...-fast_gdd.md
→ 用 native 命令读取正文
```
[codex_app_server.rs](../../apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server.rs:1482)
[codex_app_server.rs](../../apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server.rs:1160)
但这条路径有三个问题:
- 需要 Agent 自己判断“这份附件值得检索”,应用没有把附件关系告诉它;
- `agc_list_project_files` 只能返回路径、大小和类型,不返回 Markdown 正文;
- DirectProject 没有接入旧 Agent Runtime 的 `file.read` / `project.search` 工具目录,读取能力取决于 Direct app-server 的 native 工具配置。
[direct_tools_mcp.rs](../../apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs:214)
[agent_native_tools.rs](../../apps/ai-game-creator-shell/src-tauri/src/agent/agent_native_tools.rs:1349)
因此当前代码不能称为“附件已可靠进入 Agent 上下文”,只能称为“Agent 在部分配置下可能自行发现项目文件”。
## 4. 持久化与取证现状
### 4.1 这次 Direct run 没有持久化读取记录
`gameagent-77b5aa31/.agent/agent.db` 共 12 条记录,类型只有:
```text
project.init 1
asset.register 5
canvas.asset_generate 3
conversation.message 3
```
其中没有:
```text
file.read
file.list
project.search
command.exec
agent.runtime.tool_observation
agent.runtime.action_receipt
```
这能证明上传、资源生成、游戏入口写入和对话消息被记录,但不能证明 Direct app-server 没有执行过 native 文件读取。
### 4.2 Direct app-server 的 native read 不在当前 Agent DB 审计范围内
Direct app-server 使用 ephemeral thread。stdout 中的 `item/started`、`item/completed`、`commandExecution` 等事件只在运行期间被解析成有限的活动状态,再通过 Tauri event 发给前端;当前实现没有把 native 命令、读取路径、读取结果或读取 hash 追加到项目 `agent.db`。
[codex_app_server.rs](../../apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server.rs:883)
[codex_app_server.rs](../../apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server.rs:2496)
相对地,旧 Agent Runtime 的 `file.read` 会写入 `agent.runtime.action_receipt` 和 `agent.runtime.tool_observation`,因此旧路径可以审计到读取了哪个文件。
[main_loop.rs](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/main_loop.rs:3347)
这说明问题不是项目完全没有持久化能力,而是 DirectProject 的文件读取路径绕过了现有可审计工具链。
## 5. 问题定性
本 Issue 应定性为:
> 当用户明确把某个上传文档指定为本轮游戏制作的权威参考时,DirectProject 没有可靠地把“用户—附件—当前任务”的关系传给 Agent,也没有让文档发现、读取和后续消费形成可观察的工作流证据。结果是 Agent 可以从泛化的游戏目标出发完成一个可运行产物,却不一定消费用户指定的文档规格。
这属于用户意图和 Agent 上下文消费之间的契约缺失,不属于 GDD 审批状态传递错误,也不属于附件复制损坏。
## 6. 明确排除的归因与修复方向
以下内容不应作为本问题的主要根因,也不应直接作为本 Issue 的修复目标:
### 6.1 不把 `approvedGddRef` / approval receipt 缺失视为根因
用户手写 GDD、外部生成后导入的 GDD、普通文件上传的 GDD,都不一定存在 `approvedGddRef` 或审批 receipt,但只要用户在 prompt 中明确指定“按照这份 GDD 做游戏”,Agent 就应该能够正确消费它。
因此,缺失审批状态绑定不能解释这类通用失败。
### 6.2 不把所有上传文档强制当成 GDD
用户上传的文件可能是图片、素材说明、参考资料、README、代码片段或与游戏无关的文档。不能因为文件被上传,就默认它是策划案或本轮的权威规格。
只有用户明确建立“这份文档用于本轮任务”的关系时,才进入本文讨论的语义范围。
### 6.3 不采用“把所有上传文档正文直接拼进 prompt”作为通用修复
附件可能很大、可能是二进制、可能包含不可信内容,也可能只是可选参考。把所有上传文件正文无条件塞入 prompt 会混淆普通附件、参考资料和权威任务规格,也改变当前附件模型的边界。
本文不要求把上传文件正文统一注入 prompt。
### 6.4 不采用“所有附件必须先读取,否则一律阻断”作为通用硬门禁
对于用户没有要求使用的附件,系统不应强制 Agent 读取;对于非文本附件,也不能套用 Markdown 文本读取规则。
本文关注的是用户明确指定文档为权威参考时的消费缺失,不要求把所有附件都改造成强制读取工作流。
## 7. Issue 验收口径
本问题修复完成后,至少应能验证以下事实,但具体实现方式不在本文展开:
- 用户明确指定某个上传文档为本轮任务依据时,Agent 能够发现并读取对应文档;
- 用户未指定的普通附件不会被自动当成 GDD 或强制纳入任务;
- Agent 是否发现、读取以及使用该文档,应能从可共享的 run 审计产物或等价的可审计证据中判断;
- 同一语义在“做成游戏”、普通上传、外部生成后导入和用户手写文档等入口下不依赖审批 receipt 才成立;
- 文档被读取后,至少有一种可验证方式能判断其关键内容是否进入了后续任务上下文,而不是只记录了文件存在。
具体修复方案、上下文协议设计和持久化字段设计另行讨论,本 Issue 不预设实现方案。
## 8. 关联产物
- 策划 run ID`gameagent-cd7f6c81`
- 做游戏 run ID`gameagent-77b5aa31`
- 上传 GDD(项目相对路径):`assets/uploads/upload-1788083777445-fast_gdd.md`
- 建议随 Issue 附上或引用对应 run 的以下复核材料:
- Direct 对话:`.agent/conversations/project.jsonl`
- Direct Agent DB`.agent/agent.db`
- Direct manifest`.agent/manifest.json`
- 最终游戏:`game/index.html`
- 浏览器验证:`.agent/runtime/direct-codex-browser-validation/6/attempt-3/validation.json`
上述材料应以 Issue 附件、仓库归档或团队共享存储的形式提供;本文不依赖某位开发者电脑上的绝对路径。