Documentation
¶
Overview ¶
Package workflows contains the storage layer for Epic 64 (triggers & workflows).
Pure data-access on the seven Epic 64 tables. Crypto (encrypt/decrypt of webhook HMAC secrets) is NOT done here — handlers encrypt before calling CreateWebhook; the webhook receiver decrypts after calling GetWebhookByTriggerID (the public hook URL carries the trigger id). This mirrors the pkg/secrets/mcp_store.go split exactly.
Index ¶
- Constants
- Variables
- func NextCronFire(cfg *types.CronSourceConfig, now time.Time) (time.Time, error)
- func NextCronFireFromConfig(sourceConfig json.RawMessage, now time.Time) (*types.CronSourceConfig, time.Time, error)
- func NormalizeInputSchema(inputSchema json.RawMessage) json.RawMessage
- func NormalizeTriggerInputFrom(inputFrom string) string
- func RecordNodeDuration(nodeType string, durationSeconds float64)
- func RecordRunFinished(status, errorCode, ownerType string, durationSeconds float64)
- func RecordRunStarted()
- func RecordSchedulerTick(durationSeconds float64)
- func RecordTriggerFire(source, status string)
- func RecordWebhookDelivery(webhookID, status string)
- func RequiredNonEnvelopeProperties(schema json.RawMessage, sourceType string) []string
- func ResolveTriggerInput(spec TriggerInputSpec, envelope json.RawMessage) (json.RawMessage, error)
- func SchemaMismatchPayload(inputFrom string, err error) json.RawMessage
- func StaticInputPresent(raw json.RawMessage) bool
- func TriggerOptedIn(inputFrom string, input json.RawMessage) bool
- func ValidateCronSourceConfig(sourceConfig json.RawMessage) (*types.CronSourceConfig, error)
- func ValidateInputSchema(inputSchema json.RawMessage) error
- func ValidateRunInput(inputSchema, input json.RawMessage) error
- type AgentNodeData
- type ConditionCase
- type ConditionNodeData
- type DefaultsBlock
- type HTTPNodeData
- type SchemaViolation
- type ScriptNodeData
- type SessionOriginRow
- type Spec
- type SpecEdge
- type SpecNode
- type Store
- func (s *Store) ClaimDueCronTriggers(ctx context.Context, now time.Time, limit int, ...) ([]*TriggerRow, error)
- func (s *Store) ClaimQueuedRuns(ctx context.Context, limit int) ([]*WorkflowRunRow, error)
- func (s *Store) CountTriggersByOwner(ctx context.Context, ownerType, ownerID string) (int, error)
- func (s *Store) CountWorkflowsByOwner(ctx context.Context, ownerType, ownerID string) (int, error)
- func (s *Store) CreateNodeRun(ctx context.Context, row *WorkflowNodeRunRow) error
- func (s *Store) CreateTrigger(ctx context.Context, row *TriggerRow) error
- func (s *Store) CreateTriggerFire(ctx context.Context, row *TriggerFireRow) error
- func (s *Store) CreateWebhook(ctx context.Context, row *WebhookRow) error
- func (s *Store) CreateWorkflow(ctx context.Context, row *WorkflowRow) error
- func (s *Store) CreateWorkflowRun(ctx context.Context, row *WorkflowRunRow) error
- func (s *Store) CreateWorkflowRunWithFire(ctx context.Context, fire *TriggerFireRow, run *WorkflowRunRow) error
- func (s *Store) DeleteTrigger(ctx context.Context, ownerType, ownerID, triggerID string) error
- func (s *Store) DeleteWorkflow(ctx context.Context, ownerType, ownerID, workflowID string) error
- func (s *Store) DisableTrigger(ctx context.Context, triggerID string) error
- func (s *Store) GetLastRoutineResult(ctx context.Context, triggerID string) (json.RawMessage, error)
- func (s *Store) GetRecentRoutineResults(ctx context.Context, triggerID string, limit int) ([]json.RawMessage, error)
- func (s *Store) GetTrigger(ctx context.Context, ownerType, ownerID, triggerID string) (*TriggerRow, error)
- func (s *Store) GetTriggerByID(ctx context.Context, triggerID string) (*TriggerRow, error)
- func (s *Store) GetWebhookByTriggerID(ctx context.Context, triggerID string) (*WebhookRow, error)
- func (s *Store) GetWorkflow(ctx context.Context, ownerType, ownerID, workflowID string) (*WorkflowRow, error)
- func (s *Store) GetWorkflowPolicy(ctx context.Context, workflowID string) (onMissing, ownerType, ownerID string, err error)
- func (s *Store) GetWorkflowRun(ctx context.Context, runID string) (*WorkflowRunRow, error)
- func (s *Store) HasInFlightRun(ctx context.Context, workflowID string) (bool, error)
- func (s *Store) IncrementTriggerFailures(ctx context.Context, triggerID string) (int, error)
- func (s *Store) ListNodeRuns(ctx context.Context, workflowRunID string) ([]*WorkflowNodeRunRow, error)
- func (s *Store) ListPendingRoutineFires(ctx context.Context, limit int) ([]*TriggerFireRow, error)
- func (s *Store) ListSessionOrigins(ctx context.Context, workspaceID string) ([]*SessionOriginRow, error)
- func (s *Store) ListTriggerFires(ctx context.Context, triggerID string, limit, offset int) ([]*TriggerFireRow, error)
- func (s *Store) ListTriggers(ctx context.Context, ownerType, ownerID string) ([]*TriggerRow, error)
- func (s *Store) ListWorkflowRuns(ctx context.Context, workflowID string, limit, offset int) ([]*WorkflowRunRow, error)
- func (s *Store) ListWorkflowRunsByWorkspace(ctx context.Context, workspaceID string) ([]*WorkflowRunRow, error)
- func (s *Store) ListWorkflows(ctx context.Context, ownerType, ownerID string) ([]*WorkflowRow, error)
- func (s *Store) RecordSessionOrigin(ctx context.Context, row *SessionOriginRow) error
- func (s *Store) RecordWebhookDelivery(ctx context.Context, webhookID, dedupKey string) error
- func (s *Store) ResetTriggerFailures(ctx context.Context, triggerID string) error
- func (s *Store) UpdateNodeRunStatus(ctx context.Context, nodeRunID, status string, output json.RawMessage, ...) error
- func (s *Store) UpdateRunWorkspace(ctx context.Context, runID, workspaceID string) error
- func (s *Store) UpdateTrigger(ctx context.Context, ownerType, ownerID, triggerID string, upd *TriggerUpdate) (*TriggerRow, error)
- func (s *Store) UpdateTriggerFireResult(ctx context.Context, fireID string, result json.RawMessage, status string) error
- func (s *Store) UpdateWebhookSecret(ctx context.Context, triggerID string, secretCipher []byte, keyVersion int) error
- func (s *Store) UpdateWorkflow(ctx context.Context, ownerType, ownerID, workflowID string, ...) (*WorkflowRow, error)
- func (s *Store) UpdateWorkflowRunStatus(ctx context.Context, runID, status string, errorCode *string, ...) error
- func (s *Store) WorkspaceExistsByID(ctx context.Context, workspaceID string) (bool, error)
- type TriggerFireRow
- type TriggerInputSpec
- type TriggerRow
- type TriggerUpdate
- type ValidationError
- type WebhookRow
- type WorkflowNodeRunRow
- type WorkflowRow
- type WorkflowRunRow
- type WorkflowUpdate
Constants ¶
const SchemaViolationPayloadCap = 4 << 10 // 4 KiB
SchemaViolationPayloadCap is the hard cap on a marshaled schema-mismatch action_result document. The payload size is an invariant, never a best-effort.
Variables ¶
var ErrConcurrentRun = errors.New("workflow: a run is already in flight for this workflow")
ErrConcurrentRun is returned by CreateWorkflowRun when the single-in-flight partial unique index (uq_workflow_run_single_inflight) rejects the insert because another queued/running run exists for the same workflow_id. Handlers map this to 409 "already running".
var ErrDedupConflict = errors.New("workflow: duplicate webhook delivery")
ErrDedupConflict is returned by RecordWebhookDelivery when the (webhook_id, dedup_key) UNIQUE constraint rejects a duplicate delivery. Handlers map this to 200 "duplicate" (idempotent re-delivery).
var ErrInputSchemaNotObject = errors.New(`inputSchema must be object-rooted (type "object", a type list containing "object", or no root type)`)
ErrInputSchemaNotObject rejects a declared inputSchema whose root type no run input can satisfy: runs always carry a JSON object (an absent run input is validated as the JSON null document), so e.g. {"type":"string"} would fail validation on every run.
var ErrInvalidInputSchema = errors.New("invalid inputSchema")
ErrInvalidInputSchema is the sentinel for "the stored schema itself is broken" — malformed JSON or no-longer-compiling. A workflow defect, not an input defect: the fire path records a failed fire with {"code":"invalid_input_schema"} instead of a schema-mismatch payload (design 0059 D3).
var ErrNotFound = errors.New("workflow: not found")
ErrNotFound is returned by Get/Update/Delete when the row does not exist (or the caller's owner scope does not match). Handlers map this to 404.
Functions ¶
func NextCronFire ¶ added in v0.33.0
NextCronFire returns the first fire time strictly after now for a validated cron config. The config is re-validated here so the engine keeps its defensive behavior for rows written before validation existed (callers translate the error into a fallback).
func NextCronFireFromConfig ¶ added in v0.33.0
func NextCronFireFromConfig(sourceConfig json.RawMessage, now time.Time) (*types.CronSourceConfig, time.Time, error)
NextCronFireFromConfig validates source_config and computes the next fire after now in one step — the write-path convenience.
func NormalizeInputSchema ¶ added in v0.33.1
func NormalizeInputSchema(inputSchema json.RawMessage) json.RawMessage
NormalizeInputSchema collapses an explicit JSON null declaration to a nil (absent) schema so the stored row never carries a literal jsonb null: "declared null" and "not declared" are the same contract at the storage boundary — schema-less (#1433). Everything else passes through untouched.
func NormalizeTriggerInputFrom ¶ added in v0.34.0
NormalizeTriggerInputFrom maps an unset/empty mode to the legacy default "envelope" (rows scanned after migration 000031 always carry a value; in-memory rows may not).
func RecordNodeDuration ¶ added in v0.8.12
RecordNodeDuration records per-node execution timing.
func RecordRunFinished ¶ added in v0.8.12
RecordRunFinished records a run's terminal status + duration.
func RecordRunStarted ¶ added in v0.8.12
func RecordRunStarted()
RecordRunStarted increments the concurrent gauge.
func RecordSchedulerTick ¶ added in v0.8.12
func RecordSchedulerTick(durationSeconds float64)
RecordSchedulerTick records scheduler tick timing.
func RecordTriggerFire ¶ added in v0.8.12
func RecordTriggerFire(source, status string)
RecordTriggerFire records a trigger fire event.
func RecordWebhookDelivery ¶ added in v0.8.12
func RecordWebhookDelivery(webhookID, status string)
RecordWebhookDelivery records a webhook delivery.
func RequiredNonEnvelopeProperties ¶ added in v0.34.0
func RequiredNonEnvelopeProperties(schema json.RawMessage, sourceType string) []string
RequiredNonEnvelopeProperties returns the top-level `required` property names of schema that the given source's envelope key set provides no value for — the V6 wiring-guard predicate (design 0059 D4). Syntactic only: no deep schema walk (fire-time validation is the backstop for opted-in triggers). A schema that cannot be parsed requires nothing beyond the envelope — the guard skips it (a garbage stored schema is a workflow defect, caught at fire time or on the next workflow update).
func ResolveTriggerInput ¶ added in v0.34.0
func ResolveTriggerInput(spec TriggerInputSpec, envelope json.RawMessage) (json.RawMessage, error)
ResolveTriggerInput computes the input a fired run should carry per the trigger's mapping (design 0059 §3.4):
base := body mode → envelope.body; mapped → nil; else the envelope itself
no static input → base (the envelope path returns the envelope bytes
VERBATIM — legacy triggers are byte-identical)
base is an object → shallow top-level merge, static keys win
otherwise → the static document verbatim
Shallow merge is deliberate (deep-merge semantics are unspecified territory; the first 90% use case is "provide `topic` at the top level"). The envelope stays reachable under its own keys in envelope mode; mapped mode exists for additionalProperties:false schemas a merged envelope would violate.
func SchemaMismatchPayload ¶ added in v0.34.0
func SchemaMismatchPayload(inputFrom string, err error) json.RawMessage
SchemaMismatchPayload builds the capped action_result document for a fire-time input/schema mismatch (status validation_error): typed, location-only violations extracted from verr, hard-capped at SchemaViolationPayloadCap with the design's recursive drop semantics:
- records are appended only while the marshaled payload stays under the cap; a record that does not fit first drops its message, then the record — pointer included — is dropped entirely and counted in a final {"keyword":"truncated","message":"N more violations omitted"} marker;
- if even the first record cannot fit without its message, the payload degrades to the bare {"code","inputFrom"} skeleton plus marker.
An err that is not a *jsonschema.ValidationError (or extraction that yields no records) still produces a well-formed payload with a single static, instance-free record — the invariant is "always ≤ cap, never instance values", including for unexpected error shapes.
func StaticInputPresent ¶ added in v0.34.0
func StaticInputPresent(raw json.RawMessage) bool
StaticInputPresent reports whether raw carries a static input document: a non-nil, non-JSON-null document. The JSON literal null means "no static input" — same as an absent key (mirrors the #1433 null-means- absent convention on inputSchema).
func TriggerOptedIn ¶ added in v0.34.0
func TriggerOptedIn(inputFrom string, input json.RawMessage) bool
TriggerOptedIn reports whether a trigger opted in to fire-time input validation (D3): any non-default inputFrom, or a static input document present. Legacy un-opted triggers keep byte-identical envelope behavior and no validation (§3.6).
func ValidateCronSourceConfig ¶ added in v0.33.0
func ValidateCronSourceConfig(sourceConfig json.RawMessage) (*types.CronSourceConfig, error)
ValidateCronSourceConfig decodes and validates a cron trigger's source_config JSON: expr must parse under the five-field syntax and tz (when set) must be a loadable IANA location. It returns the typed config so callers don't decode twice.
func ValidateInputSchema ¶ added in v0.33.0
func ValidateInputSchema(inputSchema json.RawMessage) error
ValidateInputSchema checks that a workflow's declared inputSchema is declarable: well-formed JSON that compiles as a JSON Schema AND roots at type "object" (or leaves the root type unset). An absent schema — or the explicit JSON literal null, which means the same thing (#1433) — accepts everything. Used at workflow create/update so a broken or unsatisfiable schema fails fast instead of at run time.
func ValidateRunInput ¶ added in v0.33.0
func ValidateRunInput(inputSchema, input json.RawMessage) error
ValidateRunInput validates a run's input document against a workflow's inputSchema. An absent schema — or a stored JSON literal null row (#1433) — accepts everything; an absent input is validated as the JSON null document (so required properties fail).
Types ¶
type AgentNodeData ¶
type AgentNodeData struct {
Agent string `json:"agent,omitempty"`
Prompt string `json:"prompt"`
System string `json:"system,omitempty"`
OutputSchema json.RawMessage `json:"outputSchema,omitempty"`
EnforceStructuredOutput bool `json:"enforceStructuredOutput,omitempty"`
Session string `json:"session,omitempty"`
SessionID string `json:"sessionId,omitempty"`
}
AgentNodeData is the typed shape of SpecNode.Data for agent nodes.
type ConditionCase ¶
ConditionCase is one branch of a condition node.
type ConditionNodeData ¶
type ConditionNodeData struct {
Conditions []ConditionCase `json:"conditions"`
}
ConditionNodeData is the typed shape of SpecNode.Data for condition nodes.
type DefaultsBlock ¶
type DefaultsBlock struct {
MaxAttempts *int `json:"maxAttempts,omitempty"`
Timeout string `json:"timeout,omitempty"`
}
DefaultsBlock carries workflow-level defaults that are merged into each node's config (node-level wins). Only maxAttempts and timeout may be defaulted; behavioral fields must be per-node.
type HTTPNodeData ¶
type HTTPNodeData struct {
Method string `json:"method,omitempty"`
URL string `json:"url"`
Headers map[string]string `json:"headers,omitempty"`
Body string `json:"body,omitempty"`
Timeout string `json:"timeout,omitempty"`
}
HTTPNodeData is the typed shape of SpecNode.Data for http nodes.
type SchemaViolation ¶ added in v0.34.0
type SchemaViolation struct {
JSONPointer string `json:"jsonPointer"`
Keyword string `json:"keyword"`
Message string `json:"message,omitempty"`
}
SchemaViolation is one typed, location-only record of a schema violation. JSONPointer locates the violation in the run input (RFC 6901); Keyword is the failing schema keyword; Message is generated from keyword + schema-side fields only (e.g. a name from the schema's own `required` list — never an instance value).
func ExtractSchemaViolations ¶ added in v0.34.0
func ExtractSchemaViolations(err error) []SchemaViolation
ExtractSchemaViolations walks a validation error's typed trail and returns location-only violation records. Never consults ValidationError.Error(): pointers come from InstanceLocation, keywords from ErrorKind.KeywordPath(), and messages from the concrete kind's SCHEMA-side fields only.
type ScriptNodeData ¶
ScriptNodeData is the typed shape of SpecNode.Data for script nodes.
type SessionOriginRow ¶ added in v0.11.0
type Spec ¶
Spec is the parsed and validated DAG stored in workflows.spec_json. It is the execution-ready form: defaults merged, node types validated, edges checked for cycles/dangling/condition-coverage.
type SpecEdge ¶
type SpecEdge struct {
Source string `json:"source"`
Target string `json:"target"`
SourceHandle string `json:"sourceHandle,omitempty"`
}
SpecEdge is a directed edge in the DAG. SourceHandle carries the condition-branch id (for condition nodes) or is empty (for all other types).
type SpecNode ¶
type SpecNode struct {
ID string `json:"id"`
Type string `json:"type"`
Data json.RawMessage `json:"data"`
MaxAttempts int `json:"maxAttempts,omitempty"`
Timeout string `json:"timeout,omitempty"`
}
SpecNode is a single node in the workflow DAG.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the Postgres-backed data-access layer for Epic 64. Construct once at app boot via NewStore; share across handlers. Methods are safe for concurrent use (pgxpool serializes connections internally).
func (*Store) ClaimDueCronTriggers ¶ added in v0.12.2
func (s *Store) ClaimDueCronTriggers(ctx context.Context, now time.Time, limit int, nextFireFn func(*TriggerRow) time.Time) ([]*TriggerRow, error)
ClaimDueCronTriggers atomically claims due cron triggers and advances each trigger's last_fired_at and next_fire_at within the same transaction. This prevents sibling API replicas from claiming the same trigger concurrently: FOR UPDATE SKIP LOCKED ensures that if replica A locks a row, replica B's SELECT skips it rather than blocking.
nextFireFn computes the next fire time for each claimed trigger from its cron expression (cron parsing lives in the engine layer, not the store). The returned triggers are in their pre-advance state so the caller can use the original next_fire_at for the missed-tick skip check.
func (*Store) ClaimQueuedRuns ¶
ClaimQueuedRuns selects up to limit queued runs and atomically marks them running, returning the claimed rows. Uses FOR UPDATE SKIP LOCKED so multiple API replicas (or multiple goroutines) can claim concurrently without contention. The reconciler polls this on each tick.
func (*Store) CountTriggersByOwner ¶
CountTriggersByOwner returns the number of triggers owned by (ownerType, ownerID).
func (*Store) CountWorkflowsByOwner ¶
CountWorkflowsByOwner returns the number of workflows owned by (ownerType, ownerID). Used for quota enforcement (workflows.maxPerUser / workflows.maxPerOrg).
func (*Store) CreateNodeRun ¶
func (s *Store) CreateNodeRun(ctx context.Context, row *WorkflowNodeRunRow) error
CreateNodeRun inserts a workflow_node_runs row.
func (*Store) CreateTrigger ¶
func (s *Store) CreateTrigger(ctx context.Context, row *TriggerRow) error
func (*Store) CreateTriggerFire ¶
func (s *Store) CreateTriggerFire(ctx context.Context, row *TriggerFireRow) error
CreateTriggerFire inserts a trigger_fires row.
func (*Store) CreateWebhook ¶
func (s *Store) CreateWebhook(ctx context.Context, row *WebhookRow) error
CreateWebhook inserts a row into webhooks. The caller supplies a pre-encrypted SecretCipher (KEK for org scope, session-DEK for user scope — exact mcp_servers crypto envelope pattern). trigger_id has a 1:1 UNIQUE constraint.
func (*Store) CreateWorkflow ¶
func (s *Store) CreateWorkflow(ctx context.Context, row *WorkflowRow) error
CreateWorkflow inserts a row into workflows. The caller supplies a pre-generated UUID. spec_json must already be parsed + validated (US-64.4).
func (*Store) CreateWorkflowRun ¶
func (s *Store) CreateWorkflowRun(ctx context.Context, row *WorkflowRunRow) error
CreateWorkflowRun inserts a new run row. The single-in-flight partial unique index (uq_workflow_run_single_inflight) may reject the insert with a unique violation — mapped to ErrConcurrentRun so the handler can return 409 + Retry-After. Callers should use CreateWorkflowRunTx (with the fire row) for webhook-triggered runs; this method is for manual runs.
func (*Store) CreateWorkflowRunWithFire ¶
func (s *Store) CreateWorkflowRunWithFire(ctx context.Context, fire *TriggerFireRow, run *WorkflowRunRow) error
CreateWorkflowRunWithFire atomically inserts a trigger_fires row AND a workflow_runs row in a single transaction. If the run insert hits the single-in-flight unique violation, the whole tx rolls back (no orphan fire row claiming "fired" with no run). The caller then commits a separate trigger_fires row with status='skipped' + reason='already_running' and returns 409 + Retry-After.
This is the v1 correctness pattern for webhook fire-row + run-create atomicity (design Edge Case 4 / Webhook Security atomicity bullet).
func (*Store) DeleteTrigger ¶
DeleteTrigger deletes a trigger by ID scoped to (ownerType, ownerID). FK cascades handle webhooks + trigger_fires. Returns ErrNotFound.
func (*Store) DeleteWorkflow ¶
DeleteWorkflow deletes a workflow by ID scoped to (ownerType, ownerID). FK cascades handle workflow_runs (ON DELETE CASCADE). Returns ErrNotFound if the workflow doesn't exist or the caller's scope doesn't match.
func (*Store) DisableTrigger ¶
DisableTrigger sets enabled=false (called when the circuit breaker trips).
func (*Store) GetLastRoutineResult ¶ added in v0.10.0
func (s *Store) GetLastRoutineResult(ctx context.Context, triggerID string) (json.RawMessage, error)
GetLastRoutineResult returns the result from the most recent successful routine fire for a trigger. Used for memory_mode: last_result.
func (*Store) GetRecentRoutineResults ¶ added in v0.10.0
func (s *Store) GetRecentRoutineResults(ctx context.Context, triggerID string, limit int) ([]json.RawMessage, error)
GetRecentRoutineResults returns the N most recent successful routine results. Used for memory_max_runs > 1.
func (*Store) GetTrigger ¶
func (s *Store) GetTrigger(ctx context.Context, ownerType, ownerID, triggerID string) (*TriggerRow, error)
GetTrigger returns a single trigger by ID scoped to (ownerType, ownerID), or ErrNotFound.
func (*Store) GetTriggerByID ¶ added in v0.8.12
func (*Store) GetWebhookByTriggerID ¶
GetWebhookByTriggerID returns the webhook config for a trigger, or ErrNotFound. Used by the webhook receiver to fetch the HMAC secret + IP allowlist.
func (*Store) GetWorkflow ¶
func (s *Store) GetWorkflow(ctx context.Context, ownerType, ownerID, workflowID string) (*WorkflowRow, error)
GetWorkflow returns a single workflow by ID scoped to (ownerType, ownerID), or ErrNotFound if not found / wrong scope.
func (*Store) GetWorkflowPolicy ¶ added in v0.9.1
func (s *Store) GetWorkflowPolicy(ctx context.Context, workflowID string) (onMissing, ownerType, ownerID string, err error)
GetWorkflowPolicy returns the on_missing_workspace policy + owner for a workflow. Used by the engine to decide whether to create a workspace on missing (Epic 64).
func (*Store) GetWorkflowRun ¶
GetWorkflowRun returns a single run by ID, or ErrNotFound. Not scoped — run IDs are unguessable UUIDs and the caller has already authorized via the workflow's owner scope.
func (*Store) HasInFlightRun ¶
HasInFlightRun reports whether a non-terminal run exists for the workflow. Used for fast-path rejection at the API layer (the partial unique index is the authoritative gate; this is an early-reject optimization).
func (*Store) IncrementTriggerFailures ¶
IncrementTriggerFailures increments consecutive_failures and returns the new value. If the new value crosses auto_disable_after, the caller sets enabled=false.
func (*Store) ListNodeRuns ¶
func (s *Store) ListNodeRuns(ctx context.Context, workflowRunID string) ([]*WorkflowNodeRunRow, error)
ListNodeRuns returns all node runs for a workflow run, ordered by started_at ASC.
func (*Store) ListPendingRoutineFires ¶ added in v0.10.0
ListPendingRoutineFires returns fire rows with action_type='routine' and status='fired' that have not yet been processed (no result). Used by the scheduler to pick up webhook-triggered routines on its next tick.
func (*Store) ListSessionOrigins ¶ added in v0.11.0
func (*Store) ListTriggerFires ¶
func (s *Store) ListTriggerFires(ctx context.Context, triggerID string, limit, offset int) ([]*TriggerFireRow, error)
ListTriggerFires returns recent fires for a trigger, paginated by fired_at DESC.
func (*Store) ListTriggers ¶
func (*Store) ListWorkflowRuns ¶
func (s *Store) ListWorkflowRuns(ctx context.Context, workflowID string, limit, offset int) ([]*WorkflowRunRow, error)
ListWorkflowRuns returns runs for a workflow, paginated by created_at DESC. limit must be > 0; offset is the number of rows to skip.
func (*Store) ListWorkflowRunsByWorkspace ¶ added in v0.11.0
func (s *Store) ListWorkflowRunsByWorkspace(ctx context.Context, workspaceID string) ([]*WorkflowRunRow, error)
ListWorkflowRunsByWorkspace returns non-terminal runs for a workspace.
func (*Store) ListWorkflows ¶
func (s *Store) ListWorkflows(ctx context.Context, ownerType, ownerID string) ([]*WorkflowRow, error)
ListWorkflows returns all workflows owned by (ownerType, ownerID), ordered by created_at ASC. Never decrypts — display fields only.
func (*Store) RecordSessionOrigin ¶ added in v0.11.0
func (s *Store) RecordSessionOrigin(ctx context.Context, row *SessionOriginRow) error
func (*Store) RecordWebhookDelivery ¶
RecordWebhookDelivery inserts a dedup row. Returns ErrDedupConflict if a row with the same (webhook_id, dedup_key) already exists — the caller returns 200 "duplicate" in that case. The unique constraint name is webhook_deliveries_webhook_dedup_uniq.
func (*Store) ResetTriggerFailures ¶
ResetTriggerFailures resets consecutive_failures to 0 (called on first success).
func (*Store) UpdateNodeRunStatus ¶
func (s *Store) UpdateNodeRunStatus(ctx context.Context, nodeRunID, status string, output json.RawMessage, branch *string, errorCode *string, errMsg json.RawMessage) error
UpdateNodeRunStatus sets status + terminal fields. On a terminal transition, finished_at is set. branch is set only on condition nodes (matched edge handle).
func (*Store) UpdateRunWorkspace ¶ added in v0.9.1
UpdateRunWorkspace updates the workspace_id on a workflow run.
func (*Store) UpdateTrigger ¶
func (s *Store) UpdateTrigger(ctx context.Context, ownerType, ownerID, triggerID string, upd *TriggerUpdate) (*TriggerRow, error)
UpdateTrigger updates an existing trigger scoped to (ownerType, ownerID). source_type is NOT mutable (not in TriggerUpdate). Partial update via pointer fields: nil preserves existing values. Returns the updated row or ErrNotFound.
func (*Store) UpdateTriggerFireResult ¶ added in v0.10.0
func (s *Store) UpdateTriggerFireResult(ctx context.Context, fireID string, result json.RawMessage, status string) error
UpdateTriggerFireResult sets the result + final status on a trigger fire row. Used by the routine executor after agent execution completes.
func (*Store) UpdateWebhookSecret ¶ added in v0.9.1
func (s *Store) UpdateWebhookSecret(ctx context.Context, triggerID string, secretCipher []byte, keyVersion int) error
UpdateWebhookSecret replaces the encrypted HMAC secret + key version for a webhook. Used by the rotate-secret endpoint.
func (*Store) UpdateWorkflow ¶
func (s *Store) UpdateWorkflow(ctx context.Context, ownerType, ownerID, workflowID string, upd *WorkflowUpdate) (*WorkflowRow, error)
UpdateWorkflow updates an existing workflow scoped to (ownerType, ownerID). Partial update via WorkflowUpdate pointer fields: nil preserves existing values. Returns the updated row or ErrNotFound.
func (*Store) UpdateWorkflowRunStatus ¶
func (s *Store) UpdateWorkflowRunStatus(ctx context.Context, runID, status string, errorCode *string, errMsg json.RawMessage, output json.RawMessage) error
UpdateWorkflowRunStatus sets status + terminal fields. On a terminal transition (succeeded/failed/canceled/timed_out), finished_at is set. error_code + error are nullable (null on success).
func (*Store) WorkspaceExistsByID ¶ added in v0.34.7
WorkspaceExistsByID reports whether a workspace row with the id exists, UNSCOPED — the existence semantics of the workspaces(id) foreign keys (triggers.workspace_id, workflows.target_workspace_id). The handler parent-id contract checks ride this; ownership policy is NOT judged here (cross-owner targets remain the fire-time loud class, #1440). Same pool as the workflows tables — workspaces lives in the same database.
type TriggerFireRow ¶
type TriggerFireRow struct {
ID string
TriggerID string
SourceType string
InputEnvelope json.RawMessage
ActionType string
ActionResult json.RawMessage
Status string
FiredAt time.Time
CompletedAt *time.Time
// Result is the routine execution outcome (UpdateTriggerFireResult):
// the captured agent output on success (captureMode full) or the
// failure cause on error. Distinct from ActionResult (the
// receiver/engine's pre-execution action payload). Exposing it closes
// the routine-failure observability gap (#1441): failure causes were
// written to a column no read path selected.
Result json.RawMessage
}
TriggerFireRow is the DB row shape for trigger_fires.
type TriggerInputSpec ¶ added in v0.34.0
type TriggerInputSpec struct {
InputFrom string
Input json.RawMessage
}
TriggerInputSpec is the trigger-carried half of the resolution input: the mapping mode (InputFrom) and the optional static input document (Input). Zero values mean legacy envelope mode with no static input.
type TriggerRow ¶
type TriggerRow struct {
ID string
OwnerType string
OwnerID string
Name string
Description string
Enabled bool
SourceType string
SourceConfig json.RawMessage
WorkspaceID *string
WorkflowID *string
InputFrom string // 0059: envelope (legacy default) | body | mapped
Input json.RawMessage
Prompt string
Agent string
ScriptPath string
ScriptArgs []string
ScriptEnv json.RawMessage
MemoryMode string
MemoryMaxRuns int
CaptureMode string
PreserveSession string
ConsecutiveFailures int
AutoDisableAfter int
LastFiredAt *time.Time
NextFireAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
TriggerRow is the DB row shape for triggers.
type TriggerUpdate ¶
type TriggerUpdate struct {
Name *string
Description *string
Enabled *bool
SourceConfig json.RawMessage
WorkspaceID *string
WorkflowID *string
// InputFrom (0059): nil keeps the stored mode. Input follows the
// jsonb CASE shape — a non-nil RawMessage (including the JSON
// literal null, which lands as jsonb null = "no static input")
// replaces the stored document; nil keeps it.
InputFrom *string
Input json.RawMessage
Prompt *string
Agent *string
ScriptPath *string
ScriptArgs []string
ScriptEnv json.RawMessage
MemoryMode *string
MemoryMaxRuns *int
CaptureMode *string
PreserveSession *string
AutoDisableAfter *int
// NextFireAt is set by the handler when a schedule change must take
// effect immediately (#1410) — nil keeps the stored slot.
NextFireAt *time.Time
}
TriggerUpdate carries only the fields a partial update may change. Pointer fields: nil means "keep existing". source_type is NOT in this struct — it's immutable after create (the source defines the trigger's identity).
type ValidationError ¶
type ValidationError struct {
Code string `json:"code"`
NodeID string `json:"nodeId,omitempty"`
Detail string `json:"detail,omitempty"`
}
ValidationError describes a single problem found during DAG validation.
func ValidateSpec ¶
func ValidateSpec(spec *Spec, predecessorSchemas map[string]json.RawMessage, defaults DefaultsBlock) []ValidationError
ValidateSpec validates a workflow DAG spec and applies defaults merging. It mutates the spec in place (defaults applied to nodes that omit maxAttempts/timeout) ONLY when validation passes without structural errors (dangling edges, duplicate IDs, cycles). Non-structural errors (unreachable nodes, missing branch edges) do NOT prevent defaults merging — the spec is still mutated. Callers should discard the spec if any errors are returned. predecessorSchemas maps node ID → that node's outputSchema (JSON Schema bytes), used for expr-lang type-checking condition expressions against the upstream node's output shape. nil/empty schemas skip type-checking for that predecessor.
Returns a slice of ValidationErrors (empty if valid).
func (ValidationError) Error ¶
func (e ValidationError) Error() string
type WebhookRow ¶
type WebhookRow struct {
ID string
TriggerID string
SecretCipher []byte
KeyVersion int
AllowedIPs []string
IdempotencyMode string
IdempotencyHeader string
CreatedAt time.Time
}
WebhookRow is the DB row shape for webhooks. SecretCipher is the encrypted HMAC secret (crypto envelope); callers must decrypt before verifying signatures.
type WorkflowNodeRunRow ¶
type WorkflowNodeRunRow struct {
ID string
WorkflowRunID string
NodeID string
NodeType string
Status string
Attempt int
Input json.RawMessage
Output json.RawMessage
Branch *string
ErrorCode *string
Error json.RawMessage
StartedAt time.Time
FinishedAt *time.Time
}
WorkflowNodeRunRow is the DB row shape for workflow_node_runs.
type WorkflowRow ¶
type WorkflowRow struct {
ID string
OwnerType string
OwnerID string
Name string
Slug string
Description string
SpecYAML string
SpecJSON json.RawMessage
InputSchema json.RawMessage
TargetWorkspaceID *string
OnMissingWorkspace string
Status string
Defaults json.RawMessage
CreatedAt time.Time
UpdatedAt time.Time
}
WorkflowRow is the DB row shape for workflows.
type WorkflowRunRow ¶
type WorkflowRunRow struct {
ID string
WorkflowID string
SpecSnapshot json.RawMessage
Input json.RawMessage
Output json.RawMessage
Status string
ErrorCode *string
Error json.RawMessage
TriggerID *string
TriggerFireID *string
WorkspaceID string
StartedAt *time.Time
FinishedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
WorkflowRunRow is the DB row shape for workflow_runs.
type WorkflowUpdate ¶
type WorkflowUpdate struct {
Name *string
Slug *string
Description *string
SpecYAML *string
SpecJSON json.RawMessage
InputSchema json.RawMessage
TargetWorkspaceID *string
OnMissingWorkspace *string
Status *string
Defaults json.RawMessage
}
WorkflowUpdate carries only the fields a partial update may change. Pointer fields: nil means "keep existing". This mirrors the API DTO pattern (UpdateWorkflowRequest) so the handler can pass fields through directly. The zero-value WorkflowUpdate preserves every field (no changes).
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package exprlang compiles condition expressions for workflow DAG validation.
|
Package exprlang compiles condition expressions for workflow DAG validation. |
|
Package scriptwrap executes user-authored inline script handlers (Python, Node) inside the workspace sandbox.
|
Package scriptwrap executes user-authored inline script handlers (Python, Node) inside the workspace sandbox. |