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

# Multi-Agent and Supervisor

This page documents multi-agent orchestration constructs (`DELEGATE`, `HANDOFF`, `ESCALATE`, `COMPLETE`) and the `SUPERVISOR:` declaration for top-level routing.

***

## SUPERVISOR Declaration

A Supervisor is a top-level orchestrator that routes user messages to the appropriate child agent based on intent, context, and declarative rules. Supervisor documents use the `SUPERVISOR:` keyword instead of `AGENT:` and define agent references, routing rules, state schemas, policies, and communication settings.

### Overview

While agents handle domain-specific tasks, the Supervisor decides which agent should handle each user message. It does not execute tools or gather information directly; it classifies intent and routes accordingly.

```yaml theme={null}
SUPERVISOR: Travel_Supervisor
VERSION: "2.0"
DESCRIPTION: "Routes customers to booking, support, or sales specialists"
GOAL: "Route requests to the right specialist with full context preservation"

PERSONA: |
  Professional travel booking assistant. Friendly, efficient, and helpful.
  Routes requests quickly and transparently.
```

### Agent references

The Supervisor declares which agents are available for routing. Each reference includes a file path, an alias, and a list of capabilities.

#### Syntax

```yaml theme={null}
AGENTS:
  - REF: ./agents/flight_search.agent.abl
    ALIAS: Flight_Search
    CAPABILITIES: [flight_booking, fare_search, seat_selection]
    CHANNELS: [web, mobile, voice]
    REQUIRES_VALIDATION: false

  - REF: ./agents/support.agent.abl
    ALIAS: Support_Agent
    CAPABILITIES: [booking_management, cancellation, refund]
    REQUIRES_VALIDATION: true
```

#### Agent reference properties

| Property              | Type       | Required | Default | Description                                                           |
| --------------------- | ---------- | -------- | ------- | --------------------------------------------------------------------- |
| `REF`                 | `string`   | Yes      | --      | File path to the agent's ABL definition.                              |
| `ALIAS`               | `string`   | Yes      | --      | Local name used in routing rules and handoff targets.                 |
| `CAPABILITIES`        | `string[]` | Yes      | --      | List of capability tags describing what the agent can do.             |
| `CHANNELS`            | `string[]` | No       | --      | Channels this agent supports (for example. `web`, `mobile`, `voice`). |
| `REQUIRES_VALIDATION` | `boolean`  | No       | `false` | Whether the user must be authenticated before routing to this agent.  |

### Routing rules

Routing rules define conditional logic for directing messages to agents. Rules are evaluated in priority order.

#### Syntax

```yaml theme={null}
ROUTING:
  - NAME: escalation_route
    DESCRIPTION: "Route frustrated or explicitly requesting human"
    PRIORITY: 1
    WHEN: intent.category == "escalation" OR user.frustration_detected == true
    THEN: ROUTE_TO Live_Agent_Transfer
    FLAGS: [set_active]

  - NAME: booking_route
    PRIORITY: 5
    WHEN: intent.category == "new_booking"
    THEN: ROUTE_TO Sales_Agent
```

