> ## Documentation Index
> Fetch the complete documentation index at: https://koreai-content-gov.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Rich content and expressions

This page documents two core ABL capabilities: rich content output formats (voice, cards, carousels, interactive actions, templates) and the expression language (operators, functions, template interpolation).

***

## Rich content

ABL supports multi-format output for delivering responses across different channels (web, mobile, voice, messaging platforms). The `VOICE:`, `RICH_CONTENT:`, and `ACTIONS:` blocks can be attached to any `RESPOND` statement, `COMPLETE` condition, or lifecycle handler. A pure reasoning agent (no `FLOW:`) may also declare top-level `RICH_CONTENT:` and `ACTIONS:` blocks that attach to its generated responses.

### Overview

A single response can include:

* **Plain text** -- the default `RESPOND` string.
* **Voice configuration** -- SSML markup or natural language voice instructions.
* **Rich content** -- Markdown, Adaptive Cards, HTML, Slack Block Kit, WhatsApp, or AG-UI.
* **Carousels** -- scrollable card collections with images and buttons.
* **Interactive actions** -- buttons, select menus, and input fields.
* **Templates** -- reusable named response definitions with interpolation.

The runtime selects the appropriate format based on the delivery channel.

### Voice configuration

Voice configuration provides channel-specific voice output. The `VOICE:` block can appear alongside any `RESPOND`.

#### Syntax

```yaml theme={null}
RESPOND: "Your booking is confirmed for December 15th."
VOICE:
  ssml: |
    <speak>
      Your booking is confirmed for <say-as interpret-as="date" format="mdy">12/15/2025</say-as>.
    </speak>
  instructions: "Speak in a warm, congratulatory tone"
  plain_text: "Your booking is confirmed for December fifteenth."
```

#### Voice properties

| Property                   | Type      | Required | Default | Description                                                                      |
| -------------------------- | --------- | -------- | ------- | -------------------------------------------------------------------------------- |
| `provider`                 | `string`  | No       | --      | TTS provider (for example. `elevenlabs`, `google`, `azure`, `openai`).           |
| `voice_id`                 | `string`  | No       | --      | Provider-specific voice identifier.                                              |
| `speed`                    | `number`  | No       | `1.0`   | Speech-rate multiplier (`1.0` = normal).                                         |
| `ssml`                     | `string`  | No       | --      | W3C SSML markup for TTS engines (Google, Azure, Amazon Polly).                   |
| `instructions`             | `string`  | No       | --      | Natural language voice style instructions (OpenAI Realtime, Gemini Live).        |
| `plain_text`               | `string`  | No       | --      | Voice-optimized plaintext. Used by ElevenLabs and as a fallback for all engines. |
| `pace`                     | `number`  | No       | --      | Numeric speaking-rate multiplier (authoring alias for speed/pace controls).      |
| `temperature`              | `number`  | No       | --      | Provider-specific TTS sampling/variation control.                                |
| `auto_tts_language_switch` | `boolean` | No       | --      | Switch the TTS voice/model to match the detected language of the response.       |

#### SSML example

```yaml theme={null}
VOICE:
  ssml: |
    <speak>
      <prosody rate="slow" pitch="+2st">
        Your wire transfer of <say-as interpret-as="currency">$50,000 USD</say-as>
        has been executed.
      </prosody>
      <break time="500ms"/>
      The confirmation number is
      <say-as interpret-as="characters">WR-2024-88431</say-as>.
    </speak>
```

#### Natural language instructions

For voice platforms that accept style instructions rather than SSML:

```yaml theme={null}
VOICE:
  instructions: "Speak slowly and clearly, emphasizing the confirmation number. Use a professional but warm tone."
```

### Rich content formats

The rich-content block provides format-specific variants of a response. The runtime selects the variant matching the delivery channel.

<Note>In the `.agent.abl` format the block keyword is **`FORMATS:`**. The `.agent.yaml` format accepts `rich_content:` or `formats:`. (`RICH_CONTENT:` is a legacy alias accepted only in flow-step overrides.)</Note>

#### Syntax

```yaml theme={null}
RESPOND: "Here are your flight options."
FORMATS:
  MARKDOWN: |
    ## Flight Options
    | Flight | Departure | Arrival | Price |
    |--------|-----------|---------|-------|
    | AA 142 | 8:00 AM   | 11:30 AM | $349 |
    | UA 891 | 10:15 AM  | 1:45 PM  | $289 |

  ADAPTIVE_CARD: |
    {
      "type": "AdaptiveCard",
      "body": [
        {"type": "TextBlock", "text": "Flight Options", "size": "large"}
      ]
    }

  HTML: |
    <div class="flight-results">
      <h2>Flight Options</h2>
      <table>...</table>
    </div>

  SLACK: |
    {
      "blocks": [
        {"type": "header", "text": {"type": "plain_text", "text": "Flight Options"}}
      ]
    }
```

