fix(wechat): cancel sole active scheduled task in inbound without Goose

When a user has exactly one active automation task, cancel it by taskId
after listTasks instead of relying on Goose when the LLM provider fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-29 12:36:19 +08:00
parent 43ec144540
commit d8463829f7
4 changed files with 69 additions and 6 deletions
+21 -4
View File
@@ -1,4 +1,5 @@
import {
formatScheduledTaskCancelReply,
formatScheduledTaskListReply,
isScheduledTaskIntent,
parseScheduledTaskIntent,
@@ -29,10 +30,26 @@ export async function handleWechatScheduledTaskIntent({
return formatScheduledTaskListReply(tasks);
}
if (
taskIntent.action === 'create_scheduled_task'
|| taskIntent.action === 'cancel_scheduled_task'
) {
if (taskIntent.action === 'create_scheduled_task') {
return null;
}
if (taskIntent.action === 'cancel_scheduled_task') {
const tasks = await scheduledTaskService.listTasks({
userId: user.userId,
status: 'active',
limit: 20,
});
if (!tasks.length) {
return '你当前没有进行中的定时自动任务。';
}
if (tasks.length === 1) {
const cancelled = await scheduledTaskService.cancelTask({
userId: user.userId,
taskId: tasks[0].id,
});
return formatScheduledTaskCancelReply(cancelled);
}
return null;
}
} catch (err) {
+42 -2
View File
@@ -36,7 +36,8 @@ test('handleWechatScheduledTaskIntent passes incomplete create requests to goose
assert.equal(reply, null);
});
test('handleWechatScheduledTaskIntent passes cancel requests to goose', async () => {
test('handleWechatScheduledTaskIntent cancels the only active task in inbound', async () => {
const calls = [];
const reply = await handleWechatScheduledTaskIntent({
intent: {
msgType: 'text',
@@ -45,8 +46,47 @@ test('handleWechatScheduledTaskIntent passes cancel requests to goose', async ()
},
user: { userId: 'user-123' },
scheduledTaskService: {
async listTasks() {
return [{
id: 'task-1',
title: '每天早上6:30推送苏州市天气预报',
recurrence: 'daily',
hour: 6,
minute: 30,
timezone: 'Asia/Shanghai',
}];
},
async cancelTask(payload) {
calls.push(payload);
return {
id: 'task-1',
title: '每天早上6:30推送苏州市天气预报',
status: 'cancelled',
};
},
},
});
assert.match(reply, /已取消定时任务/u);
assert.deepEqual(calls, [{ userId: 'user-123', taskId: 'task-1' }]);
});
test('handleWechatScheduledTaskIntent passes cancel to goose when multiple active tasks', 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 regex');
throw new Error('should not cancel from inbound when ambiguous');
},
},
});