fix(wechat): rotate image_url-poisoned sessions for report follow-ups
Memind CI / Test, build, and release guards (push) Has been cancelled

Goose cannot persist historical image scrub (PUT 405), so DeepSeek rejects
image_url on the next turn. Reattach the recent report image and rotate to a
fresh session instead of treating the follow-up as a missing page source.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-14 21:45:02 +08:00
parent fe2d5d7aa1
commit 41f245c88a
7 changed files with 370 additions and 19 deletions
+26 -10
View File
@@ -1088,6 +1088,12 @@ export function isWechatPageDataTask(text) {
return isPageDataIntent(text) || isPageDataDevIntent(text);
}
export function isWechatHistoricalImageSessionError(message) {
return /historical_image_session_update_unsupported|unknown variant [`']?image_url/i.test(
String(message ?? '').trim(),
);
}
export function isRecoverableWechatAgentSessionError(message) {
const normalized = String(message ?? '').trim();
if (!normalized) return false;
@@ -1095,9 +1101,7 @@ export function isRecoverableWechatAgentSessionError(message) {
if (/wechat_page_fresh_thumbnail_required:/i.test(normalized)) return true;
if (/403|404|not found|无权访问/i.test(normalized)) return true;
if (/tool_calls|tool_call_id|insufficient tool messages/i.test(normalized)) return true;
if (/historical_image_session_update_unsupported|unknown variant [`']?image_url/i.test(normalized)) {
return true;
}
if (isWechatHistoricalImageSessionError(normalized)) return true;
if (/session already has an active request|active request.*cancel/i.test(normalized)) return true;
if (/wechat_agent_incomplete_reply/i.test(normalized)) return true;
return false;
@@ -1712,7 +1716,13 @@ export function createWechatMpService({
const attachRecentMediaForFollowup = (openid, intent, mediaAnalysisEnabled) => {
if (!mediaAnalysisEnabled || intent?.msgType !== 'text' || intent?.media?.publicUrl) return;
const text = String(intent?.agentText ?? '');
if (!/(?:刚才|之前|上一|这张|这份|图片|图像|照片|文件|文档|表格|excel|word)/iu.test(text)) return;
if (
!/(?:刚才|之前|上一|这张|这份|图片|图像|照片|文件|文档|表格|excel|word|报告|解读|化验|检验|做成页面|做个页面|做页面|生成页面)/iu.test(
text,
)
) {
return;
}
const key = String(openid ?? '').trim();
const recent = recentMediaByOpenid.get(key);
if (
@@ -3099,8 +3109,13 @@ export function createWechatMpService({
const mayBeStaleSession =
sessionId
&& (isRecoverableWechatAgentSessionError(message) || isWechatAgentApiErrorText(message));
const historicalImageError = isWechatHistoricalImageSessionError(message);
if (mayBeStaleSession) {
if (sessionPageContinuation && isWechatPageContinuationRepairableError(message)) {
if (
sessionPageContinuation
&& !historicalImageError
&& isWechatPageContinuationRepairableError(message)
) {
const text = buildPagePublishFailureText();
await userAuth.clearWechatAgentRoute(config.appId, inbound.fromUserName).catch((clearErr) => {
logger.warn?.('WeChat MP page continuation repair route clear failed:', clearErr);
@@ -3116,7 +3131,7 @@ export function createWechatMpService({
repairError.wechatAgentSessionId = sessionId;
throw repairError;
}
if (sessionPageContinuation) {
if (sessionPageContinuation && !historicalImageError) {
await userAuth.clearWechatAgentRoute(config.appId, inbound.fromUserName).catch((clearErr) => {
logger.warn?.('WeChat MP contextual follow-up route clear failed:', clearErr);
});
@@ -3144,17 +3159,18 @@ export function createWechatMpService({
await rememberWechatUserContext(sessionId, user, { forceBootstrap: route.isNewSession });
const retryId = crypto.randomUUID();
const retryStartedAt = Date.now();
const retryPageContinuation = sessionPageContinuation && !historicalImageError;
const retryPrompt =
wechatIntent.kind === 'page.generate'
? buildPageGenerateAgentPrompt(intent, {
wantsDocx: wechatIntent.wantsDocx,
imagePolicy,
preferImmediateContext: sessionPageContinuation,
carriedSessionContent,
preferImmediateContext: retryPageContinuation,
carriedSessionContent: retryPageContinuation ? carriedSessionContent : '',
})
: buildWechatAgentPrompt(intent, {
imagePolicy,
preferSessionPageContinuation: sessionPageContinuation,
preferSessionPageContinuation: retryPageContinuation,
});
const reply = await executeSessionReply(
(pathname, init) => fetchForSession(sessionId, pathname, init),
@@ -3171,7 +3187,7 @@ export function createWechatMpService({
userId: user.userId,
sessionId,
userMessage,
preserveAgentPrompt: sessionPageContinuation,
preserveAgentPrompt: retryPageContinuation,
}),
submitReply: submitSessionReply
? ({ requestId: replyRequestId, userMessage }) =>