修复策划澄清卡自由文本回答
Project CI / Repository checks (pull_request) Successful in 5m25s
Project CI / Frontend tests (pull_request) Successful in 6m36s
Project CI / Backend tests (pull_request) Successful in 29m4s
Project CI / Native shell tests (pull_request) Successful in 33m51s

将自由文本与选项回答分开提交

补充澄清卡回归测试和迁移方案说明
This commit is contained in:
2026-09-11 06:44:47 +00:00
parent f2f786d69b
commit 123c699db9
4 changed files with 89 additions and 17 deletions
@@ -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;
@@ -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 (
<section className="design-agent-controls" aria-label="策划阶段控制">
<div className="design-agent-controls__header">
@@ -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}
</button>
@@ -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 ? (
<button
type="button"
disabled={busy || !clarifyText.trim()}
onClick={() => onClarify(clarification, null, clarifyText)}
>
</button>
) : null}
<button
type="button"
disabled={busy || !clarifyText.trim()}
onClick={() => onClarify(clarification, null, clarifyText)}
>
</button>
</div>
) : null}
{view?.canRetry ? (
@@ -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<string, unknown> }).input?.type ===
'clarification' &&
(args as { input?: Record<string, unknown> }).input?.requestId ===
'clarification-1' &&
(args as { input?: Record<string, unknown> }).input?.optionIndex ===
null &&
(args as { input?: Record<string, unknown> }).input?.text ===
'PC 和主机平台都要支持',
),
).toBe(true);
});
});
}
@@ -235,7 +235,7 @@ UI 使用“批准”和“继续修改”两个文字按钮,分别配 Lucide
澄清卡是结构化的用户问询展示方式,不是阶段推进机制。普通文本问询仍然可用。用户回答澄清卡后,回答内容作为普通用户消息回到同一设计会话。
UI 选项提交应携带请求身份和所选选项,Runtime 根据已保存的问题/选项形成明确的回答内容,不只传递“3”之类的序号。保留自由补充文字;不沿用生产旧问题数量上限和固定问答字段。澄清卡待回答状态应可在重启后恢复。
澄清卡提供独立的选项回答和自由文本回答。点击选项提交请求身份和所选选项,不携带文本框草稿;Runtime 根据已保存的问题/选项形成明确的回答内容,不只传递“3”之类的序号。用户也可不选择任何选项,直接填写文本并点击“提交回答”,发送请求身份、`optionIndex: null` 和文本正文,Runtime 将其表述为“用户回答”,不将它当作某个选项的补充。新澄清请求出现时清空上一题的文本草稿。不沿用生产旧问题数量上限和固定问答字段。澄清卡待回答状态应可在重启后恢复。
## 8. 用户工作区浏览