Skip to content

Sessions and Lifecycle

theirish81 edited this page Sep 3, 2026 · 1 revision

Sessions and Lifecycle

In FML, a session represents an independent, isolated LLM execution context. Sessions form a directed acyclic graph (DAG), passing structured state downstream through the context namespace.


Session Declaration Syntax

session("session_name", 
    after   = "dependency_session", 
    expect  = "expr_condition", 
    iterate = "array_expr", 
    target  = "custom_output_key"
) {
    # 1. Tool activations
    use mcp tool_name { allowlist = ["func1", "func2"] }
    use search

    # 2. Context configuration
    context "Upstream Data: {{ .context.dependency_session | json }}"

    # 3. Session-local variables
    set local_flag = true

    # 4. Phase 1: Pre-Execution Calls
    call("fetch_item") -> vars:item {
        id = "{{ .params.item_id }}"
    }

    # 5. Phase 2: Pre-prompts (Tools ENABLED)
    + Research and analyze the item retrieved in vars: {{ .vars.item.name }}.
      Run diagnostic checks if anomalies are detected.

    # 6. Phase 3: Prompt (Tools DISABLED - Exactly one)
    - Compile the diagnostic report into the requested schema.

    # 7. Phase 4: Structured Output Schema
    schema {
        item_id: string
        status: passed|failed|warning
        notes: string[]
    }
}

Session Attributes Reference

Attribute Type Evaluation Engine Description
name (1st arg) String Static identifier Unique session name. Default output key under context.<name>.
after String Static identifier Upstream session dependency. Enforces execution order.
expect String Antonmedv expr Execution condition. If false, session and downstream dependents are skipped.
iterate String Antonmedv expr Array expression. Loops the session over each item in the array.
target String Static identifier Custom output key. Overrides default storage key in context.

The 4-Phase Execution Lifecycle

Every FML session enforces a strict four-phase execution lifecycle. This guarantees a clean separation between deterministic data retrieval, generative tool-based reasoning, and schema-constrained formatting.

graph TD
    A[Session Invocation] --> B[Phase 1: Pre-Execution Calls]
    B --> C[Phase 2: Pre-Prompts + Tool Execution]
    C --> D[Phase 3: Final Prompt - Pure Formatting]
    D --> E[Phase 4: Schema Validation]
    E --> F[Publish to context.<name> or context.<target>]

    style B fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
    style C fill:#fff3e0,stroke:#f57c00,stroke-width:2px
    style D fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
    style E fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
Loading

Phase 1: Pre-Execution (Deterministic PreCalls)

  • What runs: All call blocks declared within the session body execute sequentially and synchronously.
  • Deterministic Logic: Calls execute external tool functions or embedded JavaScript scripts (code(...)).
  • Error Handling: Any uncaught exception or runtime failure halts the session immediately and fails the entire plan.
  • Target Routing:
    • If routed via -> vars:name, data is saved to session-local variables.
    • If the target routing arrow is omitted entirely (e.g. call("fetch") { ... }), the output is automatically injected into the current session's active LLM context.

Phase 2: Context Enrichment & Tool Execution (Pre-Prompts +)

  • What runs: All pre-prompt blocks declared with the + prefix.
  • Tool Access: Fully enabled. The LLM receives the tool definitions declared with use (e.g. MCP tools, collections, use search).
  • Execution Flow: The LLM receives the pre-prompt text, invokes tools dynamically, evaluates tool responses, and may invoke further tools across multiple conversational turns.
  • Quantity: Zero or more + blocks are permitted.
  • Goal: Accumulate all necessary evidence, facts, and calculations into the session's active conversation history.

Phase 3: Final Structuring & Output Generation (Prompt -)

  • What runs: The single prompt block declared with the - prefix.
  • Tool Access: Strictly disabled. The FML engine removes all tool definitions from the LLM request. The model cannot invoke tools during this phase.
  • Quantity: Exactly one - block is permitted per session. Declaring zero or multiple - prompts results in a compilation error.
  • Goal: Direct the LLM to inspect the conversation history gathered in Phase 2 and map the findings cleanly into the requested JSON schema.

