feat(v2): add update_task MCP tool, dedup list_tasks by series

update_task lets the agent adjust prompt/recurrence/processAfter/script
on a live scheduled task without losing the series id the user already
knows. Empty string clears recurrence/script.

list_tasks now groups by series_id so recurring tasks show as one row
(the live pending/paused occurrence) instead of one per firing — the
id displayed is the stable series handle that update/cancel/pause/resume
all match against.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
exe.dev user
2026-04-16 16:30:00 +00:00
committed by Daniel
parent 8ef30ad289
commit cdf18e608f
7 changed files with 276 additions and 7 deletions

View File

@@ -33,6 +33,7 @@ import {
cancelTask,
pauseTask,
resumeTask,
updateTask,
} from './db/session-db.js';
import { log } from './log.js';
import { normalizeOptions, type RawOption } from './channels/ask-question.js';
@@ -656,6 +657,25 @@ async function handleSystemAction(
break;
}
case 'update_task': {
const taskId = content.taskId as string;
const update: Parameters<typeof updateTask>[2] = {};
if (typeof content.prompt === 'string') update.prompt = content.prompt;
if (typeof content.processAfter === 'string') update.processAfter = content.processAfter;
if (content.recurrence === null || typeof content.recurrence === 'string') {
update.recurrence = content.recurrence as string | null;
}
if (content.script === null || typeof content.script === 'string') {
update.script = content.script as string | null;
}
const touched = updateTask(inDb, taskId, update);
log.info('Task updated', { taskId, touched, fields: Object.keys(update) });
if (touched === 0) {
notifyAgent(session, `update_task: no live task matched id "${taskId}".`);
}
break;
}
case 'create_agent': {
const requestId = content.requestId as string;
const name = content.name as string;