import type { JobFrontmatter, JobFrontmatterPatch } from "./frontmatter.js"; /** * Failures a retry cannot fix because something the automation depends on is * absent. They are typed outcomes of their own, never folded into a generic * "errored", so the owner sees the real cause and the scheduler can stop * re-failing every tick. * * Most are caught before a run starts. `connection_required` is only known * after the run has yielded to a connection request, so every failed attempt * already has a thread. It skips the runtime backoff like the rest, pauses * after `PRECONDITION_PAUSE_AFTER` identical failures, and the pause is not * transient: it lasts until the owner enables the automation again. */ export declare const AUTOMATION_PRECONDITION_CODES: readonly ["missing_credentials", "missing_tools", "owner_missing", "owner_reserved", "config_invalid", "connection_required"]; export type AutomationPreconditionCode = (typeof AUTOMATION_PRECONDITION_CODES)[number]; export declare const MISSING_TOOLS_ERROR_CODE = "missing_tools"; export declare const CONNECTION_REQUIRED_ERROR_CODE = "connection_required"; export declare const OWNER_MISSING_ERROR_CODE = "owner_missing"; export declare const OWNER_RESERVED_ERROR_CODE = "owner_reserved"; export declare const CONFIG_INVALID_ERROR_CODE = "config_invalid"; export declare const BACKGROUND_AUTOMATION_FAILED_ERROR_CODE = "background_automation_failed"; /** Consecutive identical precondition failures before the automation pauses. */ export declare const PRECONDITION_PAUSE_AFTER = 3; /** Ordinary runtime errors may be transient, so they get more attempts. */ export declare const RUNTIME_PAUSE_AFTER = 5; export declare function isAutomationPreconditionCode(code: string | null | undefined): code is AutomationPreconditionCode; /** * A code that says the LLM credential is absent, rejected, or not allowed: * only a person reconnecting or an admin granting it fixes it, so retrying is * pointless. A spent quota (`exhausted`) heals on its own and is not one, and * a bare HTTP status (a gateway wave also returns them) does not name the * credential as the cause. */ export declare function isCredentialPreconditionCode(code: string | null | undefined): boolean; /** * An absent credential: connecting one is the whole fix, so a pause for it * resumes as soon as one is usable. A rejected or forbidden credential is not * one: its rejection marker expires on a timer while the key stays bad, so it * stays paused until the owner enables the automation again. */ export declare function isMissingCredentialCode(code: string | null | undefined): boolean; /** * Failures of the platform or a provider rather than of the automation: spent * credits, an unreadable credential store, a remote host, rate limits and 5xx. * They pause like any runtime failure, but the pause lifts itself on a timed * probe, so a fleet incident or a credit reset never leaves automations off. */ export declare function isTransientAutomationFailureCode(code: string | null | undefined): boolean; export interface AutomationFailure { deliveryNote?: string; /** Typed code persisted as `lastErrorCode` and the run's `error_code`. */ code: string; /** The real cause, never a generic status sentence. */ message: string; precondition: boolean; } export declare function classifyAutomationFailure(error: unknown): AutomationFailure; export type AutomationOwnerKind = "user" | "organization" | "shared"; export declare function automationOwnerKind(owner: string): AutomationOwnerKind; /** `__shared__` / `__organization__:` are scopes, not people. */ export declare function isPseudoOwner(owner: string): boolean; /** * QA fixtures such as `qa-*@local.test` are expected on local and beta * deployments; in production they only burn LLM runs against real sinks. */ export declare function isReservedIdentityBlocked(email: string): boolean; export declare function reservedIdentityMessage(email: string): string; export interface FailureTransition { consecutiveFailures: number; pause: boolean; /** Fields to persist on the job's frontmatter. */ patch: JobFrontmatterPatch; } /** * A pause the framework applied and the owner has since lifted by enabling * the job again. Any writer that flips `enabled` leaves the old pause fields * behind, so they are read as stale instead of being trusted. */ export declare function hasStalePause(meta: Pick): boolean; export declare function isPausedByFramework(meta: Pick): boolean; export declare function pausedMessage(code: string, count: number, message: string, deliveryNote?: string): string; /** The cause first, then the delivery note owners already know. */ export declare function withDeliveryNote(message: string, deliveryNote?: string): string; /** * The one place a failure becomes persisted state. `countTowardPause: false` * (a manual run) records the real cause without moving the streak, so asking * for a run never pauses the automation. `eventId` keys the streak on the * event: a queue or webhook retry of an event already counted records its * cause without counting again, so one bad event cannot pause by itself. */ export declare function applyAutomationFailure(meta: Pick, failure: AutomationFailure, now: Date, options?: { countTowardPause?: boolean; eventId?: string; }): FailureTransition; /** * A failure that happens before any run starts (owner gone, reserved * identity): nothing to retry, so it pauses on the first observation. */ export declare function pauseNow(failure: AutomationFailure, now: Date): FailureTransition; /** Fields that clear every trace of a past failure or pause. */ export declare const CLEAR_FAILURE_STATE: JobFrontmatterPatch; /** The owner enabled the job again: it starts from a clean slate. */ export declare const RESUME_AUTOMATION_PATCH: JobFrontmatterPatch; /** * Exponential backoff for repeated runtime failures, so an automation that * keeps failing is attempted at a widening interval before it pauses. * Preconditions are not backed off: they pause on their own. */ export declare function runtimeFailureNextRun(cronNext: Date, now: Date, consecutiveFailures: number): Date; /** * A transient pause is probed on the same widening backoff (capped at 6h) * that spaced the failures before it, counted from when it paused. */ export declare function isTransientPauseProbeDue(meta: Pick, now: Date): boolean; /** * Lifts a transient pause for one probe. The streak and its code stay, so a * probe that fails the same way pauses again at once (and the existing alert * chain keeps that quiet); a probe that succeeds clears everything. */ export declare const TRANSIENT_PROBE_RESUME_PATCH: JobFrontmatterPatch;