Files
clawdbot/docs/heartbeat.md
2025-12-05 17:50:02 +00:00

46 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Heartbeat polling plan (2025-11-26)
Goal: add a simple heartbeat poll for command-based auto-replies (Pi/Tau) that only notifies users when something matters, using the `HEARTBEAT_OK` sentinel. The heartbeat body we send is `HEARTBEAT /think:high` so the model can easily spot it.
## Prompt contract
- Extend the Pi/Tau system/identity text to explain: “If this is a heartbeat poll and nothing needs attention, reply exactly `HEARTBEAT_OK` and nothing else. For any alert, do **not** include `HEARTBEAT_OK`; just return the alert text.” Heartbeat prompt body is `HEARTBEAT /think:high`.
- Keep existing WhatsApp length guidance; forbid burying the sentinel inside alerts.
## Config & defaults
- New config key: `inbound.reply.heartbeatMinutes` (number of minutes; `0` or undefined disables).
- Default: 30 minutes when a command-mode reply is configured.
- New optional idle override for heartbeats: `inbound.reply.session.heartbeatIdleMinutes` (defaults to `idleMinutes`). Heartbeat skips do **not** update the session `updatedAt` so idle expiry still works.
## Poller behavior
- When relay runs with command-mode auto-reply, start a timer with the resolved heartbeat interval.
- Each tick invokes the configured command with a short heartbeat body (e.g., “(heartbeat) summarize any important changes since last turn”) while reusing the active session args so Pi context stays warm.
- Heartbeats never create a new session implicitly: if theres no stored session for the target (fallback path), the heartbeat is skipped instead of starting a fresh Pi session.
- Abort timer on SIGINT/abort of the relay.
## Sentinel handling
- Trim output. If the trimmed text equals `HEARTBEAT_OK` (case-sensitive) -> skip outbound message.
- Otherwise, send the text/media as normal, stripping the sentinel if it somehow appears.
- Treat empty output as `HEARTBEAT_OK` to avoid spurious pings.
## Logging requirements
- Normal mode: single info line per tick, e.g., `heartbeat: ok (skipped)` or `heartbeat: alert sent (32ms)`.
- `--verbose`: log start/end, command argv, duration, and whether it was skipped/sent/error; include session ID and connection/run IDs via `getChildLogger` for correlation.
- On command failure: warn-level one-liner in normal mode; verbose log includes stdout/stderr snippets.
## Failure/backoff
- If a heartbeat command errors, log it and retry on the next scheduled tick (no exponential backoff unless command repeatedly fails; keep it simple for now).
## Tests to add
- Unit: sentinel detection (`HEARTBEAT_OK`, empty output, mixed text), skip vs send decision, default interval resolver (30m, override, disable).
- Unit/integration: verbose logger emits start/end lines; normal logger emits a single line.
## Documentation
- Add a short README snippet under configuration showing `heartbeatMinutes` and the sentinel rule.
- Expose CLI triggers:
- `warelay heartbeat` (web provider, defaults to first `allowFrom`; optional `--to` override)
- `--session-id <uuid>` forces resuming a specific session for that heartbeat
- `warelay relay:heartbeat` to run the relay loop with an immediate heartbeat (no tmux)
- `warelay relay:heartbeat:tmux` to run the same in tmux (detached, attachable)
- Relay supports `--heartbeat-now` to fire once at startup (including the tmux helper).
- When multiple sessions are active or `allowFrom` is only `"*"`, require `--to <E.164>` or `--all` for manual heartbeats to avoid ambiguous targets.