From 123c699db910fa10843019af151c1fe5bd300a24 Mon Sep 17 00:00:00 2001 From: Linghong Date: Fri, 11 Sep 2026 06:44:47 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=AD=96=E5=88=92=E6=BE=84?= =?UTF-8?q?=E6=B8=85=E5=8D=A1=E8=87=AA=E7=94=B1=E6=96=87=E6=9C=AC=E5=9B=9E?= =?UTF-8?q?=E7=AD=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将自由文本与选项回答分开提交 补充澄清卡回归测试和迁移方案说明 --- .../src-tauri/src/agent/design_runtime.rs | 10 +-- .../project-workspace/DesignAgentSurface.tsx | 25 +++---- .../tests/appSurface/design-agent.suite.ts | 69 +++++++++++++++++++ ...】策划Agent生产迁移与工作区浏览-2026-09-10.md | 2 +- 4 files changed, 89 insertions(+), 17 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs index 2358d1d3a..d2fe14928 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs @@ -193,10 +193,12 @@ fn prepare_design_input( if let Some(index) = option_index { let label = question.options.get(index).ok_or("所选选项不存在")?; answer.push_str(&format!("用户选择第 {} 项:{}。", index + 1, label)); - } - if let Some(text) = text.filter(|t| !t.trim().is_empty()) { - answer.push_str(&format!("用户补充:{}", text)); - } else if option_index.is_none() { + if let Some(text) = text.filter(|t| !t.trim().is_empty()) { + answer.push_str(&format!("用户补充:{}", text)); + } + } else if let Some(text) = text.filter(|t| !t.trim().is_empty()) { + answer.push_str(&format!("用户回答:{}", text)); + } else { return Err("请选择选项或填写回答".into()); } session.pending_clarification = None; diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/DesignAgentSurface.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/DesignAgentSurface.tsx index 03d7fe6a6..ed9034bef 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/DesignAgentSurface.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/DesignAgentSurface.tsx @@ -1,5 +1,5 @@ import { Check, RotateCcw, X } from 'lucide-react'; -import { useState } from 'react'; +import { useLayoutEffect, useState } from 'react'; import type { DesignClarificationRequest, @@ -46,6 +46,9 @@ export function DesignAgentSurface({ const phase = view?.session.currentPhase ?? 'concept'; const pending = view?.session.pendingApproval; const clarification = view?.session.pendingClarification; + useLayoutEffect(() => { + setClarifyText(''); + }, [clarification?.requestId]); return (
@@ -92,7 +95,7 @@ export function DesignAgentSurface({ key={`${clarification.requestId}-${index}`} type="button" disabled={busy} - onClick={() => onClarify(clarification, index, clarifyText)} + onClick={() => onClarify(clarification, index, '')} > {option} @@ -102,18 +105,16 @@ export function DesignAgentSurface({ rows={2} value={clarifyText} disabled={busy} - placeholder="补充说明(可选)" + placeholder="或者直接输入你的回答" onChange={(event) => setClarifyText(event.currentTarget.value)} /> - {clarification.options.length === 0 ? ( - - ) : null} +
) : null} {view?.canRetry ? ( 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 8b5fac582..05b322fbf 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 @@ -32,6 +32,29 @@ function designApprovalView() { }; } +function designClarificationView() { + return { + session: { + sessionId: 'design-session-clarification', + projectId: 'local-project-draft', + currentPhase: 'concept', + approvedPhases: [], + pendingApproval: null, + pendingClarification: { + requestId: 'clarification-1', + question: '主要面向哪个平台?', + options: ['PC', '移动端'], + createdAt: 1, + }, + 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({ @@ -67,4 +90,50 @@ export function registerDesignAgentSurfaceTests() { ).toBe(true); }); }); + + it('submits clarification free text without selecting an option', async () => { + const harness = createProjectSupervisorRuntimeHarness({ + designAgentView: designClarificationView(), + designAgentContinueView: { + ...designClarificationView(), + session: { + ...designClarificationView().session, + pendingClarification: null, + }, + }, + }); + 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 answer = await screen.findByPlaceholderText('或者直接输入你的回答'); + fireEvent.change(answer, { target: { value: 'PC 和主机平台都要支持' } }); + fireEvent.click(screen.getByRole('button', { name: '提交回答' })); + await waitFor(() => { + expect( + harness.invoke.mock.calls.some( + ([command, args]) => + command === 'continue_design_agent_session' && + (args as { input?: Record }).input?.type === + 'clarification' && + (args as { input?: Record }).input?.requestId === + 'clarification-1' && + (args as { input?: Record }).input?.optionIndex === + null && + (args as { input?: Record }).input?.text === + 'PC 和主机平台都要支持', + ), + ).toBe(true); + }); + }); } diff --git a/docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md b/docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md index 611bf2a99..202ff2cbf 100644 --- a/docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md +++ b/docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md @@ -235,7 +235,7 @@ UI 使用“批准”和“继续修改”两个文字按钮,分别配 Lucide 澄清卡是结构化的用户问询展示方式,不是阶段推进机制。普通文本问询仍然可用。用户回答澄清卡后,回答内容作为普通用户消息回到同一设计会话。 -UI 选项提交应携带请求身份和所选选项,Runtime 根据已保存的问题/选项形成明确的回答内容,不只传递“3”之类的序号。保留自由补充文字;不沿用生产旧问题数量上限和固定问答字段。澄清卡待回答状态应可在重启后恢复。 +澄清卡提供独立的选项回答和自由文本回答。点击选项只提交请求身份和所选选项,不携带文本框草稿;Runtime 根据已保存的问题/选项形成明确的回答内容,不只传递“3”之类的序号。用户也可不选择任何选项,直接填写文本并点击“提交回答”,发送请求身份、`optionIndex: null` 和文本正文,Runtime 将其表述为“用户回答”,不将它当作某个选项的补充。新澄清请求出现时清空上一题的文本草稿。不沿用生产旧问题数量上限和固定问答字段。澄清卡待回答状态应可在重启后恢复。 ## 8. 用户工作区浏览