import assert from 'node:assert/strict'; import test from 'node:test'; import { handleWechatScheduleIntent } from './schedule.mjs'; function createScheduleService() { return { async createItem(payload) { return { id: 'item-1', ...payload }; }, async createDailyTodoDigest(payload) { return { id: 'digest-1', minute: payload.minute, hour: payload.hour, ...payload }; }, async createBalanceLowAlert(payload) { return { id: 'balance-1', ...payload }; }, async buildTodoDigestText() { return '今天有 2 条待办。'; }, }; } test('schedule handler keeps rule-based parsing as first priority', async () => { let llmCalled = false; const reply = await handleWechatScheduleIntent({ intent: { agentText: '帮我记一下 跟进合同', msgId: 'msg-1' }, user: { userId: 'user-1' }, scheduleService: createScheduleService(), wechatScheduleLlmConfigService: { async isScheduleLlmEnabled() { return true; } }, llmProviderService: { async createChatCompletion() { llmCalled = true; return { ok: true, reply: '{"action":"none"}' }; }, }, }); assert.match(reply, /已记录到待办列表/); assert.equal(llmCalled, false); }); test('schedule handler can use llm fallback for ambiguous todo text', async () => { const reply = await handleWechatScheduleIntent({ intent: { agentText: '下周把合同发给客户,别忘了', msgId: 'msg-2' }, user: { userId: 'user-1' }, scheduleService: createScheduleService(), wechatScheduleLlmConfigService: { async isScheduleLlmEnabled() { return true; } }, llmProviderService: { async createChatCompletion() { return { ok: true, reply: '{"action":"create_todo","title":"把合同发给客户"}', }; }, }, }); assert.match(reply, /把合同发给客户/); }); test('schedule handler directly handles daily digest shortcut phrase', async () => { const reply = await handleWechatScheduleIntent({ intent: { agentText: '每天早上7点把当天待办发给我', msgId: 'msg-digest-1' }, user: { userId: 'user-1' }, scheduleService: createScheduleService(), }); assert.match(reply, /已设置/); assert.match(reply, /每天早上 7点/); }); test('schedule handler does not call llm when switch is off', async () => { let llmCalled = false; const reply = await handleWechatScheduleIntent({ intent: { agentText: '别忘了报销', msgId: 'msg-4' }, user: { userId: 'user-1' }, scheduleService: createScheduleService(), wechatScheduleLlmConfigService: { async isScheduleLlmEnabled() { return false; } }, llmProviderService: { async createChatCompletion() { llmCalled = true; return { ok: true, reply: '{"action":"create_todo","title":"报销"}' }; }, }, }); assert.equal(reply, null); assert.equal(llmCalled, false); }); test('schedule handler falls back quietly when llm request fails', async () => { const warnings = []; const reply = await handleWechatScheduleIntent({ intent: { agentText: '别忘了报销', msgId: 'msg-5' }, user: { userId: 'user-1' }, scheduleService: createScheduleService(), wechatScheduleLlmConfigService: { async isScheduleLlmEnabled() { return true; } }, llmProviderService: { async createChatCompletion() { return { ok: false, message: 'provider unavailable' }; }, }, logger: { warn: (...args) => warnings.push(args.join(' ')) }, }); assert.equal(reply, null); assert.equal(warnings.length, 1); assert.match(warnings[0], /provider unavailable/); }); test('schedule handler falls through for llm schedule_agent results', async () => { const reply = await handleWechatScheduleIntent({ intent: { agentText: '明天下午三点提醒我开会', msgId: 'msg-3' }, user: { userId: 'user-1' }, scheduleService: createScheduleService(), wechatScheduleLlmConfigService: { async isScheduleLlmEnabled() { return true; } }, llmProviderService: { async createChatCompletion() { return { ok: true, reply: '{"action":"schedule_agent"}', }; }, }, }); assert.equal(reply, null); });