Files
memind/wechat/intent/page-continuation-context.mjs
T
john c7dcc5d002
Memind CI / Test, build, and release guards (push) Failing after 3s
fix(wechat): guard bare page-continuation follow-ups from session loss and memory drift
Prevent chat-to-page flows like writing a poem then saying "做成页面吧" from opening
a fresh session without carried content, failing with a vague error, or letting Memory
page-template preferences replace the immediate topic.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-02 18:49:57 +08:00

129 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** Guards for WeChat “做成页面” follow-ups that must bind to in-session content. */
const PAGE_SOURCE_REFERENCE_PATTERN =
/(?:这个|刚才|上面|前面|上一条|它|这首|这篇|这段|以下内容|以上内容|刚才生成|上面生成)/iu;
const PAGE_TEMPLATE_MEMORY_PATTERN =
/(?:做成页面|新闻页|新闻页面|固定格式|daily[- ]?news|国际国内热门新闻)/iu;
const ORCHESTRATION_PREFIX_PATTERN =
/^【Memind 任务编排】[\s\S]*?用户任务:\s*/u;
const MIN_SUBSTANTIVE_ASSISTANT_CHARS = 48;
export function hasExplicitPageSourceReference(text) {
return PAGE_SOURCE_REFERENCE_PATTERN.test(String(text ?? '').trim());
}
export function isBareImmediatePageCreateRequest(text) {
const normalized = String(text ?? '').trim();
if (!normalized) return false;
if (!/(?:吧|呀|呢|一下)[。.!\s]*$/u.test(normalized)) return false;
return (
/^(?:(?:请|麻烦|可以|能不能)\s*)?(?:(?:帮我|帮忙|给我)\s*)?(?:做|弄|改|转|写|排版|生成|制作)(?:成|为)?\s*(?:一个|个)?\s*(?:页面|网页)/iu.test(
normalized,
)
&& !hasExplicitPageSourceReference(normalized)
);
}
export function stripOrchestrationFromAssistantText(text) {
return String(text ?? '')
.replace(ORCHESTRATION_PREFIX_PATTERN, '')
.trim();
}
export function extractSubstantiveAssistantText(text) {
const normalized = stripOrchestrationFromAssistantText(text);
if (normalized.length < MIN_SUBSTANTIVE_ASSISTANT_CHARS) return '';
if (/^(?:好的|收到|我先|让我|ok|let me)\b/iu.test(normalized) && normalized.length < 120) {
return '';
}
return normalized;
}
export function filterMemoryForImmediatePageContext(memories) {
if (!Array.isArray(memories) || memories.length === 0) return memories;
return memories.filter((entry) => {
const label = String(entry?.label ?? entry?.type ?? '').trim().toLowerCase();
const body = String(entry?.text ?? entry?.content ?? entry?.body ?? '').trim();
if (label === 'preference' && PAGE_TEMPLATE_MEMORY_PATTERN.test(body)) return false;
return true;
});
}
export function resolveWechatPageContinuationSource({
userText = '',
carriedSessionContent = '',
sessionAssistantContent = '',
} = {}) {
const carried = extractSubstantiveAssistantText(carriedSessionContent);
if (carried) {
return { ok: true, sourceText: carried, source: 'carried_session' };
}
const inSession = extractSubstantiveAssistantText(sessionAssistantContent);
if (inSession) {
return { ok: true, sourceText: inSession, source: 'session_assistant' };
}
const normalized = String(userText ?? '').trim();
if (hasExplicitPageSourceReference(normalized) && normalized.length >= MIN_SUBSTANTIVE_ASSISTANT_CHARS) {
return { ok: true, sourceText: normalized, source: 'inline_user' };
}
return { ok: false, sourceText: '', source: 'missing' };
}
export function shouldFailFastWechatPageContinuation({
sessionPageContinuation = false,
userText = '',
carriedSessionContent = '',
sessionAssistantContent = '',
} = {}) {
if (!sessionPageContinuation) return false;
if (!isBareImmediatePageCreateRequest(userText) && hasExplicitPageSourceReference(userText)) {
return !resolveWechatPageContinuationSource({
userText,
carriedSessionContent,
sessionAssistantContent,
}).ok;
}
if (!isBareImmediatePageCreateRequest(userText)) return false;
return !resolveWechatPageContinuationSource({
userText,
carriedSessionContent,
sessionAssistantContent,
}).ok;
}
export const WECHAT_PAGE_CONTINUATION_MISSING_SOURCE_TEXT =
'我没能确定您要把哪段内容做成页面。请一条消息发完整主题,或直接粘贴要做成页面的正文(例如诗词、文章全文)。';
export function isWechatPageContinuationRepairableError(message) {
const normalized = String(message ?? '').trim();
if (!normalized) return false;
return (
/stale_session_poisoned_completion/i.test(normalized)
|| /wechat_page_fresh_thumbnail_required:/i.test(normalized)
|| /wechat_agent_incomplete_reply/i.test(normalized)
|| /missing_page_artifact/i.test(normalized)
|| /poisoned_or_fake_claim/i.test(normalized)
|| /skill_or_stub/i.test(normalized)
);
}
export function extractLastSubstantiveAssistantFromConversation(messages = []) {
for (let index = messages.length - 1; index >= 0; index -= 1) {
const message = messages[index];
if (message?.role !== 'assistant') continue;
const text = extractSubstantiveAssistantText(
Array.isArray(message?.content)
? message.content
.filter((item) => item?.type === 'text' && typeof item.text === 'string')
.map((item) => item.text)
.join('')
: String(message?.text ?? ''),
);
if (text) return text;
}
return '';
}