diff --git a/docs/docs/start-here.mdx b/docs/docs/start-here.mdx
new file mode 100644
index 000000000000..428ffecc02a4
--- /dev/null
+++ b/docs/docs/start-here.mdx
@@ -0,0 +1,211 @@
+---
+id: start-here
+sidebar_label: Start Here
+title: Start Here
+hide_table_of_contents: true
+---
+
+
+## Getting Started with Rasa
+
+This page provides an introduction to Rasa. It's intended for newcomers and for people
+familiar with earlier versions of Rasa who want to understand the new DM2 approach (name TBD).
+DM2 gives you the best of both worlds: the time-to-value and generality of LLMs, and the
+controllability of intent-based approaches.
+
+### Command Line Interface Basics
+
+Once you have installed Rasa, you can run the `init` command to create a starter project:
+
+```bash
+rasa init --dm2
+```
+
+Run the `train` command at any time to build an assistant from the current state of your project:
+
+```bash
+rasa train
+```
+
+:::note Model Training
+
+While the command is called `rasa train`, building a new version of your assistant doesn't always
+require training a model. Rasa uses a cache and only trains when necessary.
+More information on the [`rasa train` command reference](./command-line-interface.mdx#rasa-train).
+
+:::
+
+
+Run the `shell` command to talk to your assistant on the command line:
+
+```bash
+rasa shell
+```
+
+To stop the conversation, type `/stop` or use `control+C`.
+
+
+:::note Debugging
+
+Adding the flag `rasa shell --debug` can be very helpful if you want to understand what is happening in detail.
+More information on the [`rasa shell` command reference](./command-line-interface.mdx#rasa-shell)
+
+:::
+
+
+### Exploring what your assistant can do
+
+Assistants often have to collect a few pieces of information from the user in order to complete a task.
+This starter project contains an example flow which recommends restaurants. To do so, it asks the user
+for their preferred cuisine, city, and price range.
+
+To try it out, start a conversation using `rasa shell`, and say something like "I'm looking for a restaurant".
+
+Out of the box, this assistant can already handle a variety of conversations. The first is what we call the "happy path",
+where the user always provides the information the assistant requests.
+But if users change their mind, answer indirectly, or interject with questions, this assistant can handle those cases as well.
+Try out some of these conversations yourself to get a feel for things.
+If you want your assistant to sound a bit more natural, you can activate [contextual rephrasing](./llms/llm-nlg.mdx) of responses.
+
+
+
+
+ Can you recommend somewhere to eat?
+ What kind of food are you looking for?
+ Indian food
+ in what price range?
+ cheap
+ and in which city?
+ Berlin
+ Here's a recommendation: ...
+
+
+
+
+ I'm looking for a cheap Chinese restaurant in Amsterdam?
+ Here's a recommendation: ...
+
+
+
+
+ Can you recommend somewhere to eat?
+ What kind of food are you looking for?
+ Indian food
+ in what price range?
+ actually no I want Italian. A cheap spot
+ and in which city?
+ Berlin
+ Here's a recommendation: ...
+
+
+
+
+ Can you recommend somewhere to eat?
+ What kind of food are you looking for?
+ wait are you a bot?
+ I am a bot, powered by Rasa.
+ What kind of food are you looking for?
+
+
+
+
+
+### Understanding flows
+
+Given the range of conversations this assistant can handle, you might expect the implementation to be complex.
+In fact, there are only two small files that provide Rasa what it needs.
+
+The `data/flows/restaurants.yml` file defines the logic for this flow. In this example the logic is linear
+and walks the user through each of the steps in order. Each of the `question` steps fills the corresponding slot.
+
+```yaml
+flows:
+ recommend_restaurant:
+ description: This flow recommends a restaurant
+ steps:
+ - id: "0"
+ question: cuisine
+ skip_if_filled: true
+ next: "1"
+ - id: "1"
+ question: price_range
+ next: "2"
+ - id: "2"
+ question: part_of_town
+ next: "3"
+ - id: "3"
+ action: search_restaurants
+```
+
+To build more advanced flows, you can add conditional logic, link to other flows, and more. Read more on how to handle [Business Logic with Flows](./flows.mdx)
+
+In addition to the flows, the `domain.yml` file contains definitions of the slots and responses used in this flow.
+
+### Understanding DM2
+
+Rasa uses a new approach to building AI assistants called DM2 (name TBD).
+If you've built AI assistants before, you might look at your project and think that many things are missing.
+
+* There is no NLU data with intents and entities
+* There is no logic mapping an intent like "restaurant_search" to the start of the restaurant flow
+* There are no slot mappings
+* There is no explicit logic handling corrections, interruptions, or other unhappy paths.
+
+DM2 doesn't need any of these things to be able to handle the example conversations above. So, how does that work?
+
+Many developers are familiar with dialogue systems made up of separate NLU, dialogue, and NLG components
+(this is also how Rasa worked previously).
+
+In DM2, we have a different set of modules.
+
+* The *conversation handling* component (name TBD) interprets the conversation so far and predicts
+a series of commands to progress the state of the conversation.
+* The *business logic* component executes those commands and the logic of your flows.
+
+The NLU systems you might be familiar with take a single user message as input, and aim to represent
+the meaning of that message by predicting intents and entities.
+Instead, *conversation handling* considers the conversation as a whole (not just one message),
+and predicts the *intended effect* of the user's message.
+
+As an example, let's look at using a yes/no question to fill a slot called `late_delivery`:
+
+
+Has it been more than 10 business days since you placed your order?
+
+
+
+When a user answers "yes" or "no", a traditional NLU model predicts an intent like `affirm` or `deny`.
+A second step (usually handled by the dialogue manager) then maps the intents to
+the `True/False` values of the `late_delivery` slot.
+
+Instead, the *conversation handling* component directly outputs a command to set the `late_delivery` slot to `True`.
+
+The *conversation handling* approach requires much less work to set up, since you don't need to worry about
+intents and entities and slot mappings. It is also more powerful because it allows us to
+[break free from intents](https://rasa.com/blog/its-about-time-we-get-rid-of-intents/).
+
+For example, intent-based approaches struggle when context is required to understand what the user means:
+
+
+Has it been more than 10 business days since you placed your order?
+sadly
+
+
+This kind of conversation illustrates the limitations of working with intents. It's perfectly clear
+what the user means in this context, but in general the word "sadly" does not mean `affirm`.
+The *conversation handling* component will correctly output `SetSlot("late_delivery", True)`.
+
+The example project above includes a definition of the core business logic for recommending a restaurant
+and not much else. Yet, it can handle a number of advanced conversations right away.
+The advantage of DM2 is that it makes chatbots much smarter and much easier to build, while still giving
+you full control over your business logic, and the ability to override and customize all behavior.
+
+Learn more about how to use DM2 to build advanced assistants:
+
+* Advanced flow logic
+* Search-based question-answering
+* Context switching
+* Disambiguation
+* Contextual understanding and negation
+* Chitchat and digressions
+
diff --git a/docs/sidebars.js b/docs/sidebars.js
index 738bae1a6983..3b44f4a1aa2f 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -265,6 +265,7 @@ module.exports = {
},
],
"llms": [
+ 'start-here',
'llms/large-language-models',
'llms/llm-setup',
{
diff --git a/rasa/cdu/command_generator/command_prompt_template.jinja2 b/rasa/cdu/command_generator/command_prompt_template.jinja2
index d4aefd05afe9..5ce4e603827c 100644
--- a/rasa/cdu/command_generator/command_prompt_template.jinja2
+++ b/rasa/cdu/command_generator/command_prompt_template.jinja2
@@ -25,7 +25,7 @@ Here are the slots of the currently active flow with their names and values:
{% endif %}
{% else %}
You are currently not in any flow and so there are no active slots.
-In order to fill a slot, you first have to start the flow and then fill the slot.
+This means you can only set a slot if you first start a flow that requires that slot.
{% endif %}
If you start a flow, first start the flow and then optionally fill that flow's slots with information the user provided in their message.
diff --git a/rasa/cdu/command_generator/llm_command_generator.py b/rasa/cdu/command_generator/llm_command_generator.py
index a3711f0df9b7..f07b6ed0c205 100644
--- a/rasa/cdu/command_generator/llm_command_generator.py
+++ b/rasa/cdu/command_generator/llm_command_generator.py
@@ -21,8 +21,6 @@
from rasa.engine.storage.resource import Resource
from rasa.engine.storage.storage import ModelStorage
from rasa.shared.core.constants import (
- MAPPING_TYPE,
- SlotMappingType,
MAPPING_CONDITIONS,
ACTIVE_LOOP,
)
@@ -245,15 +243,14 @@ def is_extractable(q: QuestionFlowStep, tracker: DialogueStateTracker) -> bool:
return False
for mapping in slot.mappings:
- if mapping.get(MAPPING_TYPE) == str(SlotMappingType.FROM_ENTITY):
- conditions = mapping.get(MAPPING_CONDITIONS, [])
- if len(conditions) == 0:
- return True
- else:
- for condition in conditions:
- active_loop = condition.get(ACTIVE_LOOP)
- if active_loop and active_loop == tracker.active_loop_name:
- return True
+ conditions = mapping.get(MAPPING_CONDITIONS, [])
+ if len(conditions) == 0:
+ return True
+ else:
+ for condition in conditions:
+ active_loop = condition.get(ACTIVE_LOOP)
+ if active_loop and active_loop == tracker.active_loop_name:
+ return True
return False
def render_template(
diff --git a/rasa/cli/initial_project_dm2/actions/__init__.py b/rasa/cli/initial_project_dm2/actions/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/rasa/cli/initial_project_dm2/actions/actions.py b/rasa/cli/initial_project_dm2/actions/actions.py
new file mode 100644
index 000000000000..8bf1f757f851
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/actions/actions.py
@@ -0,0 +1,27 @@
+# This files contains your custom actions which can be used to run
+# custom Python code.
+#
+# See this guide on how to implement these action:
+# https://rasa.com/docs/rasa/custom-actions
+
+
+# This is a simple example for a custom action which utters "Hello World!"
+
+# from typing import Any, Text, Dict, List
+#
+# from rasa_sdk import Action, Tracker
+# from rasa_sdk.executor import CollectingDispatcher
+#
+#
+# class ActionHelloWorld(Action):
+#
+# def name(self) -> Text:
+# return "action_hello_world"
+#
+# def run(self, dispatcher: CollectingDispatcher,
+# tracker: Tracker,
+# domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
+#
+# dispatcher.utter_message(text="Hello World!")
+#
+# return []
diff --git a/rasa/cli/initial_project_dm2/config.yml b/rasa/cli/initial_project_dm2/config.yml
new file mode 100644
index 000000000000..b6638aca4dc7
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/config.yml
@@ -0,0 +1,13 @@
+recipe: default.v1
+language: en
+pipeline:
+ - name: LLMCommandGenerator
+ # llm:
+ # model_name: gpt-4
+
+policies:
+ - name: rasa.core.policies.flow_policy.FlowPolicy
+# - name: rasa_plus.ml.DocsearchPolicy
+# - name: RulePolicy
+
+assistant_id: 20230405-114328-tranquil-mustard
diff --git a/rasa/cli/initial_project_dm2/credentials.yml b/rasa/cli/initial_project_dm2/credentials.yml
new file mode 100644
index 000000000000..e9f12911e3cf
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/credentials.yml
@@ -0,0 +1,33 @@
+# This file contains the credentials for the voice & chat platforms
+# which your bot is using.
+# https://rasa.com/docs/rasa/messaging-and-voice-channels
+
+rest:
+# # you don't need to provide anything here - this channel doesn't
+# # require any credentials
+
+
+#facebook:
+# verify: ""
+# secret: ""
+# page-access-token: ""
+
+#slack:
+# slack_token: ""
+# slack_channel: ""
+# slack_signing_secret: ""
+
+#socketio:
+# user_message_evt:
+# bot_message_evt:
+# session_persistence:
+
+#mattermost:
+# url: "https:///api/v4"
+# token: ""
+# webhook_url: ""
+
+# This entry is needed if you are using Rasa Enterprise. The entry represents credentials
+# for the Rasa Enterprise "channel", i.e. Talk to your bot and Share with guest testers.
+rasa:
+ url: "http://localhost:5002/api"
diff --git a/rasa/cli/initial_project_dm2/data/flows.yml b/rasa/cli/initial_project_dm2/data/flows.yml
new file mode 100644
index 000000000000..f7a4f7e6b5f4
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/data/flows.yml
@@ -0,0 +1,46 @@
+flows:
+ say_goodbye:
+ description: say goodbye to the user
+ steps:
+ - id: "0"
+ action: utter_goodbye
+ bot_challenge:
+ description: explain to the user that they are talking to a bot, if they ask
+ steps:
+ - id: "0"
+ action: utter_iamabot
+ greet:
+ description: greet the user and ask how they are doing. cheer them up if needed.
+ steps:
+ - id: "0"
+ question: good_mood
+ description: "can be true or false"
+ next:
+ - if: good_mood
+ then: "doing_great"
+ - else: "cheer_up"
+ - id: "doing_great"
+ action: utter_happy
+ - id: "cheer_up"
+ action: utter_cheer_up
+ next: "did_that_help"
+ - id: "did_that_help"
+ action: utter_did_that_help
+ recommend_restaurant:
+ description: This flow recommends a restaurant
+ steps:
+ - id: "0"
+ question: cuisine
+ skip_if_filled: true
+ next: "1"
+ - id: "1"
+ question: price_range
+ skip_if_filled: true
+ next: "2"
+ - id: "2"
+ question: city
+ skip_if_filled: true
+ next: "3"
+ - id: "3"
+ action: utter_recommend_restaurant
+
diff --git a/rasa/cli/initial_project_dm2/data/nlu.yml b/rasa/cli/initial_project_dm2/data/nlu.yml
new file mode 100644
index 000000000000..edbbf36d42ad
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/data/nlu.yml
@@ -0,0 +1,11 @@
+version: "3.1"
+
+nlu:
+ - intent: affirm
+ examples: |
+ - yes
+ - yup
+ - intent: deny
+ examples: |
+ - no
+ - nope
\ No newline at end of file
diff --git a/rasa/cli/initial_project_dm2/domain.yml b/rasa/cli/initial_project_dm2/domain.yml
new file mode 100644
index 000000000000..eb308f751812
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/domain.yml
@@ -0,0 +1,64 @@
+version: "3.1"
+
+slots:
+ good_mood:
+ type: bool
+ mappings:
+ - type: custom
+ cuisine:
+ type: text
+ mappings:
+ - type: custom
+ price_range:
+ type: text
+ mappings:
+ - type: custom
+ city:
+ type: text
+ mappings:
+ - type: custom
+
+
+responses:
+ utter_greet:
+ - text: "Hey!"
+
+ utter_ask_good_mood:
+ - text: "How are you?"
+
+ utter_ask_cuisine:
+ - text: "What kind of food are you looking for?"
+
+ utter_ask_price_range:
+ - text: "in what price range?"
+
+ utter_ask_city:
+ - text: "and in which city?"
+
+ utter_recommend_restaurant:
+ - text: "Here's a recommendation ..."
+
+ utter_cheer_up:
+ - text: "Here is something to cheer you up:"
+ image: "https://i.imgur.com/nGF1K8f.jpg"
+
+ utter_did_that_help:
+ - text: "Did that help you?"
+
+ utter_flow_continue_interrupted:
+ - text: Let's continue with the previous topic {flow_name}.
+ metadata: {allow_variation: True}
+
+ utter_happy:
+ - text: "Great, carry on!"
+
+ utter_goodbye:
+ - text: "Bye"
+
+ utter_iamabot:
+ - text: "I am a bot, powered by Rasa."
+
+
+session_config:
+ session_expiration_time: 60
+ carry_over_slots_to_new_session: true
diff --git a/rasa/cli/initial_project_dm2/e2e_tests/complete_request.yml b/rasa/cli/initial_project_dm2/e2e_tests/complete_request.yml
new file mode 100644
index 000000000000..b0a93f5bfe37
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/e2e_tests/complete_request.yml
@@ -0,0 +1,5 @@
+test_cases:
+ - test_case: user corrects recipient in the next message
+ steps:
+ - user: I'm looking for a cheap Chinese restaurant in Amsterdam
+ - utter: utter_recommend_restaurant
\ No newline at end of file
diff --git a/rasa/cli/initial_project_dm2/e2e_tests/happy.yml b/rasa/cli/initial_project_dm2/e2e_tests/happy.yml
new file mode 100644
index 000000000000..2181e9d2bb7d
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/e2e_tests/happy.yml
@@ -0,0 +1,11 @@
+test_cases:
+ - test_case: user corrects recipient in the next message
+ steps:
+ - user: Please recommend a restaurant
+ - utter: utter_ask_cuisine
+ - user: Indian food
+ - utter: utter_ask_price_range
+ - user: cheap
+ - utter: utter_ask_city
+ - user: Berlin
+ - utter: utter_recommend_restaurant
\ No newline at end of file
diff --git a/rasa/cli/initial_project_dm2/endpoints.yml b/rasa/cli/initial_project_dm2/endpoints.yml
new file mode 100644
index 000000000000..5f65275b8802
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/endpoints.yml
@@ -0,0 +1,42 @@
+# This file contains the different endpoints your bot can use.
+
+# Server where the models are pulled from.
+# https://rasa.com/docs/rasa/model-storage#fetching-models-from-a-server
+
+#models:
+# url: http://my-server.com/models/default_core@latest
+# wait_time_between_pulls: 10 # [optional](default: 100)
+
+# Server which runs your custom actions.
+# https://rasa.com/docs/rasa/custom-actions
+
+action_endpoint:
+ url: "http://localhost:5055/webhook"
+
+# Tracker store which is used to store the conversations.
+# By default the conversations are stored in memory.
+# https://rasa.com/docs/rasa/tracker-stores
+
+#tracker_store:
+# type: redis
+# url:
+# port:
+# db:
+# password:
+# use_ssl:
+
+#tracker_store:
+# type: mongod
+# url:
+# db:
+# username:
+# password:
+
+# Event broker which all conversation events should be streamed to.
+# https://rasa.com/docs/rasa/event-brokers
+
+#event_broker:
+# url: localhost
+# username: username
+# password: password
+# queue: queue
diff --git a/rasa/cli/initial_project_dm2/tests/test_stories.yml b/rasa/cli/initial_project_dm2/tests/test_stories.yml
new file mode 100644
index 000000000000..d46e39b3ea06
--- /dev/null
+++ b/rasa/cli/initial_project_dm2/tests/test_stories.yml
@@ -0,0 +1,91 @@
+#### This file contains tests to evaluate that your bot behaves as expected.
+#### If you want to learn more, please see the docs: https://rasa.com/docs/rasa/testing-your-assistant
+
+stories:
+- story: happy path 1
+ steps:
+ - user: |
+ hello there!
+ intent: greet
+ - action: utter_greet
+ - user: |
+ amazing
+ intent: mood_great
+ - action: utter_happy
+
+- story: happy path 2
+ steps:
+ - user: |
+ hello there!
+ intent: greet
+ - action: utter_greet
+ - user: |
+ amazing
+ intent: mood_great
+ - action: utter_happy
+ - user: |
+ bye-bye!
+ intent: goodbye
+ - action: utter_goodbye
+
+- story: sad path 1
+ steps:
+ - user: |
+ hello
+ intent: greet
+ - action: utter_greet
+ - user: |
+ not good
+ intent: mood_unhappy
+ - action: utter_cheer_up
+ - action: utter_did_that_help
+ - user: |
+ yes
+ intent: affirm
+ - action: utter_happy
+
+- story: sad path 2
+ steps:
+ - user: |
+ hello
+ intent: greet
+ - action: utter_greet
+ - user: |
+ not good
+ intent: mood_unhappy
+ - action: utter_cheer_up
+ - action: utter_did_that_help
+ - user: |
+ not really
+ intent: deny
+ - action: utter_goodbye
+
+- story: sad path 3
+ steps:
+ - user: |
+ hi
+ intent: greet
+ - action: utter_greet
+ - user: |
+ very terrible
+ intent: mood_unhappy
+ - action: utter_cheer_up
+ - action: utter_did_that_help
+ - user: |
+ no
+ intent: deny
+ - action: utter_goodbye
+
+- story: say goodbye
+ steps:
+ - user: |
+ bye-bye!
+ intent: goodbye
+ - action: utter_goodbye
+
+- story: bot challenge
+ steps:
+ - user: |
+ are you a bot?
+ intent: bot_challenge
+ - action: utter_iamabot
diff --git a/rasa/cli/scaffold.py b/rasa/cli/scaffold.py
index b5f0f1e50f56..b6715519b896 100644
--- a/rasa/cli/scaffold.py
+++ b/rasa/cli/scaffold.py
@@ -42,7 +42,11 @@ def add_subparser(
default=None,
help="Directory where your project should be initialized.",
)
-
+ scaffold_parser.add_argument(
+ "--dm2",
+ action="store_true",
+ help="Temporary. Whether to create a DM2 project or a classic one",
+ )
scaffold_parser.set_defaults(func=run)
@@ -127,21 +131,23 @@ def print_run_or_instructions(args: argparse.Namespace) -> None:
def init_project(args: argparse.Namespace, path: Text) -> None:
"""Inits project."""
os.chdir(path)
- create_initial_project(".")
+ create_initial_project(".", args.dm2)
print(f"Created project directory at '{os.getcwd()}'.")
print_train_or_instructions(args)
-def create_initial_project(path: Text) -> None:
+def create_initial_project(path: Text, is_dm2: bool = False) -> None:
"""Creates directory structure and templates for initial project."""
from distutils.dir_util import copy_tree
- copy_tree(scaffold_path(), path)
+ copy_tree(scaffold_path(is_dm2), path)
-def scaffold_path() -> Text:
+def scaffold_path(is_dm2: bool = False) -> Text:
import pkg_resources
+ if is_dm2:
+ return pkg_resources.resource_filename(__name__, "initial_project_dm2")
return pkg_resources.resource_filename(__name__, "initial_project")
diff --git a/tests/cli/test_rasa_init.py b/tests/cli/test_rasa_init.py
index b7f45cb856da..62932d5039e3 100644
--- a/tests/cli/test_rasa_init.py
+++ b/tests/cli/test_rasa_init.py
@@ -46,7 +46,7 @@ def test_init_help(run: Callable[..., RunResult]):
help_text = f"""usage: {RASA_EXE} init [-h] [-v] [-vv] [--quiet]
[--logging-config-file LOGGING_CONFIG_FILE] [--no-prompt]
- [--init-dir INIT_DIR]"""
+ [--init-dir INIT_DIR] [--dm2]"""
lines = help_text.split("\n")
# expected help text lines should appear somewhere in the output