diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts
index 018ace80d..e372072ea 100644
--- a/app/(chat)/api/chat/route.ts
+++ b/app/(chat)/api/chat/route.ts
@@ -953,6 +953,45 @@ function buildAutoModeFallbackMessage(params: {
].join("\n");
}
+function hasStructuredAgentSections(message?: string): boolean {
+ if (!message) return false;
+ return /(?:###\s*需求理解|【\s*需求理解\s*】|###\s*图片分析|【\s*图片分析\s*】|###\s*执行计划|【\s*执行计划\s*】)/.test(
+ message,
+ );
+}
+
+function ensureStructuredAgentFriendlyMessage(params: {
+ message?: string;
+ text: string;
+ hasImage: boolean;
+ fromHistory: boolean;
+}): string {
+ const existingMessage = String(params.message || "").trim();
+ if (hasStructuredAgentSections(existingMessage)) {
+ return existingMessage;
+ }
+
+ const fallback = buildAutoModeFallbackMessage({
+ text: params.text,
+ hasImage: params.hasImage,
+ fromHistory: params.fromHistory,
+ });
+
+ if (!existingMessage) {
+ return fallback;
+ }
+
+ const normalizedSupplement = existingMessage.replace(/\s+/g, " ").trim();
+ if (!normalizedSupplement) {
+ return fallback;
+ }
+
+ return fallback.replace(
+ "### 执行计划\n",
+ `### 执行计划\n- 补充说明:${normalizedSupplement}\n`,
+ );
+}
+
function extractMessageImageUrls(parts: any[]): string[] {
return (parts || [])
.map((part: any) => {
@@ -1766,6 +1805,7 @@ export async function POST(request: Request) {
let smartAutoHistoryImages: string[] = []; // 从历史对话中提取的图片URL(支持多张)
let smartAutoNeedsClarification = false; // 是否需要先追问用户
let smartAutoClarificationQuestion: string | undefined;
+ let preferredAgentModelId: string | undefined;
const deepThinkingOn = deepThinkingEnabled !== false;
let shouldRunAgentConversation = finalModelId === "auto";
let shouldKeepSelectedModel = false;
@@ -1829,8 +1869,9 @@ export async function POST(request: Request) {
} else if (isFixedVisualModel) {
shouldRunAgentConversation = true;
shouldKeepSelectedModel = true;
+ preferredAgentModelId = selectedModelConfig.id;
console.log(
- `[Smart Auto Mode] 🎯 Agent conversation enabled for fixed visual model: ${selectedModelConfig.displayName} (${selectedModelProviderType || "unknown"})`
+ `[Smart Auto Mode] 🎯 Agent conversation enabled for fixed visual model: ${selectedModelConfig.displayName} (${selectedModelProviderType || "unknown"}), preferredAgentModelId=${preferredAgentModelId}`
);
}
} else if (isFixedVisualModel || isAiModelAgentAuto(selectedModelConfig)) {
@@ -2002,6 +2043,7 @@ export async function POST(request: Request) {
imageFromHistory: smartAutoHistoryImages.length > 0,
historyMessages,
context: autoContextText || undefined,
+ preferredModelId: preferredAgentModelId,
}),
"runAutoAgentGraph",
SMART_AUTO_GRAPH_TIMEOUT_MS,
@@ -2180,6 +2222,7 @@ export async function POST(request: Request) {
imageFromHistory: autoFromHistoryForFallback || smartAutoHistoryImages.length > 0,
historyMessages: [],
context: undefined,
+ preferredModelId: preferredAgentModelId,
}),
"fallbackAnalyzeIntent",
SMART_AUTO_FALLBACK_TIMEOUT_MS,
@@ -2222,6 +2265,7 @@ export async function POST(request: Request) {
text: autoTextForFallback,
imageUrls: summaryImageUrls,
context: typeof autoContext === "string" ? autoContext : undefined,
+ preferredModelId: preferredAgentModelId,
}),
"fallbackVisualSummary",
SMART_AUTO_FALLBACK_TIMEOUT_MS,
@@ -2357,6 +2401,23 @@ export async function POST(request: Request) {
console.log("[Smart Auto Mode] 🧩 Backfilled conversational reply with fallback");
}
+ if (shouldRunAgentConversation && !smartAutoNeedsClarification) {
+ const latestUserText = message.parts
+ .filter((part): part is { type: "text"; text: string } => part.type === "text")
+ .map((part) => part.text)
+ .join(" ");
+ const hasCurrentImageInput = message.parts.some((part: any) =>
+ part?.type === "file" || part?.type === "image" || part?.type === "image_url"
+ );
+ const hasHistoryImageInput = smartAutoHistoryImages.length > 0;
+ smartAutoFriendlyMessage = ensureStructuredAgentFriendlyMessage({
+ message: smartAutoFriendlyMessage,
+ text: latestUserText,
+ hasImage: hasCurrentImageInput || hasHistoryImageInput,
+ fromHistory: !hasCurrentImageInput && hasHistoryImageInput,
+ });
+ }
+
const hasUserCustomImageParams = hasUserCustomizedImageParams(requestBody.imageParams);
const hasUserCustomVideoParams = hasUserCustomizedVideoParams(requestBody.videoParams);
const shouldApplyAgentImageParams =
@@ -2437,6 +2498,7 @@ export async function POST(request: Request) {
text: latestUserText,
imageUrls: summaryImageUrls,
context: typeof autoContext === "string" ? autoContext : undefined,
+ preferredModelId: preferredAgentModelId,
}),
"enrichImageAnalysisSummary",
timeoutMs,
diff --git a/app/canvas/[id]/page.tsx b/app/canvas/[id]/page.tsx
index aff4c905a..cce29ba19 100644
--- a/app/canvas/[id]/page.tsx
+++ b/app/canvas/[id]/page.tsx
@@ -666,7 +666,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
"absolute top-4 right-4 bottom-4 z-10 w-[460px] max-w-[calc(100vw-1rem)] transition-all duration-300 ease-in-out",
isPanelOpen ? "translate-x-0 opacity-100" : "translate-x-[120%] opacity-0 pointer-events-none"
)}>
-
+
{panelMode === 'chat' ? (
// AI 对话内容 - 使用 key 强制在 id 变化时重新挂载
diff --git a/components/angle-edit-dialog.tsx b/components/angle-edit-dialog.tsx
index 1055afe79..e8c660ac8 100644
--- a/components/angle-edit-dialog.tsx
+++ b/components/angle-edit-dialog.tsx
@@ -188,7 +188,7 @@ export function AngleEditDialog({
return (