Files
memind/wechat/intent/classifier.mjs
T
john 8f88eec2bd
Memind CI / Test, build, and release guards (push) Successful in 4m40s
Separate WeChat chat, page refine, and task flows with explicit routing.
Add channel prefixes, pin edit targets in Cursor prompts, and force fresh sessions for page refine URLs so DeepSeek/Goose chat history does not pollute page tasks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-31 14:10:02 +08:00

103 lines
3.4 KiB
JavaScript

import { parseWechatChannelPrefix, WECHAT_CHANNEL_PREFIX } from './channel-prefix.mjs';
import {
CONNECTIVITY_TEST_PATTERN,
GREETING_PATTERN,
STATUS_PROBE_PATTERN,
isPageGenerateText,
isTopicResetText,
wantsDocxDownload,
} from './patterns.mjs';
import { WECHAT_SESSION_ACTION } from './session-action.mjs';
/**
* @typedef {object} WechatPageGenerateIntent
* @property {'page.generate'} kind
* @property {string} topic
* @property {boolean} wantsDocx
*
* @typedef {object} WechatSessionResetIntent
* @property {'session.reset'} kind
* @property {string} sessionAction
*
* @typedef {object} WechatStatusProbeIntent
* @property {'status.probe'} kind
*
* @typedef {object} WechatGreetingIntent
* @property {'greeting'} kind
*
* @typedef {object} WechatConnectivityTestIntent
* @property {'connectivity.test'} kind
*
* @typedef {object} WechatGeneralChatIntent
* @property {'chat.general'} kind
* @property {string} text
*
* @typedef {object} WechatUnsupportedIntent
* @property {'unsupported'} kind
* @property {string} msgType
*
* @typedef {WechatPageGenerateIntent|WechatSessionResetIntent|WechatStatusProbeIntent|WechatGreetingIntent|WechatConnectivityTestIntent|WechatGeneralChatIntent|WechatUnsupportedIntent} WechatIntent
*/
/**
* Classify a normalized WeChat inbound intent (from wechat-mp normalizeWechatInboundIntent).
* @param {{ msgType?: string, agentText?: string, displayText?: string }} intent
* @returns {WechatIntent}
*/
function withChannelMeta(result, channelPrefix) {
if (!channelPrefix) return result;
return { ...result, channelPrefix };
}
export function classifyWechatIntent(intent) {
const msgType = String(intent?.msgType ?? 'text').toLowerCase();
const rawText = String(intent?.agentText ?? intent?.displayText ?? '').trim();
const { channel: channelPrefix, body: text } = parseWechatChannelPrefix(rawText);
if (msgType === 'text' || msgType === 'voice') {
if (isTopicResetText(text)) {
return withChannelMeta(
{ kind: 'session.reset', sessionAction: WECHAT_SESSION_ACTION.RESET },
channelPrefix,
);
}
if (STATUS_PROBE_PATTERN.test(text)) {
return withChannelMeta({ kind: 'status.probe' }, channelPrefix);
}
if (GREETING_PATTERN.test(text.replace(/[!!。.\s]+$/g, ''))) {
return withChannelMeta({ kind: 'greeting' }, channelPrefix);
}
if (CONNECTIVITY_TEST_PATTERN.test(text.replace(/[!!。.\s]+$/g, ''))) {
return withChannelMeta({ kind: 'connectivity.test' }, channelPrefix);
}
if (channelPrefix === WECHAT_CHANNEL_PREFIX.CHAT) {
return withChannelMeta({ kind: 'chat.general', text }, channelPrefix);
}
if (channelPrefix === WECHAT_CHANNEL_PREFIX.PAGE) {
return withChannelMeta({
kind: 'page.generate',
topic: text,
wantsDocx: wantsDocxDownload(text),
}, channelPrefix);
}
if (isPageGenerateText(text)) {
return withChannelMeta({
kind: 'page.generate',
topic: text,
wantsDocx: wantsDocxDownload(text),
}, channelPrefix);
}
return withChannelMeta({ kind: 'chat.general', text }, channelPrefix);
}
if (msgType === 'event') {
return { kind: 'unsupported', msgType: 'event' };
}
return { kind: 'chat.general', text: text || `[${msgType}]` };
}
export function isPageGenerateIntent(intent) {
return classifyWechatIntent(intent).kind === 'page.generate';
}