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

# Responses

> Pre-defined wording the framework delivers without the LLM.

Some moments need specific wording: a recording notice at the start of a call, a
fraud warning when a card is reported stolen, a legal disclaimer after a
transaction. Responses let you declare that text once in `responses.yml` and
have the framework deliver it exactly as written. The LLM never rewrites it.

## Defining responses

Response text lives in the skill's `responses.yml`:

```yaml skills/card_replace/responses.yml theme={null}
responses:
  utter_recording_notice:
    - text: >-
        This interaction may be recorded for quality assurance
        and training purposes.

  utter_card_replacement_fee:
    - text: Standard replacement is free.
    - text: A fee applies for lost-card replacement.
      condition: 'session.card_replace.replacement_reason == "lost"'

  utter_card_replace_completed:
    - text: >-
        Your replacement card has been ordered and will ship via
        {session.card_replace.order_shipping_summary} delivery.
```

Each name maps to a **list of variants**. At delivery the engine picks **one**
variant: the first whose `condition` is true (YAML order), or the single
**default** variant with no `condition` when none match.

Placeholders in braces are filled from memory at the moment the message is sent.
Use `{session.<skill_id>.<entry>}` or `{session.project.<entry>}` to read any
value the skill can see, or the short `{entry}` form for the skill's own values.
Interpolate only values you know are set by then: a placeholder with no value is
left in the text as written.

### Conditional wording

Add `condition` on a variant when the message should change with session
memory — for example, different replacement-fee copy for lost vs stolen cards.
When any variant is conditioned, exactly one variant must omit `condition` (the
fallback). That fallback may sit anywhere in the list.

This is different from a skill `utter:` trigger with `when:` in `skill.md`:
`when:` fires a **whole response** once when memory first becomes true;
`condition` on a variant picks **which wording** to deliver each time a
reference (action step, collect ask, tool outcome, confirmation prompt, etc.)
resolves that response name. Both use the same [condition expression grammar](https://rasa.com/docs/mantle/reference/conditions.md).

See the [`responses.yml` reference](https://rasa.com/docs/mantle/reference/responses-yml#conditional-variants)
for selection order, train-time validation, and unsupported keys.

## Delivering a response

Four things can fire a response, and which one you reach for depends on what the
wording is tied to.

**On skill activation, or when a value becomes true.** A frontmatter `utter:`
trigger. This is the one that needs no ordered block:

```markdown skills/card_replace/skill.md theme={null}
---
name: Card Replace
description: Replace a credit card that was lost, stolen, damaged, or not received

utter:
  - utter_recording_notice:
      on: activate
  - utter_stolen_warning:
      when: "session.card_replace.replacement_reason == 'stolen'"
---

Help the customer replace a credit card.
```

`on: activate` fires once when the skill becomes active. `when:` fires the first
time its condition becomes true after a memory write, so a warning tied to a
value lands the moment that value is recorded, wherever in the conversation that
happens.

**Around a tool call.** `on_success:` and `on_failure:` on a `tool_constraints`
entry deliver a response after the tool runs, and `requires_confirmation:` names
the approval question and the line for a declined one. See
[Tool Constraints](https://rasa.com/docs/mantle/build-guide/tool-constraints.md).

**At a fixed point in a sequence.** Ordered-block steps:

```yaml theme={null}
:::ordered_block id=main
steps:
  - id: notice
    action: utter_recording_notice        # say it, then move on

  - id: ask_shipping
    collect: shipping_type
    utterance: utter_ask_shipping         # the question for this value
:::
```

`action:` delivers the response and advances. `utterance:` on a `collect:` step
is the question asked for that value.

## When to use a response

Reach for one when the wording is a business requirement: compliance, legal,
brand-mandated disclosures. Use it when *the exact words* are the point.

For everything else, let the LLM phrase things from your
[instructions](https://rasa.com/docs/mantle/concepts/instructions.md). Declaring every message as a response
produces an agent that sounds like a scripted phone tree, which is the thing
Mantle exists to avoid.

If you want declared text that still adapts to context, a response can opt into
LLM rewording:

```yaml theme={null}
responses:
  utter_ask_shipping:
    - text: "Rush or standard shipping?"
      metadata:
        rephrase: true
```

Rephrase applies to **whichever variant is selected** at delivery, not always
the first variant. Do not set this on anything compliance-sensitive.

## Dynamic buttons

When the tap targets under a message depend on live data, set
`buttons: {source: <tool_name>}` on the response variant. Examples include the
shipping windows a warehouse still has open, or the last four accounts a
caller used. The engine calls that local tool at delivery time, and the tool
supplies the choices with `context.set_buttons([Button(...)])`.

```yaml skills/delivery/responses.yml theme={null}
responses:
  utter_ask_delivery_window:
    - text: Which delivery window works for you?
      buttons:
        source: list_delivery_windows
```

A `Button` with `ref` writes its `value` to that fully qualified memory field
on tap, so a collect step advances without a follow-up `set_fields` call from
the LLM. A button without `ref` sends `value` (or `title` when `value` is
omitted) as plain user input. One `set_buttons()` call can mix both kinds.

Source tools are engine-only. They are hidden from the LLM tool inventory and
the model cannot dispatch them directly. A source tool cannot come from MCP or
carry `requires_confirmation`, and `rasa train` rejects any of those cases.

If the source tool is missing, a barge-in cancels it, it raises, or it
supplies no valid buttons, the engine still delivers the response text
without buttons. The engine drops invalid entries individually, so valid
siblings survive.

See [Dynamic buttons](https://rasa.com/docs/mantle/reference/responses-yml.md#dynamic-buttons) for the
YAML and Python shape, validation rules, and failure behavior.

## Overriding built-in messages

The bundled default skills (wrap-up, resume-after-digression, silence timeout)
ship their own responses. Every `responses.yml` merges into one registry keyed by
name, so declaring a name in your project-root file replaces the built-in one:

```yaml responses.yml theme={null}
responses:
  utter_silence_timeout_check_in:
    - text: "Still there? Tell me how I can help."
```

Session start is different. The bundled skill has no greeting to override. To
make the agent speak first, replace the skill itself. See
[Start a conversation](https://rasa.com/docs/mantle/orchestration/runtime-loop.md#start-a-conversation).

That shared registry is also why response names are worth prefixing with the
skill they belong to.

## Reference

For the merge order, both interpolation forms, conditional variants, and every
field, see the [`responses.yml` reference](https://rasa.com/docs/mantle/reference/responses-yml).


## Related topics

- [Responses](https://rasa.com/docs/studio/build/content-management/responses.md)
- [responses.yml](https://rasa.com/docs/mantle/reference/responses-yml.md)
- [Writing Responses](https://rasa.com/docs/pro/build/writing-responses.md)
- [Contextual Response Rephraser](https://rasa.com/docs/reference/primitives/contextual-response-rephraser.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.