/** * Task 1378 — agent-bearing scheduled dispatch. * * When a due `:Event` carries an agent dispatch (`agentChannel`/ * `agentDestination`/`agentPrompt`) instead of a tool-only `action`, the * heartbeat POSTs the prompt to the UI server's loopback inject route rather * than spawning an MCP tool. The route builds a synthetic admin inbound so the * normal channel spawn/resume/reply machine runs the turn. This module owns the * routing decision and the POST + node-recording, kept out of the script's * `main()` so it is unit-testable without executing the heartbeat. */ import { type Driver } from "neo4j-driver"; export type DispatchMode = { kind: "agent"; channel: string; destination: string; prompt: string; } | { kind: "action"; plugin: string; tool: string; args: string | null; } | { kind: "none"; }; /** * Decide how a due event dispatches from its selected node fields. An event * carries at most one mode (enforced at write); agent dispatch takes precedence * so a malformed both-set node still routes deterministically. */ export declare function chooseDispatchMode(fields: { agentChannel: string | null; agentDestination: string | null; agentPrompt: string | null; actionPlugin: string | null; actionTool: string | null; actionArgs: string | null; }): DispatchMode; /** * Fire an agent-bearing dispatch: POST the prompt to the UI server's loopback * inject route and record the outcome on the `:Event` node exactly as * `dispatchAction` does (`lastDispatchResult`/`lastDispatchAt` + a note). On the * recurring path `nextRun` has already been advanced by the caller; it is * passed here only for the log line. Never throws — a POST/Neo4j failure is * recorded, not propagated, so one event never aborts the sweep. */ export declare function dispatchAgentTurn(eventId: string, channel: string, destination: string, prompt: string, eventAccountId: string, nextRun: string | null, createdByTool: string | null, accountsDir: string, driver: Driver): Promise; /** * The no-event detector. Each heartbeat tick, over every agent-dispatch event * for a local account, re-checks the destination binding against the current * channel config so a destination removed from the house's * `adminPhones`/`accountManagers` out of band — a manager rebound to another * sub-account, or a manager whose sub-account was deleted — is surfaced before * the next fire silently mis-dispatches. It applies the SAME two-part rule * (`validateAgentDestination`) create-time validation uses, so a schedule that * passed creation but later drifts is explained with the identical reason codes * rather than silently dropped (Task 1439). Independent of any inbound: it reads * the node and the on-disk house config, nothing else. Emits one * `[schedule-audit] op=stale-dispatch` line per invalid binding; a healthy * binding emits nothing. Never throws (honours the sweep's contract). */ export declare function runStandingAudit(driver: Driver, localAccountIds: string[], accountsDir: string): Promise; /** * Task 1516 — the standing self-cancel alarm. Independent of any inbound and of * the stale-dispatch audit: each tick it counts agent-dispatch events that a * scheduler-dispatched seat cancelled in the trailing 24h window, read from the * `cancelledByOwnDispatchAt` stamp that `scheduleCancel` writes when it detects a * self-cancel (byOwnDispatch=true). Deterministic — the stamp records the exact * fact at cancel time, so this reconcile needs no seat SESSION_ID and no timing * heuristic. Emits `[sched-guard] op=audit cancelledByDispatch=` ONLY when the * count is nonzero; the line's presence IS the alarm (the loop the operator would * otherwise have to notice by hand). `nowMs` is injected for testability. Never * throws (honours the sweep contract). */ export declare function auditSelfCancels(driver: Driver, localAccountIds: string[], nowMs: number): Promise; //# sourceMappingURL=agent-turn-dispatch.d.ts.map