fix: guard WeChat page follow-up context
This commit is contained in:
+114
-33
@@ -974,6 +974,30 @@ export function shouldForceNewWechatAgentSession(wechatIntent, resetCandidate) {
|
||||
);
|
||||
}
|
||||
|
||||
const WECHAT_IMMEDIATE_CONTEXT_PAGE_PATTERN =
|
||||
/^(?:(?:请|麻烦|可以|能不能)\s*)?(?:(?:帮我|帮忙|给我)\s*)?(?:(?:把\s*)?(?:这个|刚才(?:的)?(?:诗|文章|内容)?|上面(?:的)?|前面(?:的)?|上一条|它|这首(?:诗)?|这篇(?:文章)?|这段(?:内容)?)\s*)?(?:继续\s*)?(?:做|弄|改|转|写|排版|生成|制作)(?:成|为)?\s*(?:一个|个)?\s*(?:h5|html)?\s*(?:页面|网页)(?:吧|呀|呢|一下)?[。.!!\s]*$/iu;
|
||||
|
||||
export function isWechatImmediateContextFollowup(wechatIntent, text) {
|
||||
if (wechatIntent?.kind !== 'page.generate') return false;
|
||||
const normalized = String(text ?? '').trim();
|
||||
return Boolean(normalized && WECHAT_IMMEDIATE_CONTEXT_PAGE_PATTERN.test(normalized));
|
||||
}
|
||||
|
||||
export function shouldRotateUnlinkedWechatRoute({
|
||||
routeUpdatedAt,
|
||||
wechatMessageCount,
|
||||
snapshotMessageCount,
|
||||
now = Date.now(),
|
||||
} = {}) {
|
||||
const updatedAt = Number(routeUpdatedAt ?? 0);
|
||||
return (
|
||||
updatedAt > 0 &&
|
||||
Number(now) - updatedAt > 60_000 &&
|
||||
Number(wechatMessageCount) === 0 &&
|
||||
Number(snapshotMessageCount ?? 0) > 0
|
||||
);
|
||||
}
|
||||
|
||||
export function isWechatPageDataTask(text) {
|
||||
return isPageDataIntent(text) || isPageDataDevIntent(text);
|
||||
}
|
||||
@@ -1978,42 +2002,56 @@ export function createWechatMpService({
|
||||
config.sessionIdleRotateMs > 0 &&
|
||||
routeUpdatedAt > 0 &&
|
||||
now - routeUpdatedAt > config.sessionIdleRotateMs;
|
||||
let routeWechatMessageCount = null;
|
||||
let routeSnapshotMessageCount = null;
|
||||
let routeMessageCount = 0;
|
||||
if (config.sessionMessageRotateCount > 0) {
|
||||
const counts = [];
|
||||
if (typeof userAuth.countWechatAgentSessionMessages === 'function') {
|
||||
counts.push(
|
||||
userAuth
|
||||
.countWechatAgentSessionMessages({
|
||||
appId: config.appId,
|
||||
openid,
|
||||
agentSessionId: existingRoute.agentSessionId,
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.warn?.('WeChat MP route message count lookup failed:', err);
|
||||
return 0;
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (typeof userAuth.getWechatAgentSessionSnapshotMessageCount === 'function') {
|
||||
counts.push(
|
||||
userAuth
|
||||
.getWechatAgentSessionSnapshotMessageCount(existingRoute.agentSessionId)
|
||||
.catch((err) => {
|
||||
logger.warn?.('WeChat MP snapshot message count lookup failed:', err);
|
||||
return 0;
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (counts.length > 0) {
|
||||
const resolved = await Promise.all(counts);
|
||||
routeMessageCount = Math.max(0, ...resolved.map((value) => Number(value) || 0));
|
||||
}
|
||||
[routeWechatMessageCount, routeSnapshotMessageCount] = await Promise.all([
|
||||
typeof userAuth.countWechatAgentSessionMessages === 'function'
|
||||
? userAuth
|
||||
.countWechatAgentSessionMessages({
|
||||
appId: config.appId,
|
||||
openid,
|
||||
agentSessionId: existingRoute.agentSessionId,
|
||||
})
|
||||
.then((value) => Number(value) || 0)
|
||||
.catch((err) => {
|
||||
logger.warn?.('WeChat MP route message count lookup failed:', err);
|
||||
return null;
|
||||
})
|
||||
: null,
|
||||
typeof userAuth.getWechatAgentSessionSnapshotMessageCount === 'function'
|
||||
? userAuth
|
||||
.getWechatAgentSessionSnapshotMessageCount(existingRoute.agentSessionId)
|
||||
.then((value) => Number(value) || 0)
|
||||
.catch((err) => {
|
||||
logger.warn?.('WeChat MP snapshot message count lookup failed:', err);
|
||||
return null;
|
||||
})
|
||||
: null,
|
||||
]);
|
||||
routeMessageCount = Math.max(
|
||||
0,
|
||||
Number(routeWechatMessageCount) || 0,
|
||||
Number(routeSnapshotMessageCount) || 0,
|
||||
);
|
||||
}
|
||||
const routeIsTooLong =
|
||||
config.sessionMessageRotateCount > 0 &&
|
||||
Number(routeMessageCount ?? 0) >= config.sessionMessageRotateCount;
|
||||
if (routeIsIdle || routeIsTooLong) {
|
||||
const routeHasUnlinkedConversation = shouldRotateUnlinkedWechatRoute({
|
||||
routeUpdatedAt,
|
||||
wechatMessageCount: routeWechatMessageCount,
|
||||
snapshotMessageCount: routeSnapshotMessageCount,
|
||||
now,
|
||||
});
|
||||
if (routeIsIdle || routeIsTooLong || routeHasUnlinkedConversation) {
|
||||
if (routeHasUnlinkedConversation) {
|
||||
logger.warn?.('WeChat MP orphaned route rotated before reuse:', {
|
||||
agentSessionId: existingRoute.agentSessionId,
|
||||
snapshotMessageCount: routeSnapshotMessageCount,
|
||||
});
|
||||
}
|
||||
await userAuth.clearWechatAgentRoute(config.appId, openid);
|
||||
rememberedWechatContexts.delete(existingRoute.agentSessionId);
|
||||
} else {
|
||||
@@ -2271,7 +2309,12 @@ export function createWechatMpService({
|
||||
}
|
||||
};
|
||||
|
||||
const prepareWechatAgentUserMessage = async ({ userId, sessionId, userMessage }) => {
|
||||
const prepareWechatAgentUserMessage = async ({
|
||||
userId,
|
||||
sessionId,
|
||||
userMessage,
|
||||
preserveAgentPrompt = false,
|
||||
}) => {
|
||||
if (
|
||||
!chatIntentRouter?.resolveAgentMemoryContext
|
||||
|| !chatIntentRouter?.applyAgentOrchestration
|
||||
@@ -2296,8 +2339,17 @@ export function createWechatMpService({
|
||||
) {
|
||||
return userMessage;
|
||||
}
|
||||
return chatIntentRouter.applyAgentOrchestration(
|
||||
userMessage,
|
||||
const orchestrationMessage = preserveAgentPrompt
|
||||
? {
|
||||
...userMessage,
|
||||
metadata: {
|
||||
...(userMessage?.metadata ?? {}),
|
||||
displayText: messageVisibleText(userMessage),
|
||||
},
|
||||
}
|
||||
: userMessage;
|
||||
const prepared = chatIntentRouter.applyAgentOrchestration(
|
||||
orchestrationMessage,
|
||||
{
|
||||
route: 'agent_orchestration',
|
||||
reason: '微信服务号消息由 Agent 处理',
|
||||
@@ -2305,6 +2357,14 @@ export function createWechatMpService({
|
||||
},
|
||||
{ memoryContext },
|
||||
);
|
||||
if (!preserveAgentPrompt) return prepared;
|
||||
return {
|
||||
...prepared,
|
||||
metadata: {
|
||||
...(prepared?.metadata ?? {}),
|
||||
displayText: displayText || undefined,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
logger.warn?.(
|
||||
'WeChat MP agent memory resolve skipped:',
|
||||
@@ -2371,6 +2431,8 @@ export function createWechatMpService({
|
||||
// inspect/retry unrelated historical pages from that session.
|
||||
const isPageDataRequest = isWechatPageDataTask(resetCandidate);
|
||||
const htmlArtifactDeliveryExpected = shouldDeliverWechatHtmlArtifacts(wechatIntent, intent);
|
||||
const immediateContextFollowup =
|
||||
isWechatImmediateContextFollowup(wechatIntent, resetCandidate);
|
||||
const forceNew = shouldForceNewWechatAgentSession(wechatIntent, resetCandidate);
|
||||
let route = await ensureWechatAgentSession({
|
||||
userId: user.userId,
|
||||
@@ -2417,6 +2479,7 @@ export function createWechatMpService({
|
||||
? buildPageGenerateAgentPrompt(intent, {
|
||||
wantsDocx: wechatIntent.wantsDocx,
|
||||
imagePolicy,
|
||||
preferImmediateContext: immediateContextFollowup,
|
||||
})
|
||||
: buildWechatAgentPrompt(intent, { imagePolicy });
|
||||
const reply = await executeSessionReply(
|
||||
@@ -2434,6 +2497,7 @@ export function createWechatMpService({
|
||||
userId: user.userId,
|
||||
sessionId,
|
||||
userMessage,
|
||||
preserveAgentPrompt: immediateContextFollowup,
|
||||
}),
|
||||
submitReply: submitSessionReply
|
||||
? ({ requestId: replyRequestId, userMessage }) =>
|
||||
@@ -2657,6 +2721,21 @@ export function createWechatMpService({
|
||||
sessionId
|
||||
&& (isRecoverableWechatAgentSessionError(message) || isWechatAgentApiErrorText(message));
|
||||
if (mayBeStaleSession) {
|
||||
if (immediateContextFollowup) {
|
||||
await userAuth.clearWechatAgentRoute(config.appId, inbound.fromUserName).catch((clearErr) => {
|
||||
logger.warn?.('WeChat MP contextual follow-up route clear failed:', clearErr);
|
||||
});
|
||||
const text =
|
||||
'我没能可靠确认“做成页面”指的是哪段内容,已经停止沿用旧主题。请把要做成页面的主题或原文再发一次。';
|
||||
try {
|
||||
await sendCustomerServiceText(inbound.fromUserName, text, user);
|
||||
} catch (sendErr) {
|
||||
logger.error?.('WeChat MP contextual follow-up notice failed:', sendErr);
|
||||
}
|
||||
const contextualError = markWechatUserNotified(new Error(text));
|
||||
contextualError.wechatAgentSessionId = sessionId;
|
||||
throw contextualError;
|
||||
}
|
||||
route = await ensureWechatAgentSession({
|
||||
userId: user.userId,
|
||||
openid: inbound.fromUserName,
|
||||
@@ -2673,6 +2752,7 @@ export function createWechatMpService({
|
||||
? buildPageGenerateAgentPrompt(intent, {
|
||||
wantsDocx: wechatIntent.wantsDocx,
|
||||
imagePolicy,
|
||||
preferImmediateContext: immediateContextFollowup,
|
||||
})
|
||||
: buildWechatAgentPrompt(intent, { imagePolicy });
|
||||
const reply = await executeSessionReply(
|
||||
@@ -2690,6 +2770,7 @@ export function createWechatMpService({
|
||||
userId: user.userId,
|
||||
sessionId,
|
||||
userMessage,
|
||||
preserveAgentPrompt: immediateContextFollowup,
|
||||
}),
|
||||
submitReply: submitSessionReply
|
||||
? ({ requestId: replyRequestId, userMessage }) =>
|
||||
|
||||
Reference in New Issue
Block a user