Phase 4: Schema Conformance Validation

  • What runs: Validation of the LLM's response against the session's schema.
  • Output Storage: Once validated, the JSON payload is published to the context namespace:
    • Default: context.<session_name>
    • Custom target: context.<target> (if target="custom_key" is specified)
  • Availability: Downstream sessions declaring after="session_name" can now consume this validated payload.

Pre-Prompts (+) vs. Prompt (-)

Aspect Pre-Prompt (+) Prompt (-)
Prefix Token + -
Permitted Count 0, 1, or multiple Strictly 1
Tool Calling Enabled (via use declarations) Disabled (Tool schemas stripped)
Go Templating Yes (e.g. {{ .params.query }}) Yes (e.g. {{ .vars.summary }})
Multi-line Support Yes, via indentation Yes, via indentation
Primary Objective Discovery, tool execution, iterative reasoning Schema mapping, final JSON formatting

Advanced Session Attributes

1. Dependency Chaining (after)

Sessions execute according to their dependency graph. If session B needs output from session A:

session("step_a", target="data_a") {
    - Produce data A.
    schema { id: string }
}

session("step_b", after="step_a") {
    context "From Step A: {{ .context.data_a | json }}"
    - Process data A.
    schema { result: string }
}

Important

Any session that references context.upstream in its expect, iterate, or prompt templates MUST declare after="upstream". Omitting this causes an unresolved dependency error.

2. Conditional Execution (expect)

The expect attribute evaluates an Antonmedv expr condition. If the condition evaluates to false, the session is skipped.

session("send_alert", after="check_metrics", expect="context.metrics.error_rate > 0.05") {
    use mcp pagerduty
    + Trigger an incident for elevated error rate: {{ .context.metrics.error_rate }}
    - Output alert confirmation.
    schema { incident_id: string }
}

Warning

Cascading Skips: If a session is skipped because its expect condition evaluates to false, all downstream sessions that depend on it via after are automatically skipped.

3. Array Looping (iterate)

The iterate attribute runs the session in a loop over each item in an array expression.

session("scrape_batch", after="find_urls", iterate=context.find_urls.links) {
    use mcp web_scraper

    # In an iterate session, 'it' represents the current array item
    + Scrape the URL: {{ .it.url }}
    - Summarize the contents of this page.

    # Mandatory array schema in iterate sessions
    schema {
        url: string
        summary: string
    }
}

Rules for iterate:

  1. Current Item (it): Inside the session, the current element is accessed via {{ .it }} or {{ .it.property }}.
  2. Mandatory Array Schema: The schema must be defined as an array or object element. The runtime automatically collects and sequentially appends each iteration's output in the exact order of the input array.
  3. Downstream Value: The final output published to context.scrape_batch is a JSON array containing all iterated results.

4. Custom Output Key (target)

By default, session output is saved under context.<session_name>. The target attribute overrides this key:

session("retrieve_customer_account_details_v2", target="account") {
    - Retrieve the account.
    schema { account_id: string }
}

# Downstream sessions access this via context.account instead of the lengthy session name
session("next_step", after="retrieve_customer_account_details_v2") {
    context "Account: {{ .context.account | json }}"
    - Next actions...
    schema { ok: bool }
}

Context Injection (context)

The context statement controls how prior session artifacts are loaded into the current session's initial context window:

# Option A: Inject full context as JSON
context true

# Option B: Inject custom interpolated string with specific session data
context "Prior findings: {{ .context.research | json }}\nUser preferences: {{ .params.pref }}"

Critical Initialization Constraint

Caution

Initialization Antipattern: The context block is evaluated during session initialization, before Phase 1 PreCalls execute.

Therefore, referencing local variables created by PreCalls in the current session (e.g. context "{{ .vars.local_call_result }}") will fail or evaluate to empty.

Correct Practice:

  1. Use context only to reference completed upstream sessions ({{ .context.upstream | json }}).
  2. Reference local PreCall variables inside pre-prompts (+) or prompts (-), which evaluate after PreCalls complete.

Clone this wiki locally