mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-08 06:54:24 +00:00
fix(heartbeat): return false for zero-width active-hours window (#21408)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 993860bd03
Co-authored-by: adhitShet <131381638+adhitShet@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- Heartbeat/Cron: restore interval heartbeat behavior so missing `HEARTBEAT.md` no longer suppresses runs (only effectively empty files skip), preserving prompt-driven and tagged-cron execution paths.
|
||||
- Heartbeat/Active hours: constrain active-hours `24` sentinel parsing to `24:00` in time validation so invalid values like `24:30` are rejected early. (#21410) thanks @adhitShet.
|
||||
- Heartbeat: treat `activeHours` windows with identical `start`/`end` times as zero-width (always outside the window) instead of always-active. (#21408) thanks @adhitShet.
|
||||
- Gateway/Pairing: tolerate legacy paired devices missing `roles`/`scopes` metadata in websocket upgrade checks and backfill metadata on reconnect. (#21447, fixes #21236) Thanks @joshavant.
|
||||
- Docker: pin base images to SHA256 digests in Docker builds to prevent mutable tag drift. (#7734) Thanks @coygeek.
|
||||
- Provider/HTTP: treat HTTP 503 as failover-eligible for LLM provider errors. (#21086) Thanks @Protocol-zero-0.
|
||||
|
||||
@@ -163,6 +163,16 @@ Restrict heartbeats to business hours in a specific timezone:
|
||||
|
||||
Outside this window (before 9am or after 10pm Eastern), heartbeats are skipped. The next scheduled tick inside the window will run normally.
|
||||
|
||||
### 24/7 setup
|
||||
|
||||
If you want heartbeats to run all day, use one of these patterns:
|
||||
|
||||
- Omit `activeHours` entirely (no time-window restriction; this is the default behavior).
|
||||
- Set a full-day window: `activeHours: { start: "00:00", end: "24:00" }`.
|
||||
|
||||
Do not set the same `start` and `end` time (for example `08:00` to `08:00`).
|
||||
That is treated as a zero-width window, so heartbeats are always skipped.
|
||||
|
||||
### Multi account example
|
||||
|
||||
Use `accountId` to target a specific account on multi-account channels like Telegram:
|
||||
@@ -210,10 +220,11 @@ Use `accountId` to target a specific account on multi-account channels like Tele
|
||||
- `prompt`: overrides the default prompt body (not merged).
|
||||
- `ackMaxChars`: max chars allowed after `HEARTBEAT_OK` before delivery.
|
||||
- `suppressToolErrorWarnings`: when true, suppresses tool error warning payloads during heartbeat runs.
|
||||
- `activeHours`: restricts heartbeat runs to a time window. Object with `start` (HH:MM, inclusive), `end` (HH:MM exclusive; `24:00` allowed for end-of-day), and optional `timezone`.
|
||||
- `activeHours`: restricts heartbeat runs to a time window. Object with `start` (HH:MM, inclusive; use `00:00` for start-of-day), `end` (HH:MM exclusive; `24:00` allowed for end-of-day), and optional `timezone`.
|
||||
- Omitted or `"user"`: uses your `agents.defaults.userTimezone` if set, otherwise falls back to the host system timezone.
|
||||
- `"local"`: always uses the host system timezone.
|
||||
- Any IANA identifier (e.g. `America/New_York`): used directly; if invalid, falls back to the `"user"` behavior above.
|
||||
- `start` and `end` must not be equal for an active window; equal values are treated as zero-width (always outside the window).
|
||||
- Outside the active window, heartbeats are skipped until the next tick inside the window.
|
||||
|
||||
## Delivery behavior
|
||||
|
||||
@@ -39,7 +39,7 @@ describe("isWithinActiveHours", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("returns true when activeHours start equals end", () => {
|
||||
it("returns false when activeHours start equals end", () => {
|
||||
const cfg = cfgWithUserTimezone("UTC");
|
||||
expect(
|
||||
isWithinActiveHours(
|
||||
@@ -47,7 +47,7 @@ describe("isWithinActiveHours", () => {
|
||||
heartbeatWindow("08:00", "08:00", "UTC"),
|
||||
Date.UTC(2025, 0, 1, 12, 0, 0),
|
||||
),
|
||||
).toBe(true);
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("respects user timezone windows for normal ranges", () => {
|
||||
|
||||
@@ -83,7 +83,7 @@ export function isWithinActiveHours(
|
||||
return true;
|
||||
}
|
||||
if (startMin === endMin) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const timeZone = resolveActiveHoursTimezone(cfg, active.timezone);
|
||||
|
||||
Reference in New Issue
Block a user