Fix recurring 30s cron normalization and guidance

This commit is contained in:
ilya-bov
2026-03-06 16:21:06 +03:00
parent 70d2bf6fb6
commit d4f51bdd8b
2 changed files with 49 additions and 2 deletions

View File

@@ -190,12 +190,40 @@ function normalizeScheduleFromRecord(input: UnknownRecord): CronSchedule | null
: input;
const rawKind = readString(scheduleRaw.kind)?.toLowerCase();
const scheduleKindHint = readString(scheduleRaw.scheduleKind)?.toLowerCase();
const explicitEveryKind = rawKind === "every" || scheduleKindHint === "every";
const at =
readString(scheduleRaw.at) ??
readString(scheduleRaw.scheduleAt) ??
readString(scheduleRaw.runAt) ??
readString(scheduleRaw.when);
const everyMs = readNumber(scheduleRaw.everyMs);
const everyMsDirect =
readNumber(scheduleRaw.everyMs) ??
readNumber(scheduleRaw.intervalMs) ??
readNumber(scheduleRaw.repeatMs);
const everySeconds =
readNumber(scheduleRaw.everySeconds) ??
readNumber(scheduleRaw.intervalSeconds) ??
readNumber(scheduleRaw.repeatSeconds) ??
(explicitEveryKind ? readNumber(scheduleRaw.seconds) : undefined);
const everyMinutes =
readNumber(scheduleRaw.everyMinutes) ??
readNumber(scheduleRaw.intervalMinutes) ??
readNumber(scheduleRaw.repeatMinutes);
const everyHours =
readNumber(scheduleRaw.everyHours) ??
readNumber(scheduleRaw.intervalHours) ??
readNumber(scheduleRaw.repeatHours);
const everyMs =
typeof everyMsDirect === "number" && everyMsDirect > 0
? everyMsDirect
: typeof everySeconds === "number" && everySeconds > 0
? everySeconds * 1_000
: typeof everyMinutes === "number" && everyMinutes > 0
? everyMinutes * 60_000
: typeof everyHours === "number" && everyHours > 0
? everyHours * 3_600_000
: undefined;
const anchorMs = readNumber(scheduleRaw.anchorMs);
const expr = readString(scheduleRaw.expr) ?? readString(scheduleRaw.cronExpr);
const tz = readString(scheduleRaw.tz) ?? readString(scheduleRaw.cronTz);
@@ -209,7 +237,7 @@ function normalizeScheduleFromRecord(input: UnknownRecord): CronSchedule | null
? "every"
: expr
? "cron"
: readString(scheduleRaw.scheduleKind)?.toLowerCase();
: scheduleKindHint;
if (kind === "at" && at) {
return { kind: "at", at };
@@ -244,6 +272,16 @@ function normalizeScheduleFromRecord(input: UnknownRecord): CronSchedule | null
: typeof delaySeconds === "number" && delaySeconds > 0
? delaySeconds * 1_000
: 0;
if (kind === "every" && totalMs > 0) {
return {
kind: "every",
everyMs: Math.max(1, Math.floor(totalMs)),
anchorMs:
typeof anchorMs === "number" && Number.isFinite(anchorMs)
? Math.max(0, Math.floor(anchorMs))
: undefined,
};
}
if (totalMs > 0) {
return { kind: "at", at: new Date(Date.now() + totalMs).toISOString() };
}
@@ -323,6 +361,9 @@ function explainAddInputFailure(source: UnknownRecord): string {
problems.push(
"Example: {\"action\":\"add\",\"delaySeconds\":30,\"message\":\"Отправь пользователю: привет\"}"
);
problems.push(
"Recurring example: {\"action\":\"add\",\"schedule\":{\"kind\":\"every\",\"everyMs\":30000},\"payload\":{\"kind\":\"agentTurn\",\"message\":\"Отправь пользователю: привет\"}}"
);
return problems.join(" ");
}

View File

@@ -5,8 +5,10 @@ When the user asks to "remind later", "через N минут/секунд", "
Rules:
- For one-time reminders: use `action="add"` with `schedule.kind="at"` and ISO timestamp.
- For recurring reminders: use `schedule.kind="every"` or `schedule.kind="cron"`.
- For sub-minute recurring reminders, use `schedule.kind="every"` with `everyMs` (example: 30s -> `everyMs=30000`).
- Put the actual reminder text/instruction in `payload.message`.
- Do not send raw natural-language text as the job definition; always send structured fields (`schedule` + `payload` or `delaySeconds` + `message`).
- `delaySeconds` / `delayMs` are one-shot delays and should not be used for recurring jobs.
- If cron returns a preflight validation error, immediately retry once with normalized args (`action="add"`, explicit `schedule`, explicit `payload.message`) and do not repeat identical invalid arguments.
- After creating a job, report `id`, schedule, and expected next run time.
- For management requests, use:
@@ -32,3 +34,7 @@ Examples:
- `action="add"`
- `schedule={ "kind":"cron", "expr":"47 19 * * *" }`
- `payload={ "kind":"agentTurn", "message":"Отправь пользователю: прогноз погоды в Москве" }`
- Every 30 seconds:
- `action="add"`
- `schedule={ "kind":"every", "everyMs":30000 }`
- `payload={ "kind":"agentTurn", "message":"Отправь пользователю: Привет!" }`