diff --git a/extensions/qqbot/src/engine/tools/remind-logic.test.ts b/extensions/qqbot/src/engine/tools/remind-logic.test.ts index aa7f10f8ae1..a870f740569 100644 --- a/extensions/qqbot/src/engine/tools/remind-logic.test.ts +++ b/extensions/qqbot/src/engine/tools/remind-logic.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { parseRelativeTime, isCronExpression, @@ -12,6 +12,10 @@ import { } from "./remind-logic.js"; describe("engine/tools/remind-logic", () => { + afterEach(() => { + vi.useRealTimers(); + }); + describe("parseRelativeTime", () => { it("parses minutes shorthand", () => { expect(parseRelativeTime("5m")).toBe(5 * 60_000); @@ -299,5 +303,20 @@ describe("engine/tools/remind-logic", () => { action: "remove", }); }); + + it("rejects relative reminders whose scheduled time exceeds the Date range", () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date(8_640_000_000_000_000)); + + const plan = prepareRemindCronAction( + { action: "add", content: "test reminder", to: "qqbot:c2c:123", time: "5m" }, + {}, + ); + + expect(plan).toEqual({ + ok: false, + error: "Reminder time is outside the supported Date range", + }); + }); }); }); diff --git a/extensions/qqbot/src/engine/tools/remind-logic.ts b/extensions/qqbot/src/engine/tools/remind-logic.ts index 701483d1d19..bdc79f68812 100644 --- a/extensions/qqbot/src/engine/tools/remind-logic.ts +++ b/extensions/qqbot/src/engine/tools/remind-logic.ts @@ -1,3 +1,5 @@ +import { resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime"; + /** * QQBot reminder tool core logic. * QQBot 提醒工具核心逻辑。 @@ -186,8 +188,7 @@ export function buildReminderPrompt(content: string): string { } /** Build cron job params for a one-shot delayed reminder. */ -function buildOnceJob(params: RemindParams, delayMs: number, to: string, accountId: string) { - const atMs = Date.now() + delayMs; +function buildOnceJob(params: RemindParams, atMs: number, to: string, accountId: string) { const content = params.content!; const name = params.name || generateJobName(content); return { @@ -322,11 +323,15 @@ export function prepareRemindCronAction( if (delayMs < 30_000) { return { ok: false, error: "Reminder delay must be at least 30 seconds" }; } + const atMs = resolveExpiresAtMsFromDurationMs(delayMs); + if (atMs === undefined) { + return { ok: false, error: "Reminder time is outside the supported Date range" }; + } return { ok: true, action: "add", - cronAction: buildOnceJob(params, delayMs, resolvedTo, resolvedAccountId), + cronAction: buildOnceJob(params, atMs, resolvedTo, resolvedAccountId), summary: `⏰ Reminder in ${formatDelay(delayMs)}: "${params.content}"`, }; }