import { classifyUserIntent, inferActionLevel } from '../../intent-classifier.mjs'; import { commitIntentDraft } from '../../intent-transaction-commit.mjs'; import { formatDraftCancelledReply, formatDraftCommittedReply, formatIntentActionCard, parseDraftUserReply, } from '../../intent-action-card.mjs'; import { formatQueryGuardReply } from '../../intent-query-guard.mjs'; import { isIntentTransactionEnabled } from '../../intent-transaction-config.mjs'; import { buildScheduledTaskCreatePayload } from '../../scheduled-task-intent.mjs'; import { formatScheduledTaskCreateReply } from '../../scheduled-task-intent.mjs'; import { isScheduledTaskWorkerEnabled, scheduledTaskWorkerDisabledMessage } from '../../scheduled-task-worker-config.mjs'; function buildDraftPayload(classification, { intent, user, timezone }) { const { kind, detail } = classification; const base = { sourceChannel: 'wechat', sourceMessageId: intent.msgId ?? null, sourceText: intent.agentText, timezone, }; if (kind === 'timed_reminder') { return { ...base, title: detail.title, remindLocal: detail.remindLocal, hour: detail.hour, minute: detail.minute, recurrence: detail.recurrence ?? 'once', }; } if (kind === 'create_todo') { return { ...base, title: detail.title }; } if (kind === 'create_daily_todo_digest') { return { ...base, hour: detail.hour, minute: detail.minute ?? 0 }; } if (kind === 'create_balance_alert') { return { ...base, thresholdCents: detail.thresholdCents }; } if (kind === 'scheduled_task') { return { ...base, intentDetail: detail, createPayload: buildScheduledTaskCreatePayload(detail, { userId: user.userId, sourceChannel: 'wechat', sourceMessageId: intent.msgId ?? null, sourceText: intent.agentText, timezone, }), }; } return base; } function buildCard(classification, draftPayload, actionLevel, text) { const { layer, kind, detail, clarify } = classification; if (kind === 'clarify' || classification.layer === 'ambiguous') { return formatIntentActionCard({ clarify: ['notify_vs_act'] }); } if (clarify?.length) { return formatIntentActionCard({ clarify }); } const title = detail?.title ?? detail?.taskSpec?.slice?.(0, 80) ?? draftPayload.title ?? '待确认任务'; const trigger = detail?.remindLocal ? { at: detail.remindLocal } : { hour: detail?.hour, minute: detail?.minute ?? 0 }; const frequency = /(?:每天|每日)/u.test(text) ? '每天自动执行' : detail?.recurrence === 'weekly' ? '每周自动执行' : detail?.recurrence === 'daily' ? '每天自动执行' : null; const actions = kind === 'scheduled_task' ? ['到点自动执行任务', '推送执行结果到微信'] : kind === 'timed_reminder' ? ['到点发送微信提醒'] : kind === 'create_daily_todo_digest' ? ['到点推送当天待办摘要'] : kind === 'create_balance_alert' ? ['余额低于阈值时发送微信提醒'] : ['记录到待办列表']; return formatIntentActionCard({ title, layer, actionLevel, trigger, actions, frequency, }); } export async function handleWechatIntentTransaction({ intent, user, intentDraftService, taskUnifiedService = null, scheduleService, scheduledTaskService, env = process.env, logger = console, }) { if (!isIntentTransactionEnabled(env) || !intentDraftService) return null; const timezone = env.H5_DEFAULT_TIMEZONE || 'Asia/Shanghai'; const text = intent.agentText; try { const pending = await intentDraftService.getPendingDraft(user.userId); const replyKind = parseDraftUserReply(text); if (pending && replyKind) { if (replyKind === 'cancel') { await intentDraftService.cancelDraft(pending.id, user.userId); return formatDraftCancelledReply(); } if (replyKind === 'modify') { await intentDraftService.cancelDraft(pending.id, user.userId, { reason: 'user_modify' }); return '好的,请重新发送完整的安排,例如「下午 2 点半提醒我开项目计划例会」。'; } if (replyKind === 'confirm') { if (pending.layer === 'ambiguous' || pending.draftType === 'clarify') { return '我还需要确认:你是要「到点提醒」还是「到点自动执行并交付结果」?请补充后再发「确认」。'; } const committed = await commitIntentDraft({ draft: pending, userId: user.userId, scheduleService, scheduledTaskService, taskUnifiedService, timezone, env, }); await intentDraftService.markDraftCommitted(pending.id, user.userId, committed); if (committed.kind === 'scheduled_task') { const workerWarning = isScheduledTaskWorkerEnabled(env) ? null : scheduledTaskWorkerDisabledMessage(env); let reply = formatScheduledTaskCreateReply(committed.task, { workerWarning }); reply = `${reply}\n\n(已通过确认卡片写入)`; return reply; } return formatDraftCommittedReply({ title: pending.title, kind: pending.draftType }); } } const classification = classifyUserIntent(text, { timezone }); const { layer, kind, action } = classification; if (layer === 'L0') { return formatQueryGuardReply(text, { scheduleService, scheduledTaskService, taskUnifiedService, userId: user.userId, timezone, env, }); } if (layer === 'L3' || layer === null || kind === 'agent_schedule' || kind === 'agent_automation') { return null; } if (kind === 'manage') { return null; } if (layer === 'ambiguous' || kind === 'clarify') { if (classification.clarify?.length && kind !== 'clarify') { return buildCard(classification, {}, inferActionLevel(classification, text), text); } await intentDraftService.createDraft({ userId: user.userId, layer: 'ambiguous', draftType: 'clarify', actionLevel: 2, title: '待确认意图', payload: { clarify: ['notify_vs_act'], sourceText: text }, cardText: buildCard({ layer: 'ambiguous', kind: 'clarify', clarify: ['notify_vs_act'] }, {}, 2, text), sourceMessageId: intent.msgId ?? null, sourceText: text, }); return buildCard({ layer: 'ambiguous', kind: 'clarify', clarify: ['notify_vs_act'] }, {}, 2, text); } const draftableKinds = new Set([ 'timed_reminder', 'create_todo', 'create_daily_todo_digest', 'create_balance_alert', 'scheduled_task', ]); if (!draftableKinds.has(kind)) return null; if (classification.clarify?.length) { return buildCard(classification, {}, inferActionLevel(classification, text), text); } const actionLevel = inferActionLevel(classification, text); const payload = buildDraftPayload(classification, { intent, user, timezone }); const cardText = buildCard(classification, payload, actionLevel, text); await intentDraftService.createDraft({ userId: user.userId, layer, draftType: kind, actionLevel, title: payload.title ?? payload.createPayload?.title ?? classification.detail?.title ?? '待确认任务', payload, cardText, sourceMessageId: intent.msgId ?? null, sourceText: text, }); return cardText; } catch (err) { logger.warn?.( '[wechat-intent-transaction] failed:', err instanceof Error ? err.message : err, ); return `设置预览失败:${err instanceof Error ? err.message : String(err)}`; } }