diff --git a/frontend-web/src/roundtable-planning/api/flow-extract.ts b/frontend-web/src/roundtable-planning/api/flow-extract.ts
index ebf2188e..503832d3 100644
--- a/frontend-web/src/roundtable-planning/api/flow-extract.ts
+++ b/frontend-web/src/roundtable-planning/api/flow-extract.ts
@@ -11,6 +11,41 @@ import { apiFetch } from "@/core/api/fetch-client";
import { getBackendBaseURL } from "@/core/config";
import type { FlowGraphData } from "@/roundtable-planning/lib/flow-graph";
+/** 第三步输入框意图分类结果(与后端 /intent 对应)。 */
+export type FlowIntent = "regenerate_report" | "modify_flow" | "regenerate_flow" | "qa" | "unclear";
+
+/**
+ * 识别第三步输入框消息的意图(一次模型调用)。失败回退 "unclear"(前端发起澄清)。
+ * 参考 ai_writing 的一次性 JSON 意图识别范式。
+ */
+export async function classifyFlowIntent(req: {
+ message: string;
+ hasReport: boolean;
+ hasFlow: boolean;
+ model?: string;
+ signal?: AbortSignal;
+}): Promise<{ intent: FlowIntent; reason: string }> {
+ try {
+ const res = await apiFetch(`${getBackendBaseURL()}/api/flow-extract/intent`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ message: req.message,
+ has_report: req.hasReport,
+ has_flow: req.hasFlow,
+ model: req.model,
+ }),
+ signal: req.signal,
+ });
+ if (!res.ok) return { intent: "unclear", reason: "" };
+ const data = (await res.json()) as { intent?: string; reason?: string };
+ const intent = (data.intent ?? "unclear") as FlowIntent;
+ return { intent, reason: data.reason ?? "" };
+ } catch {
+ return { intent: "unclear", reason: "" };
+ }
+}
+
export interface FlowExtractRequest {
/** 报告 Markdown(优先数据来源)。 */
reportMd?: string | null;
diff --git a/frontend-web/src/roundtable-planning/components/Step3SummaryMode.tsx b/frontend-web/src/roundtable-planning/components/Step3SummaryMode.tsx
index 6b9e0725..e5c31fae 100644
--- a/frontend-web/src/roundtable-planning/components/Step3SummaryMode.tsx
+++ b/frontend-web/src/roundtable-planning/components/Step3SummaryMode.tsx
@@ -412,6 +412,8 @@ export function Step3SummaryMode({
mdAvailable={!!mdArtifact}
flowPhase={summary.flowPhase}
onRegenerateFlow={summary.regenerateFlow}
+ pendingClarification={summary.pendingFlowClarification}
+ onResolveClarification={summary.resolveFlowClarification}
onRetry={redraw}
onAsk={handleAsk}
onPause={pause}
@@ -556,6 +558,8 @@ function AgentProgressPanel({
mdAvailable,
flowPhase,
onRegenerateFlow,
+ pendingClarification,
+ onResolveClarification,
onRetry,
onAsk,
onPause,
@@ -576,6 +580,9 @@ function AgentProgressPanel({
flowPhase: UseStep3SummaryReturn["flowPhase"];
/** 仅重新生成流程图(模型挂了切模型后重试)。 */
onRegenerateFlow: () => void;
+ /** 意图模糊待澄清的原始消息(非空 → 展示选项让用户定)。 */
+ pendingClarification: string | null;
+ onResolveClarification: UseStep3SummaryReturn["resolveFlowClarification"];
onRetry: () => void;
onAsk: (message: string, files?: File[]) => void;
onPause: () => void;
@@ -748,6 +755,35 @@ function AgentProgressPanel({
)}
{!atBottom &&