#### Rich content properties

**Channel-specific string formats:**

| Property        | Type     | Required | Default | Description                                                    |
| --------------- | -------- | -------- | ------- | -------------------------------------------------------------- |
| `MARKDOWN`      | `string` | No       | --      | Formatted markdown text.                                       |
| `ADAPTIVE_CARD` | `string` | No       | --      | JSON string conforming to the Microsoft Adaptive Cards schema. |
| `HTML`          | `string` | No       | --      | HTML content for web-based channels.                           |
| `SLACK`         | `string` | No       | --      | JSON string conforming to the Slack Block Kit format.          |
| `AG_UI`         | `string` | No       | --      | JSON string for AG-UI / CopilotKit events.                     |
| `WHATSAPP`      | `string` | No       | --      | JSON string for WhatsApp interactive messages.                 |

**Structured template formats** (channel-neutral; the runtime renders them per channel):

| Property        | Type     | Description                                                                                                                                                                 |
| --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CAROUSEL`      | `object` | Scrollable card collection. See [Carousels](#carousels).                                                                                                                    |
| `QUICK_REPLIES` | `array`  | Quick-reply chips: each `{ id, label, iconUrl? }`.                                                                                                                          |
| `LIST`          | `object` | `{ title?, items: [{ title, subtitle?, imageUrl?, defaultActionUrl? }] }`.                                                                                                  |
| `IMAGE`         | `object` | `{ url, alt?, thumbnailUrl?, caption? }`.                                                                                                                                   |
| `VIDEO`         | `object` | `{ url, alt?, thumbnailUrl?, caption? }`.                                                                                                                                   |
| `AUDIO`         | `object` | `{ url, alt?, thumbnailUrl?, caption? }`.                                                                                                                                   |
| `FILE`          | `object` | `{ url, filename, sizeBytes?, mimeType? }`.                                                                                                                                 |
| `KPI`           | `object` | `{ label, value, unit?, trend?: up/down/flat, iconUrl? }`.                                                                                                                  |
| `TABLE`         | `object` | `{ columns: [{ key, header, align?: left/center/right }], rows, maxVisibleRows? }`.                                                                                         |
| `CHART`         | `object` | `{ type: bar/line/pie, title?, data: [{ label, value, color? }] }`.                                                                                                         |
| `FORM`          | `object` | `{ title?, fields: [ActionElement], submitLabel? }`.                                                                                                                        |
| `PROGRESS`      | `object` | `{ label?, value, max?, variant?: bar/circle }`.                                                                                                                            |
| `FEEDBACK`      | `object` | `{ prompt, type: thumbs/stars/scale, max?, submit_label?, pending_message?, success_message?, error_message?, comment_threshold?, comment_prompt?, comment_placeholder? }`. |

<Note>Named templates (in the `TEMPLATES:` block) may also declare a `RENDERABLES:` list — customer-owned structured payloads with `name`, `payload`, optional `targets` (`api`/`sdk_websocket`/`http_async`), `fallbackText`, and `schemaRef`. Data-rich templates (KPI, TABLE, CHART, LIST, CAROUSEL, …) also support collection binding via `from:` / `template:` to render one entry per array item.</Note>

#### Template modifiers

Two cross-cutting modifiers apply to structured templates:

* **`when`** — a conditional render guard (expression). On an agent-level rich-content block, the template renders only when the expression is truthy at reasoning finalization. Available on the rich-content block and on each structured template.
* **`adaptive`** — on `LIST`, `KPI`, and `TABLE` templates whose items/rows are bound to a tool variable, set `adaptive: true` to let the reasoning agent narrow which items/rows/columns render for the user's request.

### Carousels

Carousels display a horizontal scrollable collection of cards, each with a title, subtitle, image, and action buttons.

#### Syntax

```yaml expandable=true theme={null}
FORMATS:
  CAROUSEL:
    - title: "Economy Class"
      subtitle: "$289 - UA 891"
      imageUrl: "https://cdn.example.com/economy.jpg"
      defaultActionUrl: "https://booking.example.com/ua891"
      buttons:
        - id: select_economy
          type: button
          label: "Select"
          value: "ua891_economy"

    - title: "Business Class"
      subtitle: "$1,249 - UA 891"
      imageUrl: "https://cdn.example.com/business.jpg"
      buttons:
        - id: select_business
          type: button
          label: "Select"
          value: "ua891_business"
