修复策划澄清卡自由文本回答
将自由文本与选项回答分开提交 补充澄清卡回归测试和迁移方案说明
This commit is contained in:
@@ -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. 用户工作区浏览
|
||||
|
||||
|
||||
Reference in New Issue
Block a user