-
Notifications
You must be signed in to change notification settings - Fork 0
Expression Systems
theirish81 edited this page Sep 3, 2026
·
1 revision
FML integrates two distinct external expression engines to balance high-speed string formatting with type-safe logical evaluation:
-
Go
text/template: The standard Go string templating engine, used for prompt rendering and string interpolation. -
Antonmedv
expr(github.com/antonmedv/expr): A high-performance, statically-typed expression evaluator used for conditional logic, looping, and native data transfer.
| 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) |
The Go template engine is used wherever textual content is rendered for LLM consumption.
- Pre-prompts (
+) - Prompts (
-) - Quoted string arguments in
callblocks:arg = "{{ .params.query }}" - The
contextblock string:context "Prior: {{ .context.prev | json }}" - Parameter
defaultstrings
-
Leading Dot Required: Variable references must begin with a period (
.) representing the root scope:{{ .params.username }} {{ .vars.auth_token }} {{ .context.ingestion.status }} {{ .it.title }} -
Nested Property Access: Standard dot chaining:
{{ .context.session_name.profile.contact.email }} -
The
| jsonFilter: 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 intojson:context "User Data: {{ .context.user_data | json }}"
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 }
}
The Antonmedv expr engine preserves native data structures and executes logical and mathematical operations.
-
Wrapped Expressions (
$( ... )): Used insidecallarguments when you need to pass native arrays, numbers, booleans, or objects to tools or scripts. -
Session
expectAttribute: Evaluated as raw strings (e.g.expect="context.code == 200"). -
Session
iterateAttribute: Evaluated as raw strings (e.g.iterate=context.records.items).
-
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! -
Type Preservation: When passing
$(vars.user_ids)into a tool argument, the tool receives[]stringor[]int, not"[1, 2, 3]":call("batch_delete") { # Preserves native array structure ids = $(vars.user_ids) } -
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)"
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 |
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
}
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"))
}
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))
}
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)]
# 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"
# WRONG: Pass as string literal
call("sync") {
items = "$(vars.my_array)"
}
# RIGHT: Passes native array
call("sync") {
items = $(vars.my_array)
}
# 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 }}"
FML (Frags Modeling Language) | Getting Started | Cheat Sheet | Examples
Documentation for FML & Gemini Agent Workflows — Maintained by Frags HQ