d4772b5f60
Adds an `annotations` JSONB column to task runs that captures where and how each run was triggered. This enables filtering and analyzing trigger origins without querying up the run tree. Also enables making scheduling decisions based on the trigger source, e.g., use separate affinities for scheduled runs. Each run records: - **triggerSource**: who initiated it (sdk, api, dashboard, cli, mcp, schedule) - **triggerAction**: what kind of action (trigger, replay, test) - **rootTriggerSource**: the trigger source of the root ancestor, propagated through the entire run tree - **rootScheduleId**: schedule id, in case the run tree was triggered from a schedule Currently the main motivation for annotations it to determine whether a run is part of a schedule-originated tree without traversing ancestors. ### A couple of design considerations - **Decoupled source from method**: triggerSource and triggerAction are separate fields to avoid combinatorial explosion (every new source × every new action) - **Server-side first**: all annotation values are primarily determined on the server, only a minor SDK change needed - **Forward-compatible**: annotation fields use `z.enum([...]).or(anyString)` so new values can be added without breaking validation; we currently don't need an explicit version field for annotations. Note: `metadata` would have been a more fitting name for the db column, as it is consistent with other tables where we store this type of information. It is already in use to store user metadata though, so we go with `annotations` instead.
10 lines
336 B
TypeScript
10 lines
336 B
TypeScript
const ALLOWED_TRIGGER_SOURCES = new Set(["sdk", "cli", "mcp"]);
|
|
|
|
/** Validates a client-provided trigger source header against the allowlist. */
|
|
export function sanitizeTriggerSource(value: string | null | undefined): string | undefined {
|
|
if (value && ALLOWED_TRIGGER_SOURCES.has(value)) {
|
|
return value;
|
|
}
|
|
return undefined;
|
|
}
|