/** Per-thread tick recurrence, in minutes. The default lines up with * nanobot's 30-min cadence; operators can override per binding with * `/heartbeat interval N` or the AGIM_HEARTBEAT_DEFAULT_INTERVAL env. */ export declare const DEFAULT_INTERVAL_MIN = 30; /** Hard lower bound on the recurrence. 1-minute heartbeats are almost * always a misconfiguration (the agent burns through API calls and * there's no time for the previous tick to even finish). */ export declare const MIN_INTERVAL_MIN = 5; /** Hard upper bound — 24h. Above this just use cron + reminders. */ export declare const MAX_INTERVAL_MIN: number; /** Max characters in a heartbeat body. Keeps prompt size bounded; the * body is the entire context the cheap decide-step LLM sees, so * unbounded text would silently blow the context window. */ export declare const MAX_BODY_CHARS = 8000; /** Tick statuses recorded per attempt. */ export type TickStatus = 'pending' | 'skipped' | 'delivered' | 'suppressed' | 'no-agent' | 'failed'; export interface HeartbeatRow { id: number; /** IM coordinates — the binding scope. */ platform: string; channelId: string; threadId: string; /** Owner of this binding (the IM user who ran /heartbeat bind). Used * for audit and for picking the same agent the user is chatting * with at tick time. */ userId: string; /** Markdown body — what the decide-step LLM and the execute-step * agent reason against. Plain UTF-8; users can include lists, code * fences, whatever they want. Max MAX_BODY_CHARS. */ body: string; /** Tick recurrence (minutes). MIN_INTERVAL_MIN ≤ x ≤ MAX_INTERVAL_MIN. */ intervalMinutes: number; /** Soft kill-switch. Disabled rows survive but never tick. */ enabled: boolean; /** ISO timestamp of the last attempted tick (null = never ticked). */ lastTickAt: string | null; /** Status of that last tick. */ lastStatus: TickStatus; /** Operator-facing one-liner from the last tick. */ lastReason: string; /** First MAX_PREVIEW_CHARS of the last successfully delivered text. */ lastTextPreview: string; createdAt: string; updatedAt: string; } /** Read the operator-provided default interval (env override or constant). */ export declare function defaultIntervalMinutes(): number; /** * Create or replace the heartbeat for a thread. UPSERT semantics — one * binding per thread, calling bind() again overwrites the body and * resets last_tick_at so the new body takes effect on the next tick * (not 30 min later). */ export declare function upsertBinding(input: { platform: string; channelId: string; threadId: string; userId: string; body: string; intervalMinutes?: number; }): HeartbeatRow | null; /** Disable (don't delete) a binding for the given thread. */ export declare function disableBinding(platform: string, channelId: string, threadId: string): boolean; /** Soft-enable an existing binding (no-op if missing). */ export declare function enableBinding(platform: string, channelId: string, threadId: string): boolean; /** Replace the interval for an existing binding (no-op if missing). */ export declare function updateInterval(platform: string, channelId: string, threadId: string, intervalMinutes: number): boolean; /** Stamp the outcome of a tick. Caller is the scheduler / runForBinding. */ export declare function recordTick(input: { id: number; status: TickStatus; reason: string; /** When delivered, the (truncated) body text. Ignored for non-delivered. */ deliveredText?: string; }): void; export declare function getBinding(platform: string, channelId: string, threadId: string): HeartbeatRow | null; /** All bindings, regardless of enabled state. Admin-facing /heartbeat list. */ export declare function listAllBindings(): HeartbeatRow[]; /** * All enabled bindings whose next tick is due. "Due" = `last_tick_at IS * NULL` OR `datetime(last_tick_at) <= datetime('now', '-N minutes')`. * * Each row carries its own interval, so we can't precompute a single * cutoff — the SQL filter checks per-row using interval_minutes. */ export declare function listDueBindings(): HeartbeatRow[]; /** Strictly for tests: drop the table contents. NEVER call from runtime * paths — the alternative is `disableBinding` per row. */ export declare function _truncateForTests(): void; //# sourceMappingURL=heartbeat-store.d.ts.map