From bd647a2affb51c1c45ec0fb828979f5e2b288a53 Mon Sep 17 00:00:00 2001 From: AIGameCreator App Date: Sun, 12 Jul 2026 04:19:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DAgent=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E4=B8=8E=E7=AD=89=E5=BE=85=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 固定空Runtime场景的消息区和输入区网格行位 让长聊天记录仅在消息面板内部滚动 为等待LLM回复状态补充aria-busy并强化回归测试 同步更新实施方案和决策记录 --- apps/ai-game-creator-shell/src/App.tsx | 1 + apps/ai-game-creator-shell/src/styles.css | 6 ++---- .../ai-game-creator-shell/tests/appSurface.test.ts | 14 +++++++++++++- docs/project-memory/shared-memory/decision-log.md | 1 + ...术方案】AI游戏创作智能体App实施计划-2026-06-24.md | 1 + 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index b6e143972..9d7549a86 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -6055,6 +6055,7 @@ export function WorkspaceLauncher({ className="launcher-agent-chat-messages" role="log" aria-label="Agent 聊天记录" + aria-busy={currentAgentChatWaiting} tabIndex={0} > {agentChatMessages.length > 0 ? ( diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index 217709382..0dceb21ed 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -1259,6 +1259,7 @@ textarea { } .launcher-agent-chat-messages { + grid-row: 5; display: grid; align-content: start; gap: 10px; @@ -1333,6 +1334,7 @@ textarea { } .launcher-agent-chat-composer { + grid-row: 6; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; @@ -1390,10 +1392,6 @@ textarea { gap: 8px; } -.launcher-agent-runtime-stack:empty { - display: none; -} - .launcher-agent-runtime-stack .agent-runtime-status { margin-top: 0; } diff --git a/apps/ai-game-creator-shell/tests/appSurface.test.ts b/apps/ai-game-creator-shell/tests/appSurface.test.ts index 661c12404..caecf4f76 100644 --- a/apps/ai-game-creator-shell/tests/appSurface.test.ts +++ b/apps/ai-game-creator-shell/tests/appSurface.test.ts @@ -1951,6 +1951,9 @@ describe('AI 游戏创作 App 界面边界', () => { expect(screen.getByLabelText('Agent 聊天记录').getAttribute('role')).toBe( 'log', ); + expect( + screen.getByLabelText('Agent 聊天记录').getAttribute('aria-busy'), + ).toBe('true'); expect(screen.getByLabelText('Agent 聊天记录').tabIndex).toBe(0); await act(async () => { releaseFirstDelta?.(); @@ -1999,6 +2002,9 @@ describe('AI 游戏创作 App 界面边界', () => { expect( within(screen.getByLabelText('Agent 聊天记录')).queryByRole('status'), ).toBeNull(); + expect( + screen.getByLabelText('Agent 聊天记录').getAttribute('aria-busy'), + ).toBe('false'); expect(persistedMessages).toEqual([ { role: 'user', @@ -16551,7 +16557,13 @@ describe('AI 游戏创作 App 界面边界', () => { /\.launcher-agent-chat-main\s*\{[^}]*grid-template-rows:[^;]*clamp\(260px,\s*40vh,\s*380px\)/s, ); expect(styles).toMatch( - /\.launcher-agent-chat-messages\s*\{[^}]*overflow-y:\s*auto/s, + /\.launcher-agent-chat-messages\s*\{[^}]*grid-row:\s*5[^}]*overflow-y:\s*auto/s, + ); + expect(styles).toMatch( + /\.launcher-agent-chat-composer\s*\{[^}]*grid-row:\s*6/s, + ); + expect(styles).not.toMatch( + /\.launcher-agent-runtime-stack:empty\s*\{[^}]*display:\s*none/s, ); }); diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 937120b0b..8154a104b 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -4145,6 +4145,7 @@ ## 2026-07-10 AI 游戏创作 Agent Runtime 执行边界 - 决策:开发单 Agent 对话默认使用可执行 Runtime,输入区通过 `执行 / 聊天` 分段控件显式区分;`执行` 调用 `start_game_creator_agent_runtime_task` 并保留工具策略、确认、取消、排队和状态事件,`聊天` 才使用无工具流式回复,不再保留并列的“后台运行”按钮。消息区使用固定响应式网格行和内部滚动,并在 Runtime 非终态期间显示当前等待对象。Runtime 完成前必须先把 assistant 回复写入发起 Session,再写 completed 终态和广播;落盘失败只能进入 failed。前端收到匹配当前项目、Agent、Session 和 runId 的终态后自动重读对话,切换 Session 会清除当前等待投影,旧 run 事件不得覆盖新 Session。 +- 2026-07-12 修正:Runtime 状态为空时也要保留其网格行位,消息区和输入区显式固定到第 5、6 行,禁止空 Runtime 容器通过 `display:none` 让长消息落入 `auto` 行并撑高页面;等待 LLM 期间消息区同步使用 `aria-busy` 暴露忙碌状态。 - 决策:后台 Agent 首轮不得预加载任何需要工具权限控制的项目内容。planning 与 final reply 只拿身份、session/run 元数据、任务、工具策略和已获准 observation;记忆、黑板、对话、资产和文件内容必须通过对应工具进入。最新黑板、记忆和对话采用尾部保留截断。 - 决策:同一 Agent 的前台聊天与后台队列共享 per-Agent OS 执行锁,前台 LLM 等待期间不持有项目写锁;同 Agent 后台投递保持 pending,前台结束后把当前锁直接移交给 drain,drain 异常不得反写已经完成的聊天结果,不同 Agent 继续并行。 - 决策:重启恢复继续遵守 `agent.resume` 默认确认策略。自动 command 只允许 auto;默认 confirm 由主工作区或独立开发 Agent 聊天窗口的 UI 明确确认后调用独立 command,确认绑定发起项目,切换项目取消旧确认且旧项目异步结果不得污染新项目状态;独立 command 只忽略 confirm、不允许绕过 deny,临时失败必须允许重试。 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 4084abe8a..1537fab7d 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -341,6 +341,7 @@ game-project/ - 通过 Evaluator 和 `game.static_smoke` 后,Agent loop 会把本次 runId、状态、轮次、下一步、active / carry-over 任务和最终本地产物摘要追加到 `memory/session.md` 与 `memory/project.md`,把重要跨 agent 决策 / 依赖 / 风险摘要追加到 `memory/blackboard.md`,并把各角色本轮成功产出的角色摘要追加到 `memory/agents//.md`;下一次 Planner、组内角色和 Generator 会通过记忆输入自然读取上一轮稳定原型状态,而不只依赖开发窗口 trace。 - 单 agent 对话入口读取对应 agent conversation;用户提交后先追加用户消息,再调用 `chat_with_game_creator_role_agent` / `chat_with_game_creator_role_agent_stream` 让对应 `agentLlm.` 结合项目上下文、Agent 私有记忆和本 Agent 历史对话生成回复,随后把回复写入对应 `.agent/conversations/agents/.jsonl`。这里的 `` 以任务 `taskId` 为规范值,Tauri 只兼容旧 `group-role` 别名并映射到 taskId。每轮对话会同步写 `.agent/runtime/agents/.json` 和 `.agent/runtime/events/.jsonl`,字段包含 `agentId`、`taskId`、`sessionId`、`runId`、`source`、`status`、`phase`、`currentTask`、`currentGoal`、`currentAction`、`waitingOn`、`nextStep`、`loopIteration`、`maxLoopIterations`、`toolActionBudget`、`plan`、`planSteps`、`activePlanStepIndex`、`observations`、`recentToolCalls`、`toolPolicy`、`allowedTools`、`lastResponse` 和 `error`;流式事件会把最新 `runtimeState` 回传给界面。Runtime state 写入使用临时文件替换,event JSONL 读取会跳过坏行;`currentTask`、`currentGoal`、event detail、`lastResponse` 和 `agent.db` 摘要复用敏感上下文过滤,不保存明显 API Key / Bearer / Cookie 片段。单 agent 面板可把当前输入手动追加到对应 `memory/agents//.md`,写入前复用 `memory.write` 项目策略和本地项目锁;最近对话可作为本次生成 prompt 上下文读取,但只有经过显式总结、用户显式手动沉淀或生成 loop 成功沉淀的稳定结论,才追加到 `memory/blackboard.md` 或 `memory/agents//.md`。 - 2026-07-10 补充:每个 Agent 支持多个持久化 Session。旧 `agent-session-` 永久映射原 `.agent/conversations/agents/.jsonl`,不迁移、不复制、不删除;新 Session 写入 `.agent/conversations/agents//sessions/.jsonl`,目录索引和 active Session 写入 `.agent/runtime/sessions/.json`。开发单 Agent 聊天页提供创建、切换、归档和已归档只读查看;归档只更新元数据,不截断对话。直接聊天、流式回调和后台任务在启动时捕获 `agentId + sessionId`,Runtime task / event 继续使用每 Agent append-only JSONL,但列表、任务队列、连续上下文和最近对话按 Session 过滤;Runtime 内的 `conversation.read` 和 self `agent.run_status` 通过 runId 继续使用该 Session,恢复或处理待确认动作前校验 task、runtime state 和 pending action 的 Session 一致性。同一 Agent 仍共享一把 OS 锁并严格串行,不允许借 Session 绕过 pending、确认或 `needs-reconciliation` 屏障;不同 Agent 仍可并行。 +- 2026-07-12 补充:开发单 Agent 聊天页的 Runtime 容器即使为空也必须保留网格行位,消息区和输入区固定落在第 5、6 行;长历史只增加消息区 `scrollHeight`,不得改变主面板高度。保存用户消息、连接 LLM、等待首个片段和流式接收期间,消息区持续显示等待状态并标记 `aria-busy=true`。 - 生成 loop 中的角色 brief 也写同一套 Agent Runtime state / event:active 角色用 `source=generate-draft` 和当前 `runId` 标记正在读取上下文、调用角色专属 LLM 或本地编排、生成 brief、完成或失败;carry-over 角色同样写入开始 / 完成事件,但不会伪装成重新调用 LLM。主窗口 Agent 状态列表、开发单 Agent 聊天页和项目内单 Agent 对话弹窗只读展示当前 Agent 的 runtime 状态、最近 task/run、阶段、当前目标、动作、等待对象、下一步、计划、观测和最近工具动作;这只是 V1 可观测性,不代表已经有独立后台常驻进程或可中断任意上游 LLM 请求。 - `.agent/agent.db` 当前作为最小本地项目索引文件使用 JSONL:初始化写入 `project.init`,每次 `game.generate_draft` 追加目标、标题、本地产物路径、checkpoint 和 diff 摘要,上传 / 登记 / 画板导入资产时追加 `asset.register` 或 `asset.update`;v1 不引入 SQLite 依赖。 - `game.generate_draft`、资产登记 / 导入、记忆写入、预览状态写入、checkpoint / restore、agent 生命周期控制、画板资源回流 / 生成和 policy 写入会先按 `.agent/policy.json` 判断本次命令是否被项目策略拒绝,再拿项目级 `.agent/project.lock` 串行化;锁只保护同一本地项目,v1 不做后台锁管理。`confirmCommands` 可把索引、状态读取、资产登记、checkpoint、预览、agent 生命周期、画板资源回流 / 生成、memory 读写删除和 conversation 读写等命令转成项目策略确认,命中时用户确认后才执行;用户可用 `/policy-confirm 命令` 加入确认列表,用 `/policy-auto 命令` 移除确认项。