import type { CronConfig } from "../../config/types.cron.js"; import type { HeartbeatRunResult, HeartbeatWakeRequest } from "../../infra/heartbeat-wake.js"; import type { CronDeliveryStatus, CronDeliveryTrace, CronJob, CronJobCreate, CronJobPatch, CronRunDiagnostics, CronMessageChannel, CronAgentExecutionStarted, CronRunOutcome, CronRunStatus, CronRunTelemetry, CronStoreFile } from "../types.js"; export type CronEvent = { jobId: string; action: "added" | "updated" | "removed" | "started" | "finished"; /** Snapshot of the job at the time of the event. Present for all actions where the job is accessible. */ job?: CronJob; runAtMs?: number; durationMs?: number; status?: CronRunStatus; error?: string; summary?: string; diagnostics?: CronRunDiagnostics; delivered?: boolean; deliveryStatus?: CronDeliveryStatus; deliveryError?: string; delivery?: CronDeliveryTrace; sessionId?: string; sessionKey?: string; runId?: string; nextRunAtMs?: number; } & CronRunTelemetry; export type Logger = { debug: (obj: unknown, msg?: string) => void; info: (obj: unknown, msg?: string) => void; warn: (obj: unknown, msg?: string) => void; error: (obj: unknown, msg?: string) => void; }; export type CronServiceDeps = { nowMs?: () => number; log: Logger; storePath: string; cronEnabled: boolean; /** CronConfig for session retention settings. */ cronConfig?: CronConfig; /** Default agent id for jobs without an agent id. */ defaultAgentId?: string; /** Resolve session store path for a given agent id. */ resolveSessionStorePath?: (agentId?: string) => string; /** Path to the session store (sessions.json) for reaper use. */ sessionStorePath?: string; /** * Delay in ms between missed job executions on startup. * Prevents overwhelming the gateway when many jobs are overdue. * See: https://github.com/openclaw/openclaw/issues/18892 */ missedJobStaggerMs?: number; /** * Maximum number of missed jobs to run immediately on startup. * Additional missed jobs will be rescheduled to fire gradually. * See: https://github.com/openclaw/openclaw/issues/18892 */ maxMissedJobsPerRestart?: number; /** * Delay before replaying missed agent-turn jobs found during gateway startup. * Keeps model/tool bootstrap work out of the channel connect window. */ startupDeferredMissedAgentJobDelayMs?: number; enqueueSystemEvent: (text: string, opts?: { agentId?: string; sessionKey?: string; contextKey?: string; trusted?: boolean; }) => void; requestHeartbeat: (opts: HeartbeatWakeRequest) => void; runHeartbeatOnce?: (opts?: { source?: HeartbeatWakeRequest["source"]; intent?: HeartbeatWakeRequest["intent"]; reason?: string; agentId?: string; sessionKey?: string; /** Optional heartbeat config override (e.g. target: "last" for cron-triggered heartbeats). */ heartbeat?: { target?: string; }; }) => Promise; /** * WakeMode=now: max time to wait for runHeartbeatOnce to stop returning * { status:"skipped", reason:"requests-in-flight" } before falling back to * requestHeartbeat. */ wakeNowHeartbeatBusyMaxWaitMs?: number; /** WakeMode=now: delay between runHeartbeatOnce retries while busy. */ wakeNowHeartbeatBusyRetryDelayMs?: number; runIsolatedAgentJob: (params: { job: CronJob; message: string; abortSignal?: AbortSignal; onExecutionStarted?: (info?: CronAgentExecutionStarted) => void; }) => Promise<{ summary?: string; /** Last non-empty agent text output (not truncated). */ outputText?: string; /** * `true` when the isolated run already delivered its output to the target * channel (including matching messaging-tool sends). See: * https://github.com/openclaw/openclaw/issues/15692 */ delivered?: boolean; /** * `true` when announce/direct delivery was attempted for this run, even * if the final per-message ack status is uncertain. */ deliveryAttempted?: boolean; delivery?: CronDeliveryTrace; } & CronRunOutcome & CronRunTelemetry>; cleanupTimedOutAgentRun?: (params: { job: CronJob; timeoutMs: number; execution?: CronAgentExecutionStarted; }) => Promise; sendCronFailureAlert?: (params: { job: CronJob; text: string; channel: CronMessageChannel; to?: string; mode?: "announce" | "webhook"; accountId?: string; }) => Promise; onEvent?: (evt: CronEvent) => void; }; export type CronServiceDepsInternal = Omit & { nowMs: () => number; }; export type CronServiceState = { deps: CronServiceDepsInternal; store: CronStoreFile | null; timer: NodeJS.Timeout | null; running: boolean; op: Promise; warnedDisabled: boolean; /** * Job ids whose missing `sessionTarget` was defaulted at load and warned * about. Used to suppress duplicate warns across forceReload ticks so a * single broken job does not spam the log on every scheduler cycle. */ warnedMissingSessionTargetJobIds: Set; storeLoadedAtMs: number | null; storeFileMtimeMs: number | null; }; export declare function createCronServiceState(deps: CronServiceDeps): CronServiceState; export type CronRunMode = "due" | "force"; export type CronWakeMode = "now" | "next-heartbeat"; export type CronStatusSummary = { enabled: boolean; storePath: string; jobs: number; nextWakeAtMs: number | null; }; export type CronRunResult = { ok: true; ran: true; } | { ok: true; enqueued: true; runId: string; } | { ok: true; ran: false; reason: "not-due"; } | { ok: true; ran: false; reason: "already-running"; } | { ok: false; }; export type CronRemoveResult = { ok: true; removed: boolean; } | { ok: false; removed: false; }; export type CronAddResult = CronJob; export type CronUpdateResult = CronJob; export type CronListResult = CronJob[]; export type CronAddInput = CronJobCreate; export type CronUpdateInput = CronJobPatch;