Merge codex/ai-game-creator-app:融合客户端运行时配置与 LLM api_kind 链路

以 codex/ai-game-creator-app 的客户端配置文件架构(game-creator.config.json)为底,
融合当前分支的 LlmRunRequest/LlmApiKind(openai_responses/openai_chat/anthropic)维度。

手工融合 6 个冲突文件:
- src-tauri/src/main.rs:LLM 配置统一走客户端配置文件,配置字段 protocol→apiKind,
  读取/解析/校验改为 parse_game_creator_llm_api_kind,丢弃 env 读取分支,测试改用配置文件路径
- game-creator.config.json / App.tsx / appSurface.test.ts:配置 schema protocol→apiKind,
  配置面板下拉项改为三种 api_kind
- scripts/smoke-agent-run-local-provider + check-config:smoke 写入 apiKind,drift 校验同步
- 三份文档(decision-log / 技术方案 / 开发运维):改用客户端配置文件 + apiKind 口径

验证:cargo check 全目标通过;63/67 Rust 单测通过(4 个为既有 mock-server flaky 集成测试,
经核实在合并前分支上同样间歇失败,与本次合并无关);TS typecheck、vitest(45)、check-config drift 全通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 18:02:22 +08:00
13 changed files with 1381 additions and 434 deletions
@@ -16,6 +16,14 @@
---
## 2026-06-30 AI 游戏创作 App 使用客户端配置文件
- 背景:`apps/ai-game-creator-shell` 是客户端 App,不应通过 `.env` 或进程环境变量承载 LLM / 画板同步配置;旧口径会让本地 secrets、CLI wrapper 和桌面 App 启动逻辑混在一起。
- 决策:仓库内 `apps/ai-game-creator-shell/game-creator.config.json` 只作为默认模板;发布 App 启动时在 Tauri 应用配置目录写入默认 `game-creator.config.json`,真实密钥和本机覆盖项都保存在该运行时配置文件中。主窗口提供“配置”面板读写该运行时 JSON;开发 CLI 无 AppHandle 时才回退读取仓库旁边的模板和 gitignored 本机覆盖文件。`llm.apiKey/baseUrl/model/protocol/stream/requestTimeoutMs/maxRetries/retryBackoffMs` 驱动真实 LLM 路径,`editorApi.baseUrl/apiKey` 驱动画板项目同步;`/llm-status` 只展示 baseUrl、model、protocol 和 API Key 是否存在,不显示密钥。
- 影响范围:AI 游戏创作 App 的 Tauri Rust 配置加载、主窗口配置面板、CLI wrapper、agent-run smoke、`check-config` 门禁、`.gitignore` 和实施计划文档。
- 验证方式:运行 `npm run ai-game-creator-shell:typecheck``cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml``npm run check:encoding``git diff --check`
- 关联文档:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`
## 2026-06-26 AI 游戏创作 App 生成过程必须在聊天可见
- 背景:普通用户窗口只保留聊天入口,但如果生成确认后只显示“已生成草案”和本地产物路径,真实 LLM / Agent loop 会被误解成固定模板落盘。
@@ -35,12 +43,12 @@
## 2026-06-25 AI 游戏创作 App 真实 LLM 联调用流式请求
- 背景:AI 游戏创作 App 的真实 OpenAI-compatible provider 验收中,小请求可返回,但 Planner 等稍长非流式请求会在上游响应前被网关空闲连接切断,表现为 TLS record 解密失败;本地无密钥 provider smoke 不能覆盖该真实网关行为。
- 决策:`platform-llm` 文本 client 使用系统 TLS backend,并保留底层错误链用于排障;AI 游戏创作 App 增加 `GENARRATIVE_GAME_CREATOR_LLM_STREAM=true` 开关,打开后 Planner、组内角色和 Generator 走流式请求。默认本地 smoke 继续使用非流式 OpenAI-compatible 测试 provider,避免把测试桩改重。
- 决策:`platform-llm` 文本 client 使用系统 TLS backend,并保留底层错误链用于排障;AI 游戏创作 App 通过客户端配置项 `llm.stream=true` 开关打开流式请求,打开后 Planner、组内角色和 Generator 走流式请求。
- 影响范围:`server-rs/crates/platform-llm``apps/ai-game-creator-shell/src-tauri/src/main.rs` 和 AI 游戏创作智能体 App 实施计划。
- 验证方式:运行 `cargo test -p platform-llm --manifest-path server-rs/Cargo.toml request_text_parses_non_stream_response`,并用真实 OpenAI-compatible 环境变量执行 `npm run ai-game-creator-shell:agent-run -- --no-wait /tmp/genarrative-ai-game-real-loop-test-6 "做一个像素风反弹弹幕厨房小游戏..."`,确认 36 个 trace step、36 次 tool call、`game.static_smoke``preview.start``preview.stop` 完成。
- 验证方式:运行 `cargo test -p platform-llm --manifest-path server-rs/Cargo.toml request_text_parses_non_stream_response`,并用真实 OpenAI-compatible 本机配置执行 `npm run ai-game-creator-shell:agent-run -- --no-wait /tmp/genarrative-ai-game-real-loop-test-6 "做一个像素风反弹弹幕厨房小游戏..."`,确认 36 个 trace step、36 次 tool call、`game.static_smoke``preview.start``preview.stop` 完成。
- 关联文档:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`
2026-06-29 追加:`platform-llm``LlmTextRequest` / `LlmTextResponse` 已直接替换为 provider-neutral 的 `LlmRunRequest` / `LlmRunResponse`API kind 先固定为 `openai_chat``openai_responses``anthropic` 三类。AI 游戏创作 App 默认 `openai_responses`,可 `GENARRATIVE_GAME_CREATOR_LLM_API_KIND=openai_chat` 接旧 Chat Completions 兼容网关,或 `GENARRATIVE_GAME_CREATOR_LLM_API_KIND=anthropic` 接 Anthropic Messages。当前 run 响应只保留通用文本、finish reason、response id 和 usage,高级能力后续按 capability 扩展,不把业务层绑死到 Responses 字段。
2026-06-27 追加2026-06-30 更新`platform-llm``LlmTextRequest` / `LlmTextResponse` 已直接替换为 provider-neutral 的 `LlmRunRequest` / `LlmRunResponse`API kind 先固定为 `openai_chat``openai_responses``anthropic` 三类。AI 游戏创作 App 改用客户端运行时配置(Tauri 应用配置目录的 `game-creator.config.json`),LLM 维度由 `llm.apiKind` 控制,默认 `openai_responses`,可设为 `openai_chat` 接旧 Chat Completions 兼容网关,或 `anthropic` 接 Anthropic Messages。当前 run 响应只保留通用文本、finish reason、response id 和 usage,高级能力后续按 capability 扩展,不把业务层绑死到 Responses 字段。
## 2026-06-24 AI 游戏创作 App 生成编排使用文件驱动 loop
@@ -3766,7 +3774,7 @@
- 决策:AI 游戏创作桌面入口新建 `apps/ai-game-creator-shell`。普通用户界面只保留聊天和上传入口;任务、能力、文件、记忆、预览和日志只放在开发模式或开发窗口。Agent 能力、manifest、内置命令和权限枚举写入 `packages/shared/src/contracts/gameCreationApp.ts``server-rs/crates/shared-contracts/src/game_creation_app.rs`;专业组和种子任务图写入 `server-rs/crates/platform-agent/src/game_creation.rs``canvas.project_open` 只允许打开本机 Genarrative 编辑器 `/editor/canvas?projectid=...`,默认本机端口为 `3000`,不得扩展成任意 URL 打开能力。
- 本地边界:生成代码、上传资产、短期记忆、长期记忆和预览入口必须保存到用户授权的本地项目目录;正式预览使用只读 `127.0.0.1:<port>` HTTP server,不使用 `file://``game.generate_draft``asset.upload` 这类 `confirm` 命令先在聊天区形成待确认命令,用户确认后才写本地产物;开发窗口中的 `confirm` 命令使用原生确认门,取消时只写日志不执行。`command.run_limited` 只执行白名单内置命令,当前最小真实命令是 `game.static_smoke`,用于检查 `game/index.html` 是否具备 canvas、canvas 渲染上下文、绘制调用、主循环、输入监听、明确目标、失败或胜利状态和重开路径,且不使用远程资源、`eval``new Function``localStorage``fetch``WebSocket``ServiceWorker`,不得把任意 shell 执行暴露给普通用户界面。`.agent/manifest.json` 是本地最小状态源,记录专业组种子任务、资产、预览状态和受限命令运行结果;开发窗口专业组面板读取 manifest task state,不使用前端硬编码作为真相源。`file.list/read/write/delete` 只能访问本地项目目录内的相对路径,禁止绝对路径、`..`、反斜杠和符号链接逃逸。`asset.register` 只登记项目目录内已经存在的文件,并可记录 `uploaded``generated``canvas` 来源元数据。`canvas.asset_import` 是画板回流的本地落点,只导入项目内已有文件为 `canvas` 来源资产,并要求画板项目 ID 与 resourceId / assetObjectId 可追踪;`canvas.export_import` 复用现有画板素材导出 ZIP,把 `metadata.json` 引用的 `images/``media/``sequences/` 文件复制到本地项目 `assets/canvas-imports/` 并登记为 `canvas` 来源资产。
- 2026-06-24 调整:`game.generate_draft` 必须作为一次本地 agent 协作回合记录,用户确认后同时写入短期记忆、长期记忆、设计草案、数值配置、美术清单、音乐音效清单、发布包装草案、可运行 HTML、`.agent/logs/agent.log` 和 manifest `commandRuns`;manifest 任务状态必须反映策划、数值、美术、音乐、程序组首轮完成,预览试玩等待确认。
- 2026-06-24 调整:`game.generate_draft` 必须通过 OpenAI-compatible LLM 生成结构化 JSON 草案,读取 `GENARRATIVE_GAME_CREATOR_LLM_*` 或既有 `GENARRATIVE_LLM_*` / `LLM_*` / `OPENAI_*` 环境变量;LLM 配置缺失、上游失败、返回非 JSON、HTML 非自包含、缺少 `canvas` / `requestAnimationFrame` 或把危险用户输入原样写入 HTML 时直接失败,不得静默回退固定模板并声称 AI 生成。
- 2026-06-24 调整2026-06-30 更新`game.generate_draft` 必须通过 OpenAI-compatible LLM 生成结构化 JSON 草案;发布 App 读取 Tauri 应用配置目录中 `game-creator.config.json``llm.*` 配置项,开发 CLI 无 AppHandle 时才读仓库旁边的 fallback 配置。LLM 配置缺失、上游失败、返回非 JSON、HTML 非自包含、缺少 `canvas` / `requestAnimationFrame` 或把危险用户输入原样写入 HTML 时直接失败,不得静默回退固定模板并声称 AI 生成。
- 2026-06-24 调整:`game.generate_draft` 生成的 `game/index.html` 必须是可试玩原型,至少具备输入、主循环、目标、失败或胜利状态和重开路径;不得退回按钮计分、纯展示页或占位式游戏。
- 2026-06-24 调整:`game.generate_draft` 的设计草案、发布包装草案和 agent log 必须包含专业组 / 角色 / 产物交接摘要,作为 6 组 agent 协作的最小可追踪证据。
- 2026-06-25 调整:`game.generate_draft` 的 loop 不能只由 Generator 在提示词里模拟六组协作;每一轮必须在 Planner 之后分别调用策划、数值、美术、音乐、程序、运营 6 组下的角色 agent 产出 brief,写入 `.agent/passes/pass-N/groups/<group>/*.md`,再汇总为 `.agent/passes/pass-N/groups/*.md`,由 Generator 读取这些汇总 brief、spec、findings 和记忆整合成结构化草案。`.agent/run.latest.json` 必须记录 `llm.chat.group.<group>.<role>` toolCall 和 brief artifact,作为多智能体协作的最小真实证据。
@@ -3784,7 +3792,7 @@
- 2026-06-25 调整:新增 `npm run ai-game-creator-shell:agent-run:smoke` 作为无密钥开发验证入口。脚本在本机启动 OpenAI-compatible 测试 provider,预置一个本地上传图片和一个本地上传音频,并复用真实 `--agent-run`、本地落盘、`game.static_smoke` 和本地 HTTP 预览;脚本会断言 provider 请求体包含图片与音频资产上下文、生成 HTML 引用 `/assets/...`、预览服务能用 `GET` 读取这些资产、用 `HEAD` 返回真实资源长度和对应 MIME、headless Chrome 打开预览后至少执行一帧游戏 JS,且通过确定性亮色探针采样证明 canvas 不是空白画布、第二轮重跑 Evaluator 命中任务及其下游影响任务,未受影响组 carry-over,再自动给 CLI 发送回车停止预览。该脚本仅验证 runtime,不作为产品生成 fallback。
- 2026-06-25 调整:新增根级 `npm run ai-game-creator-shell:check` 作为 v1 开发验收入口,串起壳 typecheck、`platform-agent` 编排测试、`shared-contracts` 契约测试、Tauri Rust 测试和无密钥本地 provider 端到端 smoke,避免测试口径散落成多条手工命令。
- 2026-06-25 调整:`scripts/check-native-shells.mjs` 的 AI 游戏创作项从单独 typecheck 升级为 `npm run ai-game-creator-shell:check`,让原生壳总门禁覆盖 agent loop、本地落盘、静态自检和本地 HTTP 预览 smoke。
- 2026-06-25 调整:普通用户通过聊天输入 `/llm-status` 触发只读 `llm.config_check`,用于检查 LLM base_url、model 和 API Key 是否已从环境变量读取;状态消息不得显示或保存 API Key。终端可用 `npm run ai-game-creator-shell:llm-status` 做同类配置自检,缺配置时以非零状态退出。生成仍只从环境变量读取配置,不新增仓库文件、项目文件或普通用户界面里的 secret 持久化
- 2026-06-25 调整2026-06-30 更新:普通用户通过聊天输入 `/llm-status` 触发只读 `llm.config_check`,用于检查 LLM base_url、model 和 API Key 是否已从客户端配置读取;状态消息不得显示或保存 API Key。终端可用 `npm run ai-game-creator-shell:llm-status` 做同类配置自检,缺配置时以非零状态退出。发布 App 的真实密钥只放 Tauri 应用配置目录中的 `game-creator.config.json`;主窗口“配置”面板可读写该文件,但 API Key 不写入聊天、本地项目、trace 或 manifest
- 2026-06-25 调整:`npm run ai-game-creator-shell:dev` 固定加载 `http://127.0.0.1:3080/`Vite 继续 `strictPort` 与 Tauri `devUrl` 对齐。`beforeDevCommand` 改为先复用已经跑在 3080 且页面标题为 `AI 游戏创作` 的本 app Vite server,避免上次 Tauri 退出后遗留的同 app Vite 进程导致二次启动失败;如果 3080 是其它服务,仍直接失败并要求释放端口,不做端口漂移。
- 2026-06-25 调整:`preview.start` / `preview.stop` 必须追加 `.agent/logs/preview.log`,并把该日志列入 Preview trace step 的输出路径和 artifact 清单;这样 `preview-playtest` 任务声明的日志产物与实际本地 HTTP 预览行为一致。
- 2026-06-25 调整:AI 游戏创作 App v1 仍只维护一个全局本地 HTTP 预览实例;启动新项目预览替换旧预览时,必须 best-effort 把旧项目的 manifest preview 状态、`.agent/logs/preview.log` 和 run trace 记录为 stopped,避免旧项目状态残留 `running`。旧项目目录已删除时不阻断新预览启动。
@@ -3796,7 +3804,7 @@
- 2026-06-25 调整:普通用户通过聊天输入 `/run` 触发待确认 `game.run_local`,确认后只能复用白名单 `game.static_smoke` 自检当前 `game/index.html`,通过后启动 `127.0.0.1` 本地 HTTP 预览。独立执行 `game.static_smoke` 时如果已有 `.agent/run.latest.json`,必须追加 `Playtest / game.static_smoke` trace step,避免“运行了代码但编排 trace 不可见”。
- 2026-06-25 调整:普通用户通过聊天输入 `/trace` 触发只读 `agent.trace_read`,读取 `.agent/run.latest.json` 并在聊天里摘要 loop 轮次、stopReason、nextStep、active / carry-over 任务、repairRoutes、agent 建议命令和最近 step。trace 面板仍只在开发窗口展示,普通用户窗口不新增面板。
- 2026-06-25 调整:普通用户通过聊天输入 `/import-canvas-export /绝对/画板素材.zip 画板项目ID` 触发待确认 `canvas.export_import`,读取现有 `/editor/canvas` 素材导出 ZIP。导入命令只读取用户指定 ZIP,写入当前本地项目 `assets/canvas-imports/`,基础护栏限制路径逃逸、文件数量和解压体积;导出包没有真实 resourceId 时,用 `canvas-export:<file>` 作为可追踪 assetObjectId,不伪造后端画板资源行。
- 2026-06-25 调整:普通用户通过聊天输入 `/sync-canvas-project 画板项目ID` 触发待确认 `canvas.project_sync`,复用现有 `/api/external/v1/editor/projects/{projectId}` 读取画板项目快照,再用 `/api/external/v1/assets/read-url` 对 objectKey 或 legacy path 换签,下载资源到本地项目 `assets/canvas-sync/` 并登记为 `canvas` 来源资产;该命令从 `GENARRATIVE_GAME_CREATOR_EDITOR_API_KEY``GENARRATIVE_EXTERNAL_API_KEY` 读取平台 API Key,默认 base URL 为 `http://127.0.0.1:8082`,可用 `GENARRATIVE_GAME_CREATOR_EDITOR_API_BASE_URL` 覆盖。API Key 不写入 manifest、agent.db、trace 或日志。该路径不伪装浏览器登录态,也不绕过画板生成、钱包扣费或外部生成 worker;它只同步用户 API Key 已有权限读取的画板资源。
- 2026-06-25 调整2026-06-30 更新:普通用户通过聊天输入 `/sync-canvas-project 画板项目ID` 触发待确认 `canvas.project_sync`,复用现有 `/api/external/v1/editor/projects/{projectId}` 读取画板项目快照,再用 `/api/external/v1/assets/read-url` 对 objectKey 或 legacy path 换签,下载资源到本地项目 `assets/canvas-sync/` 并登记为 `canvas` 来源资产;该命令从客户端配置项 `editorApi.apiKey` 读取平台 API Key,默认 base URL 为 `http://127.0.0.1:8082`,可用 `editorApi.baseUrl` 覆盖。API Key 不写入 manifest、agent.db、trace 或日志。该路径不伪装浏览器登录态,也不绕过画板生成、钱包扣费或外部生成 worker;它只同步用户 API Key 已有权限读取的画板资源。
- 2026-06-25 调整:美术组 `Asset` 和音乐组 `SFX` 角色在 loop 中读取 `.agent/manifest.json`;当本地项目还没有对应类型的 `canvas` 来源资产时,角色 step 会追加 `agent.tool.suggest.canvas.project_sync` toolCall:美术组需要 `image/*``application/vnd.genarrative.image-sequence`,音乐组需要 `audio/*`。该 toolCall 只作为 trace 中的建议,不自动调用 External Editor API,也不绕过用户确认。
- 2026-06-24 调整:同一本地项目多次 `game.generate_draft` 必须追加 `memory/session.md``memory/project.md`,不得覆盖历史对话和创作目标记录。
- 2026-06-24 调整:普通用户通过聊天输入 `/help` 发现可用内置命令;命令发现必须留在聊天消息里,不得因此暴露开发面板。
@@ -3809,7 +3817,7 @@
- 2026-06-24 调整:普通用户只能通过聊天触发内置命令;当前 `/smoke` 映射到白名单 `command.run_limited game.static_smoke` 并走待确认卡片,不允许扩展成任意 shell 或自由命令解析。
- 2026-06-24 调整:普通用户通过聊天输入 `/project /绝对路径` 触发 `project.create` 待确认命令,用于授权并初始化本地项目目录;相对路径不会生成待确认命令;不要把开发窗口项目路径输入框暴露到正式用户界面。
- 2026-06-25 调整:普通用户侧所有会写入、运行、查看 / 打开预览或导入本地产物的命令必须先完成 `/project` 初始化,包括 `game.generate_draft``asset.upload``game.run_local``command.run_limited``preview.start``preview.status``preview.open``preview.stop``memory.write``memory.delete``canvas.project_sync``canvas.asset_import``canvas.export_import`;没有已授权本地项目时只提示设置项目,不得落到默认 `/tmp` 草稿目录。
- 2026-06-24 调整:终端测试入口使用同一个 Tauri Rust 二进制的 `--agent-run <本地项目绝对路径> <创作需求>`,只复用现有 `game.generate_draft``game.static_smoke` 和本地 HTTP 预览链路,不另建第二套 agent runtimeLLM 配置只从环境变量读取,不写入仓库或项目文件。需要自动验证时可追加 `--no-wait`,生成预览 trace 后立即停止本地预览,避免命令卡在回车等待。
- 2026-06-24 调整2026-06-30 更新:终端测试入口使用同一个 Tauri Rust 二进制的 `--agent-run <本地项目绝对路径> <创作需求>`,只复用现有 `game.generate_draft``game.static_smoke` 和本地 HTTP 预览链路,不另建第二套 agent runtime发布 App 的 LLM 配置从 Tauri 应用配置目录读取,不写入仓库默认配置或项目文件。需要自动验证时可追加 `--no-wait`,生成预览 trace 后立即停止本地预览,避免命令卡在回车等待。
- 2026-06-24 调整:AI 游戏创作 App 的 release 配置只登记 `main` 聊天窗口,主窗口保持聊天尺寸;任务、文件、记忆、预览、日志和能力面板只能通过 debug/dev 下额外创建的 `developer` 窗口或 Vite dev `?dev/#dev` 查看,不进入普通用户窗口。
- 2026-06-24 调整:`check:native-shells` 必须静态守住 AI 游戏创作 App 的用户 / 开发边界:release 只保留 `main` 聊天窗口,`developer` 窗口只在 debug 创建,开发面板只能在 `devMode` 分支渲染。
- 2026-06-25 调整:`check:native-shells``ai-game-creator-shell:check` 之后必须追加 `ai-game-creator-shell:build -- --no-bundle`,让原生壳总门禁同时证明 AI 游戏创作独立 Tauri 壳能完成 release 编译,而不是只证明前端 / Rust 逻辑测试通过。