import { formatUnifiedTaskListReply } from './task-unified-service.mjs'; function normalizeCompact(text) { return String(text ?? '').replace(/\s+/g, '').trim(); } /** Layer 0: 只读查询,禁止 Draft / Commit */ export function detectQueryGuard(text) { const compact = normalizeCompact(text); if (!compact) return false; if (/看看我的待办/u.test(compact)) return true; if (/查看我的(?:待办|日程|行程|计划)/u.test(compact)) return true; if (/(?:列出|看看).{0,8}(?:定时|自动).{0,8}任务/u.test(compact)) return true; if (/(?:有没有|是否有).{0,16}(?:定时|自动).{0,8}任务/u.test(compact)) return true; if (/(?:取消|停止|关闭|删除).{0,8}(?:定时|提醒|任务)/u.test(compact)) return false; const queryCue = /(?:查一下|查询|看看有没有|有没有(?!新的)|是否有|是否已有|是否还在|是否设置|我有哪些|有哪些提醒|有没有执行|有没有设置)/u.test(compact); const createCue = /(?:帮我设置|请设置|创建|添加|记一下|设个|设一个|每天|每日|帮我每天|到点提醒)/u.test(compact) || (/(?:定时任务|自动任务)/u.test(compact) && !queryCue); if (queryCue && !createCue) return true; if (/^查/u.test(compact) && /(?:任务|提醒|定时)/u.test(compact) && !/(?:设置|创建)/u.test(compact)) return true; return false; } export async function formatQueryGuardReply(text, { scheduleService, scheduledTaskService, taskUnifiedService = null, userId, timezone = 'Asia/Shanghai', env = process.env, } = {}) { const compact = normalizeCompact(text); if (/待办/u.test(compact) && scheduleService?.buildTodoDigestText) { return scheduleService.buildTodoDigestText({ userId, timezone }); } if (/(?:定时|自动).{0,8}任务/u.test(compact)) { if (taskUnifiedService?.listUserTasks) { const tasks = await taskUnifiedService.listUserTasks({ userId, status: 'active', limit: 10, timezone }); return formatUnifiedTaskListReply(tasks, { timezone }); } if (scheduledTaskService?.listTasks) { const tasks = await scheduledTaskService.listTasks({ userId, status: 'active', limit: 10 }); return formatScheduledTaskListReply(tasks); } } return '这是查询请求,我不会新建或修改任何提醒/任务。如需设置,请直接说「下午 2 点半提醒我开会」或「每天 6 点帮我做新闻页面」。'; } function formatScheduledTaskListReply(tasks) { if (!tasks?.length) return '你当前没有进行中的定时自动任务。'; const lines = ['你的定时自动任务:']; for (const task of tasks.slice(0, 10)) { const when = task.recurrence === 'once' ? new Date(Number(task.nextRunAt)).toLocaleString('zh-CN', { timeZone: task.timezone || 'Asia/Shanghai', hour12: false }) : `${String(task.hour).padStart(2, '0')}:${String(task.minute ?? 0).padStart(2, '0')}`; lines.push(`- ${task.title}(${task.recurrence} ${when})`); } return lines.join('\n'); }