fix: preserve image follow-up context
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-16 15:50:01 +08:00
parent 3bd022fc15
commit 0a105b5c94
2 changed files with 81 additions and 10 deletions

View File

@ -182,6 +182,16 @@ type ConversationStateProtocolEventObserver = (event: {
payload: Record<string, unknown>;
}) => void;
function preferIncomingNonEmptyArray(
incoming?: string[] | null,
fallback?: string[] | null,
): string[] | null | undefined {
if (incoming === undefined) return fallback ?? undefined;
if (Array.isArray(incoming) && incoming.length > 0) return incoming;
if (Array.isArray(fallback) && fallback.length > 0) return fallback;
return incoming;
}
let protocolEventObserver: ConversationStateProtocolEventObserver | null = null;
export function bootstrapConversationStateProtocol(params: {
@ -671,21 +681,63 @@ export async function persistConversationStateEvent<T extends ConversationStateE
case "target_resolved": {
const typed = parsed as ConversationStateEventPayload<"target_resolved">;
const existing = await getConversationWorkingStateByChatId({
chatId: typed.chatId,
}).catch(() => null);
const existingImageWorkflowMemory = extractImageWorkflowMemory(existing);
const preservedCurrentFocusAssetIds = preferIncomingNonEmptyArray(
typed.currentFocusAssetIds,
existing?.currentFocusAssetIds,
);
const preservedCurrentFocusImageUrls = preferIncomingNonEmptyArray(
typed.currentFocusImageUrls,
existing?.currentFocusImageUrls,
);
const preservedLastUploadedAssetIds = preferIncomingNonEmptyArray(
typed.lastUploadedAssetIds,
existing?.lastUploadedAssetIds,
);
const preservedLastUploadedImageUrls = preferIncomingNonEmptyArray(
typed.lastUploadedImageUrls,
existing?.lastUploadedImageUrls,
);
const preservedLastReferencedAssetIds = preferIncomingNonEmptyArray(
typed.lastReferencedAssetIds,
existing?.lastReferencedAssetIds,
);
const preservedLastReferencedImageUrls = preferIncomingNonEmptyArray(
typed.lastReferencedImageUrls,
existing?.lastReferencedImageUrls,
);
const preservedLastResolvedTargetAssetIds = preferIncomingNonEmptyArray(
typed.lastResolvedTargetAssetIds,
existing?.lastResolvedTargetAssetIds,
);
const preservedLastResolvedTargetImageUrls = preferIncomingNonEmptyArray(
typed.lastResolvedTargetImageUrls,
existing?.lastResolvedTargetImageUrls,
);
const workflowSourceImageUrls =
(Array.isArray(preservedLastResolvedTargetImageUrls) &&
preservedLastResolvedTargetImageUrls.length > 0
? preservedLastResolvedTargetImageUrls
: preservedLastUploadedImageUrls) || null;
return persistConversationStateProtocol({
userId: typed.userId,
chatId: typed.chatId,
projectId: typed.projectId,
currentIntent: typed.currentIntent,
currentFocusAssetIds: typed.currentFocusAssetIds,
currentFocusImageUrls: typed.currentFocusImageUrls,
currentFocusAssetIds: preservedCurrentFocusAssetIds,
currentFocusImageUrls: preservedCurrentFocusImageUrls,
selectedAssetIds: typed.selectedAssetIds,
selectedImageUrls: typed.selectedImageUrls,
lastUploadedAssetIds: typed.lastUploadedAssetIds,
lastUploadedImageUrls: typed.lastUploadedImageUrls,
lastReferencedAssetIds: typed.lastReferencedAssetIds,
lastReferencedImageUrls: typed.lastReferencedImageUrls,
lastResolvedTargetAssetIds: typed.lastResolvedTargetAssetIds,
lastResolvedTargetImageUrls: typed.lastResolvedTargetImageUrls,
lastUploadedAssetIds: preservedLastUploadedAssetIds,
lastUploadedImageUrls: preservedLastUploadedImageUrls,
lastReferencedAssetIds: preservedLastReferencedAssetIds,
lastReferencedImageUrls: preservedLastReferencedImageUrls,
lastResolvedTargetAssetIds: preservedLastResolvedTargetAssetIds,
lastResolvedTargetImageUrls: preservedLastResolvedTargetImageUrls,
activeCanvasNodeIds: typed.activeCanvasNodeIds,
lastCanvasSnapshot: typed.lastCanvasSnapshot,
lastMessageId: typed.lastMessageId,
@ -694,6 +746,17 @@ export async function persistConversationStateEvent<T extends ConversationStateE
text: typed.text.slice(0, 500),
resolutionMode: typed.resolutionMode,
confidence: typed.confidence,
imageWorkflowMemory:
typed.currentIntent === "image_edit" ||
typed.currentIntent === "image_gen" ||
typed.currentIntent === "vision"
? buildImageWorkflowMemoryUpdate({
existing: existingImageWorkflowMemory,
lastIntent: typed.currentIntent,
lastUserPrompt: typed.text.slice(0, 500),
lastSourceImageUrls: workflowSourceImageUrls,
})
: undefined,
},
});
}

View File

@ -11,8 +11,16 @@ function normalizeCompactText(text: string) {
}
export function mentionsImageEditFollowup(text: string): boolean {
return /继续改|继续调整|再改一下|再调一下|上一版|上一张结果|这张继续改|保留.*不变|只改|继续优化这张图|继续修这张图/.test(
normalizeCompactText(text)
const normalized = normalizeCompactText(text);
if (!normalized) return false;
return (
/继续改|继续调整|再改一下|再调一下|上一版|上一张结果|这张继续改|保留.*不变|只改|继续优化这张图|继续修这张图/.test(
normalized
) ||
/^(图|图片|这张图|这张|这个图|上传的图|上传图片|刚才那张图|那张图)$/.test(
normalized
)
);
}