# AST and evaluation

How the JSX transform creates AML nodes and how the runtime normalizes and evaluates them.
Canonical: https://agent-markup-language.com/docs/ast/
Documentation index: https://agent-markup-language.com/docs/
Complete documentation: https://agent-markup-language.com/docs/llms.txt

AML has three distinct stages. Keeping them separate prevents a common mistake: treating authored JSX as if it were already a provider request.

| Stage             | What exists                                                                                      | What it does not do                                         |
| ----------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- |
| Authoring         | TypeScript/TSX expressions and component functions                                               | It does not contact a provider just because JSX was written |
| Node construction | Immutable AML JSX descriptors produced by the automatic JSX runtime                              | It does not invoke the component function                   |
| Evaluation        | [`AmlRuntime`](https://agent-markup-language.com/docs/reference/runtime/) normalizes values and executes runtime-owned primitives | It does not render DOM or accept unknown intrinsic elements |

## Authored JSX is ordinary TypeScript

Configure TypeScript to use AML's automatic JSX runtime:

```json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@aml-jsx/sdk"
  }
}
```

The transform turns this:

```tsx
const workflow = <Agent model="reviewer">Inspect the change.</Agent>
```

into a call equivalent to `jsx(Agent, { model: "reviewer", children: "Inspect the change." })`. The returned value is data. Holding it in a variable does not run `<Agent />`.

## What the JSX runtime constructs

Internally, the JSX runtime stores a component reference and frozen props in an AML node descriptor. The descriptor class is deliberately not a root-package value export: application code should treat JSX values as `JSX.Element` or `AmlRenderable` and hand them to the runtime. The component function is invoked only while an evaluation owns an active component context.

```tsx
import { AmlRuntime, Agent, type AmlRenderable } from "@aml-jsx/sdk"

const workflow: AmlRenderable = <Agent>Inspect the change.</Agent>

const result = await new AmlRuntime({ agentProvider }).evaluate(workflow)
```

Do not import implementation paths or call a descriptor's component reference yourself. That bypasses evaluation domains, lexical scopes, placement checks, limits, tracing, and cleanup.

## Normalization rules

The evaluator accepts these renderable values:

- strings and numbers, which become text;
- `null`, `undefined`, and booleans, which contribute no output;
- AML JSX descriptors, which are evaluated by their component type;
- promises, which are awaited;
- arrays, which are flattened in authored order;
- fragments, which group children without creating a runtime resource boundary.

Unknown objects, DOM-like intrinsic elements, cyclic arrays, and cyclic nodes are rejected with `EvaluationError`. AML intentionally does not coerce arbitrary objects into `[object Object]` prompt text.

**Note — Fragments are grouping, not scheduling**

A fragment adds no prompt text and no provider lifecycle. It also does not create implicit concurrency. Use
[`<Parallel>`](https://agent-markup-language.com/docs/reference/primitives/parallel/) when independent text-producing branches may safely overlap.

## Runtime-owned primitive nodes

Built-in primitive components are marked for special evaluation. They are not ordinary components that merely return a string.

| Primitive                                                                                                                                                                                                                                                   | Status | Owner                | Meaning                                                                        |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -------------------- | ------------------------------------------------------------------------------ |
| [`<Agent />`](https://agent-markup-language.com/docs/reference/primitives/agent/)                                                                                                                                                                                                            | Stable | Agent executor       | Collects a request plan and runs a provider session.                           |
| [`<System />`](https://agent-markup-language.com/docs/reference/primitives/system/), [`<Tool />`](https://agent-markup-language.com/docs/reference/primitives/tool/), [`<Mcp />`](https://agent-markup-language.com/docs/reference/primitives/mcp/), [`<Skill />`](https://agent-markup-language.com/docs/reference/primitives/skill/), [`<FollowUp />`](https://agent-markup-language.com/docs/reference/primitives/follow-up/) | Stable | nearest `<Agent />`  | Adds typed data to one `<Agent />` plan.                                       |
| [`<Include />`](https://agent-markup-language.com/docs/reference/primitives/include/)                                                                                                                                                                                                        | Stable | Include evaluator    | Reads live UTF-8 prompt content or authors a bounded file reference.           |
| [`<Sandbox />`](https://agent-markup-language.com/docs/reference/primitives/sandbox/)                                                                                                                                                                                                        | Stable | Sandbox evaluator    | Acquires and narrows an execution lease.                                       |
| [`<Script />`](https://agent-markup-language.com/docs/reference/primitives/script/)                                                                                                                                                                                                          | Stable | Script evaluator     | Runs one literal command or shell source on the host or in the active Sandbox. |
| [`<Workspace />`](https://agent-markup-language.com/docs/reference/primitives/workspace/)                                                                                                                                                                                                    | Stable | Workspace evaluator  | Materializes and publishes durable files.                                      |
| [`<File />`](https://agent-markup-language.com/docs/reference/primitives/file/)                                                                                                                                                                                                              | Stable | Filesystem evaluator | Writes a local source or resolved text through the nearest active filesystem.  |
| [`<Block />`](https://agent-markup-language.com/docs/reference/primitives/block/)                                                                                                                                                                                                            | Stable | JSX composition      | Adds blank-line separation and optional named sections without another scope.  |
| [`<>…</>`](https://agent-markup-language.com/docs/reference/primitives/fragment/)                                                                                                                                                                                                            | Stable | JSX runtime          | Groups authored values without adding another boundary.                        |

Placement is part of the contract. For example, `<Tool />`, `<Mcp />`, and `<Skill />` are valid only in an Agent plan. `<File />` requires an active Workspace or Sandbox, while `<Include path>` requires the same read scope and `<Include src>` reads from the application cwd. `<Script />` may execute on the host without a Sandbox; an enclosing Sandbox changes its execution location. `<Block />` is transparent, so descriptors nested inside it keep their normal owner.

`<Parallel>` is intentionally different from the runtime-owned nodes above: it is a normal exported function component
built on component-local `evaluate()`. That existing boundary supplies inherited scopes, limits, cancellation, tracing,
and cleanup joining without adding a second evaluator primitive.

## Post-order consumers versus lexical scopes

`<Agent />` is a post-order consumer: its child content and descriptors resolve before the session starts. `<Workspace />` and `<Sandbox />` are lexical scopes: each enters before descendants and releases after them.

Function component bodies run as AML descends into their descriptors. Returning AML then lets that value resolve naturally and flow upward; this is **return to compose**. If the component body instead needs a nested result before it can decide what to return, it must `await evaluate(...)`; this is **evaluate to collect**. [The component mental model](https://agent-markup-language.com/docs/concepts/#component-bodies-descend-results-ascend) shows both forms and why neither happens at JSX authoring time.

```tsx
<Workspace id="review" provider={workspaceProvider}>
  <Sandbox provider={sandboxProvider}>
    <Agent provider={agentProvider}>
      <Tool use={readTool} />
      Inspect the repository.
    </Agent>
  </Sandbox>
</Workspace>
```

Conceptually, this is:

```text
enter Workspace
  enter Sandbox
    resolve Agent plan
      resolve Tool descriptor
      resolve prompt text
    execute Agent session
  release Sandbox
publish/release Workspace
```

The actual runtime uses an explicit frame stack rather than relying on JavaScript recursion. That implementation detail allows asynchronous components and deep trees to share the same depth accounting and lifecycle checks.

## Component-local `evaluate()`

[`evaluate()`](https://agent-markup-language.com/docs/reference/runtime/#component-local-evaluation) is only valid while an AML function component is active. It is AML's **evaluate to collect** boundary: the component pauses, the nested value resolves in the current domain, and the call returns its text or validates one [`<Agent />`](https://agent-markup-language.com/docs/reference/primitives/agent/) result against a Standard Schema-compatible schema before the component body continues:

```tsx
import { Agent, evaluate } from "@aml-jsx/sdk"
import { z } from "zod"

const Finding = z.object({ severity: z.enum(["low", "high"]), summary: z.string() })

async function Review() {
  const finding = await evaluate(<Agent>Inspect the authorization change.</Agent>, Finding)
  return (
    <Agent>
      Explain this {finding.severity} finding: {finding.summary}
    </Agent>
  )
}
```

Structured evaluation must resolve exactly one `<Agent />` result. Schema failure rejects the domain; unvalidated model text is never returned as if it were typed data.

## Read the implementation contract

The normative details live in [SPEC.md](https://github.com/we-are-singular/aml/blob/main/SPEC.md): [evaluation model](https://github.com/we-are-singular/aml/blob/main/SPEC.md#2-evaluation-model), [Agent sessions](https://github.com/we-are-singular/aml/blob/main/SPEC.md#5-agent-sessions), and [`evaluate()`](https://github.com/we-are-singular/aml/blob/main/SPEC.md#10-evaluate-and-structured-data).