```

#### Carousel card properties

| Property           | Type     | Required | Default | Description                                                      |
| ------------------ | -------- | -------- | ------- | ---------------------------------------------------------------- |
| `title`            | `string` | Yes      | --      | Card title.                                                      |
| `subtitle`         | `string` | No       | --      | Card subtitle or description.                                    |
| `imageUrl`         | `string` | No       | --      | URL for the card image.                                          |
| `defaultActionUrl` | `string` | No       | --      | URL opened when the card itself is tapped.                       |
| `buttons`          | `array`  | No       | --      | Action buttons. See [Interactive actions](#interactive-actions). |

### Interactive actions

Interactive actions add buttons, select menus, and input fields to a response. Users interact with these elements, and the agent handles the interactions via `ON_ACTION` blocks.

#### Syntax

```yaml expandable=true theme={null}
RESPOND: "How would you like to proceed?"
ACTIONS:
  - id: confirm_wire
    type: button
    label: "Confirm Wire"
    value: "confirmed"

  - id: modify_amount
    type: button
    label: "Modify Amount"
    value: "modify"

  - id: cancel
    type: button
    label: "Cancel"
    value: "cancelled"
```

#### Action element properties

| Property      | Type      | Required | Default | Description                                                                                                                    |
| ------------- | --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `id`          | `string`  | Yes      | --      | Unique action identifier. Referenced in `ON_ACTION` handlers.                                                                  |
| `type`        | `string`  | Yes      | --      | Element type: `button`, `select`, or `input`.                                                                                  |
| `label`       | `string`  | Yes      | --      | Display label.                                                                                                                 |
| `value`       | `string`  | No       | --      | Hidden value sent when the user interacts with this element.                                                                   |
| `url`         | `string`  | No       | --      | For `button` type only: clicking opens this link instead of posting the value back to the agent. (Aliases: `link`, `web_url`.) |
| `description` | `string`  | No       | --      | Subtitle or help text (for list items).                                                                                        |
| `options`     | `array`   | No       | --      | Options for `select` type. Each has `id`, `label`, `description`.                                                              |
| `inputType`   | `string`  | No       | --      | Input type for `input` elements: `text`, `number`, `date`, `time`, `email`.                                                    |
| `placeholder` | `string`  | No       | --      | Placeholder text for `input` elements.                                                                                         |
| `required`    | `boolean` | No       | --      | Whether the input is required before submission.                                                                               |

#### Select element example

```yaml theme={null}
ACTIONS:
  - id: select_account
    type: select
    label: "Choose Account"
    options:
      - id: checking
        label: "Checking ****4521"
        description: "Available: $12,340.50"
      - id: savings
        label: "Savings ****8872"
        description: "Available: $45,200.00"
```

#### Input element example

```yaml expandable=true theme={null}
ACTIONS:
  - id: amount_input
    type: input
    label: "Transfer Amount"
    inputType: number
    placeholder: "Enter amount"
    required: true

  - id: reference_input
    type: input
    label: "Reference (optional)"
    inputType: text
    placeholder: "Invoice number, memo, etc."
    required: false
  submitLabel: "Submit"
  submitId: "submit_transfer"
```

#### Form submission

When the `ACTIONS` block contains `input` elements, you can specify a `submitLabel` and `submitId` for the form submission button:

| Property      | Type     | Required | Default | Description                                   |
| ------------- | -------- | -------- | ------- | --------------------------------------------- |
| `submitLabel` | `string` | No       | --      | Label for the form submit button.             |
| `submitId`    | `string` | No       | --      | Action ID emitted when the form is submitted. |

#### ON\_ACTION handlers

Handle user interactions with action elements in flow steps:

```yaml expandable=true theme={null}
FLOW:
  review_wire:
    RESPOND: "Ready to proceed?"
    ACTIONS:
      - id: confirm
        type: button
        label: "Confirm"
      - id: cancel
        type: button
        label: "Cancel"
    ON_ACTION:
      confirm:
        DO:
          - SET: user_confirmed = true
          - RESPOND: "Executing your wire transfer."
            FORMATS:
              MARKDOWN: "**Executing your wire transfer.**"
          - GOTO: execute_wire_step
      cancel:
        RESPOND: "Wire transfer cancelled."
        GOTO: cleanup
