/** 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 ''; }