import type { AiUtils } from "@cargo-ai/types"; import { type Token } from "../core.js"; import { type AgentRef, type ConnectorActionRef, type ConnectorRef, type FolderRef, type ModelRef, type ToolRef, type WorkflowRef } from "../refs.js"; import type { ConnectorActionInput, Templated } from "./actions.js"; import type { AgentHandle } from "./agent.js"; import type { ConnectorHandle } from "./connector.js"; import type { Filter } from "./filter.js"; import type { FolderHandle } from "./folder.js"; import type { ModelHandle } from "./model.js"; import type { PlayHandle } from "./play.js"; import type { ToolHandle } from "./tool.js"; export type AlertSpansScopeSpec = { kind: "spans"; /** * Restrict to one workflow: a play / tool handle, or `workflowRef(uuid)` for * a workflow not authored in code. Not `toolRef`/`agentRef`: those carry the * tool / agent row uuid, which is not the uuid spans are keyed by. */ workflow?: PlayHandle | ToolHandle | WorkflowRef; /** * Restrict to the spans of runs this agent spawned — an agent handle or * `agentRef(uuid)`. An agent is not backed by a workflow, so this is how an * agent-triggered alert scopes; it is distinct from `agent` below, which * matches an agent *node* inside the watched spans. */ parentAgent?: AgentHandle | AgentRef; nodeKind?: "native" | "connector" | "tool" | "agent" | "worker" | "capability" | "autocomplete" | "harness" | "mcpServer"; integration?: string; /** Restrict to one connector — a connector handle or `connectorRef(uuid)`. */ connector?: ConnectorHandle | ConnectorRef; action?: string; /** Restrict to one tool — a tool handle or `toolRef(uuid)`. */ tool?: ToolHandle | ToolRef; /** Restrict to one agent *node* — an agent handle or `agentRef(uuid)`. */ agent?: AgentHandle | AgentRef; /** * Match spans whose execution title or error message contains this text * (case-insensitive) — the Spans view search. */ executionTitleOrErrorMessage?: string; /** Restrict to spans with these execution statuses. */ executionStatuses?: ("pending" | "success" | "error")[]; /** Restrict to spans of runs started by this user (uuid). */ userUuid?: string; }; export type AlertRunsScopeSpec = { kind: "runs"; /** * Restrict to one workflow: a play / tool handle, or `workflowRef(uuid)` for * a workflow not authored in code. Omitted watches every play and tool. */ workflow?: PlayHandle | ToolHandle | WorkflowRef; /** Restrict to runs in these statuses. */ statuses?: ("idle" | "pending" | "running" | "success" | "error" | "cancelling" | "cancelled" | "skipped")[]; /** * Match runs whose record title or error message contains this text * (case-insensitive). Same as the run list search. */ recordTitleOrErrorMessage?: string; /** Restrict to runs of one release (uuid); releases are not authored in code. */ releaseUuid?: string; /** Restrict to runs started by this user (uuid). */ userUuid?: string; }; export type AlertRecordsScopeSpec = { kind: "records"; /** * Restrict to one workflow: a play / tool handle, or `workflowRef(uuid)` for * a workflow not authored in code. Omitted watches every play and tool. */ workflow?: PlayHandle | ToolHandle | WorkflowRef; /** Restrict to records in these statuses; a record is never idle or skipped. */ statuses?: ("pending" | "running" | "success" | "error" | "cancelling" | "cancelled")[]; /** * Match records whose title or error message contains this text * (case-insensitive). Same as the record list search. */ titleOrErrorMessage?: string; /** Restrict to records of one release (uuid); releases are not authored in code. */ releaseUuid?: string; /** Restrict to records started by this user (uuid). */ userUuid?: string; }; export type AlertOrchestrationQueryScopeSpec = { kind: "orchestrationQuery"; /** Read-only ClickHouse SQL over `spans`, `runs`, `batches` and `records`. */ query: string; }; export type AlertStorageQueryScopeSpec = { kind: "storageQuery"; /** * Read-only SQL over the warehouse, referencing models as * `.`. Unlike the orchestration engine, nothing windows it: * the query sees the models as they stand. */ query: string; }; export type AlertModelScopeSpec = { kind: "model"; /** The model whose records the alert watches: a model handle or `modelRef(uuid)`. */ model: ModelHandle | ModelRef; /** * Narrows the records the alert measures. Required by the `recordsShare` * metric, which is a share *of a filtered set*. */ filter?: Filter; }; export type AlertScopeSpec = AlertSpansScopeSpec | AlertRunsScopeSpec | AlertRecordsScopeSpec | AlertOrchestrationQueryScopeSpec | AlertStorageQueryScopeSpec | AlertModelScopeSpec; export type AlertTelemetryThresholdSpec = { /** Failed rows as a percentage (0–100) of the window's finished ones. */ metric: "errorRate"; operator: "gte" | "lte"; value: number; } | { /** Duration in seconds, over finished rows only. */ metric: "duration"; aggregation: "avg" | "p50" | "p95" | "p99"; operator: "gte" | "lte"; value: number; } | { /** Credits consumed by the window's rows. */ metric: "credits"; aggregation: "sum" | "avg" | "p95"; operator: "gte" | "lte"; value: number; } | { /** * Span / run / record count over the window. With `lte` this is a * dead-man's switch: an empty window evaluates to 0, so silence can * breach. */ metric: "count"; operator: "gte" | "lte"; value: number; }; export type AlertModelThresholdSpec = { /** * Records matching the scope. With `lte` this catches a model that * stopped filling: no record evaluates to 0. */ metric: "recordsCount"; operator: "gte" | "lte"; value: number; } | { /** * Matching records as a percentage (0–100) of the model's total. Requires * the scope's `filter`, without which it is always 100. */ metric: "recordsShare"; operator: "gte" | "lte"; value: number; } | { /** Minutes since the model last emitted records. */ metric: "freshness"; operator: "gte" | "lte"; value: number; } | { /** Duration in seconds of the model's last finished sync. */ metric: "syncDuration"; operator: "gte" | "lte"; value: number; }; export type AlertQueryThresholdSpec = { operator: "gte" | "lte"; value: number; }; export type AlertThresholdSpec = AlertTelemetryThresholdSpec | AlertModelThresholdSpec | AlertQueryThresholdSpec; /** Fire a connector action on breach — `config` is the action's input. */ export type AlertConnectorActionSpec = { ref: ConnectorActionRef; config: Record; /** * A connector action has neither a release nor a wait — declaring them as * `never` is what makes the union reject them, since an object literal checked * against a union may otherwise carry any property one of its members has (and * lowering would drop these silently). */ release?: never; waitUntilFinished?: never; }; /** * Fire an agent on breach (optional release / wait). Every agent takes the same * config — the engine validates each one against `AiUtils.agentConfig` — so * unlike a connector action or a tool there is no per-resource schema to infer, * and the shape is simply written here. A `{{ … }}` prompt needs no widening: * a template is a string, which is what `prompt` already is. */ export type AlertAgentActionSpec = { ref: AgentHandle | AgentRef; config: AiUtils.AgentConfig; release?: string; waitUntilFinished?: boolean; }; /** Fire a tool on breach — `config` is the tool's input, `{}` if it takes none. */ export type AlertToolActionSpec = { ref: ToolHandle | ToolRef; config: Record; release?: string; waitUntilFinished?: boolean; }; export type AlertActionSpec = AlertConnectorActionSpec | AlertAgentActionSpec | AlertToolActionSpec; /** * Fire a connector action on breach, with `config` checked against the action's * input schema — the typed alternative to a bare `{ ref, config }` literal: * * alertConnectorAction({ * ref: slack.actions.postMessage, * config: { channel: "#alerts", text: "Error rate {{event.value}}%" }, * }) * * Two reasons this is a helper rather than the type of `actions`: TypeScript * can't infer a per-element generic through an array literal (the same reason * `agentConnectorTrigger` exists), and the schemas only exist once `cargo-ai cdk * types` has run — an unsynced integration keeps the loose record. Every leaf * also accepts a `{{ … }}` template string, since the config is interpolated * against the firing context when the alert fires. */ export declare function alertConnectorAction(spec: { ref: ConnectorActionRef; config: Templated>; }): AlertConnectorActionSpec; /** * Fire a tool on breach, with `config` checked against the tool's own input — * the typed alternative to a bare `{ ref, config }` literal: * * alertToolAction({ * ref: enrich, * config: { domain: "acme.com", limit: "{{event.value}}" }, * }) * * A `defineTool` handle carries its backing workflow's input type, so unlike a * connector action nothing needs `cargo-ai cdk types` to have run — but the * handle's type only survives through a generic call, which is why this is a * helper (an array literal can't infer per element). A `toolRef(uuid)` names a * tool that isn't authored here and has no input type to check, so its config * stays loose. Every leaf also accepts a `{{ … }}` template string, since the * config is interpolated against the firing context when the alert fires. */ export declare function alertToolAction(spec: { ref: ToolHandle | ToolRef; config: Templated; release?: string; waitUntilFinished?: boolean; }): AlertToolActionSpec; export type AlertSpec = { name?: string; /** What this alert watches, for humans. */ description?: string; /** When the check runs — a cron schedule. */ schedule: { type: "cron"; cron: string; }; /** What fires on breach — each becomes a run. */ actions: AlertActionSpec[]; /** Whether the alert is active. Defaults to true. */ enabled?: boolean; /** File the alert under an "alert"-kind folder. */ folder?: FolderHandle | FolderRef; } & ({ /** Which spans this alert watches. */ scope: AlertSpansScopeSpec; /** When it breaches (metric / aggregation / operator / value). */ threshold: AlertTelemetryThresholdSpec; } | { /** Which runs this alert watches. */ scope: AlertRunsScopeSpec; /** When it breaches (metric / aggregation / operator / value). */ threshold: AlertTelemetryThresholdSpec; } | { /** Which records this alert watches. */ scope: AlertRecordsScopeSpec; /** When it breaches (metric / aggregation / operator / value). */ threshold: AlertTelemetryThresholdSpec; } | { /** The ClickHouse SQL query whose first value this alert watches. */ scope: AlertOrchestrationQueryScopeSpec; /** When it breaches (operator / value). */ threshold: AlertQueryThresholdSpec; } | { /** The warehouse SQL query whose first value this alert watches. */ scope: AlertStorageQueryScopeSpec; /** When it breaches (operator / value). */ threshold: AlertQueryThresholdSpec; } | { /** The model whose records this alert watches. */ scope: AlertModelScopeSpec; /** When it breaches (metric / operator / value). */ threshold: AlertModelThresholdSpec; }); export type AlertHandle = { readonly slug: string; readonly uuid: Token; readonly resource: "alert"; }; export declare function lowerAlertAction(action: AlertActionSpec): Record; export declare function defineAlert(slug: string, spec: AlertSpec): AlertHandle; //# sourceMappingURL=alert.d.ts.map