Skip to content

Expression Systems

theirish81 edited this page Sep 3, 2026 · 1 revision

Expression Systems

FML integrates two distinct external expression engines to balance high-speed string formatting with type-safe logical evaluation:

  1. Go text/template: The standard Go string templating engine, used for prompt rendering and string interpolation.
  2. Antonmedv expr (github.com/antonmedv/expr): A high-performance, statically-typed expression evaluator used for conditional logic, looping, and native data transfer.

Comparison Matrix

Feature Go text/template Antonmedv expr
Engine Go standard library text/template github.com/antonmedv/expr
Enclosing Syntax {{ ... }} $( ... ) (in call args) or raw string in attributes
Root Variable Syntax Leading dot required: {{ .params.x }} No leading dot: $(params.x)
Primary Use Cases Prompts (+ and -), string call args, context definitions, default strings Tool call arguments, expect="...", iterate="..."
Output Type Always string Native Go/JSON types (array, object, int, bool)
Custom Filters ` json` (serializes structures to JSON)
Null Checks Not natively supported nil or null (e.g. context.item != nil)

1. Go text/template Engine (String Interpolation)

The Go template engine is used wherever textual content is rendered for LLM consumption.

Locations Where Go Templates Apply

  • Pre-prompts (+)
  • Prompts (-)
  • Quoted string arguments in call blocks: arg = "{{ .params.query }}"
  • The context block string: context "Prior: {{ .context.prev | json }}"
  • Parameter default strings

Syntax Rules

  1. Leading Dot Required: Variable references must begin with a period (.) representing the root scope:
    {{ .params.username }}
    {{ .vars.auth_token }}
    {{ .context.ingestion.status }}
    {{ .it.title }}
    
  2. Nested Property Access: Standard dot chaining:
    {{ .context.session_name.profile.contact.email }}
    
  3. The | json Filter: By default, stringifying a complex Go struct or map produces Go's internal representation (e.g., map[id:123]). To serialize objects or arrays as valid JSON strings for LLM prompts, pipe them into json:
    context "User Data: {{ .context.user_data | json }}"
    

Example

session("format_response") {
    context "All results: {{ .context.search_results | json }}"

    + Given user query '{{ .params.search_term }}' and region '{{ .vars.region }}':
      Review the search results provided in context.

    - Summarize the top findings into the schema.
    schema { summary: string }
}

2. Antonmedv expr Engine (Typed Evaluations)

The Antonmedv expr engine preserves native data structures and executes logical and mathematical operations.

Locations Where Antonmedv Expr Applies

  • Wrapped Expressions ($( ... )): Used inside call arguments when you need to pass native arrays, numbers, booleans, or objects to tools or scripts.
  • Session expect Attribute: Evaluated as raw strings (e.g. expect="context.code == 200").
  • Session iterate Attribute: Evaluated as raw strings (e.g. iterate=context.records.items).

Syntax Rules

  1. No Leading Dot: Root namespaces must not have a leading dot:
    # CORRECT:
    $(vars.user_list)
    expect="params.retry_count > 0"
    iterate=context.items
    
    # INCORRECT:
    $(.vars.user_list)              # ERROR: Do not use leading dot!
    expect=".params.retry_count > 0" # ERROR: Do not use leading dot!
    
  2. Type Preservation: When passing $(vars.user_ids) into a tool argument, the tool receives []string or []int, not "[1, 2, 3]":
    call("batch_delete") {
        # Preserves native array structure
        ids = $(vars.user_ids)
    }
    
  3. Never Wrap $(...) in Quotes:
    # CORRECT: Evaluates to native array
    records = $(context.users)
    
    # INCORRECT: Treats $(...) as a literal string or forces string conversion
    records = "$(context.users)"
    

Operators & Logical Expressions

Antonmedv expr supports a rich set of operators:

Operator Category Operators Examples
Comparison ==, !=, <, >, <=, >= context.score >= 0.85
Logical &&, `
Membership in 'admin' in vars.user_roles
Regex Match matches params.email matches '^[a-z0-9]+@example\\.com$'
Null Checks == nil, != nil, == null context.previous_stage != nil

Built-in Functions

1. len(array | string | map)

Returns the length of a collection:

session("send_digest", after="fetch_news", expect="len(context.fetch_news.articles) > 0") {
    # Only runs if articles array has elements
}

2. filter(array, predicate)

Filters an array using # to represent each item:

call("process_active_users") {
    # Filters active users without LLM overhead
    active_users = $(filter(context.fetch_users.users, #.status == "ACTIVE"))
}

3. map(array, transform)

Transforms an array of objects into an array of values:

call("notify_emails") {
    # Extracts an array of email strings from user objects
    recipient_emails = $(map(context.fetch_users.users, #.email))
}

Decision Flowchart: Which Syntax to Use?

graph TD
    Q1{Where are you writing the expression?}
    
    Q1 -->|In pre-prompt + or prompt -| A[Go Template: {{ .namespace.field }}]
    Q1 -->|In context definition| A
    Q1 -->|In expect or iterate attribute| B[Antonmedv Expr: raw string namespace.field]
    Q1 -->|Inside call arguments| Q2{What type do you want to pass?}

    Q2 -->|String value / Text interpolation| A
    Q2 -->|Native type: Array, Object, Number, Bool| C[Wrapped Expr: $(namespace.field)]
Loading

Common Pitfalls & Mistakes

1. The Leading Dot Trap

# WRONG in Go template (missing dot):
+ Hello {{ params.name }}

# RIGHT in Go template:
+ Hello {{ .params.name }}

# WRONG in Antonmedv Expr (unwanted dot):
expect=".params.count > 5"

# RIGHT in Antonmedv Expr:
expect="params.count > 5"

2. Quoting Wrapped Expressions in call

# WRONG: Pass as string literal
call("sync") {
    items = "$(vars.my_array)"
}

# RIGHT: Passes native array
call("sync") {
    items = $(vars.my_array)
}

3. Forgetting the | json Filter

# WRONG: LLM receives Go struct string representation: map[author:Alice id:10]
context "Post: {{ .context.post }}"

# RIGHT: LLM receives valid JSON: {"author": "Alice", "id": 10}
context "Post: {{ .context.post | json }}"

Clone this wiki locally