From 9f40f044a55ceacfc6bbbf9665d06c4e41d3c295 Mon Sep 17 00:00:00 2001 From: Linghong Date: Mon, 14 Sep 2026 14:47:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=AD=96=E5=88=92=20Agent=20?= =?UTF-8?q?=E6=8E=A8=E7=90=86=E5=B1=95=E7=A4=BA=E7=94=9F=E5=91=BD=E5=91=A8?= =?UTF-8?q?=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按项目与回合绑定 reasoning 事件 保留回合结束后的思考过程并在新回合清理 补充默认折叠的展开收起交互与定向测试 更新推理与正文分离里程碑进度 --- apps/ai-game-creator-shell/src/App.tsx | 26 ++++++- .../ProjectSupervisorView.tsx | 7 +- .../tests/appSurface/design-agent.suite.ts | 69 +++++++++++++++++++ .../tests/appSurface/harness.ts | 13 ++++ ...ider推理与正文分离及策划Agent展示-2026-09-14.md | 8 ++- 5 files changed, 119 insertions(+), 4 deletions(-) diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index fc4bee85b..87683987d 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -833,6 +833,11 @@ export function App({ view: DesignView; } | null>(null); const [planningV2Reasoning, setPlanningV2Reasoning] = useState(''); + const designAgentReasoningTurnRef = useRef<{ + projectPath: string; + clientTurnId: string; + text: string; + } | null>(null); const planningV2TurnRef = useRef<{ projectPath: string; clientTurnId: string; @@ -1125,6 +1130,11 @@ export function App({ projectPath: nextProjectPath, clientTurnId, }; + designAgentReasoningTurnRef.current = { + projectPath: nextProjectPath, + clientTurnId, + text: '', + }; designAgentPendingViewRef.current = null; await designAgentEventSubscriptionReady(); setChatAgentBusy(true); @@ -1648,6 +1658,7 @@ export function App({ setPlanningV2Session(null); setPlanningV2TransientReplyTarget(''); designAgentPendingViewRef.current = null; + designAgentReasoningTurnRef.current = null; setPlanningV2Reasoning(''); setPlanningV2Active(planningStartMode); planningV2ActiveRef.current = planningStartMode; @@ -2108,7 +2119,15 @@ export function App({ setPlanningV2TransientReplyTarget(payload.text); } if (payload.reasoningText != null) { - setPlanningV2Reasoning(payload.reasoningText); + const reasoningTurn = designAgentReasoningTurnRef.current; + if ( + reasoningTurn && + reasoningTurn.projectPath === payload.projectPath && + reasoningTurn.clientTurnId === payload.clientTurnId + ) { + reasoningTurn.text = payload.reasoningText; + setPlanningV2Reasoning(payload.reasoningText); + } } if (payload.kind === 'tool' && payload.text) { setPlanningV2TransientReplyTarget(payload.text); @@ -11936,6 +11955,11 @@ export function App({ projectPath: nextProjectPath, clientTurnId, }; + designAgentReasoningTurnRef.current = { + projectPath: nextProjectPath, + clientTurnId, + text: '', + }; designAgentPendingViewRef.current = null; setPlanningV2TransientReplyTarget(''); setPlanningV2Reasoning(''); diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx index ef8a6b119..f111ac332 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx @@ -263,8 +263,11 @@ export function ProjectSupervisorView({ ))} {designReasoning ? ( -
- 显示思考过程 +
+ 思考过程(点击展开)
{designReasoning}
) : null} diff --git a/apps/ai-game-creator-shell/tests/appSurface/design-agent.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/design-agent.suite.ts index 5fa401401..3160d8756 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/design-agent.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/design-agent.suite.ts @@ -7,6 +7,7 @@ import { React, render, screen, + setComposerText, waitFor, } from './harness'; @@ -55,6 +56,24 @@ function designClarificationView() { }; } +function designConversationView() { + return { + session: { + sessionId: 'design-session-reasoning', + projectId: 'local-project-draft', + currentPhase: 'concept', + approvedPhases: [], + pendingApproval: null, + pendingClarification: null, + turnIndex: 1, + lastError: null, + }, + messages: [], + running: false, + canRetry: false, + }; +} + export function registerDesignAgentSurfaceTests() { it('hydrates an existing design session and decides approval through design commands', async () => { const harness = createProjectSupervisorRuntimeHarness({ @@ -141,4 +160,54 @@ export function registerDesignAgentSurfaceTests() { ).toBe(true); }); }); + + it('keeps the current turn reasoning after completion and supports collapse/expand', async () => { + const harness = createProjectSupervisorRuntimeHarness({ + designAgentView: designConversationView(), + designAgentContinueView: designConversationView(), + }); + window.__TAURI__ = { + core: { invoke: harness.invoke }, + event: { listen: harness.listen }, + }; + window.history.pushState({}, '', '/'); + render( + React.createElement(App, { + initialProjectPath: harness.projectPath, + orchestrationMode: 'single-supervisor', + planningStartMode: true, + projectSupervisorOnly: true, + }), + ); + + const input = await screen.findByLabelText('项目需求'); + await setComposerText(input, '请给出核心玩法方案'); + fireEvent.submit(input.closest('form') as HTMLFormElement); + await waitFor(() => { + expect( + harness.invoke.mock.calls.some( + ([command]) => command === 'continue_design_agent_session', + ), + ).toBe(true); + }); + const continueCall = [...harness.invoke.mock.calls] + .reverse() + .find(([command]) => command === 'continue_design_agent_session'); + const clientTurnId = String( + (continueCall?.[1] as { clientTurnId?: string }).clientTurnId, + ); + harness.emitDesignAgentEvent({ + projectPath: harness.projectPath, + clientTurnId, + kind: 'reasoning', + reasoningText: '先分析需求,再组织方案。', + }); + + const summary = await screen.findByText('思考过程(点击展开)'); + const details = summary.closest('details') as HTMLDetailsElement; + expect(details.open).toBe(false); + fireEvent.click(summary); + expect(details.open).toBe(true); + expect(screen.getByText('先分析需求,再组织方案。')).not.toBeNull(); + }); } diff --git a/apps/ai-game-creator-shell/tests/appSurface/harness.ts b/apps/ai-game-creator-shell/tests/appSurface/harness.ts index 3c6da89f6..2400ea259 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/harness.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/harness.ts @@ -741,6 +741,9 @@ function createProjectSupervisorRuntimeHarness({ }; }) => void) | null = null; + let designAgentUpdateHandler: + | ((event: { payload: Record }) => void) + | null = null; const conversationRecord = ( role: 'user' | 'assistant', @@ -1113,6 +1116,10 @@ function createProjectSupervisorRuntimeHarness({ if (eventName === 'game-creator-agent-progress') { progressHandler = handler as unknown as typeof progressHandler; } + if (eventName === 'design-agent-update') { + designAgentUpdateHandler = + handler as unknown as typeof designAgentUpdateHandler; + } return () => { if (runtimeUpdateHandler === handler) { runtimeUpdateHandler = null; @@ -1123,6 +1130,9 @@ function createProjectSupervisorRuntimeHarness({ if (progressHandler === handler) { progressHandler = null; } + if (designAgentUpdateHandler === handler) { + designAgentUpdateHandler = null; + } }; }, ); @@ -1149,6 +1159,9 @@ function createProjectSupervisorRuntimeHarness({ setPlanningV2Result(state: Record | null) { currentPlanningV2Result = state; }, + emitDesignAgentEvent(payload: Record) { + designAgentUpdateHandler?.({ payload }); + }, setPlanningV2StartResult(state: Record | null) { currentPlanningV2StartResult = state; }, diff --git a/docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md b/docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md index 44322109d..dc122b85c 100644 --- a/docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md +++ b/docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | awaiting-review | +| Status | in-progress | | Date | 2026-09-14 | | Parent Spec | `docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md` | | Related Issue | `GenarrativeAI/Genarrative#331` | @@ -12,6 +12,12 @@ 让策划 Agent 能在流式回合中单独收到 Provider reasoning,并在 UI 中以默认折叠的思考过程展示;用户可见正文、工具调用和 GameAgent 现有行为保持不变。 +## 当前实现进度(2026-09-14) + +- 已完成共享 reasoning 字段、Provider 解析、策划事件映射以及正文流式收尾的前两轮提交。 +- 当前第三轮聚焦策划 Agent 前端 reasoning 生命周期:按 `projectPath + clientTurnId` 绑定事件,回合结束后保留本轮 reasoning,下一轮或项目切换时清理。 +- 现有 `
` 展示保持默认收起,并提供明确的展开/收起入口;不新增持久化字段,也不改动 GameAgent、Direct/Codex、supervisor 或已退役链路。 + ## 背景与现状 - `platform-llm` 当前只向上层提供正文累计值、正文增量和结束状态。