ai-chatbot/lib/ai/runtime/canvas-agent-kernel.ts
2026-07-07 21:39:56 +08:00

157 lines
5.7 KiB
TypeScript

import type { DirectAgentToolCapability } from "@/lib/ai/runtime/direct-agent-execution";
export type CanvasAgentComposerMode = "agent" | "image" | "video" | "detail" | "clawd";
export type CanvasAgentEntryMode = "auto" | "preset";
export interface CanvasAgentRequestPolicy {
effectiveSelectedChatModel: string;
shouldForceToolOrchestration: boolean;
reason: string | null;
}
export interface CanvasAgentTargetPreference {
shouldPreferLatestResult: boolean;
shouldPreferWorkingMemoryTarget: boolean;
confidence: number;
reason: string | null;
}
const DEICTIC_TARGET_REGEX =
/(这张图|这只|这个|这款|这套|当前这张|当前这个|当前这只|这一张|这一只|这个产品|这个物体|这只猫|这只狗)/i;
const ACTIONABLE_IMAGE_EDIT_REGEX =
/(抠图|去背景|透明背景|去背|扣图|抠出|扣出|抠出来|扣出来|移除背景|去水印|水印|去logo|去\s*logo|移除logo|去除logo|换背景|改背景|背景换成|背景改成|白底|纯色背景|替换.*背景|变清晰|高清|锐化|降噪|提升质量|修复|清晰化|扩展|拓展|延伸|扩图|outpainting|拓宽|扩大|多视角|换视角|改视角|视角变体|新角度|换角度|改角度|去除|消除|擦掉|删除|移除|p掉|重绘|风格化|卡通化|动漫风|油画风|调色|调整颜色|亮度|对比度|饱和度|缩放|放大|缩小|调整尺寸|裁剪|resize|crop|修图|p图|改图|调图|编辑.*图|优化.*图|重做|再调整|继续改|继续调|处理)/i;
export function normalizeCanvasAgentRequestText(text: string) {
return String(text || "").toLowerCase().replace(/\s+/g, "").trim();
}
export function hasCanvasAgentDeicticTarget(text: string) {
return DEICTIC_TARGET_REGEX.test(String(text || ""));
}
export function hasCanvasAgentActionableImageEditIntent(text: string) {
return ACTIONABLE_IMAGE_EDIT_REGEX.test(String(text || ""));
}
export function inferCanvasAgentImageEditCapability(
text: string,
): DirectAgentToolCapability | null {
const normalizedText = normalizeCanvasAgentRequestText(text);
if (!normalizedText) return null;
if (/去水印|水印|去logo|移除logo|去除logo/.test(normalizedText)) {
return "remove_watermark";
}
if (/抠图|去背景|透明背景|去背|扣图|抠出|扣出|抠出来|扣出来|移除背景/.test(normalizedText)) {
return "remove_background";
}
if (/多视角|换视角|改视角|视角变体|新角度|换角度|改角度|侧面|侧视|背面|背后|俯视|俯拍|仰视|仰拍|低机位|高机位/.test(normalizedText)) {
return "angle_variant";
}
if (/扩展|拓展|延伸|扩图|outpainting|拓宽|扩大|比例|画幅|竖版|横版|竖图|横图|9:16|16:9|1:1/.test(normalizedText)) {
return "extend";
}
if (/调整尺寸|裁剪|resize|crop|缩放|放大|缩小/.test(normalizedText)) {
return "resize";
}
if (/局部|框选|选区|区域|涂抹|蒙版/.test(normalizedText)) {
return "local_edit";
}
if (/高清|清晰|锐化|降噪|提升质量|修复|清晰化/.test(normalizedText)) {
return "enhance";
}
if (hasCanvasAgentActionableImageEditIntent(text)) {
return "generic_edit";
}
return null;
}
export function resolveCanvasAgentRequestPolicy(params: {
composerMode?: string | null;
agentEntryMode?: string | null;
selectedChatModel?: string | null;
hasCanvasControlIntentFastPath?: boolean;
}): CanvasAgentRequestPolicy {
const composerMode = String(params.composerMode || "").trim();
const agentEntryMode = String(params.agentEntryMode || "").trim();
const selectedChatModel = String(params.selectedChatModel || "").trim() || "auto";
const isAgentAutoComposer = composerMode === "agent" && agentEntryMode !== "preset";
const shouldForceToolOrchestration =
isAgentAutoComposer || Boolean(params.hasCanvasControlIntentFastPath);
if (isAgentAutoComposer) {
return {
effectiveSelectedChatModel: "auto",
shouldForceToolOrchestration: true,
reason: "agent_auto_composer",
};
}
if (params.hasCanvasControlIntentFastPath) {
return {
effectiveSelectedChatModel: selectedChatModel,
shouldForceToolOrchestration: true,
reason: "canvas_control_fast_path",
};
}
return {
effectiveSelectedChatModel: selectedChatModel,
shouldForceToolOrchestration,
reason: null,
};
}
export function resolveCanvasAgentTargetPreference(params: {
text: string;
selectedImageCount: number;
latestResultImageCount: number;
workingMemoryTargetImageCount: number;
}): CanvasAgentTargetPreference {
const hasDeicticTarget = hasCanvasAgentDeicticTarget(params.text);
const hasEditIntent = hasCanvasAgentActionableImageEditIntent(params.text);
const selectedImageCount = Math.max(0, Math.round(params.selectedImageCount || 0));
const latestResultImageCount = Math.max(
0,
Math.round(params.latestResultImageCount || 0),
);
const workingMemoryTargetImageCount = Math.max(
0,
Math.round(params.workingMemoryTargetImageCount || 0),
);
if (!hasDeicticTarget || !hasEditIntent || selectedImageCount > 0) {
return {
shouldPreferLatestResult: false,
shouldPreferWorkingMemoryTarget: false,
confidence: 0,
reason: null,
};
}
if (latestResultImageCount > 0) {
return {
shouldPreferLatestResult: true,
shouldPreferWorkingMemoryTarget: false,
confidence: 90,
reason: "deictic_edit_prefers_latest_result",
};
}
if (workingMemoryTargetImageCount > 0) {
return {
shouldPreferLatestResult: false,
shouldPreferWorkingMemoryTarget: true,
confidence: 86,
reason: "deictic_edit_uses_working_memory_target",
};
}
return {
shouldPreferLatestResult: false,
shouldPreferWorkingMemoryTarget: false,
confidence: 0,
reason: null,
};
}