import { isAwaitingUserConfirmationWorkflow, type AgentWorkflowState, type AgentWorkflowStatus, type AgentWorkflowType, } from "@/lib/ai/runtime/agent-workflow-state"; import type { AgentThreadState } from "@/lib/ai/runtime/agent-thread-state"; export type HumanConfirmationIntent = | "none" | "confirm" | "revise" | "cancel" | "unclear"; export type HumanConfirmationGateAction = | "pass" | "awaiting_confirmation" | "confirmed" | "revision_requested" | "cancel_requested"; export interface HumanConfirmationGateDecision { action: HumanConfirmationGateAction; confirmationIntent: HumanConfirmationIntent; workflowId?: string; workflowType?: AgentWorkflowType; nextWorkflowStatus?: AgentWorkflowStatus; allowWorkflowExecution: boolean; shouldBypassPlanner: boolean; friendlyMessage?: string; } const CONFIRM_PATTERNS = [ /确认开始生成视频/, /确认开始生成/, /按这个分镜生成/, /开始生成视频/, /开始生成$/, /可以开始了/, /可以执行了/, /就按这个/, /没问题开始/, /确认无误/, ]; const REVISE_PATTERNS = [ /修改第\d+镜头/, /第\d+镜头/, /调整第\d+镜头/, /重生第\d+/, /重做第\d+/, /改一下/, /修改/, /调整/, /不要这样/, /不对/, /不行/, /换成/, ]; const CANCEL_PATTERNS = [ /取消/, /先不要/, /暂停/, /停止/, /先别生成/, /不用生成了/, ]; function normalizeCompactText(text: string) { return String(text || "").toLowerCase().replace(/\s+/g, "").trim(); } export function detectHumanConfirmationIntent(text: string): HumanConfirmationIntent { const normalized = normalizeCompactText(text); if (!normalized) return "unclear"; if (CANCEL_PATTERNS.some((pattern) => pattern.test(normalized))) { return "cancel"; } if (REVISE_PATTERNS.some((pattern) => pattern.test(normalized))) { return "revise"; } if (CONFIRM_PATTERNS.some((pattern) => pattern.test(normalized))) { return "confirm"; } return "unclear"; } function buildAwaitingConfirmationMessage(workflowState: AgentWorkflowState): string { const title = workflowState.title || "当前工作流"; const summary = workflowState.summary ? `\n当前待确认内容:${workflowState.summary}` : ""; const pendingItemsPreview = workflowState.pendingItems .slice(0, 3) .map((item) => { const indexText = item.index ? `镜头${item.index}` : item.title || "待确认项"; const summaryText = item.summary ? `:${item.summary}` : ""; return `- ${indexText}${summaryText}`; }) .join("\n"); const previewBlock = pendingItemsPreview ? `\n${pendingItemsPreview}` : ""; const confirmExample = workflowState.confirmPhrases[0] || "确认开始生成视频"; const reviseExample = workflowState.revisionHints[0] || "修改第3镜头"; return [ `当前有一个待确认流程:${title}。`, summary ? summary.trim() : "", previewBlock.trim(), `如果确认无误,请回复“${confirmExample}”。`, `如果需要修改,请直接回复类似“${reviseExample}”。`, ] .filter(Boolean) .join("\n"); } function buildConfirmMessage(workflowState: AgentWorkflowState): string { const title = workflowState.title || "当前流程"; return `已收到确认:${title} 可以进入下一步执行。我会按已确认内容继续处理。`; } function buildRevisionMessage(workflowState: AgentWorkflowState): string { const title = workflowState.title || "当前流程"; return `收到修改意见。我会先更新 ${title} 的草案内容,并在重新确认前暂停执行。`; } function buildCancelMessage(workflowState: AgentWorkflowState): string { const title = workflowState.title || "当前流程"; return `已收到取消指令。${title} 会继续停留在人工确认前状态,不会继续自动执行。`; } export function runHumanConfirmationGate(params: { text: string; threadState?: AgentThreadState | null; }): HumanConfirmationGateDecision { const workflowState = params.threadState?.workflowState; if (!workflowState || !isAwaitingUserConfirmationWorkflow(workflowState)) { return { action: "pass", confirmationIntent: "none", allowWorkflowExecution: true, shouldBypassPlanner: false, }; } const confirmationIntent = detectHumanConfirmationIntent(params.text); const baseDecision = { workflowId: workflowState.workflowId, workflowType: workflowState.type, shouldBypassPlanner: true, }; switch (confirmationIntent) { case "confirm": return { ...baseDecision, action: "confirmed", confirmationIntent, nextWorkflowStatus: "confirmed", allowWorkflowExecution: true, friendlyMessage: buildConfirmMessage(workflowState), }; case "revise": return { ...baseDecision, action: "revision_requested", confirmationIntent, nextWorkflowStatus: "draft", allowWorkflowExecution: false, friendlyMessage: buildRevisionMessage(workflowState), }; case "cancel": return { ...baseDecision, action: "cancel_requested", confirmationIntent, nextWorkflowStatus: "cancelled", allowWorkflowExecution: false, friendlyMessage: buildCancelMessage(workflowState), }; case "unclear": case "none": default: return { ...baseDecision, action: "awaiting_confirmation", confirmationIntent: "unclear", nextWorkflowStatus: workflowState.status, allowWorkflowExecution: false, friendlyMessage: buildAwaitingConfirmationMessage(workflowState), }; } }