From 31f8c004b2f0370301dddc30d4d2d57792c16f3b Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 16 Mar 2026 14:25:02 +0800 Subject: [PATCH] fix: prioritize task boundary decisions --- app/(chat)/api/chat/route.ts | 62 ++++++++++++++++------ lib/ai/runtime/task-boundary-classifier.ts | 55 ++++++++++++++----- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts index d74b34b11..366826312 100644 --- a/app/(chat)/api/chat/route.ts +++ b/app/(chat)/api/chat/route.ts @@ -3296,6 +3296,17 @@ export async function POST(request: Request) { confirmedPromptForConversationState = conversationStateBootstrap.confirmedPrompt; const resolvedConversationAction = conversationStateBootstrap.actionResolution; const taskBoundaryDecision = conversationStateBootstrap.taskBoundaryDecision; + const taskBoundaryRequiresAgentConversation = + taskBoundaryDecision.taskType === "prompt_only" || + taskBoundaryDecision.taskType === "analysis_only" || + taskBoundaryDecision.taskType === "execution_image" || + taskBoundaryDecision.taskType === "execution_video" || + taskBoundaryDecision.taskType === "workflow_followup"; + const taskBoundaryOverridesLegacyWorkflow = + taskBoundaryDecision.taskType === "greeting" || + taskBoundaryDecision.taskType === "chat" || + taskBoundaryDecision.taskType === "analysis_only" || + taskBoundaryDecision.taskType === "prompt_only"; const prunedTaskBoundaryContext = pruneTaskBoundaryContext({ decision: taskBoundaryDecision, contextPayload: contextPayload || undefined, @@ -3307,24 +3318,45 @@ export async function POST(request: Request) { const effectiveAutoContextText = prunedTaskBoundaryContext.autoContextText || ""; const effectiveWorkingState = prunedTaskBoundaryContext.workingState; - if (resolvedConversationAction.forceAgentConversation && !shouldRunAgentConversation) { + if (taskBoundaryRequiresAgentConversation && !shouldRunAgentConversation) { shouldRunAgentConversation = true; - shouldKeepSelectedModel = resolvedConversationAction.shouldKeepSelectedModel; - if (resolvedConversationAction.kind === "grid_confirmation_followup" && pendingGridConfirmation) { + shouldKeepSelectedModel = false; + console.log( + `[Smart Auto Mode] 🧭 Force agent conversation due to task boundary: ${taskBoundaryDecision.taskType}/${taskBoundaryDecision.taskMode}`, + ); + } + + if (taskBoundaryOverridesLegacyWorkflow && shouldKeepSelectedModel) { + shouldKeepSelectedModel = false; + console.log( + `[Smart Auto Mode] 🧼 Release selected-model lock due to task boundary override: ${taskBoundaryDecision.taskType}`, + ); + } + + if (resolvedConversationAction.forceAgentConversation && !shouldRunAgentConversation) { + if (taskBoundaryOverridesLegacyWorkflow) { console.log( - `[Smart Auto Mode] 🧩 Force agent conversation due to pending grid confirmation: ${pendingGridConfirmation.label}` + `[Smart Auto Mode] 🪫 Ignore legacy workflow follow-up due to task boundary override: ${resolvedConversationAction.kind} -> ${taskBoundaryDecision.taskType}`, ); - } else if ( - resolvedConversationAction.kind === "active_storyboard_followup" && - activeStoryboardTaskForChat?.task?.id - ) { - console.log( - `[Smart Auto Mode] 🔐 Force agent conversation due to active storyboard task: ${activeStoryboardTaskForChat.task.id}` - ); - } else if (resolvedConversationAction.kind === "image_generation_followup") { - console.log("[Smart Auto Mode] 🪄 Force agent conversation due to image generation follow-up workflow"); - } else if (resolvedConversationAction.kind === "image_edit_followup") { - console.log("[Smart Auto Mode] 🖼️ Force agent conversation due to image edit follow-up workflow"); + } else { + shouldRunAgentConversation = true; + shouldKeepSelectedModel = resolvedConversationAction.shouldKeepSelectedModel; + if (resolvedConversationAction.kind === "grid_confirmation_followup" && pendingGridConfirmation) { + console.log( + `[Smart Auto Mode] 🧩 Force agent conversation due to pending grid confirmation: ${pendingGridConfirmation.label}` + ); + } else if ( + resolvedConversationAction.kind === "active_storyboard_followup" && + activeStoryboardTaskForChat?.task?.id + ) { + console.log( + `[Smart Auto Mode] 🔐 Force agent conversation due to active storyboard task: ${activeStoryboardTaskForChat.task.id}` + ); + } else if (resolvedConversationAction.kind === "image_generation_followup") { + console.log("[Smart Auto Mode] 🪄 Force agent conversation due to image generation follow-up workflow"); + } else if (resolvedConversationAction.kind === "image_edit_followup") { + console.log("[Smart Auto Mode] 🖼️ Force agent conversation due to image edit follow-up workflow"); + } } } diff --git a/lib/ai/runtime/task-boundary-classifier.ts b/lib/ai/runtime/task-boundary-classifier.ts index ffcb63379..3196a6d81 100644 --- a/lib/ai/runtime/task-boundary-classifier.ts +++ b/lib/ai/runtime/task-boundary-classifier.ts @@ -60,6 +60,15 @@ function isLikelyImageExecutionRequest(text: string): boolean { ); } +function isLikelyChatOnlyRequest(text: string): boolean { + const normalized = normalizeCompactText(text); + if (!normalized) return false; + + return /你能做什么|你会什么|你可以做什么|你能帮我做什么|你能干什么|你可以帮我做什么|介绍一下你自己|介绍一下自己|说说你的能力|你有哪些功能|你有什么功能|怎么用|怎么玩|如何使用|帮助说明|帮助手册|功能介绍/.test( + normalized, + ); +} + function isLikelyAnalysisOnlyRequest(text: string, hasImageContext: boolean): boolean { if (!hasImageContext) return false; const normalized = normalizeCompactText(text); @@ -101,7 +110,12 @@ export function classifyTaskBoundary(params: { pendingGridConfirmation?: PendingGridConfirmation | null; hasActiveStoryboardTask: boolean; }) { - const hasImageContext = params.hasCurrentImageInput || params.hasCanvasSelection; + const hasWorkflowImageContext = + params.actionResolution.kind === "image_edit_followup" || + params.actionResolution.kind === "image_generation_followup" || + params.actionResolution.kind === "prompt_carry_forward"; + const hasImageContext = + params.hasCurrentImageInput || params.hasCanvasSelection || hasWorkflowImageContext; if (isPureGreetingTurnRequest(params.text) && !params.hasCurrentImageInput) { return { @@ -129,6 +143,32 @@ export function classifyTaskBoundary(params: { } satisfies TaskBoundaryDecision; } + if (isLikelyAnalysisOnlyRequest(params.text, hasImageContext)) { + return { + taskType: "analysis_only", + taskMode: "new", + shouldUseCanvasContext: params.hasCanvasSelection, + shouldUseHistoryImages: !params.hasCurrentImageInput && !params.hasCanvasSelection, + shouldUseWorkflowMemory: false, + shouldAllowExecution: false, + confidence: 0.9, + reason: "analysis_only_request", + } satisfies TaskBoundaryDecision; + } + + if (isLikelyChatOnlyRequest(params.text)) { + return { + taskType: "chat", + taskMode: "new", + shouldUseCanvasContext: false, + shouldUseHistoryImages: false, + shouldUseWorkflowMemory: false, + shouldAllowExecution: false, + confidence: 0.96, + reason: "chat_only_request", + } satisfies TaskBoundaryDecision; + } + switch (params.actionResolution.kind) { case "grid_confirmation_followup": case "active_storyboard_followup": @@ -200,19 +240,6 @@ export function classifyTaskBoundary(params: { } satisfies TaskBoundaryDecision; } - if (isLikelyAnalysisOnlyRequest(params.text, hasImageContext)) { - return { - taskType: "analysis_only", - taskMode: "new", - shouldUseCanvasContext: params.hasCanvasSelection, - shouldUseHistoryImages: !params.hasCurrentImageInput && !params.hasCanvasSelection, - shouldUseWorkflowMemory: false, - shouldAllowExecution: false, - confidence: 0.9, - reason: "analysis_only_request", - } satisfies TaskBoundaryDecision; - } - return { taskType: "chat", taskMode: "new",