Alternatively, routing can be declared using the `HANDOFF:` block within a Supervisor, following the same syntax as [agent handoffs](#handoff):

```yaml theme={null}
HANDOFF:
  - TO: Sales_Agent
    WHEN: intent.category == "new_booking"
    CONTEXT:
      pass: [search_context, user_preferences, budget]
      summary: "User looking to book new travel"
    EXPECT_RETURN: false
```

#### Routing rule properties

| Property      | Type            | Required | Default | Description                                                       |
| ------------- | --------------- | -------- | ------- | ----------------------------------------------------------------- |
| `NAME`        | `string`        | Yes      | --      | Unique name for the routing rule.                                 |
| `DESCRIPTION` | `string`        | No       | --      | Human-readable description.                                       |
| `PRIORITY`    | `number`        | Yes      | --      | Evaluation order. Lower values are evaluated first.               |
| `WHEN`        | `string`        | Yes      | --      | Condition expression that must be true for this rule to activate. |
| `THEN`        | `RoutingAction` | Yes      | --      | Action to take. See [Routing actions](#routing-actions).          |
| `FLAGS`       | `string[]`      | No       | --      | Behavioral flags. See [Routing flags](#routing-flags).            |
| `CONSTRAINTS` | `object`        | No       | --      | Additional constraints on when this rule applies.                 |

#### Routing actions

| Action               | Syntax                       | Description                                           |
| -------------------- | ---------------------------- | ----------------------------------------------------- |
| Route to agent       | `ROUTE_TO Agent_Name`        | Send the message to a specific agent.                 |
| Route to user        | `ROUTE_TO_USER "message"`    | Send a message and wait for user input.               |
| Route by variable    | `ROUTE_TO_VARIABLE var_name` | Route to the agent named in a variable.               |
| Intent-based routing | `INTENT_MATCH`               | Route based on detected intent. See below.            |
| End conversation     | `END_CONVERSATION`           | End the session.                                      |
| System action        | `SYSTEM_ACTION action_name`  | Execute a system-level action (for example. handoff). |

#### Intent-based routing

For more granular routing, use `INTENT_MATCH` with intent-to-agent mappings:

```yaml theme={null}
ROUTING:
  - NAME: intent_router
    PRIORITY: 10
    WHEN: true
    THEN:
      INTENT_MATCH:
        - INTENTS: [flight_search, hotel_search]
          ACTION: ROUTE_TO Sales_Agent
        - INTENTS: [manage_booking, cancel_booking]
          ACTION: ROUTE_TO Support_Agent
        FALLBACK: ROUTE_TO Fallback_Handler
```

#### Routing flags

| Flag             | Effect                                                             |
| ---------------- | ------------------------------------------------------------------ |
| `set_active`     | Mark the target agent as the active agent for subsequent messages. |
| `silent`         | Route without sending a user-visible message.                      |
| `no_log`         | Do not log this routing decision in the trace store.               |
| `priority_boost` | Apply a priority boost in the target agent's queue.                |

#### Conditional routing (WHEN clauses)

WHEN clauses use the same expression syntax as [Expressions & functions](/agent-platform/abl-reference/rich-content-and-expressions#expressions-and-functions). Common patterns include:

```yaml theme={null}
# Intent-based
WHEN: intent.category == "complaint"

# State-based
WHEN: user.is_authenticated == true AND intent.category == "manage_booking"

# Negation
WHEN: NOT intent.has_specific_request

# Compound
WHEN: intent.unclear == true OR intent.confidence < 0.5

# Variable check
WHEN: handoff_count >= 4
```

#### Routing constraint blocks

Add constraints to limit when a rule applies beyond the WHEN condition:

```yaml theme={null}
ROUTING:
  - NAME: voice_only_route
    PRIORITY: 3
    WHEN: intent.category == "voice_action"
    THEN: ROUTE_TO Voice_Agent
    CONSTRAINTS:
      channels: [voice]
      requiresState: [user.is_authenticated]
      ignoreIntents: [greeting, farewell]
```

| Constraint      | Type       | Description                                                     |
| --------------- | ---------- | --------------------------------------------------------------- |
| `ignoreIntents` | `string[]` | Intents that should not trigger this rule.                      |
| `channels`      | `string[]` | Channels where this rule applies (for example. `[web, voice]`). |
| `requiresState` | `string[]` | State variables that must be set for this rule to activate.     |

### State schema

The Supervisor can declare a state schema that defines typed variables organized by namespace.

```yaml theme={null}
STATE:
  user:
    is_authenticated:
      type: boolean
      required: false
      default: false
      description: "Whether the user has been authenticated"
    language:
      type: string
      required: false
      source: user
  system:
    routing_failures:
      type: number
      required: false
      default: 0
      source: system
```

State variables follow the same [VariableDefinition](/agent-platform/abl-reference/data-types-and-utilities) structure as agent variables, with the addition of namespace grouping.

#### State variable properties

| Property      | Type                                                                     | Required | Default | Description                                          |
| ------------- | ------------------------------------------------------------------------ | -------- | ------- | ---------------------------------------------------- |
| `type`        | See [Data types](/agent-platform/abl-reference/data-types-and-utilities) | Yes      | --      | Variable type.                                       |
| `required`    | `boolean`                                                                | No       | `false` | Whether the variable must have a value.              |
| `default`     | any                                                                      | No       | --      | Default value.                                       |
| `description` | `string`                                                                 | No       | --      | Human-readable description.                          |
| `source`      | `system`, `user` , `agent`, `computed`                                   | No       | --      | Origin of the variable value.                        |
| `updatedBy`   | `string[]`                                                               | No       | --      | List of agent aliases that can update this variable. |

### Policies

Policies define high-level behavioral rules for the Supervisor, constraining what it is allowed and forbidden to do.

```yaml theme={null}
POLICIES:
  - NAME: no_direct_booking
    DESCRIPTION: "Supervisor must not make bookings directly"
    RULES:
      forbiddenWhen: intent.category == "booking" AND active_agent IS NOT SET
      behavior: "Route to Sales_Agent instead of handling directly"

  - NAME: auth_required_for_account
    DESCRIPTION: "Account operations require authentication"
    RULES:
      allowedWhen: user.is_authenticated == true
      triggerSignal: "auth_required"
```

#### Policy properties

| Property      | Type     | Required | Default | Description                         |
| ------------- | -------- | -------- | ------- | ----------------------------------- |
| `NAME`        | `string` | Yes      | --      | Unique policy name.                 |
| `DESCRIPTION` | `string` | No       | --      | Human-readable description.         |
| `RULES`       | `object` | Yes      | --      | Policy rule definitions. See below. |

#### Policy rule properties

| Property        | Type     | Required | Default | Description                                          |
| --------------- | -------- | -------- | ------- | ---------------------------------------------------- |
| `allowedWhen`   | `string` | No       | --      | Condition under which the action is allowed.         |
| `forbiddenWhen` | `string` | No       | --      | Condition under which the action is forbidden.       |
| `triggerSignal` | `string` | No       | --      | Signal to emit when the policy is triggered.         |
| `behavior`      | `string` | No       | --      | Description of the expected behavior when triggered. |

### Communication settings

Communication settings define the Supervisor's language, tone, and vocabulary preferences.

```yaml theme={null}
COMMUNICATION:
  language: en
  formality: neutral
  pronouns:
    use: "we"
    avoid: "I"
  vocabulary:
    prefer: [assist, help, guide]
    avoid: [unfortunately, regrettably]
  constraints:
    - "Never reveal internal agent names to the user"
    - "Always explain why a transfer is happening"
```

#### Communication properties

| Property      | Type                            | Required | Default | Description                                      |
| ------------- | ------------------------------- | -------- | ------- | ------------------------------------------------ |
| `language`    | `string`                        | Yes      | --      | Primary language code (for example. `en`, `es`). |
| `formality`   | `formal`, `informal`, `neutral` | Yes      | --      | Communication tone.                              |
| `pronouns`    | `object`                        | No       | --      | Pronoun preferences (`use` and `avoid`).         |
| `vocabulary`  | `object`                        | No       | --      | Preferred and avoided vocabulary.                |
| `constraints` | `string[]`                      | Yes      | --      | Communication behavioral constraints.            |

### Behavior settings

The `BEHAVIOR` block defines whether the Supervisor can respond directly to users or must always route to an agent.

```yaml theme={null}
BEHAVIOR:
  canRespondDirectly: false
  allowedDirectActions: [greet, clarify_intent]
  forbiddenActions: [make_booking, process_payment, access_account]
```

| Property               | Type       | Required | Default | Description                                                 |
| ---------------------- | ---------- | -------- | ------- | ----------------------------------------------------------- |
| `canRespondDirectly`   | `boolean`  | Yes      | --      | Whether the Supervisor can send messages directly to users. |
| `allowedDirectActions` | `string[]` | No       | `[]`    | Actions the Supervisor can perform directly.                |
| `forbiddenActions`     | `string[]` | No       | `[]`    | Actions the Supervisor must never perform.                  |

### Intents

In addition to `INTENT_MATCH` inside a routing rule, a Supervisor may declare a top-level `INTENTS:`
block listing intent labels (and optional lexical-fallback behavior) that routing and classification
draw on. Supervisors can also hand off to **other supervisors**, enabling hierarchical composition,
and may declare an `ON_ERROR` block to handle routing failures.

### Execution pipeline (pre-classification)

<Note>
  This is an advanced, opt-in optimization. Most supervisors do not need it — routing works without
  an `EXECUTION` block.
</Note>

A Supervisor can enable a pre-classification pipeline that runs a smaller, faster model before the
main reasoning LLM. The classifier detects user intent and can short-circuit routing for obvious
cases, avoiding the cost of a full reasoning call.

```yaml theme={null}
SUPERVISOR: Support_Router

EXECUTION:
  model: claude-sonnet-4-5-20250929   # main reasoning model
  pipeline:
    enabled: true
    mode: sequential          # 'parallel' | 'sequential'
    shortCircuit:
      enabled: true
      confidenceThreshold: 0.85
    toolFilter:
      enabled: true
      maxTools: 6
    keywordVeto:
      enabled: true
      keywords: [reset, cancel, undo]
    intentBridge:
      enabled: true
      programmaticThreshold: 0.85
      guidedThreshold: 0.5
      outOfScopeDecline: true
      multiIntentSignal: true

HANDOFF:
  - TO: Billing_Agent
    WHEN: intent.category == "billing"
  - TO: General_Inquiry
    WHEN: true
```

<Note>
  The classifier **model** is not selected in the agent's `EXECUTION.pipeline` block — it is resolved
  from **project-level runtime configuration** via `modelSource` (`default` uses the platform's
  tool-selection model; `tenant` uses a specific tenant model identified by `tenantModelId`). A
  `model:` key inside the `pipeline` block is deprecated and ignored by the runtime. The top-level
  `EXECUTION.model` still sets the **main reasoning** model as usual.
</Note>

#### Pipeline options

| Option                               | Type       | Default    | Description                                                                                                                       |
| ------------------------------------ | ---------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`                            | `boolean`  | `false`    | Enable the pre-classification pipeline.                                                                                           |
| `mode`                               | `string`   | `parallel` | `parallel` — classifier and main LLM run simultaneously; `sequential` — classifier runs first, main LLM only if no short-circuit. |
| `shortCircuit.enabled`               | `boolean`  | `true`     | Allow direct routing when classifier confidence is high.                                                                          |
| `shortCircuit.confidenceThreshold`   | `number`   | `0.85`     | Minimum confidence to skip the reasoning loop.                                                                                    |
| `toolFilter.enabled`                 | `boolean`  | `true`     | Filter tools to only relevant ones before reasoning.                                                                              |
| `toolFilter.maxTools`                | `number`   | `6`        | Maximum tools passed to the reasoning loop.                                                                                       |
| `keywordVeto.enabled`                | `boolean`  | `true`     | Prevent short-circuit when the user mentions local tool keywords.                                                                 |
| `keywordVeto.keywords`               | `string[]` | `[]`       | Additional keywords that veto short-circuit routing.                                                                              |
| `intentBridge.enabled`               | `boolean`  | `true`     | Bridge classifier intent into routing decisions.                                                                                  |
| `intentBridge.programmaticThreshold` | `number`   | `0.85`     | Confidence at/above which intent routing is applied programmatically.                                                             |
| `intentBridge.guidedThreshold`       | `number`   | `0.5`      | Confidence at/above which intent is offered to the model as guidance.                                                             |
| `intentBridge.outOfScopeDecline`     | `boolean`  | `true`     | Decline out-of-scope requests detected by the classifier.                                                                         |
| `intentBridge.multiIntentSignal`     | `boolean`  | `true`     | Signal when the message contains multiple distinct intents.                                                                       |

For pure routing supervisors, `sequential` mode with `shortCircuit.enabled: true` gives the best
cost savings. In `parallel` mode the classifier adds latency protection but no cost savings, since
both calls run regardless.

***

## HANDOFF

HANDOFF transfers conversational control from the current agent to another agent, passing context and optionally expecting a return.

### Syntax

```yaml theme={null}
HANDOFF:
  - TO: Compliance_Officer
    WHEN: sanctions_clear == false
    PRIORITY: 0
    CONTEXT:
      pass: [customer_id, beneficiary_name, amount, sanctions_match_score]
      summary: "Wire flagged during sanctions screening (score: {{sanctions_match_score}})."
      history: full
      memory_grants:
        - path: user.compliance_notes
          access: readwrite
    EXPECT_RETURN: true
    ON_FAILURE: ESCALATE
    ON_RETURN:
      action: continue
      map:
        compliance_decision: sanctions_clear
        review_notes: compliance_review_notes
```

### Properties

| Property          | Type                | Required | Default | Description                                                                                                                                                   |
| ----------------- | ------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TO`              | `string`            | Yes      | --      | Target agent name.                                                                                                                                            |
| `WHEN`            | `string`            | Yes      | --      | Condition that triggers the handoff.                                                                                                                          |
| `PRIORITY`        | `number`            | No       | --      | Evaluation priority. Lower values are evaluated first when multiple handoff rules match.                                                                      |
| `CONTEXT`         | `object`            | Yes      | --      | Context to pass to the target agent. See [Context](#handoff-context).                                                                                         |
| `EXPECT_RETURN`   | `boolean`           | Yes      | `false` | Whether control should return to this agent after the target completes. `RETURN` is accepted as a backward-compatible alias.                                  |
| `ON_FAILURE`      | `string` / `object` | No       | --      | Parent-side fallback for setup or dispatch failures **before** the target accepts the handoff. See [Handoff failure strategies](#handoff-failure-strategies). |
| `ON_RETURN`       | `string` / `object` | No       | --      | How to handle the target returning control. See [Return expectations](#return-expectations).                                                                  |
| `EXPERIENCE_MODE` | `string`            | No       | --      | End-user experience when the transfer happens. See [Experience modes](#experience-modes).                                                                     |
| `REMOTE`          | `object`            | No       | --      | Remote agent configuration. Can also be expressed as top-level `LOCATION`/`ENDPOINT`/`PROTOCOL` keys. See [Remote agent support](#remote-agent-support).      |
| `ASYNC`           | `boolean`           | No       | `false` | Use async dispatch with push notifications for remote agents.                                                                                                 |
| `ASYNC_TIMEOUT`   | `number`            | No       | --      | Timeout in seconds for async handoff. (Also accepted as `TIMEOUT`.)                                                                                           |

<Note>
  The primary keyword is **`EXPECT_RETURN`**. The older `RETURN` keyword is still parsed for
  backward compatibility, but new agents should use `EXPECT_RETURN`. The legacy top-level `MAP`
  block is superseded by `ON_RETURN.map` (see [Return expectations](#return-expectations)).
</Note>

### Handoff context

The `CONTEXT` block defines what information the target agent receives.

| Property        | Type                | Required | Default | Description                                                                                       |
| --------------- | ------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------- |
| `pass`          | `string[]`          | Yes      | --      | Session variable names to include in the handoff context.                                         |
| `summary`       | `string`            | Yes      | --      | Human-readable summary of why the handoff is occurring. Supports `{{}}` interpolation.            |
| `history`       | `string` / `object` | No       | `auto`  | Conversation history strategy. See [History strategies](#history-strategies).                     |
| `memory_grants` | `object[]`          | No       | --      | Persistent memory paths to grant the target agent access to. See [Memory grants](#memory-grants). |

<Warning>
  The legacy `grant_memory: [path, ...]` form is **no longer supported** and produces a parse
  error. Use `memory_grants` with explicit `path`/`access` entries instead (see
  [Memory grants](#memory-grants)).
</Warning>

`CONTEXT` may also be expressed as a shorthand where `pass`, `summary`, and `history` appear as
direct siblings of the handoff entry rather than nested under `CONTEXT:`.

### History strategies

The `history` property controls how much conversation history the target agent receives.

| Value                          | Behavior                                                                                                                                          |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `auto`                         | Platform default. Uses the handoff summary when available; otherwise passes a bounded recent transcript. Usually you can omit `history` entirely. |
| `none`                         | No conversation history is passed. The target agent starts fresh.                                                                                 |
| `summary_only`                 | Only the `summary` text is passed, no raw messages.                                                                                               |
| `full`                         | The complete conversation history is passed.                                                                                                      |
| `{ mode: last_n, count: <n> }` | The last N messages are passed.                                                                                                                   |

```yaml theme={null}
CONTEXT:
  pass: [customer_id, amount]
  summary: "Customer needs fraud review."
  history:
    mode: last_n
    count: 10
```

<Note>
  The legacy shorthand `history: last_10` is still accepted during the compatibility window, but
  new agents should use the typed `mode` + `count` block.
</Note>

### Return expectations

When `EXPECT_RETURN: true`, the calling agent pauses and waits for the target agent to complete.
When the target explicitly returns control (via its built-in return capability), the parent resumes.
When `EXPECT_RETURN: false`, the handoff is a one-way transfer and the calling agent's turn ends.

`ON_RETURN` controls what happens when the target returns. It accepts either a **string** (the name
of a named return handler, or a built-in action) or a **structured block**:

```yaml theme={null}
HANDOFF:
  - TO: Authentication_Agent
    WHEN: user.is_authenticated == false
    CONTEXT:
      pass: [session_context]
      summary: "User needs authentication"
    EXPECT_RETURN: true
    ON_RETURN:
      action: continue          # continue | resume_intent
      handler: route_to_booking # optional: named RETURN_HANDLERS entry
      resume_with: latest_session_user_utterance
      map:                      # child result field -> parent variable
        user_id: auth_result.user_id
        auth_token: auth_result.token
      set:                      # parent assignments after mapping
        auth_summary: "Authenticated {{auth_result.user_id}}"
```

#### `ON_RETURN` properties

| Property      | Type                    | Description                                                                                                                                                               |
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`      | `string`                | Built-in resume behavior: `continue` (resume the parent's current flow) or `resume_intent` (re-run routing against the original user intent with the returned context).   |
| `handler`     | `string`                | Name of a [named return handler](#return-handlers) declared in the top-level `RETURN_HANDLERS:` block.                                                                    |
| `resume_with` | `string`                | Which utterance to replay when resuming. One of `original_handoff_utterance`, `latest_child_user_utterance`, `latest_session_user_utterance`, `forwarded_return_message`. |
| `map`         | `Record<string,string>` | Copies child return fields into parent variables (child key → parent variable).                                                                                           |
| `set`         | `Record<string,string>` | Parent assignments applied after `map`, using the same templated assignment shape as flow `ON_RESULT` branches.                                                           |

### Return handlers

A top-level `RETURN_HANDLERS:` block declares reusable named handlers that run on the parent after a
`EXPECT_RETURN: true` child returns. Reference one from `ON_RETURN.handler`.

```yaml theme={null}
RETURN_HANDLERS:
  route_to_booking:
    RESPOND: "You're verified — let's finish your booking."
    CLEAR: [pending_auth_reason]
    CONTINUE: true          # leave the parent waiting for the next user turn
    # RESUME_INTENT: true   # or replay the parent's last user message
```

| Property        | Type       | Description                                            |
| --------------- | ---------- | ------------------------------------------------------ |
| `RESPOND`       | `string`   | Message to send when the handler runs.                 |
| `CLEAR`         | `string[]` | Session variables to reset after the child returns.    |
| `CONTINUE`      | `boolean`  | Leave the parent waiting for the next user turn.       |
| `RESUME_INTENT` | `boolean`  | Replay the parent's last user message through routing. |

### Handoff failure strategies

`ON_FAILURE` defines a parent-side fallback for failures that occur **before** the target accepts the
handoff — for example target lookup, pre-transfer validation, or dispatch failures. It does not
replace the timeout path after an accepted returnable handoff, and it does not fire when a downstream
child later reports its own failure.

```yaml theme={null}
HANDOFF:
  - TO: Specialist_Agent
    WHEN: needs_specialist == true
    CONTEXT:
      pass: [user_id, query]
      summary: "User needs specialist help"
    ON_FAILURE: ESCALATE          # CONTINUE | ESCALATE | RESPOND "message"
```

| Value               | Behavior                                          |
| ------------------- | ------------------------------------------------- |
| `CONTINUE`          | Silently continue in the current agent.           |
| `ESCALATE`          | Trigger human escalation.                         |
| `RESPOND "message"` | Send a message and continue in the current agent. |

### Experience modes

`EXPERIENCE_MODE` shapes how the transfer is presented to the end user. It is valid on both
`HANDOFF` and `DELEGATE`.

| Value                  | Behavior                                                                  |
| ---------------------- | ------------------------------------------------------------------------- |
| `shared_voice_handoff` | Voice channels — hand off while keeping a single shared voice experience. |
| `visible_handoff`      | The user is told the conversation is being transferred.                   |
| `silent_delegate`      | The sub-agent runs without a user-visible transfer.                       |
| `human_escalation`     | Present the transfer as an escalation to a human.                         |

### Async dispatch

For remote agents, set `ASYNC: true` to dispatch the handoff asynchronously. The calling agent receives a notification when the remote agent completes rather than blocking.

```yaml theme={null}
HANDOFF:
  - TO: External_Review
    WHEN: requires_external_review == true
    CONTEXT:
      pass: [case_id, documents]
      summary: "Documents require external review."
    EXPECT_RETURN: true
    REMOTE:
      location: remote
      endpoint: "https://review.partner.com/api/v1/submit"
      protocol: a2a
    ASYNC: true
    ASYNC_TIMEOUT: 3600
```

### Memory grants

Use `memory_grants` to give the target agent scoped access to specific persistent memory paths.
Without this, the target agent cannot read or write the parent's persistent variables. Each grant
declares a `path` and an `access` level.

```yaml theme={null}
CONTEXT:
  pass: [user_id, booking_reference]
  summary: "User needs to authenticate to manage booking."
  memory_grants:
    - path: user.last_verified_at
      access: read
    - path: workflow.auth_token
      access: readwrite
```

| Property | Type     | Required | Default | Description                           |
| -------- | -------- | -------- | ------- | ------------------------------------- |
| `path`   | `string` | Yes      | --      | Persistent memory path being granted. |
| `access` | `string` | No       | `read`  | Access level: `read` or `readwrite`.  |

***

## DELEGATE

DELEGATE invokes a sub-agent synchronously, waits for it to complete, and maps the result back into the calling agent's context. The sub-agent runs in its own scope and does not have direct access to the parent's session variables.

### Syntax

```yaml theme={null}
DELEGATE:
  - AGENT: Sanctions_Screening
    WHEN: beneficiary_name IS SET AND beneficiary_country IS SET
    PURPOSE: "Screen beneficiary against OFAC SDN and EU sanctions lists"
    INPUT:
      name: beneficiary_name
      account: beneficiary_account
      country: beneficiary_country
    RETURNS:
      cleared: sanctions_clear
      match_score: sanctions_match_score
    USE_RESULT: "Block if match_score > 85. Proceed only if cleared."
    TIMEOUT: "15s"
    ON_FAIL: escalate
```

### Properties

| Property          | Type                    | Required | Default | Description                                                                                                                                                  |
| ----------------- | ----------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `AGENT`           | `string`                | Yes      | --      | Name of the sub-agent to invoke. `TO` is accepted as an alias.                                                                                               |
| `WHEN`            | `string`                | Yes      | --      | Condition that must be true for delegation to occur.                                                                                                         |
| `PURPOSE`         | `string`                | Yes      | --      | Description of why this delegation exists. Included in trace events. `SUMMARY` is accepted as an alias.                                                      |
| `INPUT`           | `Record<string,string>` | Yes      | --      | Input mapping. Keys are sub-agent parameter names; values are expressions from the parent's context. `PASS` is accepted as an alias.                         |
| `RETURNS`         | `Record<string,string>` | Yes      | --      | Output mapping. Keys are sub-agent result fields; values are parent context variable names to write to.                                                      |
| `USE_RESULT`      | `string`                | Yes      | --      | Instructions for interpreting the sub-agent's result.                                                                                                        |
| `MEMORY_GRANTS`   | `object[]`              | No       | --      | Persistent memory paths to grant the sub-agent, each with `path` and `access` (`read` / `readwrite`). Same shape as [handoff memory grants](#memory-grants). |
| `TIMEOUT`         | `string`                | No       | --      | Maximum time to wait for the sub-agent. Format: `"Ns"` (seconds).                                                                                            |
| `ON_FAIL`         | `string`, `object`      | No       | --      | Action when the sub-agent fails or times out. See [Failure strategies](#delegate-failure-strategies).                                                        |
| `EXPERIENCE_MODE` | `string`                | No       | --      | End-user experience for the delegation. See [Experience modes](#experience-modes).                                                                           |
| `REMOTE`          | `object`                | No       | --      | Remote agent configuration. Can also be given as top-level `LOCATION`/`ENDPOINT`/`PROTOCOL` keys. See [Remote agent support](#remote-agent-support).         |
| `FAILURE_MESSAGE` | `string`                | No       | --      | Message to display when delegation fails.                                                                                                                    |

### Input/output mapping

The `INPUT` block maps values from the parent agent's session context into the sub-agent's input parameters:

```yaml theme={null}
INPUT:
  name: beneficiary_name          # parent's beneficiary_name -> sub-agent's "name" parameter
  account: beneficiary_account
  amount: amount
```

The `RETURNS` block maps the sub-agent's result fields back into the parent's session variables:

```yaml theme={null}
RETURNS:
  cleared: sanctions_clear        # sub-agent's "cleared" field -> parent's sanctions_clear
  match_score: sanctions_match_score
```

### Delegate failure strategies

| Value      | Behavior                                                 |
| ---------- | -------------------------------------------------------- |
| `respond`  | Send a message and continue. Requires `FAILURE_MESSAGE`. |
| `continue` | Silently continue without the sub-agent's result.        |
| `escalate` | Trigger human escalation.                                |
| `retry`    | Retry the delegation. Accepts a `count` for max retries. |

Structured failure example:

```yaml theme={null}
ON_FAIL:
  type: retry
  count: 2
```

### Remote agent support

DELEGATE supports invoking agents running on remote services. Add a `REMOTE` block to configure the connection.

```yaml theme={null}
DELEGATE:
  - AGENT: External_Compliance
    WHEN: amount > 10000
    PURPOSE: "External compliance check for high-value transfers"
    INPUT:
      transaction_id: wire_reference
      amount: amount
    RETURNS:
      approved: compliance_approved
    USE_RESULT: "Proceed only if approved."
    REMOTE:
      location: remote
      endpoint: "https://compliance.partner.com/api/v1/check"
      protocol: a2a
      auth:
        type: bearer
      timeout: "30s"
```

#### Remote properties

| Property   | Type              | Required | Default | Description                                                                                                                                                                                                                        |
| ---------- | ----------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `location` | `local`, `remote` | No       | `local` | Whether the agent is co-located or remote.                                                                                                                                                                                         |
| `endpoint` | `string`          | No       | --      | URL for remote agent invocation.                                                                                                                                                                                                   |
| `protocol` | `a2a` , `rest`    | No       | --      | Communication protocol. `a2a` for Agent-to-Agent, `rest` for REST API.                                                                                                                                                             |
| `auth`     | `object`          | No       | --      | Authentication configuration. `type` is `bearer` or `api_key`; an optional `header` names the header to carry the credential. Credential values are resolved from runtime config / auth-profile resolution — never inlined in ABL. |
| `timeout`  | `string`          | No       | --      | Override timeout for the remote call.                                                                                                                                                                                              |

<Note>
  `LOCATION: remote` is explicit and recommended, but the compiler also treats an `ENDPOINT`
  without `LOCATION` as remote. The remote block can be authored either nested under `REMOTE:` or
  as top-level `LOCATION`/`ENDPOINT`/`PROTOCOL` keys on the entry.
</Note>

***

## Parallel delegation (fan-out)

<Note>
  There is no `FAN_OUT:` section in ABL. Fan-out is a runtime capability, not an authored
  construct — agents do not declare it directly.
</Note>

When a single user message contains **multiple distinct requests** that need different specialists,
a supervisor's runtime can dispatch them in parallel and then synthesize the branch results into one
unified response. This is exposed to the reasoning model as a built-in `__fan_out__` system tool
(you never write this tool yourself) and is bounded to **2–5 sub-tasks** per message.

Separately, when multiple `DELEGATE` entries have their `WHEN` conditions satisfied on the same
turn, the runtime can run those delegations concurrently. Each delegation runs in its own scope and
its `RETURNS` are mapped back into the parent context as it completes.

```yaml theme={null}
DELEGATE:
  - AGENT: Sanctions_Screening
    WHEN: beneficiary_name IS SET
    PURPOSE: "Screen beneficiary"
    INPUT:
      name: beneficiary_name
    RETURNS:
      cleared: sanctions_clear

  - AGENT: Fraud_Detection
    WHEN: amount IS SET
    PURPOSE: "Score fraud risk"
    INPUT:
      amount: amount
      account: source_account
    RETURNS:
      score: fraud_score
```

***

## ESCALATE

ESCALATE transfers the conversation to a human operator. It is designed for situations where the agent cannot or should not continue autonomously.

### Syntax

```yaml theme={null}
ESCALATE:
  triggers:
    - WHEN: sanctions_screening_unavailable == true AND retry_count >= 2
      REASON: "Sanctions screening service down. Compliance check cannot be bypassed."
      PRIORITY: critical
      TAGS: [compliance, service_outage]

    - WHEN: user.wants_human_agent == true
      REASON: "Customer requesting human specialist."
      PRIORITY: medium
      TAGS: [human_request]

  context_for_human:
    - customer_id
    - customer_name
    - amount
    - conversation_history

  routing:
    connection: livechat
    queue: "wire_operations_l2"
    skills: [wire_transfer, compliance]
    priority: 1

  on_human_complete:
    - IF human.resolved == true: COMPLETE
    - IF human.needs_agent == true: HANDOFF to specified_agent

  CONNECTOR_ACTION: create_servicenow_incident
```

### Trigger properties

| Property   | Type                    | Required | Default  | Description                                                                     |
| ---------- | ----------------------- | -------- | -------- | ------------------------------------------------------------------------------- |
| `WHEN`     | `string`                | Yes      | --       | Condition that triggers escalation.                                             |
| `REASON`   | `string`                | Yes      | --       | Human-readable reason for the escalation.                                       |
| `PRIORITY` | `string` / `number`     | No       | `medium` | Priority level: `low`, `medium`, `high`, `critical`, or a non-negative integer. |
| `TAGS`     | `string[]`              | No       | --       | Tags for routing and categorization in the human agent queue.                   |
| `SET`      | `Record<string,string>` | No       | --       | Session variable assignments applied when this trigger fires (`key = value`).   |

<Note>
  `PRIORITY` is optional and defaults to `medium`. Note that `ESCALATE` inside an `ON_ERROR` handler
  is **not** parsed — to escalate from an error handler use `THEN: ESCALATE with REASON: "..."`
  instead of an inline `ESCALATE:` block.
</Note>

### Connector action

`CONNECTOR_ACTION` names a connector action to invoke for ITSM integration when the escalation
fires (for example, opening an incident in an external ticketing system). It is declared at the top
level of the `ESCALATE` block, alongside `triggers`, `context_for_human`, `routing`, and
`on_human_complete`.

### Priority levels

| Level      | Use case                                                                  |
| ---------- | ------------------------------------------------------------------------- |
| `low`      | Non-urgent requests (for example. general feedback).                      |
| `medium`   | Standard requests (for example. customer asks to speak with a human).     |
| `high`     | Urgent issues (for example. service outages, repeated failures).          |
| `critical` | Immediate attention required (for example. compliance violations, fraud). |

### Context for human

The `context_for_human` block lists session variable names to include in the escalation package. The human agent sees these values in their interface.

```yaml theme={null}
context_for_human:
  - customer_id
  - customer_name
  - source_account
  - amount
  - fraud_score
  - conversation_history
```

You can also use structured context items with templates:

```yaml theme={null}
context_for_human:
  - NAME: case_summary
    TEMPLATE: "Customer {{customer_name}} requesting wire of {{amount}} {{currency}}"
    INCLUDE: [fraud_score, sanctions_match_score]
```

### Routing configuration

The `routing` block controls how the escalation is routed in the human agent system.

| Property     | Type       | Required | Default | Description                                                     |
| ------------ | ---------- | -------- | ------- | --------------------------------------------------------------- |
| `connection` | `string`   | No       | --      | Human-agent connection/channel to route through.                |
| `queue`      | `string`   | No       | --      | Target queue name in the human agent system.                    |
| `skills`     | `string[]` | No       | --      | Required skills for the human agent.                            |
| `priority`   | `number`   | No       | --      | Numeric routing priority for the queue entry.                   |
| `post_agent` | `string`   | No       | --      | What happens after the human agent finishes: `return` or `end`. |

<Note>
  Earlier drafts used `skill_tags` and `priority_boost`. The current runtime contract uses `skills`
  and `priority` — the older keys are silently ignored. Additional advanced routing keys
  (`sub_type`, `named_agents`, `named_agent_options`, `agent_matching_conditions`, `voice`,
  `flow_policy_ref` / `transfer_flow_policy_ref`, `provider_config`) are also supported for
  human-agent integrations.
</Note>

### Post-completion actions

The `on_human_complete` block defines what happens after the human agent finishes.

```yaml theme={null}
on_human_complete:
  - IF human.resolved == true: COMPLETE
  - IF human.needs_agent == true: HANDOFF to specified_agent
  - IF human.needs_followup == true: CONTINUE
```

Each entry has a `condition` and an `action`. The action can be `COMPLETE` (end the conversation), `HANDOFF` (transfer to another agent), or `CONTINUE` (resume the current agent).

***

## COMPLETE

COMPLETE defines the conditions under which the agent considers its task finished. Each completion condition specifies a `WHEN` expression and an optional response.

### Syntax

```yaml theme={null}
COMPLETE:
  - WHEN: confirmation_number IS SET AND transfer_status == "released"
    RESPOND: |
      Your wire transfer has been executed successfully.

      **Confirmation:** {{confirmation_number}}
      **Amount:** {{amount}} {{currency}}
      **To:** {{beneficiary_name}}
      **Estimated Arrival:** {{estimated_arrival}}
    STORE: "wire_transfers"

  - WHEN: transfer_status == "queued"
    RESPOND: "Your wire has been queued for the next processing window."
```

### Properties

| Property  | Type     | Required | Default | Description                                                            |
| --------- | -------- | -------- | ------- | ---------------------------------------------------------------------- |
| `WHEN`    | `string` | Yes      | --      | Condition expression. The agent completes when this evaluates to true. |
| `RESPOND` | `string` | No       | --      | Final message to the user. Supports `{{}}` template interpolation.     |
| `STORE`   | `string` | No       | --      | Collection or path name to store the completion result for analytics.  |

### Rich content in completion

COMPLETE responses support voice configuration and rich content, the same as any RESPOND:

```yaml theme={null}
COMPLETE:
  - WHEN: booking_confirmed == true
    RESPOND: "Your booking is confirmed!"
    VOICE:
      ssml: "<speak>Your booking is confirmed!</speak>"
    RICH_CONTENT:
      MARKDOWN: |
        ## Booking Confirmed
        | Detail | Value |
        |--------|-------|
        | Reference | {{booking_ref}} |
        | Date | {{travel_date}} |
    ACTIONS:
      - id: view_itinerary
        type: button
        label: "View Itinerary"
```

### Completion evaluation

Completion conditions are evaluated after every turn, in declaration order. The first matching condition triggers completion. If no condition matches, the agent continues the conversation.

***

## Context Passing

### Evaluation order across constructs

When multiple multi-agent constructs apply on the same turn, the runtime evaluates them in this order:

1. **ESCALATE triggers** -- checked first; critical safety and compliance.
2. **HANDOFF rules** -- evaluated by priority (lower first).
3. **DELEGATE conditions** -- evaluated in declaration order.
4. **COMPLETE conditions** -- checked last.

***

## Complete Supervisor example

```yaml theme={null}
SUPERVISOR: Customer_Service_Hub
VERSION: "2.0"
GOAL: "Route customers to the right specialist"

PERSONA: |
  Professional customer service coordinator. Routes requests
  efficiently and preserves context across agent transfers.

HANDOFF:
  - TO: Live_Agent
    WHEN: intent.category == "escalation"
    CONTEXT:
      pass: [user_id, conversation_summary]
      summary: "User requests human assistance"
    EXPECT_RETURN: false

  - TO: Sales_Agent
    WHEN: intent.category == "new_booking"
    CONTEXT:
      pass: [search_context, preferences]
      summary: "User looking to book"
    EXPECT_RETURN: false

ESCALATE:
  triggers:
    - WHEN: routing_failures >= 3
      REASON: "Multiple routing failures"
      PRIORITY: high

ON_ERROR:
  routing_failure:
    RESPOND: "Let me connect you with someone who can help."
    RETRY: 1
    THEN: HANDOFF Live_Agent

COMPLETE:
  - WHEN: handoff_successful == true
    RESPOND: "I've connected you with the right specialist."
```

## Related pages

* [NLU](/agent-platform/abl-reference/nlu) -- intent classification that drives routing decisions
* [Memory & Constraints](/agent-platform/abl-reference/memory-and-constraints) -- session and persistent state used in routing conditions
* [Expressions & functions](/agent-platform/abl-reference/rich-content-and-expressions#expressions-and-functions) -- condition syntax for WHEN clauses
* [Lifecycle & hooks](/agent-platform/abl-reference/lifecycle-and-hooks) -- ON\_START and hooks that interact with multi-agent flows
* [Rich Content & Expressions](/agent-platform/abl-reference/rich-content-and-expressions) -- formatting for RESPOND and COMPLETE messages
