ai-chatbot/lib/ai/runtime/middlewares/human-confirmation-gate.ts
Your Name ec988be30a
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
Update agent workflow and video task handling
2026-03-13 11:21:42 +08:00

148 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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";
import { interpretStoryboardCommand } from "@/lib/video-agent/storyboard-command-interpreter";
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;
}
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 async function runHumanConfirmationGate(params: {
text: string;
threadState?: AgentThreadState | null;
}): Promise<HumanConfirmationGateDecision> {
const workflowState = params.threadState?.workflowState;
if (!workflowState || !isAwaitingUserConfirmationWorkflow(workflowState)) {
return {
action: "pass",
confirmationIntent: "none",
allowWorkflowExecution: true,
shouldBypassPlanner: false,
};
}
const interpreted = await interpretStoryboardCommand({
text: params.text,
totalShots: workflowState.pendingItems.length || undefined,
items: workflowState.pendingItems.map((item) => ({
index: item.index || 0,
title: item.title,
summary: item.summary,
})),
});
const confirmationIntent = interpreted.intent;
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":
default:
return {
...baseDecision,
action: "awaiting_confirmation",
confirmationIntent: "unclear",
nextWorkflowStatus: workflowState.status,
allowWorkflowExecution: false,
friendlyMessage: buildAwaitingConfirmationMessage(workflowState),
};
}
}