expressions

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 11, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Index

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

func NewCELEngine() (*CELEngine, error)

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.

func (*CELEngine) Name

func (e *CELEngine) Name() string

Name returns the engine identifier.

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.

func (*ExprEngine) Name

func (e *ExprEngine) Name() string

Name returns the engine identifier.

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.

func (*GoJQEngine) Name

func (e *GoJQEngine) Name() string

Name returns the engine identifier.

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 LoopVars

type LoopVars struct {
	Item  any // current iteration value
	Index int // current iteration index
}

LoopVars holds the 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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL