export type AgentPlanningBriefIntent = | "image_edit" | "vision" | "image_gen" | "video_gen" | "chat"; export type AgentPlanningBriefAction = | "respond" | "clarify" | "analyze_image" | "generate_image" | "edit_image" | "generate_video"; export type AgentPlanningBriefTargetSource = | "explicit_selection" | "current_upload" | "text_reference" | "working_memory" | "latest_result" | "clarification" | "none"; export type AgentPlanningBriefCapability = | "respond" | "analyze" | "generic_edit" | "remove_background" | "remove_watermark" | "enhance" | "extend" | "resize" | "angle_variant" | "local_edit" | "box_cutout" | "generate_image" | "generate_video" | "publish_canvas"; export interface AgentPlanningBriefInput { userText: string; intent: AgentPlanningBriefIntent; subIntent?: string; nextAction?: AgentPlanningBriefAction; preferredCapability?: AgentPlanningBriefCapability; targetSource?: AgentPlanningBriefTargetSource; hasImage?: boolean; imageFromHistory?: boolean; selectedImageCount?: number; currentUploadImageCount?: number; historyImageCount?: number; imageCount?: number; aspectRatio?: string; imageSize?: string; planGoal?: string; } export interface AgentTaskGroup { label: string; count?: number; description: string; } const CHINESE_NUMBER_VALUES: Record = { 一: 1, 二: 2, 两: 2, 三: 3, 四: 4, 五: 5, 六: 6, 七: 7, 八: 8, 九: 9, 十: 10, }; function compactLine(value: string, maxLength: number) { const normalized = String(value || "").replace(/\s+/g, " ").trim(); if (normalized.length <= maxLength) return normalized; return `${normalized.slice(0, maxLength)}...`; } function parseCountToken(token?: string | null) { const value = String(token || "").trim(); if (!value) return undefined; if (/^\d+$/.test(value)) { const numeric = Number(value); return Number.isFinite(numeric) && numeric > 0 ? Math.round(numeric) : undefined; } return CHINESE_NUMBER_VALUES[value]; } function countFromText(text: string) { const match = String(text || "").match(/([1-9]\d?|一|二|两|三|四|五|六|七|八|九|十)\s*张/); return parseCountToken(match?.[1]); } function normalizeGroupDescription(description: string) { return String(description || "") .replace(/^[为是::,,\s]+/, "") .replace(/[。;;,,]\s*$/, "") .trim(); } export function extractAgentTaskGroups(text: string): AgentTaskGroup[] { const normalized = String(text || "").replace(/\s+/g, " ").trim(); if (!normalized) return []; const groups: AgentTaskGroup[] = []; const groupPattern = /第([一二两三四五六七八九十]|\d{1,2})组(?:为|是|:|:)?([\s\S]*?)(?=(?:第[一二两三四五六七八九十\d]{1,2}组)|[。;;]|$)/g; let match: RegExpExecArray | null; while ((match = groupPattern.exec(normalized)) !== null) { const labelToken = match[1]; const description = normalizeGroupDescription(match[2] || ""); if (!description) continue; const labelNumber = parseCountToken(labelToken); groups.push({ label: `第${labelNumber || labelToken}组`, count: countFromText(description), description: compactLine(description, 96), }); } return groups.slice(0, 8); } function getTargetSourceLabel(source?: AgentPlanningBriefTargetSource) { switch (source) { case "explicit_selection": return "画布选中图片"; case "current_upload": return "当前上传图片"; case "text_reference": return "文本指定图片"; case "working_memory": return "会话工作记忆图片"; case "latest_result": return "最近生成结果"; case "clarification": return "待确认目标"; case "none": default: return "无需现有图片"; } } function getCapabilityLabel(capability?: AgentPlanningBriefCapability, subIntent?: string) { switch (capability || subIntent) { case "remove_background": return "主体抠图/去背景"; case "remove_watermark": return "去水印"; case "enhance": return "清晰度增强"; case "extend": return "扩图/画幅延展"; case "resize": return "尺寸调整"; case "angle_variant": case "generate_angle_variant": return "多视角变体"; case "local_edit": case "inpaint_region": return "局部编辑"; case "box_cutout": return "框选抠图"; case "generate_video": return "视频生成"; case "generate_image": return "图片生成"; case "analyze": return "图片分析"; default: return "图片编辑"; } } function inferTotalCount(params: AgentPlanningBriefInput, groups: AgentTaskGroup[]) { if (typeof params.imageCount === "number" && Number.isFinite(params.imageCount)) { return Math.max(1, Math.round(params.imageCount)); } const groupedTotal = groups.reduce((sum, group) => sum + (group.count || 0), 0); return groupedTotal > 0 ? groupedTotal : undefined; } function buildIntentLine(params: AgentPlanningBriefInput, groups: AgentTaskGroup[]) { const target = getTargetSourceLabel(params.targetSource); const capability = getCapabilityLabel(params.preferredCapability, params.subIntent); const totalCount = inferTotalCount(params, groups); const demand = compactLine(params.planGoal || params.userText || "", 120); if (params.intent === "image_gen") { const countText = totalCount ? `,共 ${totalCount} 张` : ""; const groupText = groups.length > 0 ? `,拆成 ${groups.length} 组` : ""; const referenceText = params.hasImage ? ",并保持参考图主体核心特征一致" : ""; return `用户需要生成新图片${groupText}${countText}${referenceText};核心目标是:${demand || "完成本轮生图任务"}。`; } if (params.intent === "image_edit") { return `用户需要基于${target}执行${capability};核心目标是:${demand || "完成本轮图片处理"}。`; } if (params.intent === "video_gen") { return `用户需要生成视频;先拆解镜头、主体连续性和运动节奏,再提交视频生成。`; } if (params.intent === "vision") { return `用户需要理解或分析图片内容;先观察主体、场景、构图和潜在问题,再给出结论。`; } return `用户当前主要是在对话或咨询;先回答问题,不主动触发生图或修图工具。`; } function buildImageGenerationPlan(params: AgentPlanningBriefInput, groups: AgentTaskGroup[]) { if (groups.length > 0) { return groups.map((group, index) => { const countText = group.count ? `${group.count}张` : "一组"; return `${index + 1}. ${group.label}:生成${countText}${group.description.replace(/^\d+\s*张/, "")},保持主体识别一致。`; }); } const count = inferTotalCount(params, groups) || 1; return [ `1. 锁定主体、场景、风格和构图约束,整理成可执行提示词。`, `2. 生成 ${count} 张候选图,优先保证主体一致性和画面完成度。`, `3. 输出结果并保留可继续追改的上下文。`, ]; } function buildImageEditPlan(params: AgentPlanningBriefInput) { const target = getTargetSourceLabel(params.targetSource); const capability = getCapabilityLabel(params.preferredCapability, params.subIntent); return [ `1. 先锁定${target}作为本轮处理目标,避免误处理其他图片。`, `2. 调用${capability}能力执行核心改动,同时尽量保留主体结构和画质。`, `3. 输出处理结果,并保留原图用于对比或继续微调。`, ]; } function buildGenericPlan(params: AgentPlanningBriefInput) { if (params.intent === "video_gen") { return [ "1. 拆解视频主体、场景、动作节奏和镜头关系。", "2. 生成脚本与分镜,并整理可直接提交的视频提示词。", "3. 按规划提交视频生成,返回结果后支持继续调整。", ]; } if (params.intent === "vision") { return [ "1. 先识别图片主体、背景、构图和关键信息。", "2. 结合用户问题输出判断、建议或可执行修改方向。", ]; } return ["1. 先直接回答用户问题;如果需要执行工具,再根据明确指令进入下一步。"]; } function buildOutputSettings(params: AgentPlanningBriefInput, groups: AgentTaskGroup[]) { const lines: string[] = []; const totalCount = inferTotalCount(params, groups); if (params.intent === "image_gen" || params.intent === "image_edit") { lines.push(`- 输出数量:${params.intent === "image_edit" ? "1 张处理结果" : `${totalCount || 1} 张`}`); lines.push(`- 图片比例:${params.aspectRatio && params.aspectRatio !== "auto" ? params.aspectRatio : "按需求自适应"}`); lines.push(`- 清晰度:${params.imageSize || (params.intent === "image_edit" ? "4K优先" : "2K优先")}`); if (params.intent === "image_edit") { lines.push(`- 目标来源:${getTargetSourceLabel(params.targetSource)}`); } } else if (params.intent === "video_gen") { lines.push("- 输出形式:视频结果 + 可继续追改的分镜上下文"); } else { lines.push("- 输出形式:直接回答,不主动触发生成工具"); } return lines; } export function buildAgentPlanningBriefMarkdown(params: AgentPlanningBriefInput) { const groups = extractAgentTaskGroups(params.userText); const planLines = params.intent === "image_gen" ? buildImageGenerationPlan(params, groups) : params.intent === "image_edit" ? buildImageEditPlan(params) : buildGenericPlan(params); const outputSettings = buildOutputSettings(params, groups); return [ "### 意图分析", `- ${buildIntentLine(params, groups)}`, "### 任务规划", ...planLines.map((line) => (line.startsWith("- ") ? line : `- ${line}`)), "### 输出设置", ...outputSettings, ].join("\n"); } export function isAgentPlanningBriefMarkdown(text: string) { const normalized = String(text || ""); return /###\s*意图分析|【\s*意图分析\s*】/.test(normalized) && /###\s*任务规划|【\s*任务规划\s*】/.test(normalized); }