196 lines
5.6 KiB
TypeScript
196 lines
5.6 KiB
TypeScript
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),
|
||
};
|
||
}
|
||
}
|