2026-08-24 15:59:17 +08:00
|
|
|
|
import { detectQueryGuard } from './intent-query-guard.mjs';
|
2026-08-24 18:02:19 +08:00
|
|
|
|
import {
|
|
|
|
|
|
parseScheduleIntent,
|
|
|
|
|
|
shouldUseScheduleAssistant,
|
|
|
|
|
|
tryResolveTimedReminderIntent,
|
|
|
|
|
|
} from './schedule-intent.mjs';
|
2026-08-24 15:59:17 +08:00
|
|
|
|
import {
|
|
|
|
|
|
isScheduledTaskIntent,
|
|
|
|
|
|
parseScheduledTaskIntent,
|
|
|
|
|
|
shouldUseScheduledTaskAutomation,
|
|
|
|
|
|
} from './scheduled-task-intent.mjs';
|
|
|
|
|
|
|
|
|
|
|
|
function detectAmbiguity(text) {
|
|
|
|
|
|
const compact = String(text ?? '').replace(/\s+/g, '');
|
2026-08-24 18:02:19 +08:00
|
|
|
|
const notifyCue =
|
|
|
|
|
|
/(?:提醒我|设置提醒|设个?提醒|闹钟|闹铃|叫我|到点提醒|提醒一下)/u.test(compact)
|
|
|
|
|
|
|| /(?:设置|设|加|添加|创建|安排|定)(?:一个|个|一下)?(?:每天|每日|天天)?(?:.{0,40})?提醒/u.test(compact);
|
2026-08-24 15:59:17 +08:00
|
|
|
|
const actCue = /(?:生成|制作|创建|做|执行|推送|发送|整理).{0,12}(?:页面|日报|报告|摘要)/u.test(compact);
|
|
|
|
|
|
if (notifyCue && actCue) return true;
|
2026-08-24 18:02:19 +08:00
|
|
|
|
if (notifyCue && /(?:自动|生成)/u.test(compact) && actCue) return true;
|
2026-08-24 15:59:17 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function classifyUserIntent(text, { now = Date.now(), timezone = 'Asia/Shanghai' } = {}) {
|
|
|
|
|
|
if (detectQueryGuard(text)) {
|
|
|
|
|
|
return { layer: 'L0', kind: 'query', action: 'answer_only' };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const schedTask = parseScheduledTaskIntent(text, { now, timezone });
|
|
|
|
|
|
if (isScheduledTaskIntent(schedTask)) {
|
|
|
|
|
|
if (schedTask.action === 'create_scheduled_task') {
|
|
|
|
|
|
return {
|
|
|
|
|
|
layer: 'L2',
|
|
|
|
|
|
kind: 'scheduled_task',
|
|
|
|
|
|
action: schedTask.action,
|
|
|
|
|
|
detail: schedTask,
|
|
|
|
|
|
clarify: schedTask.needsClarification ?? [],
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return { layer: 'L2', kind: 'manage', action: schedTask.action, detail: schedTask };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const sched = parseScheduleIntent(text, { timezone, now });
|
|
|
|
|
|
if (sched.action === 'create_timed_reminder') {
|
|
|
|
|
|
return {
|
|
|
|
|
|
layer: 'L1',
|
|
|
|
|
|
kind: 'timed_reminder',
|
|
|
|
|
|
action: sched.action,
|
|
|
|
|
|
detail: sched,
|
|
|
|
|
|
clarify: sched.needsClarification ?? [],
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
if (['create_todo', 'create_daily_todo_digest', 'create_balance_alert'].includes(sched.action)) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
layer: 'L1',
|
|
|
|
|
|
kind: sched.action,
|
|
|
|
|
|
action: sched.action,
|
|
|
|
|
|
detail: sched,
|
|
|
|
|
|
clarify: sched.needsClarification ?? [],
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
if (sched.action === 'query_schedule') {
|
|
|
|
|
|
return { layer: 'L0', kind: 'query', action: sched.action, detail: sched };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (detectAmbiguity(text)) {
|
|
|
|
|
|
return { layer: 'ambiguous', kind: 'clarify', action: 'clarify_notify_vs_act' };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldUseScheduledTaskAutomation(text)) {
|
|
|
|
|
|
return { layer: 'L2', kind: 'scheduled_task', action: 'agent_automation', detail: schedTask };
|
|
|
|
|
|
}
|
2026-08-24 18:02:19 +08:00
|
|
|
|
|
|
|
|
|
|
const timedFallback = tryResolveTimedReminderIntent(text, { now, timezone });
|
|
|
|
|
|
if (timedFallback?.action === 'create_timed_reminder') {
|
|
|
|
|
|
return {
|
|
|
|
|
|
layer: 'L1',
|
|
|
|
|
|
kind: 'timed_reminder',
|
|
|
|
|
|
action: timedFallback.action,
|
|
|
|
|
|
detail: timedFallback,
|
|
|
|
|
|
clarify: timedFallback.needsClarification ?? [],
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-24 15:59:17 +08:00
|
|
|
|
if (shouldUseScheduleAssistant(text)) {
|
|
|
|
|
|
const multiTime = (String(text).match(/[0-9零一二两三四五六七八九十]{1,3}(?:点|:|:)/gu) ?? []).length > 1;
|
|
|
|
|
|
return { layer: multiTime ? 'L3' : 'L1', kind: 'agent_schedule', action: 'agent_schedule' };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return { layer: null, kind: 'none', action: 'none' };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function inferActionLevel(classification, text = '') {
|
|
|
|
|
|
const { layer, kind, detail } = classification;
|
|
|
|
|
|
if (layer === 'L0' || layer === null) return 0;
|
|
|
|
|
|
if (layer === 'ambiguous') return 2;
|
|
|
|
|
|
if (/(?:客户|报价|群发|发邮件)/u.test(text)) return 3;
|
|
|
|
|
|
if (layer === 'L2') return 2;
|
|
|
|
|
|
if (kind === 'create_balance_alert') return 2;
|
|
|
|
|
|
if (detail?.recurrence === 'daily' || /(?:每天|每日)/u.test(text)) return 2;
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|