Documentation
¶
Index ¶
- func DetectCircularRefs(steps map[string]*schema.StepDefinition) error
- func HasInterpolation(raw json.RawMessage) bool
- type CELEngine
- type Engine
- type ExprEngine
- type GoJQEngine
- func (e *GoJQEngine) Evaluate(ctx context.Context, expression string, data map[string]any) (any, error)
- func (e *GoJQEngine) EvaluateAll(ctx context.Context, expression string, data map[string]any) ([]any, error)
- func (e *GoJQEngine) EvaluateNormalized(ctx context.Context, expression string, data map[string]any) (any, error)
- func (e *GoJQEngine) Name() string
- type InterpolationScope
- type Interpolator
- type LoopScope
- type LoopVars
- type ScopeBuilder
- func (sb *ScopeBuilder) AddStepOutput(stepID string, output json.RawMessage) error
- func (sb *ScopeBuilder) Build() *InterpolationScope
- func (sb *ScopeBuilder) ForParallelBranch() *ScopeBuilder
- func (sb *ScopeBuilder) MergeBranchOutputs(branch *ScopeBuilder)
- func (sb *ScopeBuilder) StepOutputs() map[string]any
- func (sb *ScopeBuilder) WithLoopVars(item any, index int) *ScopeBuilder
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DetectCircularRefs ¶
func DetectCircularRefs(steps map[string]*schema.StepDefinition) error
DetectCircularRefs checks for circular references in step params. A circular reference occurs when step A's params reference step B's output and step B's params reference step A's output (at the same DAG level). This is called before execution with the set of step definitions at one level.
func HasInterpolation ¶
func HasInterpolation(raw json.RawMessage) bool
HasInterpolation checks if a JSON blob contains any ${{...}} references.
Types ¶
type CELEngine ¶
type CELEngine struct {
// contains filtered or unexported fields
}
CELEngine implements the Engine interface using Google's Common Expression Language. It evaluates step conditions, switch/if routing, and guard expressions. Thread-safe: compiled programs are cached and reused across goroutines.
func NewCELEngine ¶
NewCELEngine creates a new CEL expression engine with a sandboxed environment. The environment exposes four top-level variables matching InterpolationScope:
- steps: map(string, dyn) — step outputs keyed by step ID
- inputs: map(string, dyn) — workflow input parameters
- workflow: map(string, dyn) — workflow metadata (run_id, etc.)
- context: map(string, dyn) — workflow context (intent, etc.)
func (*CELEngine) Evaluate ¶
func (e *CELEngine) Evaluate(ctx context.Context, expression string, data map[string]any) (any, error)
Evaluate compiles (or retrieves from cache) a CEL expression and evaluates it against the provided data. The data map should contain keys matching the environment variables: steps, inputs, workflow, context.
Returns the evaluation result or an OpcodeError with clear, actionable messages.
type Engine ¶
type Engine interface {
Name() string
Evaluate(ctx context.Context, expression string, data map[string]any) (any, error)
}
Engine evaluates expressions within workflow steps. Three implementations: CEL (conditions), GoJQ (transforms), Expr (logic).
type ExprEngine ¶
type ExprEngine struct {
// contains filtered or unexported fields
}
ExprEngine implements the Engine interface using expr-lang/expr for complex deterministic logic. It supports let bindings, array operations (filter, map, count, any, all, sum, min, max), string operations, nil coalescing (??), optional chaining (?.), and pipe chaining (|). Thread-safe: compiled *vm.Program objects are cached and reused across goroutines.
func NewExprEngine ¶
func NewExprEngine() *ExprEngine
NewExprEngine creates a new Expr expression engine.
func (*ExprEngine) Evaluate ¶
func (e *ExprEngine) Evaluate(ctx context.Context, expression string, data map[string]any) (any, error)
Evaluate compiles (or retrieves from cache) an Expr expression and evaluates it against the provided data. The data map is injected as the expression environment, making all keys available as top-level variables.
type GoJQEngine ¶
type GoJQEngine struct {
// contains filtered or unexported fields
}
GoJQEngine implements the Engine interface using GoJQ for JSON data transformation. It evaluates jq expressions for filtering, reshaping, and aggregating step outputs. Thread-safe: compiled *Code objects are cached and reused across goroutines.
func NewGoJQEngine ¶
func NewGoJQEngine() *GoJQEngine
NewGoJQEngine creates a new GoJQ expression engine.
func (*GoJQEngine) Evaluate ¶
func (e *GoJQEngine) Evaluate(ctx context.Context, expression string, data map[string]any) (any, error)
Evaluate compiles (or retrieves from cache) a jq expression and evaluates it against the provided data. The data map is used as the input JSON object.
jq expressions can produce multiple outputs. When there is exactly one output, it is returned directly. When there are multiple outputs, they are collected into a slice and returned as []any.
func (*GoJQEngine) EvaluateAll ¶
func (e *GoJQEngine) EvaluateAll(ctx context.Context, expression string, data map[string]any) ([]any, error)
EvaluateAll is like Evaluate but always returns a slice of all outputs, even if there is only one or zero results.
func (*GoJQEngine) EvaluateNormalized ¶
func (e *GoJQEngine) EvaluateNormalized(ctx context.Context, expression string, data map[string]any) (any, error)
EvaluateNormalized is like Evaluate but normalizes integer types to float64 before evaluation, which matches jq's native number handling.
type InterpolationScope ¶
type InterpolationScope struct {
Steps map[string]any // step ID -> output (unmarshalled)
Inputs map[string]any // workflow input params
Workflow map[string]any // workflow metadata (run_id, etc.)
Context map[string]any // workflow context (intent, etc.)
Loop *LoopScope // loop iteration variables (nil when not in a loop)
}
InterpolationScope holds all data available for variable resolution.
type Interpolator ¶
type Interpolator struct {
// contains filtered or unexported fields
}
Interpolator resolves ${{...}} references in step params. Two-pass: first resolves non-secret variables, second resolves secrets.
func NewInterpolator ¶
func NewInterpolator(vault secrets.Vault) *Interpolator
NewInterpolator creates a new Interpolator with an optional Vault for secret resolution.
func (*Interpolator) Resolve ¶
func (interp *Interpolator) Resolve(ctx context.Context, raw json.RawMessage, scope *InterpolationScope) (json.RawMessage, error)
Resolve performs two-pass interpolation on raw JSON params. Pass 1: resolves steps.*, inputs.*, workflow.*, context.* references. Pass 2: resolves secrets.* references via the Vault. Returns the interpolated JSON bytes.
type LoopScope ¶
type LoopScope struct {
Item any // current item value
Index int // current iteration index (0-based)
}
LoopScope holds scoped variables for a single loop iteration.
type ScopeBuilder ¶
type ScopeBuilder struct {
// contains filtered or unexported fields
}
ScopeBuilder constructs InterpolationScopes with proper variable isolation. It enforces:
- Step outputs are immutable after completion (frozen on insert).
- Append-only: new step outputs are added after each DAG level completes.
- Loop variables ($item, $index) are scoped per iteration.
- Parallel branch variables are isolated from sibling branches.
- Resolution order: step local -> workflow inputs -> secrets.
func NewScopeBuilder ¶
func NewScopeBuilder(inputs, workflow, context map[string]any) *ScopeBuilder
NewScopeBuilder creates a ScopeBuilder initialized with workflow-level data. inputs, workflow, and context are deep-copied to prevent external mutation.
func (*ScopeBuilder) AddStepOutput ¶
func (sb *ScopeBuilder) AddStepOutput(stepID string, output json.RawMessage) error
AddStepOutput registers a completed step's output. The output is frozen (deep-copied) at the time of insertion. Subsequent calls with the same stepID are rejected -- step outputs are immutable after completion.
func (*ScopeBuilder) Build ¶
func (sb *ScopeBuilder) Build() *InterpolationScope
Build creates an InterpolationScope snapshot. The returned scope is safe for concurrent use (all data is copied). If loop vars are set, they are included under the "loop" namespace.
func (*ScopeBuilder) ForParallelBranch ¶
func (sb *ScopeBuilder) ForParallelBranch() *ScopeBuilder
ForParallelBranch returns a child ScopeBuilder for a parallel branch. The child gets a snapshot of current step outputs but has its own isolated step output map. Branch-local step completions do NOT leak to siblings.
func (*ScopeBuilder) MergeBranchOutputs ¶
func (sb *ScopeBuilder) MergeBranchOutputs(branch *ScopeBuilder)
MergeBranchOutputs merges completed step outputs from a parallel branch back into the parent scope. Only new step IDs are added; existing ones are preserved (immutability rule).
func (*ScopeBuilder) StepOutputs ¶
func (sb *ScopeBuilder) StepOutputs() map[string]any
StepOutputs returns a read-only copy of the current step outputs.
func (*ScopeBuilder) WithLoopVars ¶
func (sb *ScopeBuilder) WithLoopVars(item any, index int) *ScopeBuilder
WithLoopVars returns a child ScopeBuilder with loop-scoped variables. The child shares the same steps/inputs/workflow/context but has its own loop vars. This ensures loop vars are scoped to the iteration.