diff --git a/lib/ai/context-memory/target-resolution.ts b/lib/ai/context-memory/target-resolution.ts index f204e720d..1ee5bc629 100644 --- a/lib/ai/context-memory/target-resolution.ts +++ b/lib/ai/context-memory/target-resolution.ts @@ -7,9 +7,9 @@ import type { } from "@/lib/ai/context-memory/types"; const ORIGINAL_IMAGE_REGEX = - /(原图|上传图|参考图|最初那张|第一张图|素材图|源图|原始图片|原始那张)/i; + /(原图|上传图|参考图|最初那张|第一张图|素材图|源图|原始图片|原始那张|我发的那张|上传的那张|原来的图)/i; const LATEST_RESULT_REGEX = - /(上一张|上一轮|刚生成|最新生成|这个结果|该结果|按这个结果|继续在这张|基于这张结果|延续上一次结果|上一版|刚才那张结果)/i; + /(上一张|上一轮|刚生成|最新生成|这个结果|该结果|按这个结果|继续在这张|基于这张结果|延续上一次结果|上一版|刚才那张结果|生成的图|生成图|结果图|出图结果|刚出的图|上一张生成图|上一轮结果图|现在这张生成图)/i; const SELECTION_REGEX = /(选中的|当前这张|我选的|这几张|这些图|选中图)/i; const ACTIONABLE_EDIT_REGEX = /(改|调整|优化|换|替换|去掉|抠|重绘|增强|修|处理|按照|按|保留|统一|色差|背景|清晰|风格|亮一点|暗一点|白底|透明底)/i; @@ -154,6 +154,23 @@ function buildResolvedTargetAssets(params: { }; } +function toWorkingMemoryRefs(urls: string[]): ResolvedImageRef[] { + return urls.map((url) => ({ + url, + normalizedUrl: url, + source: "working_memory" as const, + role: "working_memory" as const, + })); +} + +function buildNormalizedUrlSet(refs: ResolvedImageRef[]): Set { + return new Set( + refs + .map((ref) => String(ref.normalizedUrl || ref.url || "").trim()) + .filter(Boolean), + ); +} + export function resolveTargetAssets( params: ResolveTargetAssetsParams, ): ResolvedTargetAssets { @@ -167,10 +184,47 @@ export function resolveTargetAssets( const candidateRefs = mediaInput.imageRefs; const workingState = params.workingState; const focusPolicy = params.contextPayload?.focusPolicy || "auto"; + const workingStateGeneratedUrls = normalizeStringArray(workingState?.lastGeneratedImageUrls); + const workingStateUploadedUrls = normalizeStringArray(workingState?.lastUploadedImageUrls); + const generatedRefs = + workingStateGeneratedUrls.length > 0 ? toWorkingMemoryRefs(workingStateGeneratedUrls) : assistantRefs; + const originalRefs = + workingStateUploadedUrls.length > 0 ? toWorkingMemoryRefs(workingStateUploadedUrls) : userRefs; + const selectedLooksLikeOriginal = (() => { + if (selectedRefs.length === 0 || originalRefs.length === 0) return false; + const originalKeys = buildNormalizedUrlSet(originalRefs); + return selectedRefs.every((ref) => + originalKeys.has(String(ref.normalizedUrl || ref.url || "").trim()), + ); + })(); - if (focusPolicy === "original" && userRefs.length > 0) { + if (ORIGINAL_IMAGE_REGEX.test(text) && originalRefs.length > 0) { return buildResolvedTargetAssets({ - targetRefs: userRefs, + targetRefs: originalRefs, + candidateRefs, + resolutionMode: "text_reference", + confidence: 95, + needsClarification: false, + reason: "用户文本明确指向原图/上传图", + fromHistory: true, + }); + } + + if (LATEST_RESULT_REGEX.test(text) && generatedRefs.length > 0) { + return buildResolvedTargetAssets({ + targetRefs: generatedRefs, + candidateRefs, + resolutionMode: "latest_result", + confidence: 95, + needsClarification: false, + reason: "用户文本明确指向上一轮结果/生成图", + fromHistory: true, + }); + } + + if (focusPolicy === "original" && originalRefs.length > 0) { + return buildResolvedTargetAssets({ + targetRefs: originalRefs, candidateRefs, resolutionMode: "text_reference", confidence: 96, @@ -180,9 +234,9 @@ export function resolveTargetAssets( }); } - if (focusPolicy === "latest_result" && assistantRefs.length > 0) { + if (focusPolicy === "latest_result" && generatedRefs.length > 0) { return buildResolvedTargetAssets({ - targetRefs: assistantRefs, + targetRefs: generatedRefs, candidateRefs, resolutionMode: "latest_result", confidence: 96, @@ -192,42 +246,6 @@ export function resolveTargetAssets( }); } - if (focusPolicy === "selected" && selectedRefs.length > 0) { - return buildResolvedTargetAssets({ - targetRefs: selectedRefs, - candidateRefs, - resolutionMode: "explicit_selection", - confidence: 97, - needsClarification: false, - reason: "前端已明确选中目标图片", - fromHistory: true, - }); - } - - if (ORIGINAL_IMAGE_REGEX.test(text) && userRefs.length > 0) { - return buildResolvedTargetAssets({ - targetRefs: userRefs, - candidateRefs, - resolutionMode: "text_reference", - confidence: 94, - needsClarification: false, - reason: "用户文本明确指向原图/上传图", - fromHistory: true, - }); - } - - if (LATEST_RESULT_REGEX.test(text) && assistantRefs.length > 0) { - return buildResolvedTargetAssets({ - targetRefs: assistantRefs, - candidateRefs, - resolutionMode: "latest_result", - confidence: 94, - needsClarification: false, - reason: "用户文本明确指向上一轮结果", - fromHistory: true, - }); - } - const ordinalRefs = pickByOrdinal(text, canvasRefs); if (ordinalRefs.length > 0) { return buildResolvedTargetAssets({ @@ -266,6 +284,37 @@ export function resolveTargetAssets( }); } + if ( + ACTIONABLE_EDIT_REGEX.test(text) && + currentRefs.length === 0 && + generatedRefs.length > 0 && + selectedLooksLikeOriginal && + !SELECTION_REGEX.test(text) && + !ORIGINAL_IMAGE_REGEX.test(text) + ) { + return buildResolvedTargetAssets({ + targetRefs: generatedRefs, + candidateRefs, + resolutionMode: "latest_result", + confidence: 89, + needsClarification: false, + reason: "连续对话默认续接上一轮生成结果,避免误回退到原始选中图", + fromHistory: true, + }); + } + + if (focusPolicy === "selected" && selectedRefs.length > 0) { + return buildResolvedTargetAssets({ + targetRefs: selectedRefs, + candidateRefs, + resolutionMode: "explicit_selection", + confidence: 97, + needsClarification: false, + reason: "前端已明确选中目标图片", + fromHistory: true, + }); + } + if ((SELECTION_REGEX.test(text) || focusPolicy === "selected") && selectedRefs.length > 0) { return buildResolvedTargetAssets({ targetRefs: selectedRefs, @@ -290,16 +339,9 @@ export function resolveTargetAssets( }); } - const workingStateResolvedUrls = normalizeStringArray( - workingState?.lastResolvedTargetImageUrls, - ); + const workingStateResolvedUrls = normalizeStringArray(workingState?.lastResolvedTargetImageUrls); if (workingStateResolvedUrls.length > 0) { - const refs = workingStateResolvedUrls.map((url) => ({ - url, - normalizedUrl: url, - source: "working_memory" as const, - role: "working_memory" as const, - })); + const refs = toWorkingMemoryRefs(workingStateResolvedUrls); return buildResolvedTargetAssets({ targetRefs: refs, candidateRefs, @@ -311,14 +353,8 @@ export function resolveTargetAssets( }); } - const workingStateGeneratedUrls = normalizeStringArray(workingState?.lastGeneratedImageUrls); if (workingStateGeneratedUrls.length > 0) { - const refs = workingStateGeneratedUrls.map((url) => ({ - url, - normalizedUrl: url, - source: "working_memory" as const, - role: "working_memory" as const, - })); + const refs = toWorkingMemoryRefs(workingStateGeneratedUrls); return buildResolvedTargetAssets({ targetRefs: refs, candidateRefs, @@ -330,9 +366,9 @@ export function resolveTargetAssets( }); } - if (assistantRefs.length > 0) { + if (generatedRefs.length > 0) { return buildResolvedTargetAssets({ - targetRefs: assistantRefs, + targetRefs: generatedRefs, candidateRefs, resolutionMode: "latest_result", confidence: 74, @@ -342,9 +378,9 @@ export function resolveTargetAssets( }); } - if (userRefs.length > 0) { + if (originalRefs.length > 0) { return buildResolvedTargetAssets({ - targetRefs: userRefs, + targetRefs: originalRefs, candidateRefs, resolutionMode: "working_memory", confidence: 68,