```

The `ON_ACTION` handler properties are described below.

| Property                       | Type                    | Required | Default | Description                                                               |
| ------------------------------ | ----------------------- | -------- | ------- | ------------------------------------------------------------------------- |
| `ACTION_ID`                    | `string`                | Yes      | --      | Which action element triggered this handler.                              |
| `CONDITION`                    | `string`                | No       | --      | Optional condition based on the action value.                             |
| `DO`                           | ordered action list     | No       | --      | Preferred form when order or nested rich `FORMATS:` matters.              |
| `RESPOND`                      | `string`                | No       | --      | Response message; supports nested `FORMATS:` inside a `DO` action.        |
| `SET`                          | `Record<string,string>` | No       | --      | Variable assignments.                                                     |
| `CLEAR`                        | `string[]`              | No       | --      | Session variables to clear.                                               |
| `CALL`                         | `string`                | No       | --      | Tool call; use `AS result_key` to store the result.                       |
| `GOTO` / `TRANSITION` / `THEN` | `string`                | No       | --      | Flow step to transition to.                                               |
| `HANDOFF`                      | `string`                | No       | --      | Declared handoff target agent.                                            |
| `DELEGATE`                     | `string`                | No       | --      | Declared delegate target agent; supports nested `RETURN` and `ON_RETURN`. |
| `COMPLETE`                     | `boolean`               | No       | `true`  | Complete the current flow.                                                |

If a handler `RESPOND` includes rich `FORMATS:` before terminal routing, that payload is forwarded as the fallback final channel payload. The terminal target's own rich payload takes precedence.

#### Reusable handlers (`ACTION_HANDLERS:`)

`ON_ACTION` inside a flow step handles actions for that step only. To define **reusable** action handlers available across the whole agent, declare a top-level `ACTION_HANDLERS:` section. Each entry is keyed by the action element `id` and uses the same grammar as `ON_ACTION` (an optional `CONDITION`, shorthand `RESPOND`/`SET`/`TRANSITION`, or a canonical `DO:` block of ordered actions — `SET`, `CLEAR`, `LOG`, `RESPOND`, `CALL`, `GOTO`/`TRANSITION`/`THEN`, `HANDOFF`, `DELEGATE`, `COMPLETE`).

```yaml theme={null}
ACTION_HANDLERS:
  open_summary:
    DO:
      - SET: selected_action = "open_summary"
      - RESPOND: TEMPLATE(account_summary)
      - TRANSITION: display_summary

  contact_support:
    CONDITION: user.tier == "premium"
    DO:
      - RESPOND: "Connecting you to premium support."
      - HANDOFF: Support_Agent
