diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4240f66d13e..4f333080228 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -26,8 +26,8 @@ Removed
 
 Fixed
 -----
-- ``MappingPolicy`` now works correctly when used as part of a PolicyEnsemble
 - ``rasa run`` without ``--enable-api`` does not require a local model anymore
+- actions, intents, and utterances created in ``rasa interactive`` can no longer be empty
 
 
 [1.1.5] - 2019-07-10
@@ -68,6 +68,7 @@ Fixed
 - ``rasa interactive`` now looks for endpoints in ``endpoints.yml`` if no ``--endpoints`` arg is passed
 - custom files, e.g. custom components and channels, load correctly when using
   the command line interface
+- ``MappingPolicy`` now works correctly when used as part of a PolicyEnsemble
 
 
 [1.1.4] - 2019-06-18
diff --git a/rasa/core/training/interactive.py b/rasa/core/training/interactive.py
index 96da8a1644d..ea225da0108 100644
--- a/rasa/core/training/interactive.py
+++ b/rasa/core/training/interactive.py
@@ -334,20 +334,31 @@ def _selection_choices_from_intent_prediction(
 
 
 async def _request_free_text_intent(sender_id: Text, endpoint: EndpointConfig) -> Text:
-    question = questionary.text("Please type the intent name:")
+    question = questionary.text(
+        message="Please type the intent name:",
+        validate=io_utils.not_empty_validator("Please enter an intent name"),
+    )
     return await _ask_questions(question, sender_id, endpoint)
 
 
 async def _request_free_text_action(sender_id: Text, endpoint: EndpointConfig) -> Text:
-    question = questionary.text("Please type the action name:")
+    question = questionary.text(
+        message="Please type the action name:",
+        validate=io_utils.not_empty_validator("Please enter an action name"),
+    )
     return await _ask_questions(question, sender_id, endpoint)
 
 
 async def _request_free_text_utterance(
     sender_id: Text, endpoint: EndpointConfig, action: Text
 ) -> Text:
+
     question = questionary.text(
-        "Please type the message for your new utter_template '{}':".format(action)
+        message=(
+            "Please type the message for your new utterance "
+            "template '{}':".format(action)
+        ),
+        validate=io_utils.not_empty_validator("Please enter a template message"),
     )
     return await _ask_questions(question, sender_id, endpoint)
 
@@ -661,7 +672,7 @@ def _request_export_info() -> Tuple[Text, Text, Text]:
             message="Export stories to (if file exists, this "
             "will append the stories)",
             default=PATHS["stories"],
-            validate=io_utils.questionary_file_path_validator(
+            validate=io_utils.file_type_validator(
                 [".md"],
                 "Please provide a valid export path for the stories, e.g. 'stories.md'.",
             ),
@@ -670,7 +681,7 @@ def _request_export_info() -> Tuple[Text, Text, Text]:
             message="Export NLU data to (if file exists, this will "
             "merge learned data with previous training examples)",
             default=PATHS["nlu"],
-            validate=io_utils.questionary_file_path_validator(
+            validate=io_utils.file_type_validator(
                 [".md"],
                 "Please provide a valid export path for the NLU data, e.g. 'nlu.md'.",
             ),
@@ -679,7 +690,7 @@ def _request_export_info() -> Tuple[Text, Text, Text]:
             message="Export domain file to (if file exists, this "
             "will be overwritten)",
             default=PATHS["domain"],
-            validate=io_utils.questionary_file_path_validator(
+            validate=io_utils.file_type_validator(
                 [".yml", ".yaml"],
                 "Please provide a valid export path for the domain file, e.g. 'domain.yml'.",
             ),
diff --git a/rasa/utils/io.py b/rasa/utils/io.py
index b504b7d71ed..7d757d490a8 100644
--- a/rasa/utils/io.py
+++ b/rasa/utils/io.py
@@ -7,7 +7,7 @@ import tempfile
 import warnings
 import zipfile
 from asyncio import AbstractEventLoop
-from typing import Text, Any, Dict, Union, List, Type
+from typing import Text, Any, Dict, Union, List, Type, Callable
 import ruamel.yaml as yaml
 from io import BytesIO as IOReader
 
@@ -257,23 +257,45 @@ def create_directory_for_file(file_path: Text) -> None:
             raise
 
 
-def questionary_file_path_validator(
+def file_type_validator(
     valid_file_types: List[Text], error_message: Text
 ) -> Type["Validator"]:
     """Creates a `Validator` class which can be used with `questionary` to validate
        file paths.
     """
 
+    def is_valid(path: Text) -> bool:
+        return path is not None and any(
+            [path.endswith(file_type) for file_type in valid_file_types]
+        )
+
+    return create_validator(is_valid, error_message)
+
+
+def not_empty_validator(error_message: Text) -> Type["Validator"]:
+    """Creates a `Validator` class which can be used with `questionary` to validate
+    that the user entered something other than whitespace.
+    """
+
+    def is_valid(input: Text) -> bool:
+        return input is not None and input.strip() != ""
+
+    return create_validator(is_valid, error_message)
+
+
+def create_validator(
+    function: Callable[[Text], bool], error_message: Text
+) -> Type["Validator"]:
+    """Helper method to create `Validator` classes from callable functions. Should be
+    removed when questionary supports `Validator` objects."""
+
     from prompt_toolkit.validation import Validator, ValidationError
     from prompt_toolkit.document import Document
 
-    class ExportPathValidator(Validator):
-        def validate(self, document: Document) -> None:
-            path = document.text
-            is_valid = path is not None and any(
-                [path.endswith(file_type) for file_type in valid_file_types]
-            )
+    class FunctionValidator(Validator):
+        def validate(document: Document) -> None:
+            is_valid = function(document.text)
             if not is_valid:
                 raise ValidationError(message=error_message)
 
-    return ExportPathValidator
+    return FunctionValidator

Exporting interactive training session failes if intent 'None' appears during training
**Rasa Core version**:
0.12.x
**Python version**: 
3.6
**Operating system** (windows, osx, ...):
ubuntu
**Issue**:
Exporting fails if e.g. during a FormAction you only provide an answer for a slot, without assigning the answer to an intent. In this case the story has an element like this:

> * shopping.add_items_to_wishlist
>     - form_shopping.search_items
>     - form{"name": "form_shopping.search_items"}
>     - slot{"requested_slot": "shopping.item"}
> * form: None

In that scenario, once you try to quit & export the execution crashes.

I think it should be either OK to not declare an intent or the user should be forced to do it. Otherwise it might crash after a long training session and you need to start all over.
diff --git a/tests/test_utils.py b/tests/test_utils.py
index ebeadc06487..8cd3866efda 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -2,6 +2,8 @@ import logging
 
 import pytest
 from aioresponses import aioresponses
+from prompt_toolkit.document import Document
+from prompt_toolkit.validation import ValidationError
 
 from rasa.constants import DOMAIN_SCHEMA_FILE, CONFIG_SCHEMA_FILE
 from rasa.utils.validation import validate_yaml_schema, InvalidYamlFileError
@@ -127,14 +129,10 @@ def test_read_file_with_not_existing_path():
 
 @pytest.mark.parametrize("actual_path", ["", "file.md", "file"])
 def test_file_path_validator_with_invalid_paths(actual_path):
-    from prompt_toolkit.validation import ValidationError
-    from prompt_toolkit.document import Document
 
     test_error_message = actual_path
 
-    validator = rasa.utils.io.questionary_file_path_validator(
-        [".yml"], test_error_message
-    )()
+    validator = rasa.utils.io.file_type_validator([".yml"], test_error_message)
 
     document = Document(actual_path)
     with pytest.raises(ValidationError) as e:
@@ -145,12 +143,51 @@ def test_file_path_validator_with_invalid_paths(actual_path):
 
 @pytest.mark.parametrize("actual_path", ["domain.yml", "lala.yaml"])
 def test_file_path_validator_with_valid_paths(actual_path):
-    from prompt_toolkit.document import Document
 
-    validator = rasa.utils.io.questionary_file_path_validator(
-        [".yml", ".yaml"], "error message"
-    )()
+    validator = rasa.utils.io.file_type_validator([".yml", ".yaml"], "error message")
 
     document = Document(actual_path)
     # If the path is valid there shouldn't be an exception
     assert validator.validate(document) is None
+
+
+@pytest.mark.parametrize("user_input", ["", "   ", "\t", "\n"])
+def test_non_empty_text_validator_with_empty_input(user_input):
+
+    test_error_message = "enter something"
+
+    validator = rasa.utils.io.not_empty_validator(test_error_message)
+
+    document = Document(user_input)
+    with pytest.raises(ValidationError) as e:
+        validator.validate(document)
+
+    assert e.value.message == test_error_message
+
+
+@pytest.mark.parametrize("user_input", ["utter_greet", "greet", "Hi there!"])
+def test_non_empty_text_validator_with_valid_input(user_input):
+
+    validator = rasa.utils.io.not_empty_validator("error message")
+
+    document = Document(user_input)
+    # If there is input there shouldn't be an exception
+    assert validator.validate(document) is None
+
+
+def test_create_validator_from_callable():
+    def is_valid(user_input) -> None:
+        return user_input == "this passes"
+
+    error_message = "try again"
+
+    validator = rasa.utils.io.create_validator(is_valid, error_message)
+
+    document = Document("this passes")
+    assert validator.validate(document) is None
+
+    document = Document("this doesn't")
+    with pytest.raises(ValidationError) as e:
+        validator.validate(document)
+
+    assert e.value.message == error_message

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-localserver pytest-sanic responses freezegun nbsphinx aioresponses moto
apt-get update apt-get install -y gcc
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
absl-py==1.4.0
aiofiles==0.8.0
aiohttp==3.5.4
aioresponses==0.7.6
alabaster==0.7.13
anyio==3.6.2
APScheduler==3.6.0
astor==0.8.1
async-generator==1.10
async-timeout==3.0.1
attrs==22.2.0
Babel==2.11.0
backports.zoneinfo==0.2.1
bleach==4.1.0
boto3==1.23.10
botocore==1.26.10
cached-property==1.5.2
certifi==2021.5.30
cffi==1.15.1
chardet==3.0.4
charset-normalizer==3.0.1
click==7.1.2
colorclass==2.2.0
coloredlogs==10.0
colorhash==1.0.2
ConfigArgParse==0.15.2
contextvars==2.4
coverage==6.2
cryptography==40.0.2
cycler==0.11.0
dataclasses==0.8
decorator==5.1.1
defusedxml==0.7.1
docopt==0.6.2
docutils==0.15.2
entrypoints==0.4
fakeredis==1.0.3
fbmessenger==6.0.0
Flask==1.1.4
Flask-Cors==3.0.10
freezegun==1.2.2
future==0.18.3
gast==0.6.0
gevent==1.4.0
greenlet==2.0.2
grpcio==1.48.2
h11==0.12.0
h5py==3.1.0
httpcore==0.14.7
httptools==0.6.0
httpx==0.22.0
humanfriendly==10.0
idna==2.8
idna-ssl==1.1.0
imagesize==1.4.1
immutables==0.19
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
ipython-genutils==0.2.0
itsdangerous==1.1.0
Jinja2==2.11.3
jmespath==0.10.0
jsonpickle==1.1
jsonschema==2.6.0
jupyter-client==7.1.2
jupyter-core==4.9.2
jupyterlab-pygments==0.1.2
kafka-python==1.4.6
Keras-Applications==1.0.8
Keras-Preprocessing==1.1.2
kiwisolver==1.3.1
Markdown==3.3.7
MarkupSafe==2.0.1
matplotlib==3.0.3
mattermostwrapper==2.1
mistune==0.8.4
mock==5.2.0
moto==4.0.13
multidict==4.7.6
nbclient==0.5.9
nbconvert==6.0.7
nbformat==5.1.3
nbsphinx==0.8.8
nest-asyncio==1.6.0
networkx==2.3
numpy==1.16.3
packaging==19.2
pandocfilters==1.5.1
pika==1.0.1
pluggy==1.0.0
prompt-toolkit==2.0.10
protobuf==3.19.6
psycopg2-binary==2.8.2
py==1.11.0
pycparser==2.21
pydot==1.4.1
Pygments==2.14.0
PyJWT==2.4.0
pykwalify==1.7.0
pymongo==3.8.0
pyparsing==3.1.4
PySocks==1.7.1
pytest==7.0.1
pytest-cov==4.0.0
pytest-localserver==0.9.0.post0
pytest-sanic==1.7.1
python-crfsuite==0.9.10
python-dateutil==2.8.0
python-engineio==4.11.2
python-socketio==4.0.1
python-telegram-bot==11.1.0
pytz==2019.1
pytz-deprecation-shim==0.1.0.post0
PyYAML==6.0.1
pyzmq==25.1.2
questionary==1.1.1
-e git+https://github.com/RasaHQ/rasa.git@1b16a3c39e0ca1ec5438f71c987def59b8255d86#egg=rasa
rasa-sdk==1.1.1
redis==3.2.1
requests==2.22.0
requests-toolbelt==1.0.0
responses==0.17.0
rfc3986==1.5.0
rocketchat-API==0.6.31
ruamel.yaml==0.15.94
s3transfer==0.5.2
sanic==19.3.1
Sanic-Cors==0.9.8
sanic-jwt==1.3.1
Sanic-Plugins-Framework==0.9.5
scikit-learn==0.20.2
scipy==1.2.1
simple-websocket==1.1.0
simplejson==3.16.0
six==1.17.0
sklearn-crfsuite==0.3.6
slackclient==1.3.1
sniffio==1.2.0
snowballstemmer==2.2.0
sortedcontainers==2.4.0
Sphinx==5.3.0
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
SQLAlchemy==1.3.24
tabulate==0.8.10
tensorboard==1.13.1
tensorflow==1.13.1
tensorflow-estimator==1.13.0
termcolor==1.1.0
terminaltables==3.1.0
testpath==0.6.0
tomli==1.2.3
tornado==6.1
tqdm==4.31.0
traitlets==4.3.3
twilio==6.26.3
typing_extensions==4.1.1
tzdata==2025.2
tzlocal==4.2
ujson==4.3.0
urllib3==1.25.11
uvloop==0.14.0
wcwidth==0.2.13
webencodings==0.5.1
webexteamssdk==1.1.1
websocket-client==0.54.0
websockets==6.0
Werkzeug==1.0.1
wsproto==1.0.0
xmltodict==0.14.2
yarl==1.7.2
zipp==3.6.0

name: rasa
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - absl-py==1.4.0
      - aiofiles==0.8.0
      - aiohttp==3.5.4
      - aioresponses==0.7.6
      - alabaster==0.7.13
      - anyio==3.6.2
      - apscheduler==3.6.0
      - astor==0.8.1
      - async-generator==1.10
      - async-timeout==3.0.1
      - attrs==22.2.0
      - babel==2.11.0
      - backports-zoneinfo==0.2.1
      - bleach==4.1.0
      - boto3==1.23.10
      - botocore==1.26.10
      - cached-property==1.5.2
      - cffi==1.15.1
      - chardet==3.0.4
      - charset-normalizer==3.0.1
      - click==7.1.2
      - colorclass==2.2.0
      - coloredlogs==10.0
      - colorhash==1.0.2
      - configargparse==0.15.2
      - contextvars==2.4
      - coverage==6.2
      - cryptography==40.0.2
      - cycler==0.11.0
      - dataclasses==0.8
      - decorator==5.1.1
      - defusedxml==0.7.1
      - docopt==0.6.2
      - docutils==0.15.2
      - entrypoints==0.4
      - fakeredis==1.0.3
      - fbmessenger==6.0.0
      - flask==1.1.4
      - flask-cors==3.0.10
      - freezegun==1.2.2
      - future==0.18.3
      - gast==0.6.0
      - gevent==1.4.0
      - greenlet==2.0.2
      - grpcio==1.48.2
      - h11==0.12.0
      - h5py==3.1.0
      - httpcore==0.14.7
      - httptools==0.6.0
      - httpx==0.22.0
      - humanfriendly==10.0
      - idna==2.8
      - idna-ssl==1.1.0
      - imagesize==1.4.1
      - immutables==0.19
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - ipython-genutils==0.2.0
      - itsdangerous==1.1.0
      - jinja2==2.11.3
      - jmespath==0.10.0
      - jsonpickle==1.1
      - jsonschema==2.6.0
      - jupyter-client==7.1.2
      - jupyter-core==4.9.2
      - jupyterlab-pygments==0.1.2
      - kafka-python==1.4.6
      - keras-applications==1.0.8
      - keras-preprocessing==1.1.2
      - kiwisolver==1.3.1
      - markdown==3.3.7
      - markupsafe==2.0.1
      - matplotlib==3.0.3
      - mattermostwrapper==2.1
      - mistune==0.8.4
      - mock==5.2.0
      - moto==4.0.13
      - multidict==4.7.6
      - nbclient==0.5.9
      - nbconvert==6.0.7
      - nbformat==5.1.3
      - nbsphinx==0.8.8
      - nest-asyncio==1.6.0
      - networkx==2.3
      - numpy==1.16.3
      - packaging==19.2
      - pandocfilters==1.5.1
      - pika==1.0.1
      - pluggy==1.0.0
      - prompt-toolkit==2.0.10
      - protobuf==3.19.6
      - psycopg2-binary==2.8.2
      - py==1.11.0
      - pycparser==2.21
      - pydot==1.4.1
      - pygments==2.14.0
      - pyjwt==2.4.0
      - pykwalify==1.7.0
      - pymongo==3.8.0
      - pyparsing==3.1.4
      - pysocks==1.7.1
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pytest-localserver==0.9.0.post0
      - pytest-sanic==1.7.1
      - python-crfsuite==0.9.10
      - python-dateutil==2.8.0
      - python-engineio==4.11.2
      - python-socketio==4.0.1
      - python-telegram-bot==11.1.0
      - pytz==2019.1
      - pytz-deprecation-shim==0.1.0.post0
      - pyyaml==6.0.1
      - pyzmq==25.1.2
      - questionary==1.1.1
      - rasa-sdk==1.1.1
      - redis==3.2.1
      - requests==2.22.0
      - requests-toolbelt==1.0.0
      - responses==0.17.0
      - rfc3986==1.5.0
      - rocketchat-api==0.6.31
      - ruamel-yaml==0.15.94
      - s3transfer==0.5.2
      - sanic==19.3.1
      - sanic-cors==0.9.8
      - sanic-jwt==1.3.1
      - sanic-plugins-framework==0.9.5
      - scikit-learn==0.20.2
      - scipy==1.2.1
      - simple-websocket==1.1.0
      - simplejson==3.16.0
      - six==1.17.0
      - sklearn-crfsuite==0.3.6
      - slackclient==1.3.1
      - sniffio==1.2.0
      - snowballstemmer==2.2.0
      - sortedcontainers==2.4.0
      - sphinx==5.3.0
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - sqlalchemy==1.3.24
      - tabulate==0.8.10
      - tensorboard==1.13.1
      - tensorflow==1.13.1
      - tensorflow-estimator==1.13.0
      - termcolor==1.1.0
      - terminaltables==3.1.0
      - testpath==0.6.0
      - tomli==1.2.3
      - tornado==6.1
      - tqdm==4.31.0
      - traitlets==4.3.3
      - twilio==6.26.3
      - typing-extensions==4.1.1
      - tzdata==2025.2
      - tzlocal==4.2
      - ujson==4.3.0
      - urllib3==1.25.11
      - uvloop==0.14.0
      - wcwidth==0.2.13
      - webencodings==0.5.1
      - webexteamssdk==1.1.1
      - websocket-client==0.54.0
      - websockets==6.0
      - werkzeug==1.0.1
      - wsproto==1.0.0
      - xmltodict==0.14.2
      - yarl==1.7.2
      - zipp==3.6.0
prefix: /opt/conda/envs/rasa

tests/test_utils.py::test_file_path_validator_with_invalid_paths[] tests/test_utils.py::test_file_path_validator_with_invalid_paths[file.md] tests/test_utils.py::test_file_path_validator_with_invalid_paths[file] tests/test_utils.py::test_file_path_validator_with_valid_paths[domain.yml] tests/test_utils.py::test_file_path_validator_with_valid_paths[lala.yaml] tests/test_utils.py::test_non_empty_text_validator_with_empty_input[] tests/test_utils.py::test_non_empty_text_validator_with_empty_input[ tests/test_utils.py::test_non_empty_text_validator_with_empty_input[\t] tests/test_utils.py::test_non_empty_text_validator_with_empty_input[\n] tests/test_utils.py::test_non_empty_text_validator_with_valid_input[utter_greet] tests/test_utils.py::test_non_empty_text_validator_with_valid_input[greet] tests/test_utils.py::test_non_empty_text_validator_with_valid_input[Hi tests/test_utils.py::test_create_validator_from_callable
[ tests/test_utils.py::test_endpoint_config tests/test_utils.py::test_sort_dicts_by_keys tests/test_utils.py::test_validate_yaml_schema[examples/restaurantbot/domain.yml-core/schemas/domain.yml] tests/test_utils.py::test_validate_yaml_schema[sample_configs/config_defaults.yml-nlu/schemas/config.yml] tests/test_utils.py::test_validate_yaml_schema[sample_configs/config_supervised_embeddings.yml-nlu/schemas/config.yml] tests/test_utils.py::test_validate_yaml_schema[sample_configs/config_crf_custom_features.yml-nlu/schemas/config.yml] tests/test_utils.py::test_validate_yaml_schema_raise_exception[data/test_domains/invalid_format.yml-core/schemas/domain.yml] tests/test_utils.py::test_validate_yaml_schema_raise_exception[examples/restaurantbot/data/nlu.md-core/schemas/domain.yml] tests/test_utils.py::test_validate_yaml_schema_raise_exception[data/test_config/example_config.yaml-nlu/schemas/config.yml] tests/test_utils.py::test_concat_url[https://example.com-None-https://example.com] tests/test_utils.py::test_concat_url[https://example.com/test-None-https://example.com/test] tests/test_utils.py::test_concat_url[https://example.com/-None-https://example.com/] tests/test_utils.py::test_concat_url[https://example.com/-test-https://example.com/test] tests/test_utils.py::test_concat_url[https://example.com/-test/-https://example.com/test/] tests/test_utils.py::test_warning_for_base_paths_with_trailing_slash tests/test_utils.py::test_read_file_with_not_existing_path
CHANGELOG.rst rasa/core/training/interactive.py rasa/utils/io.py
CHANGELOG.rst rasa/core/training/interactive.py rasa/utils/io.py