From 43ec144540b8260bf7423e5bff18b3fe29e2f7e5 Mon Sep 17 00:00:00 2001 From: john Date: Sat, 29 Aug 2026 11:38:17 +0800 Subject: [PATCH] fix(wechat): yield schedule handler when scheduled-task intent matches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop schedule todo replies from intercepting cancel/list/create automation requests, and recognize 有哪些 for inbound scheduled task listing. Co-authored-by: Cursor --- scheduled-task-intent.mjs | 2 +- scheduled-task-intent.test.mjs | 1 + wechat/handlers/schedule.mjs | 5 ++++ wechat/handlers/schedule.test.mjs | 32 +++++++++++++++++++++++++ wechat/handlers/scheduled-task.test.mjs | 17 +++++++++++++ 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/scheduled-task-intent.mjs b/scheduled-task-intent.mjs index 924f86a..65d38e2 100644 --- a/scheduled-task-intent.mjs +++ b/scheduled-task-intent.mjs @@ -164,7 +164,7 @@ export function parseScheduledTaskIntent(text, { now = Date.now(), timezone = 'A return { action: 'cancel_scheduled_task' }; } - const wantsList = /(?:查看|看看|列出|我的).{0,12}(?:定时|自动).{0,12}(?:任务|自动化)/u.test(compact) + const wantsList = /(?:查看|看看|列出|我的|有哪些).{0,12}(?:定时|自动).{0,12}(?:任务|自动化)/u.test(compact) || /(?:list|show).{0,12}(?:scheduled|automation).{0,12}tasks/iu.test(compact); if (wantsList) { return { action: 'list_scheduled_tasks' }; diff --git a/scheduled-task-intent.test.mjs b/scheduled-task-intent.test.mjs index 5cc5a51..deaa851 100644 --- a/scheduled-task-intent.test.mjs +++ b/scheduled-task-intent.test.mjs @@ -47,6 +47,7 @@ test('scheduled automation takes precedence over schedule assistant keyword over test('parses cancel and list intents', () => { assert.equal(parseScheduledTaskIntent('取消我的定时任务').action, 'cancel_scheduled_task'); assert.equal(parseScheduledTaskIntent('看看我的定时自动任务').action, 'list_scheduled_tasks'); + assert.equal(parseScheduledTaskIntent('我有哪些定时任务').action, 'list_scheduled_tasks'); }); test('parses one-shot tonight schedule with task spec', () => { diff --git a/wechat/handlers/schedule.mjs b/wechat/handlers/schedule.mjs index 80e00f3..ec91c59 100644 --- a/wechat/handlers/schedule.mjs +++ b/wechat/handlers/schedule.mjs @@ -1,5 +1,6 @@ import { isScheduleIntent, parseScheduleIntent } from '../../schedule-intent.mjs'; import { formatLocalTime, resolveScheduleTimestamp } from '../../schedule-time.mjs'; +import { isScheduledTaskIntent, parseScheduledTaskIntent } from '../../scheduled-task-intent.mjs'; function normalizeHour(value) { const hour = Number(value); @@ -160,6 +161,10 @@ export async function handleWechatScheduleIntent({ logger = console, }) { if (!scheduleService) return null; + const scheduledTaskIntent = parseScheduledTaskIntent(intent.agentText); + if (isScheduledTaskIntent(scheduledTaskIntent)) { + return null; + } const scheduleIntent = await resolveScheduleIntent({ text: intent.agentText, wechatScheduleLlmConfigService, diff --git a/wechat/handlers/schedule.test.mjs b/wechat/handlers/schedule.test.mjs index 4b83275..dbc06e2 100644 --- a/wechat/handlers/schedule.test.mjs +++ b/wechat/handlers/schedule.test.mjs @@ -182,3 +182,35 @@ test('schedule handler falls through for multi-time reminder requests', async () }); assert.equal(reply, null); }); + +test('schedule handler yields cancel scheduled task requests to goose', async () => { + let scheduleCalled = false; + const reply = await handleWechatScheduleIntent({ + intent: { agentText: '取消定时推送苏州天气任务', msgId: 'msg-cancel-1' }, + user: { userId: 'user-123' }, + scheduleService: { + async createItem() { + scheduleCalled = true; + return { id: 'item-1' }; + }, + }, + }); + assert.equal(reply, null); + assert.equal(scheduleCalled, false); +}); + +test('schedule handler yields list scheduled task requests to scheduled-task handler', async () => { + let scheduleCalled = false; + const reply = await handleWechatScheduleIntent({ + intent: { agentText: '我有哪些定时任务', msgId: 'msg-list-1' }, + user: { userId: 'user-123' }, + scheduleService: { + async createItem() { + scheduleCalled = true; + return { id: 'item-1' }; + }, + }, + }); + assert.equal(reply, null); + assert.equal(scheduleCalled, false); +}); diff --git a/wechat/handlers/scheduled-task.test.mjs b/wechat/handlers/scheduled-task.test.mjs index 1b70a1c..bf163ec 100644 --- a/wechat/handlers/scheduled-task.test.mjs +++ b/wechat/handlers/scheduled-task.test.mjs @@ -86,3 +86,20 @@ test('handleWechatScheduledTaskIntent still lists tasks', async () => { }); 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); +});