```

### Templates

Templates are named, reusable response definitions declared in the `TEMPLATES:` block. They support `{{}}` interpolation and multi-format variants.

#### Syntax

```yaml expandable=true theme={null}
TEMPLATES:
  wire_confirmation:
    DEFAULT: |
      **Wire Confirmation -- {{confirmation_number}}**
      From: ****{{source_last4}} | To: {{beneficiary_name}}
      Amount: {{amount}} {{currency}} | Fees: {{fees}} | Total: {{total_debit}}
      Status: {{status}} | ETA: {{estimated_arrival}}
    MARKDOWN: |
      ## Wire Transfer Confirmation
      | Field | Value |
      |-------|-------|
      | Confirmation | {{confirmation_number}} |
      | Amount | {{amount}} {{currency}} |
      | Status | {{status}} |

  fee_breakdown:
    DEFAULT: |
      **Fee Breakdown for {{transfer_type}} wire**
      Wire fee: {{wire_fee}} {{currency}}
      {{#if intermediary_fee}}Intermediary fee: {{intermediary_fee}} {{currency}}{{/if}}
      **Total fees: {{total_fees}} {{currency}}**
```

#### Template properties

| Property        | Type       | Required | Default | Description                                                                                              |
| --------------- | ---------- | -------- | ------- | -------------------------------------------------------------------------------------------------------- |
| `name`          | `string`   | Yes      | --      | Template name (the YAML key). Referenced via `TEMPLATE(name)`.                                           |
| `DEFAULT`       | `string`   | Yes      | --      | Default template body with `{{}}` interpolation.                                                         |
| `MARKDOWN`      | `string`   | No       | --      | Markdown variant.                                                                                        |
| `ADAPTIVE_CARD` | `string`   | No       | --      | Adaptive Card JSON variant.                                                                              |
| `ACTIONS`       | `object`   | No       | --      | Interactive actions attached to this template.                                                           |
| `VOICE`         | `object`   | No       | --      | Voice (TTS) overrides for this template. Same shape as [Voice configuration](#voice-configuration).      |
| `RENDERABLES`   | `object[]` | No       | --      | Customer-owned structured payload contracts (`name`, `payload`, `targets`, `fallbackText`, `schemaRef`). |

#### Referencing templates

Use `TEMPLATE(name)` in any RESPOND value:

```yaml theme={null}
RESPOND: TEMPLATE(wire_confirmation)
```

#### Template interpolation

Templates use `{{variable_name}}` for value substitution and `{{#if variable}}...{{/if}}` for conditional sections:

```yaml theme={null}
DEFAULT: |
  Hello, {{customer_name}}.
  {{#if has_loyalty}}Your loyalty tier: {{loyalty_tier}}.{{/if}}
  How can I help you today?
```

### Channel selection

The runtime selects the response format based on the delivery channel.

| Channel  | Priority format                           | Fallback     |
| -------- | ----------------------------------------- | ------------ |
| Web/SDK  | `RICH_CONTENT` (Markdown, HTML, AG-UI)    | Plain text   |
| Mobile   | `RICH_CONTENT` (Adaptive Card, Carousel)  | Plain text   |
| Voice    | `VOICE` (SSML, instructions, plain\_text) | RESPOND text |
| Slack    | `RICH_CONTENT` (SLACK)                    | Markdown     |
| WhatsApp | `RICH_CONTENT` (WHATSAPP)                 | Plain text   |

If the preferred format isn't available, the runtime falls back through the priority chain until it finds a defined format. Plain text (`RESPOND`) is always the final fallback.

***

## Expressions and functions

ABL expressions are used in conditions (`WHEN`, `CHECK`, constraint rules), value assignments (`SET`), template interpolation (`{{}}`), and function calls. This section documents the expression syntax and all 36 built-in functions.

### Expression syntax

#### Comparison operators

| Operator     | Syntax           | Description                                           |
| ------------ | ---------------- | ----------------------------------------------------- |
| `==`         | `a == b`         | Equal to.                                             |
| `!=`         | `a != b`         | Not equal to.                                         |
| `>`          | `a > b`          | Greater than.                                         |
| `<`          | `a < b`          | Less than.                                            |
| `>=`         | `a >= b`         | Greater than or equal to.                             |
| `<=`         | `a <= b`         | Less than or equal to.                                |
| `in`         | `a IN [x,y,z]`   | Value is in the list.                                 |
| `not_in`     | `a NOT IN [x]`   | Value is not in the list.                             |
| `matches`    | `a matches r`    | Value matches a regular expression.                   |
| `contains`   | `a contains b`   | String contains substring, or array contains element. |
| `startsWith` | `a startsWith b` | String starts with a prefix.                          |
| `endsWith`   | `a endsWith b`   | String ends with a suffix.                            |

#### Logical operators

| Operator | Syntax    | Description                   |
| -------- | --------- | ----------------------------- |
| `AND`    | `a AND b` | Both conditions must be true. |
| `OR`     | `a OR b`  | At least one must be true.    |
| `NOT`    | `NOT a`   | Negates the condition.        |

Write logical operators in uppercase (`AND`, `OR`, `NOT`). `!` is also accepted as a prefix negation.

#### Unary operators

| Operator     | Syntax                         | Description                                                              |
| ------------ | ------------------------------ | ------------------------------------------------------------------------ |
| `NOT` / `!`  | `NOT condition` / `!condition` | Negates a condition.                                                     |
| `IS SET`     | `var IS SET`                   | True if the variable is not null/undefined (empty string counts as set). |
| `IS NOT SET` | `var IS NOT SET`               | True if the variable is null or undefined.                               |
| `is_number`  | `var is_number`                | True if the variable is a number.                                        |

#### Operator precedence

1. Parentheses `()`
2. Unary operators (`NOT`, `IS SET`, `IS NOT SET`)
3. Comparison operators (`==`, `!=`, `>`, `<`, `>=`, `<=`, `contains`, `matches`)
4. `AND`
5. `OR`

Use parentheses to override default precedence:

```yaml theme={null}
WHEN: (status == "active" OR status == "pending") AND amount > 0
```

### Variable paths and dot notation

Reference variables using dot notation to access nested values.

```yaml theme={null}
user.name                  # Access nested property
user.addresses[0].city     # Array index access
acctResult.status          # Tool result field
```

#### Path resolution rules

* The evaluator looks up the full path in the session context.
* The Platform resolves each segment left to right: `user.address.city` resolves `user`, then `address` on the result, then `city`.
* If any segment resolves to `null` or `undefined`, the entire path resolves to `undefined`.
* Array access uses bracket notation: `items[0]`, `items[2].name`.

### Template strings

Template strings use `{{}}` syntax for variable interpolation within `RESPOND`, `summary`, and other string properties:

```yaml theme={null}
RESPOND: "Hello, {{customer_name}}! Your balance is {{available_balance}}."
```

#### Conditional sections

Templates support conditional rendering with `{{#if}}...{{/if}}`:

```yaml theme={null}
RESPOND: |
  Transfer complete.
  {{#if fx_rate}}Exchange rate: {{fx_rate}}{{/if}}
  Estimated arrival: {{estimated_arrival}}.
```

#### Function calls in templates

You can call built-in functions within template strings:

```yaml theme={null}
SET:
  formatted_balance = FORMAT_CURRENCY(available_balance, "USD")
RESPOND: "Your balance is {{formatted_balance}}."
```

### Built-in function reference

ABL provides 36 built-in functions organized into seven categories (plus the CEL-only content-analysis helpers described below). All functions are called with `FUNCTION_NAME(arg1, arg2, ...)` syntax. Function names are **uppercase**.

#### Math functions

| Function | Signature                       | Description                                         | Example                            |
| -------- | ------------------------------- | --------------------------------------------------- | ---------------------------------- |
| `ADD`    | `ADD(a, b) -> number`           | Add two numbers.                                    | `ADD(2, 3)` returns `5`            |
| `SUB`    | `SUB(a, b) -> number`           | Subtract b from a.                                  | `SUB(10, 3)` returns `7`           |
| `MUL`    | `MUL(a, b) -> number`           | Multiply two numbers.                               | `MUL(4, 5)` returns `20`           |
| `DIV`    | `DIV(a, b) -> number`           | Divide a by b. Returns `null` for division by zero. | `DIV(10, 2)` returns `5`           |
| `ROUND`  | `ROUND(n, decimals?) -> number` | Round to specified decimal places. Default: 0.      | `ROUND(3.14159, 2)` returns `3.14` |
| `ABS`    | `ABS(n) -> number`              | Absolute value.                                     | `ABS(-5)` returns `5`              |
| `MIN`    | `MIN(a, b) -> number`           | Return the smaller of two numbers.                  | `MIN(3, 7)` returns `3`            |
| `MAX`    | `MAX(a, b) -> number`           | Return the larger of two numbers.                   | `MAX(3, 7)` returns `7`            |

Math functions coerce string arguments to numbers automatically: `ADD("2", "3")` returns `5`.

#### String functions

| Function    | Signature                               | Description                        | Example                                        |
| ----------- | --------------------------------------- | ---------------------------------- | ---------------------------------------------- |
| `UPPER`     | `UPPER(s) -> string`                    | Convert to uppercase.              | `UPPER("hello")` returns `"HELLO"`             |
| `LOWER`     | `LOWER(s) -> string`                    | Convert to lowercase.              | `LOWER("HELLO")` returns `"hello"`             |
| `TRIM`      | `TRIM(s) -> string`                     | Strip leading/trailing whitespace. | `TRIM("  hi  ")` returns `"hi"`                |
| `SUBSTRING` | `SUBSTRING(s, start, end?) -> string`   | Extract a substring.               | `SUBSTRING("hello", 0, 3)` returns `"hel"`     |
| `REPLACE`   | `REPLACE(s, find, repl) -> string`      | Replace all occurrences.           | `REPLACE("a,b,c", ",", "-")` returns `"a-b-c"` |
| `SPLIT`     | `SPLIT(s, delimiter) -> string[]`       | Split string into array.           | `SPLIT("a,b,c", ",")` returns `["a","b","c"]`  |
| `JOIN`      | `JOIN(arr, delimiter) -> string`        | Join array into string.            | `JOIN(["a","b"], ", ")` returns `"a, b"`       |
| `PAD_START` | `PAD_START(s, length, char?) -> string` | Left-pad to specified length.      | `PAD_START("42", 6, "0")` returns `"000042"`   |
| `PAD_END`   | `PAD_END(s, length, char?) -> string`   | Right-pad to specified length.     | `PAD_END("42", 6, "0")` returns `"420000"`     |
| `REPEAT`    | `REPEAT(s, count) -> string`            | Repeat string N times.             | `REPEAT("*", 4)` returns `"****"`              |

The string functions gracefully handle `null` and `undefined` and return an empty string: `UPPER(null)` returns `""`.

To prevent memory issues, the limit on string output is 100,000 characters.

#### Formatting functions

| Function          | Signature                                         | Description                             | Example                                                                    |
| ----------------- | ------------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------- |
| `MASK`            | `MASK(s, pattern, char?) -> string`               | Mask a string. See Mask Patterns below. | `MASK("4111111111111111", "last4")` returns `"************1111"`           |
| `FORMAT_CURRENCY` | `FORMAT_CURRENCY(n, currency, locale?) -> string` | Format a number as currency.            | `FORMAT_CURRENCY(1234.5, "USD")` returns `"$1,234.50"`                     |
| `FORMAT_DATE`     | `FORMAT_DATE(d, format, tz?) -> string`           | Format a date string.                   | `FORMAT_DATE("2024-03-15T10:30:00Z", "YYYY-MM-DD")` returns `"2024-03-15"` |
| `ORDINAL`         | `ORDINAL(n) -> string`                            | Convert number to ordinal string.       | `ORDINAL(1)` returns `"1st"`, `ORDINAL(22)` returns `"22nd"`               |

The mask patterns are explained below.

| Pattern  | Behavior                                           | Example result             |
| -------- | -------------------------------------------------- | -------------------------- |
| `last4`  | Mask all characters except the last 4.             | `"************1111"`       |
| `first4` | Mask all characters except the first 4.            | `"4111************"`       |
| `N*N`    | Show N chars at start, mask middle, show N at end. | `MASK(s, "4*4")` shows 4+4 |

The default mask character is `*`. Pass a third argument to use a different character: `MASK(ssn, "last4", "x")`.

The date format uses the following notations:

| Token  | Description          | Example |
| ------ | -------------------- | ------- |
| `YYYY` | Four-digit year      | `2024`  |
| `MM`   | Two-digit month      | `03`    |
| `DD`   | Two-digit day        | `15`    |
| `HH`   | Two-digit hour (24h) | `10`    |
| `mm`   | Two-digit minute     | `30`    |
| `ss`   | Two-digit second     | `00`    |

Example: `FORMAT_DATE("2024-03-15T10:30:00Z", "YYYY-MM-DD HH:mm")` returns `"2024-03-15 10:30"`.

`FORMAT_DATE` formats in **UTC by default** — a date-time string without an explicit offset is interpreted as UTC, so the output is deterministic regardless of where the runtime executes. Pass an optional IANA timezone name as the third argument to format in that zone instead:

```
FORMAT_DATE("2024-03-15T10:30:00Z", "YYYY-MM-DD HH:mm", "America/New_York")  # "2024-03-15 06:30"
```

An unrecognized timezone falls back to UTC.

#### Type checking and coercion functions

| Function    | Signature                 | Description                                         | Example                                                                               |
| ----------- | ------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `IS_ARRAY`  | `IS_ARRAY(x) -> boolean`  | True if the value is an array.                      | `IS_ARRAY([1,2])` returns `true`                                                      |
| `IS_NUMBER` | `IS_NUMBER(x) -> boolean` | True if the value is a number (not NaN).            | `IS_NUMBER(42)` returns `true`                                                        |
| `IS_STRING` | `IS_STRING(x) -> boolean` | True if the value is a string.                      | `IS_STRING("hi")` returns `true`                                                      |
| `TO_NUMBER` | `TO_NUMBER(x) -> number`  | null                                                | Convert to number. Returns `null` if conversion fails. `TO_NUMBER("42")` returns `42` |
| `TO_STRING` | `TO_STRING(x) -> string`  | Convert to string. Returns `""` for null/undefined. | `TO_STRING(42)` returns `"42"`                                                        |

#### Array functions

| Function           | Signature                                       | Description                                               | Example                                                                                              |
| ------------------ | ----------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `LENGTH`           | `LENGTH(x) -> number`                           | Array length or string length. Returns 0 for other types. | `LENGTH([1,2,3])` returns `3`                                                                        |
| `ARRAY_FIND`       | `ARRAY_FIND(arr, field, value) -> object`       | null                                                      | Find first element where `field == value`. `ARRAY_FIND(users, "id", 42)` returns the matching object |
| `ARRAY_FIND_INDEX` | `ARRAY_FIND_INDEX(arr, field, value) -> number` | Find index of first match. Returns -1 if not found.       | `ARRAY_FIND_INDEX(items, "type", "b")` returns the index                                             |

#### Object functions

| Function        | Signature                                 | Description                                       | Example                                           |
| --------------- | ----------------------------------------- | ------------------------------------------------- | ------------------------------------------------- |
| `OBJECT_KEYS`   | `OBJECT_KEYS(obj) -> string[]`            | Return array of object keys.                      | `OBJECT_KEYS({a:1, b:2})` returns `["a","b"]`     |
| `OBJECT_VALUES` | `OBJECT_VALUES(obj) -> any[]`             | Return array of object values.                    | `OBJECT_VALUES({a:1, b:2})` returns `[1, 2]`      |
| `OBJECT_MERGE`  | `OBJECT_MERGE(obj1, obj2, ...) -> object` | Merge objects. Right-side values win on conflict. | `OBJECT_MERGE({a:1}, {b:2})` returns `{a:1, b:2}` |

`OBJECT_KEYS` and `OBJECT_VALUES` return an empty array for non-object inputs (null, arrays, strings).

`OBJECT_MERGE` accepts any number of arguments and skips non-object values.

#### Utility functions

| Function    | Signature                      | Description                                                                               | Example                                                |
| ----------- | ------------------------------ | ----------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `COALESCE`  | `COALESCE(a, b, ...) -> any`   | Return the first non-null, non-undefined value. Returns `null` if all arguments are null. | `COALESCE(null, undefined, "hello")` returns `"hello"` |
| `NOW`       | `NOW() -> string`              | Return the current timestamp as an ISO 8601 string.                                       | `NOW()` returns `"2024-03-15T10:30:00.000Z"`           |
| `UNIQUE_ID` | `UNIQUE_ID(length?) -> string` | Generate a random alphanumeric string. Default length: 6.                                 | `UNIQUE_ID(12)` returns `"aB3kM9pQ2xLw"`               |

`COALESCE` considers `0` and `false` as valid (non-null) values: `COALESCE(0, "fallback")` returns `0`.

`UNIQUE_ID` generates a random alphanumeric string suitable for reference numbers. It is **not** cryptographically secure — do not use it for tokens or secrets.

#### Content-analysis functions (CEL guardrails)

CEL-based [guardrail](/agent-platform/abl-reference/guardrails) checks have access to an additional
`abl.*` namespace of content-analysis helpers:

| Function                                 | Description                                    |
| ---------------------------------------- | ---------------------------------------------- |
| `abl.contains_pii(text)`                 | True if the text contains PII.                 |
| `abl.detect_pii(text)`                   | Structured PII detection result.               |
| `abl.redact_pii(text)`                   | Returns the text with PII redacted.            |
| `abl.matches_pattern(text, pattern)`     | Regex match (RE2-backed).                      |
| `abl.not_matches_pattern(text, pattern)` | Negation of `matches_pattern`.                 |
| `abl.word_count(text)`                   | Word count.                                    |
| `abl.sentence_count(text)`               | Sentence count.                                |
| `abl.contains_url(text)`                 | True if the text contains a URL.               |
| `abl.contains_email(text)`               | True if the text contains an email address.    |
| `abl.contains_code(text)`                | True if the text contains a fenced code block. |

<Note>In CEL expressions the core functions above are also available under the `abl.` namespace with lowercase names (e.g. `abl.upper(x)`), and CEL-native operators (`&&`, `||`, `!`, `%`, `in`, ternary `? :`) and macros (`size()`, `has()`) can be used.</Note>

### Nested function calls

Functions can be nested as arguments to other functions:

```yaml theme={null}
SET:
  result = ADD(MUL(2, 3), SUB(10, 4))     # Returns 12
  name = UPPER(TRIM("  hello  "))           # Returns "HELLO"
  fallback = COALESCE(user.lastName, "Guest")
```

Nesting is limited to a maximum depth of 32 to prevent stack overflow.

### Using expressions in ABL

#### In conditions (WHEN, CHECK, constraint rules)

```yaml theme={null}
WHEN: user.age >= 18 AND user.verified == true
CHECK: amount <= available_balance
- REQUIRE sanctions_clear == true
```

#### In SET assignments

```yaml theme={null}
SET:
  balance_formatted = FORMAT_CURRENCY(available_balance, "USD")
  wire_reference = UNIQUE_ID(12)
  greeting = COALESCE(user.name, "valued customer")
```

#### In template interpolation

```yaml theme={null}
RESPOND: "Hello, {{customer_name}}! Balance: {{FORMAT_CURRENCY(available_balance, 'USD')}}."
```

#### In TRANSFORM pipelines

```yaml theme={null}
TRANSFORM:
  SOURCE: search_results
  AS: item
  INTO: filtered_results
  FILTER: item.price <= budget AND item.available == true
  MAP:
    name: item.hotel_name
    price: FORMAT_CURRENCY(item.price, "USD")
  SORT_BY: price ASC
  LIMIT: 5
```

### Type coercion rules

The evaluator applies these coercion rules during expression evaluation:

| Context                    | Rule                                                                                                                  |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Equality (`==`)            | null/undefined == null/undefined is true. Strings compared case-sensitively. Numbers parsed from strings.             |
| Inequality (`!=`)          | If either side is undefined/null, returns true.                                                                       |
| Numeric (`>`, `<`, etc.)   | Strings parsed to numbers. Booleans become 0/1. Arrays become length. Undefined becomes 0.                            |
| Truthiness (bare variable) | `false`, `0`, `""`, `"false"`, `null`, `undefined`, empty arrays, empty objects are falsy. Everything else is truthy. |
| IS SET / IS NOT SET        | Checks for null/undefined only. Empty string IS SET.                                                                  |

***

**Related articles:**

* [Memory and constraints](/agent-platform/abl-reference/memory-and-constraints) -- condition expressions in constraint rules, variable paths and session context
* [Lifecycle and hooks](/agent-platform/abl-reference/lifecycle-and-hooks) -- ON\_START and hooks that support rich content
* [Multi-Agent and supervisor](/agent-platform/abl-reference/multi-agent-and-supervisor) -- COMPLETE conditions with rich responses
* [Data Types and utilities](/agent-platform/abl-reference/data-types-and-utilities) -- types used in function signatures, lookup validation functions
