Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions skills/rasa-building-flows/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ description: >
license: Apache-2.0
metadata:
author: rasa
version: "3.x"
version: "0.1.0"
rasa_version: ">=3.9.0"
docs-url: https://rasa.com/docs/reference/primitives/flows/
---

Expand All @@ -30,7 +31,9 @@ metadata:
(see "Branching and conditions").
10. Extract reusable sub-tasks into child flows via `call` (see "Connecting flows").
11. Connect follow-up flows via `link` if a separate process should start after.
12. Validate the project.
12. Ensure all referenced slots, responses, and actions exist in the domain
(see "Ensure domain completeness").
13. Validate the project (see "Fixing validation errors").

## Scoping a flow

Expand Down Expand Up @@ -343,6 +346,27 @@ collect_patient_info:
if: False
```

## Full reference
## Ensure domain completeness

<!-- TODO: Add references/flows-reference.md with complete syntax documentation -->
Every element a flow references must be defined in the domain (`domain.yml` or split
domain files). After writing or editing a flow, walk through each step and verify the
items below are present. Missing entries cause validation errors or silent runtime
failures.

- Every slot used in the flow → `slots:`
(see `rasa-managing-slots`)
- Every `collect: slot_name` → `utter_ask_{slot_name}` in `responses:`
(see `rasa-writing-responses`)
- Every `action: utter_*` step → matching entry in `responses:`
- Every custom action / validation action → `actions:`
(see `rasa-writing-custom-actions`)
- Rejection responses → `responses:`

## Fixing validation errors

When validation fails, preserve the user's **intent** — what the flow is supposed to
accomplish. The flow steps themselves can change, but the intended behavior must not be
lost.

Never strip down a flow's intended behavior to make validation pass. If needed, fix the
domain: slots, responses, and actions to support what the user asked for.
118 changes: 118 additions & 0 deletions skills/rasa-building-skills/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
name: rasa-building-skills
description: >
Builds skills (capabilities) for a Rasa CALM assistant. Use when the user asks to
create, add, or build a skill, capability, or feature for their Rasa assistant.
license: Apache-2.0
metadata:
author: rasa
version: "0.1.0"
rasa_version: ">=3.14.0"
---

# Building Skills for a Rasa Assistant

## Terminology

In Rasa, a **skill** is a self-contained module inside a Rasa assistant that packages a
specific capability or domain (e.g. booking, payments, order tracking).

The term "skill" can also refer to a IDE agent skill (SKILL.md). Use conversation
context to determine which meaning the user intends. If ambiguous, **ask**.

A Rasa skill defines its interface (slots / memory) and logic (flows, prompts, actions,
or tools). It is implemented as either:

1. **Flow-based** — a bundle of flows and slots for guided, deterministic behavior.
2. **Sub-agent** — a sub-agent that plans and acts autonomously using tools.
3. **Hybrid** — an orchestrator flow that delegates some steps to a sub-agent.

## Workflow

1. Clarify what the user wants the Rasa assistant to do.
2. Choose the implementation approach (see "Choosing the approach").
3. Design the skill boundary — slots, flows, responses, actions, sub-agents
(see "Designing the skill boundary").
4. Implement using the appropriate skill:
- Flow-based → `rasa-building-flows`
- ReAct sub-agent → `rasa-setting-up-react-agents`
- A2A sub-agent → `rasa-setting-up-a2a-agents`
5. Ensure the new flows or sub-agents are reachable (via `call`/`link` steps or
triggerable by their description).

## Choosing the approach

The first design choice is how autonomous the skill should be:

```
if high-risk domain (payments, auth, KYC, PII, compliance):
use flow-based
elif business logic must be tightly controlled (strict validation, fixed steps):
use flow-based
elif most steps are deterministic but some need autonomy:
use hybrid (flow orchestrates, sub-agent handles open-ended steps)
else:
use sub-agent (start autonomous, add flows later for guardrails as needed)
```

If the approach is not obvious from context, ask the user whether they want more control
over the conversation (flow-based) or a more autonomous experience (sub-agent). Frame it
in terms of the trade-off: flows give predictability and auditability, sub-agents give
flexibility and a more natural interaction. This is especially important when the user
asks for multiple skills at once — each skill may warrant a different approach, so
confirm the intent per skill before implementing.

## Designing the skill boundary

Before implementing, outline:

1. **Slots** — the skill's interface. See `rasa-managing-slots`.
2. **Flows** — one per user goal. See `rasa-building-flows`.
3. **Responses** — See `rasa-writing-responses`.
4. **Actions** — backend operations. See `rasa-writing-custom-actions`.
5. **Sub-agents** — MCP servers and tools. See `rasa-setting-up-react-agents` or
`rasa-setting-up-a2a-agents`.

### File organization

A single-flow skill can live in one file (e.g. `data/track_order.yml`). When a skill
contains multiple flows, group them in a subdirectory named after the skill:

```
data/
├── track_order.yml # single-flow skill
├── booking/ # multi-flow skill
│ ├── book_flight.yml
│ ├── select_destination.yml
│ └── choose_seats.yml
├── payments/
│ ├── process_payment.yml
│ └── verify_payment.yml
domain/
├── booking.yml
├── payments.yml
sub_agents/
├── policy_search/
│ └── config.yml
```

## Related skills

| Skill | Use for |
|-------|---------|
| `rasa-building-flows` | Writing flows, branching logic, `call`/`link` steps |
| `rasa-managing-slots` | Defining slots, types, mappings, persistence |
| `rasa-writing-responses` | Bot responses and `utter_ask_*` templates |
| `rasa-writing-custom-actions` | Custom actions and validation actions |
| `rasa-setting-up-react-agents` | ReAct sub-agents with MCP tools |
| `rasa-setting-up-a2a-agents` | External sub-agents via A2A protocol |
| `rasa-calling-mcp-tools-from-flows` | Invoking MCP tools directly from flow steps |
| `rasa-configuring-mcp-server` | MCP server setup in `endpoints.yml` |
| `rasa-configuring-assistant` | Pipeline, policies, `config.yml` / `endpoints.yml` |
| `rasa-writing-e2e-tests` | End-to-end conversation tests |


## Examples

For worked examples (flight booking, stock research, payments, insurance claims, Jira),
see [references/examples.md](references/examples.md).
66 changes: 66 additions & 0 deletions skills/rasa-building-skills/references/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Skill examples

### "Create a skill that books flights"

Well-defined multi-step process → **flow-based**.

- **Flows**: `book_flight`, `select_destination` (child), `choose_seats` (child)
- **Slots**: `departure_city`, `destination_city`, `travel_date`, `return_date`,
`passenger_count`, `seat_preference`, `selected_flight`
- **Actions**: `action_search_flights`, `action_book_flight`

→ `rasa-building-flows`

### "Create a skill that explores stock options"

Open-ended research with dynamic tool selection → **sub-agent**.

- **Flows**: `stock_research` (thin wrapper calling the sub-agent)
- **Sub-agent**: `stock_explorer` — ReAct agent with financial data MCP server
- **Slots**: `portfolio_id` (input), `analysis_result` (output)

→ `rasa-setting-up-react-agents`

### "Create a payment skill"

High-risk financial domain → **flow-based**.

- **Flows**: `process_payment`, `select_payment_method` (child),
`verify_payment` (child)
- **Slots**: `payment_amount`, `payment_method`, `card_last_four`, `payment_confirmed`
- **Actions**: `action_validate_payment`, `action_process_payment`

→ `rasa-building-flows`

### "Create an insurance claim skill"

Deterministic collection but open-ended policy search → **hybrid**.

- **Flows**: `file_insurance_claim` (orchestrator), `confirm_and_submit_claim` (child)
- **Sub-agent**: `policy_search_agent` — searches policy clauses autonomously
- **Slots**: `claim_type`, `incident_date`, `incident_description`, `matching_policy`

```yaml
flows:
file_insurance_claim:
description: Helps users file an insurance claim and find relevant policy coverage.
steps:
- collect: claim_type
- collect: incident_date
- collect: incident_description
- call: policy_search_agent
exit_if:
- slots.matching_policy is not null
- action: utter_claim_summary
- call: confirm_and_submit_claim
```

→ `rasa-building-flows` + `rasa-setting-up-react-agents`

### "Create a Jira ticket skill"

Depends on scope — ask the user:

- Fixed fields, single API call → **flow-based** with a custom action.
- Needs to search projects, look up tickets, pick from many operations →
**sub-agent** with Jira MCP server.
131 changes: 131 additions & 0 deletions skills/rasa-calling-mcp-tools-from-flows/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
name: rasa-calling-mcp-tools-from-flows
description: >
Calls MCP tools directly from Rasa flow steps. Use when invoking an MCP tool via a
call step, mapping slot values to tool parameters, or extracting tool results into
slots. This replaces custom action code for simple API integrations.
license: Apache-2.0
metadata:
author: rasa
version: "0.1.0"
rasa_version: ">=3.14.0"
docs-url: https://rasa.com/docs/pro/build/mcp-integration
---

# Calling MCP Tools from Flows

MCP tools can be invoked directly from flow steps using a `call` step with explicit
input/output mappings. This replaces the need for custom action code when you only need
to call an external API.

MCP servers must be defined in `endpoints.yml` before calling their tools. See the
`rasa-configuring-mcp-server` skill for server setup and authentication.

This feature is in **beta** and available starting from **Rasa 3.14.0**.

## When to use MCP vs a custom action

Use an MCP tool call when:

- The tool already exists on an MCP server
- You just need to pass slot values in and store results back
- No complex logic around the call (branching, retries, multiple sequential API calls)

Use a custom action instead when:

- You need complex business logic (multiple API calls, conditionals, error handling)
- You need access to the full tracker (conversation history, events, sender ID)
- You need to send custom messages via the dispatcher
- The data transformation can't be expressed in a Jinja2 output mapping
- The external API isn't exposed via MCP

See `rasa-writing-custom-actions` for custom action guidance.

## Workflow

1. Ensure the MCP server is defined in `endpoints.yml`
(see `rasa-configuring-mcp-server` skill).
2. Call the MCP tool from a flow using a `call` step with `mcp_server` and `mapping`
(see "Calling an MCP tool from a flow").
3. Map tool results to slots, handling both structured and unstructured output
(see "Tool result formats").
4. Validate the project.

## Calling an MCP tool from a flow

Use a `call` step with `mcp_server` and `mapping` to invoke a tool directly.

| Key | Required | Description |
|------------------|----------|-------------|
| `call` | yes | Tool name as exposed by the MCP server |
| `mcp_server` | yes | Must exactly match a `name` in `endpoints.yml`. Fails at runtime if mismatched |
| `mapping.input` | yes | Maps slot values to tool parameters. Each entry: `param` (tool parameter name) + `slot` (Rasa slot name) |
| `mapping.output` | yes | Maps tool results back to slots. Each entry: `slot` (target slot) + `value` (Jinja2 expression to extract the result) |

```yaml
flows:
buy_order:
description: helps users place a buy order for a particular stock
steps:
- collect: stock_name
- collect: order_quantity
- action: check_feasibility
next:
- if: slots.order_feasible is True
then:
- call: place_buy_order
mcp_server: trade_server
mapping:
input:
- param: ticker_symbol
slot: stock_name
- param: quantity
slot: order_quantity
output:
- slot: order_status
value: result.structuredContent.order_status.success
- else:
- action: utter_invalid_order
next: END
```

## Tool result formats

MCP tools return results in one of two formats. Handle both in your output mapping.

### Structured content

When the tool defines an output schema, Rasa returns structured data. Access specific
values using dot notation in the `value` field:

```yaml
# Tool returns: {"result": {"structuredContent": {"order_status": {"success": true, "order_id": "abc123"}}}}
output:
- slot: order_status
value: result.structuredContent.order_status.success
- slot: order_id
value: result.structuredContent.order_status.order_id
```

### Unstructured content

When the tool has no output schema, the entire result is a serialized string. Capture
it in a single slot for downstream processing:

```yaml
# Tool returns: {"result": {"content": [{"type": "text", "text": "{\"order_status\": ...}"}]}}
output:
- slot: order_data
value: result.content
```

## Common pitfalls

- **MCP server name mismatch** — the `mcp_server` value in a flow `call` step must
exactly match a `name` in `endpoints.yml`. A typo means the call fails at runtime
with no compile-time warning.
- **Missing tool on server** — if the tool name in `call` doesn't exist on the
referenced MCP server, the call fails at runtime.
- **Ignoring unstructured content** — when a tool has no output schema, results come
back as a serialized string under `result.content`, not as `result.structuredContent`.
Always account for both formats.
Loading