import assert from 'node:assert/strict'; import test from 'node:test'; import { handleWechatScheduledTaskIntent } from './scheduled-task.mjs'; test('handleWechatScheduledTaskIntent passes create requests to goose', async () => { const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '每天6点帮我做今日新闻页面', msgId: 'msg-1', }, user: { userId: 'user-1' }, scheduledTaskService: { async createTask() { throw new Error('should not create from inbound regex'); }, }, }); assert.equal(reply, null); }); test('handleWechatScheduledTaskIntent passes incomplete create requests to goose', async () => { const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '帮我设一个定时自动任务', msgId: 'msg-1', }, user: { userId: 'user-1' }, scheduledTaskService: { async createTask() { throw new Error('should not create from inbound regex'); }, }, }); assert.equal(reply, null); }); test('handleWechatScheduledTaskIntent yields page.generate requests to cursor/goose path', async () => { const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '帮我做一个苏州天气展示页面', msgId: 'msg-page-1', }, user: { userId: 'user-tang' }, scheduledTaskService: { async listTasks() { throw new Error('should not list for page.generate'); }, }, }); assert.equal(reply, null); }); test('handleWechatScheduledTaskIntent cancels via manage llm when task is identified', async () => { const calls = []; const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '取消定时推送苏州天气任务', msgId: 'msg-123-1', }, user: { userId: 'user-123' }, scheduledTaskService: { async listTasks() { return [{ id: 'task-suzhou', title: '每天早上6:30推送苏州市天气预报', recurrence: 'daily', hour: 6, minute: 30, timezone: 'Asia/Shanghai', }]; }, async cancelTask(payload) { calls.push(payload); return { id: 'task-suzhou', title: '每天早上6:30推送苏州市天气预报', status: 'cancelled', }; }, }, wechatScheduledTaskManageLlmConfigService: { async isManageLlmEnabled() { return true; }, async getConfig() { return { modelProviderKeyId: 'key-1', model: 'deepseek-chat' }; }, }, llmProviderService: { async createChatCompletion() { return { ok: true, reply: JSON.stringify({ action: 'cancel', taskId: 'task-suzhou' }), }; }, }, }); assert.match(reply, /已取消定时任务/u); assert.deepEqual(calls, [{ userId: 'user-123', taskId: 'task-suzhou' }]); }); test('handleWechatScheduledTaskIntent passes cancel to goose when manage llm is disabled', async () => { const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '取消定时推送苏州天气任务', msgId: 'msg-123-2', }, user: { userId: 'user-123' }, scheduledTaskService: { async listTasks() { return [ { id: 'task-1', title: '苏州天气', recurrence: 'daily', hour: 6, minute: 30, timezone: 'Asia/Shanghai' }, { id: 'task-2', title: '新闻早报', recurrence: 'daily', hour: 5, minute: 30, timezone: 'Asia/Shanghai' }, ]; }, async cancelTask() { throw new Error('should not cancel from inbound when llm disabled'); }, }, wechatScheduledTaskManageLlmConfigService: { async isManageLlmEnabled() { return false; }, }, }); assert.equal(reply, null); }); test('handleWechatScheduledTaskIntent outage-fallback cancels sole active task when manage llm is unavailable', async () => { const calls = []; const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '取消定时推送苏州天气任务', msgId: 'msg-123-outage', }, user: { userId: 'user-123' }, scheduledTaskService: { async listTasks() { return [{ id: 'task-suzhou', title: '每天早上6:30推送苏州市天气预报', recurrence: 'daily', hour: 6, minute: 30, timezone: 'Asia/Shanghai', }]; }, async cancelTask(payload) { calls.push(payload); return { id: 'task-suzhou', title: '每天早上6:30推送苏州市天气预报', status: 'cancelled', }; }, }, wechatScheduledTaskManageLlmConfigService: { async isManageLlmEnabled() { return true; }, async getConfig() { return { modelProviderKeyId: 'deepseek-key', model: 'deepseek-chat' }; }, }, llmProviderService: { async listKeys() { return [{ id: 'deepseek-key', name: 'DeepSeek', status: 'active', defaultModel: 'deepseek-chat', models: ['deepseek-chat'] }]; }, async createChatCompletion() { return { ok: false, status: 402, message: '{"error":{"message":"Insufficient Balance"}}' }; }, }, }); assert.match(reply, /已取消定时任务/u); assert.deepEqual(calls, [{ userId: 'user-123', taskId: 'task-suzhou' }]); }); test('handleWechatScheduledTaskIntent returns clarify message when manage llm is ambiguous', async () => { const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '帮我取消定时任务', msgId: 'msg-123-3', }, user: { userId: 'user-tang' }, scheduledTaskService: { async listTasks() { return [ { id: 'task-news', title: '每日新闻早报页面(5:30)', recurrence: 'daily', hour: 5, minute: 30 }, { id: 'task-checkin', title: '每日打卡提醒', recurrence: 'daily', hour: 18, minute: 0 }, ]; }, }, wechatScheduledTaskManageLlmConfigService: { async isManageLlmEnabled() { return true; }, async getConfig() { return { modelProviderKeyId: 'key-1', model: 'deepseek-chat' }; }, }, llmProviderService: { async createChatCompletion() { return { ok: true, reply: JSON.stringify({ action: 'clarify', message: '你是想取消 5:30 新闻早报,还是 18:00 打卡提醒?', }), }; }, }, }); assert.match(reply, /新闻早报/u); }); test('handleWechatScheduledTaskIntent ignores non automation text', async () => { const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '明天下午三点提醒我开会', msgId: 'msg-1', }, user: { userId: 'user-1' }, scheduledTaskService: { async createTask() { throw new Error('should not create'); }, }, }); assert.equal(reply, null); }); test('handleWechatScheduledTaskIntent still lists tasks', async () => { const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '看看我的定时自动任务', msgId: 'msg-1', }, user: { userId: 'user-1' }, scheduledTaskService: { async listTasks() { return [{ title: '新闻页面', recurrence: 'daily', hour: 6, minute: 0, timezone: 'Asia/Shanghai' }]; }, }, }); assert.match(reply, /新闻页面/u); }); test('handleWechatScheduledTaskIntent lists tasks for 有哪些 phrasing', async () => { const reply = await handleWechatScheduledTaskIntent({ intent: { msgType: 'text', agentText: '我有哪些定时任务', msgId: 'msg-2', }, user: { userId: 'user-1' }, scheduledTaskService: { async listTasks() { return [{ title: '苏州天气', recurrence: 'daily', hour: 6, minute: 30, timezone: 'Asia/Shanghai' }]; }, }, }); assert.match(reply, /苏州天气/u); });