rasa-pro 3.10.15__py3-none-any.whl → 3.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rasa-pro might be problematic. Click here for more details.

Files changed (238) hide show
  1. rasa/__main__.py +31 -15
  2. rasa/api.py +12 -2
  3. rasa/cli/arguments/default_arguments.py +24 -4
  4. rasa/cli/arguments/run.py +15 -0
  5. rasa/cli/arguments/shell.py +5 -1
  6. rasa/cli/arguments/train.py +17 -9
  7. rasa/cli/evaluate.py +7 -7
  8. rasa/cli/inspect.py +19 -7
  9. rasa/cli/interactive.py +1 -0
  10. rasa/cli/project_templates/calm/config.yml +5 -7
  11. rasa/cli/project_templates/calm/endpoints.yml +15 -2
  12. rasa/cli/project_templates/tutorial/config.yml +8 -5
  13. rasa/cli/project_templates/tutorial/data/flows.yml +1 -1
  14. rasa/cli/project_templates/tutorial/data/patterns.yml +5 -0
  15. rasa/cli/project_templates/tutorial/domain.yml +14 -0
  16. rasa/cli/project_templates/tutorial/endpoints.yml +5 -0
  17. rasa/cli/run.py +7 -0
  18. rasa/cli/scaffold.py +4 -2
  19. rasa/cli/studio/upload.py +0 -15
  20. rasa/cli/train.py +14 -53
  21. rasa/cli/utils.py +14 -11
  22. rasa/cli/x.py +7 -7
  23. rasa/constants.py +3 -1
  24. rasa/core/actions/action.py +77 -33
  25. rasa/core/actions/action_hangup.py +29 -0
  26. rasa/core/actions/action_repeat_bot_messages.py +89 -0
  27. rasa/core/actions/e2e_stub_custom_action_executor.py +5 -1
  28. rasa/core/actions/http_custom_action_executor.py +4 -0
  29. rasa/core/agent.py +2 -2
  30. rasa/core/brokers/kafka.py +3 -1
  31. rasa/core/brokers/pika.py +3 -1
  32. rasa/core/channels/__init__.py +10 -6
  33. rasa/core/channels/channel.py +41 -4
  34. rasa/core/channels/development_inspector.py +150 -46
  35. rasa/core/channels/inspector/README.md +1 -1
  36. rasa/core/channels/inspector/dist/assets/{arc-b6e548fe.js → arc-bc141fb2.js} +1 -1
  37. rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-fa03ac9e.js → c4Diagram-d0fbc5ce-be2db283.js} +1 -1
  38. rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-ee67392a.js → classDiagram-936ed81e-55366915.js} +1 -1
  39. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-9b283fae.js → classDiagram-v2-c3cb15f1-bb529518.js} +1 -1
  40. rasa/core/channels/inspector/dist/assets/{createText-62fc7601-8b6fcc2a.js → createText-62fc7601-b0ec81d6.js} +1 -1
  41. rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-22e77f4f.js → edges-f2ad444c-6166330c.js} +1 -1
  42. rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-60ffc87f.js → erDiagram-9d236eb7-5ccc6a8e.js} +1 -1
  43. rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-9dd802e4.js → flowDb-1972c806-fca3bfe4.js} +1 -1
  44. rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-5fa1912f.js → flowDiagram-7ea5b25a-4739080f.js} +1 -1
  45. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-736177bf.js +1 -0
  46. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-622a1fd2.js → flowchart-elk-definition-abe16c3d-7c1b0e0f.js} +1 -1
  47. rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-e285a63a.js → ganttDiagram-9b5ea136-772fd050.js} +1 -1
  48. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-f237bdca.js → gitGraphDiagram-99d0ae7c-8eae1dc9.js} +1 -1
  49. rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-4b03d70e.js → index-2c4b9a3b-f55afcdf.js} +1 -1
  50. rasa/core/channels/inspector/dist/assets/index-e7cef9de.js +1317 -0
  51. rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-72a0fa5f.js → infoDiagram-736b4530-124d4a14.js} +1 -1
  52. rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-82218c41.js → journeyDiagram-df861f2b-7c4fae44.js} +1 -1
  53. rasa/core/channels/inspector/dist/assets/{layout-78cff630.js → layout-b9885fb6.js} +1 -1
  54. rasa/core/channels/inspector/dist/assets/{line-5038b469.js → line-7c59abb6.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{linear-c4fc4098.js → linear-4776f780.js} +1 -1
  56. rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-c33c8ea6.js → mindmap-definition-beec6740-2332c46c.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-a8d03059.js → pieDiagram-dbbf0591-8fb39303.js} +1 -1
  58. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-6a0e56b2.js → quadrantDiagram-4d7f4fd6-3c7180a2.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-2dc7c7bd.js → requirementDiagram-6fc4c22a-e910bcb8.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-2360fe39.js → sankeyDiagram-8f13d901-ead16c89.js} +1 -1
  61. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-41b9f9ad.js → sequenceDiagram-b655622a-29a02a19.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-0aad326f.js → stateDiagram-59f0c015-042b3137.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-9847d984.js → stateDiagram-v2-2b26beab-2178c0f3.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{styles-080da4f6-564d890e.js → styles-080da4f6-23ffa4fc.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-38957613.js → styles-3dcbcfbf-94f59763.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/{styles-9c745c82-f0fc6921.js → styles-9c745c82-78a6bebc.js} +1 -1
  67. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-ef3c5a77.js → svgDrawCommon-4835440b-eae2a6f6.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-bf3e91c1.js → timeline-definition-5b62e21b-5c968d92.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-4d4026c0.js → xychartDiagram-2b33534f-fd3db0d5.js} +1 -1
  70. rasa/core/channels/inspector/dist/index.html +18 -15
  71. rasa/core/channels/inspector/index.html +17 -14
  72. rasa/core/channels/inspector/package.json +5 -1
  73. rasa/core/channels/inspector/src/App.tsx +118 -68
  74. rasa/core/channels/inspector/src/components/Chat.tsx +95 -0
  75. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +11 -10
  76. rasa/core/channels/inspector/src/components/DialogueStack.tsx +10 -25
  77. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -3
  78. rasa/core/channels/inspector/src/helpers/audiostream.ts +165 -0
  79. rasa/core/channels/inspector/src/helpers/formatters.test.ts +10 -0
  80. rasa/core/channels/inspector/src/helpers/formatters.ts +107 -41
  81. rasa/core/channels/inspector/src/helpers/utils.ts +92 -7
  82. rasa/core/channels/inspector/src/types.ts +21 -1
  83. rasa/core/channels/inspector/yarn.lock +94 -1
  84. rasa/core/channels/rest.py +51 -46
  85. rasa/core/channels/socketio.py +28 -1
  86. rasa/core/channels/telegram.py +1 -1
  87. rasa/core/channels/twilio.py +1 -1
  88. rasa/core/channels/{audiocodes.py → voice_ready/audiocodes.py} +122 -69
  89. rasa/core/channels/{voice_aware → voice_ready}/jambonz.py +26 -8
  90. rasa/core/channels/{voice_aware → voice_ready}/jambonz_protocol.py +57 -5
  91. rasa/core/channels/{twilio_voice.py → voice_ready/twilio_voice.py} +64 -28
  92. rasa/core/channels/voice_ready/utils.py +37 -0
  93. rasa/core/channels/voice_stream/asr/__init__.py +0 -0
  94. rasa/core/channels/voice_stream/asr/asr_engine.py +89 -0
  95. rasa/core/channels/voice_stream/asr/asr_event.py +18 -0
  96. rasa/core/channels/voice_stream/asr/azure.py +129 -0
  97. rasa/core/channels/voice_stream/asr/deepgram.py +90 -0
  98. rasa/core/channels/voice_stream/audio_bytes.py +8 -0
  99. rasa/core/channels/voice_stream/browser_audio.py +107 -0
  100. rasa/core/channels/voice_stream/call_state.py +23 -0
  101. rasa/core/channels/voice_stream/tts/__init__.py +0 -0
  102. rasa/core/channels/voice_stream/tts/azure.py +106 -0
  103. rasa/core/channels/voice_stream/tts/cartesia.py +118 -0
  104. rasa/core/channels/voice_stream/tts/tts_cache.py +27 -0
  105. rasa/core/channels/voice_stream/tts/tts_engine.py +58 -0
  106. rasa/core/channels/voice_stream/twilio_media_streams.py +173 -0
  107. rasa/core/channels/voice_stream/util.py +57 -0
  108. rasa/core/channels/voice_stream/voice_channel.py +427 -0
  109. rasa/core/information_retrieval/qdrant.py +1 -0
  110. rasa/core/nlg/contextual_response_rephraser.py +45 -17
  111. rasa/{nlu → core}/persistor.py +203 -68
  112. rasa/core/policies/enterprise_search_policy.py +119 -63
  113. rasa/core/policies/flows/flow_executor.py +15 -22
  114. rasa/core/policies/intentless_policy.py +83 -28
  115. rasa/core/processor.py +25 -0
  116. rasa/core/run.py +12 -2
  117. rasa/core/secrets_manager/constants.py +4 -0
  118. rasa/core/secrets_manager/factory.py +8 -0
  119. rasa/core/secrets_manager/vault.py +11 -1
  120. rasa/core/training/interactive.py +33 -34
  121. rasa/core/utils.py +47 -21
  122. rasa/dialogue_understanding/coexistence/llm_based_router.py +41 -14
  123. rasa/dialogue_understanding/commands/__init__.py +6 -0
  124. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +60 -0
  125. rasa/dialogue_understanding/commands/session_end_command.py +61 -0
  126. rasa/dialogue_understanding/commands/user_silence_command.py +59 -0
  127. rasa/dialogue_understanding/commands/utils.py +5 -0
  128. rasa/dialogue_understanding/generator/constants.py +2 -0
  129. rasa/dialogue_understanding/generator/flow_retrieval.py +47 -9
  130. rasa/dialogue_understanding/generator/llm_based_command_generator.py +38 -15
  131. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
  132. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +35 -13
  133. rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +3 -0
  134. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +60 -13
  135. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +53 -0
  136. rasa/dialogue_understanding/patterns/repeat.py +37 -0
  137. rasa/dialogue_understanding/patterns/user_silence.py +37 -0
  138. rasa/dialogue_understanding/processor/command_processor.py +21 -1
  139. rasa/e2e_test/aggregate_test_stats_calculator.py +1 -11
  140. rasa/e2e_test/assertions.py +136 -61
  141. rasa/e2e_test/assertions_schema.yml +23 -0
  142. rasa/e2e_test/e2e_test_case.py +85 -6
  143. rasa/e2e_test/e2e_test_runner.py +2 -3
  144. rasa/engine/graph.py +0 -1
  145. rasa/engine/loader.py +12 -0
  146. rasa/engine/recipes/config_files/default_config.yml +0 -3
  147. rasa/engine/recipes/default_recipe.py +0 -1
  148. rasa/engine/recipes/graph_recipe.py +0 -1
  149. rasa/engine/runner/dask.py +2 -2
  150. rasa/engine/storage/local_model_storage.py +12 -42
  151. rasa/engine/storage/storage.py +1 -5
  152. rasa/engine/validation.py +527 -74
  153. rasa/model_manager/__init__.py +0 -0
  154. rasa/model_manager/config.py +40 -0
  155. rasa/model_manager/model_api.py +559 -0
  156. rasa/model_manager/runner_service.py +286 -0
  157. rasa/model_manager/socket_bridge.py +146 -0
  158. rasa/model_manager/studio_jwt_auth.py +86 -0
  159. rasa/model_manager/trainer_service.py +325 -0
  160. rasa/model_manager/utils.py +87 -0
  161. rasa/model_manager/warm_rasa_process.py +187 -0
  162. rasa/model_service.py +112 -0
  163. rasa/model_training.py +42 -23
  164. rasa/nlu/tokenizers/whitespace_tokenizer.py +3 -14
  165. rasa/server.py +4 -2
  166. rasa/shared/constants.py +60 -8
  167. rasa/shared/core/constants.py +13 -0
  168. rasa/shared/core/domain.py +107 -50
  169. rasa/shared/core/events.py +29 -0
  170. rasa/shared/core/flows/flow.py +5 -0
  171. rasa/shared/core/flows/flows_list.py +19 -6
  172. rasa/shared/core/flows/flows_yaml_schema.json +10 -0
  173. rasa/shared/core/flows/utils.py +39 -0
  174. rasa/shared/core/flows/validation.py +121 -0
  175. rasa/shared/core/flows/yaml_flows_io.py +15 -27
  176. rasa/shared/core/slots.py +5 -0
  177. rasa/shared/importers/importer.py +59 -41
  178. rasa/shared/importers/multi_project.py +23 -11
  179. rasa/shared/importers/rasa.py +12 -3
  180. rasa/shared/importers/remote_importer.py +196 -0
  181. rasa/shared/importers/utils.py +3 -1
  182. rasa/shared/nlu/training_data/formats/rasa_yaml.py +18 -3
  183. rasa/shared/nlu/training_data/training_data.py +18 -19
  184. rasa/shared/providers/_configs/litellm_router_client_config.py +220 -0
  185. rasa/shared/providers/_configs/model_group_config.py +167 -0
  186. rasa/shared/providers/_configs/openai_client_config.py +1 -1
  187. rasa/shared/providers/_configs/rasa_llm_client_config.py +73 -0
  188. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -0
  189. rasa/shared/providers/_configs/utils.py +16 -0
  190. rasa/shared/providers/_utils.py +79 -0
  191. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +13 -29
  192. rasa/shared/providers/embedding/azure_openai_embedding_client.py +54 -21
  193. rasa/shared/providers/embedding/default_litellm_embedding_client.py +24 -0
  194. rasa/shared/providers/embedding/litellm_router_embedding_client.py +135 -0
  195. rasa/shared/providers/llm/_base_litellm_client.py +34 -22
  196. rasa/shared/providers/llm/azure_openai_llm_client.py +50 -29
  197. rasa/shared/providers/llm/default_litellm_llm_client.py +24 -0
  198. rasa/shared/providers/llm/litellm_router_llm_client.py +182 -0
  199. rasa/shared/providers/llm/rasa_llm_client.py +112 -0
  200. rasa/shared/providers/llm/self_hosted_llm_client.py +5 -29
  201. rasa/shared/providers/mappings.py +19 -0
  202. rasa/shared/providers/router/__init__.py +0 -0
  203. rasa/shared/providers/router/_base_litellm_router_client.py +183 -0
  204. rasa/shared/providers/router/router_client.py +73 -0
  205. rasa/shared/utils/common.py +40 -24
  206. rasa/shared/utils/health_check/__init__.py +0 -0
  207. rasa/shared/utils/health_check/embeddings_health_check_mixin.py +31 -0
  208. rasa/shared/utils/health_check/health_check.py +258 -0
  209. rasa/shared/utils/health_check/llm_health_check_mixin.py +31 -0
  210. rasa/shared/utils/io.py +27 -6
  211. rasa/shared/utils/llm.py +353 -43
  212. rasa/shared/utils/schemas/events.py +2 -0
  213. rasa/shared/utils/schemas/model_config.yml +0 -10
  214. rasa/shared/utils/yaml.py +181 -38
  215. rasa/studio/data_handler.py +3 -1
  216. rasa/studio/upload.py +160 -74
  217. rasa/telemetry.py +94 -17
  218. rasa/tracing/config.py +3 -1
  219. rasa/tracing/instrumentation/attribute_extractors.py +95 -18
  220. rasa/tracing/instrumentation/instrumentation.py +121 -0
  221. rasa/utils/common.py +5 -0
  222. rasa/utils/endpoints.py +27 -1
  223. rasa/utils/io.py +8 -16
  224. rasa/utils/log_utils.py +9 -2
  225. rasa/utils/sanic_error_handler.py +32 -0
  226. rasa/validator.py +110 -4
  227. rasa/version.py +1 -1
  228. {rasa_pro-3.10.15.dist-info → rasa_pro-3.11.0.dist-info}/METADATA +14 -12
  229. {rasa_pro-3.10.15.dist-info → rasa_pro-3.11.0.dist-info}/RECORD +234 -183
  230. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-1844e5a5.js +0 -1
  231. rasa/core/channels/inspector/dist/assets/index-a5d3e69d.js +0 -1040
  232. rasa/core/channels/voice_aware/utils.py +0 -20
  233. rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +0 -407
  234. /rasa/core/channels/{voice_aware → voice_ready}/__init__.py +0 -0
  235. /rasa/core/channels/{voice_native → voice_stream}/__init__.py +0 -0
  236. {rasa_pro-3.10.15.dist-info → rasa_pro-3.11.0.dist-info}/NOTICE +0 -0
  237. {rasa_pro-3.10.15.dist-info → rasa_pro-3.11.0.dist-info}/WHEEL +0 -0
  238. {rasa_pro-3.10.15.dist-info → rasa_pro-3.11.0.dist-info}/entry_points.txt +0 -0
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import re
4
4
  import typing
5
5
  from collections import defaultdict
6
+ from dataclasses import dataclass
6
7
  from typing import Optional, Set, Text, List
7
8
 
8
9
  from rasa.shared.constants import (
@@ -26,6 +27,12 @@ from rasa.shared.core.flows.steps.call import CallFlowStep
26
27
  from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
27
28
  from rasa.shared.core.flows.steps.constants import CONTINUE_STEP_PREFIX, DEFAULT_STEPS
28
29
  from rasa.shared.core.flows.steps.link import LinkFlowStep
30
+ from rasa.shared.core.flows.steps.set_slots import SetSlotsFlowStep
31
+ from rasa.shared.core.flows.utils import (
32
+ warn_deprecated_collect_step_config,
33
+ get_duplicate_slot_persistence_config_error_message,
34
+ get_invalid_slot_persistence_config_error_message,
35
+ )
29
36
  from rasa.shared.exceptions import RasaException
30
37
 
31
38
  if typing.TYPE_CHECKING:
@@ -101,6 +108,31 @@ class DuplicatedStepIdException(RasaException):
101
108
  )
102
109
 
103
110
 
111
+ class DuplicatedFlowIdException(RasaException):
112
+ """Raised when a flow is using the same id as another flow."""
113
+
114
+ def __init__(
115
+ self, flow_id: str, first_file_path: str, second_file_path: str
116
+ ) -> None:
117
+ """Initializes the exception."""
118
+ self.flow_id = flow_id
119
+ self.first_file_path = first_file_path
120
+ self.second_file_path = second_file_path
121
+
122
+ def __str__(self) -> str:
123
+ """Return a string representation of the exception."""
124
+ if self.first_file_path == self.second_file_path:
125
+ return (
126
+ f"Flow '{self.flow_id}' is used twice in `{self.first_file_path}`. "
127
+ f"Please make sure flow IDs are unique across all files."
128
+ )
129
+ return (
130
+ f"Flow '{self.flow_id}' is used in both "
131
+ f"`{self.first_file_path}` and `{self.second_file_path}`. "
132
+ f"Please make sure flow IDs are unique across all files."
133
+ )
134
+
135
+
104
136
  class MissingElseBranchException(RasaException):
105
137
  """Raised when a flow step is missing an else branch."""
106
138
 
@@ -354,6 +386,42 @@ class FlowIdNamingException(RasaException):
354
386
  )
355
387
 
356
388
 
389
+ class DuplicateSlotPersistConfigException(RasaException):
390
+ """Raised when a slot persist configuration is duplicated."""
391
+
392
+ def __init__(self, flow_id: str, collect_step: str) -> None:
393
+ """Initializes the exception."""
394
+ self.flow_id = flow_id
395
+ self.collect_step = collect_step
396
+
397
+ def __str__(self) -> str:
398
+ """Return a string representation of the exception."""
399
+ return get_duplicate_slot_persistence_config_error_message(
400
+ self.flow_id, self.collect_step
401
+ )
402
+
403
+
404
+ class InvalidPersistSlotsException(RasaException):
405
+ """Raised when a slot persist configuration is duplicated."""
406
+
407
+ def __init__(self, flow_id: str, invalid_slots: Set[str]) -> None:
408
+ """Initializes the exception."""
409
+ self.flow_id = flow_id
410
+ self.invalid_slots = invalid_slots
411
+
412
+ def __str__(self) -> str:
413
+ """Return a string representation of the exception."""
414
+ return get_invalid_slot_persistence_config_error_message(
415
+ self.flow_id, self.invalid_slots
416
+ )
417
+
418
+
419
+ @dataclass
420
+ class ValidationResult:
421
+ is_valid: bool
422
+ invalid_slots: Set[str]
423
+
424
+
357
425
  def validate_flow(flow: Flow) -> None:
358
426
  """Validates the flow configuration.
359
427
 
@@ -362,6 +430,8 @@ def validate_flow(flow: Flow) -> None:
362
430
  - whether all next links point to existing steps
363
431
  - whether all steps can be reached from the start step
364
432
  """
433
+ from rasa.cli.utils import is_skip_validation_flag_set
434
+
365
435
  validate_flow_not_empty(flow)
366
436
  validate_no_empty_step_sequences(flow)
367
437
  validate_all_steps_next_property(flow)
@@ -372,6 +442,12 @@ def validate_flow(flow: Flow) -> None:
372
442
  validate_slot_names_to_be_collected(flow)
373
443
  validate_flow_id(flow)
374
444
 
445
+ if is_skip_validation_flag_set():
446
+ # we only want to run this validation if the --skip-validation flag is used
447
+ # during training because Flow Validation exceptions are raised one by one
448
+ # as opposed to all at once with the Validator class
449
+ validate_slot_persistence_configuration(flow)
450
+
375
451
 
376
452
  def validate_flow_not_empty(flow: Flow) -> None:
377
453
  """Validate that the flow is not empty."""
@@ -612,3 +688,48 @@ def validate_flow_id(flow: Flow) -> None:
612
688
  flow_re = re.compile(FLOW_ID_REGEX)
613
689
  if not flow_re.search(flow.id):
614
690
  raise FlowIdNamingException(flow.id)
691
+
692
+
693
+ def validate_slot_persistence_configuration(flow: Flow) -> None:
694
+ """Validates that slot persistence configuration is valid.
695
+
696
+ Only slots used in either a collect step or a set_slot step can be persisted
697
+ and the configuration can either be set at the flow level or the collect step level,
698
+ but not both.
699
+
700
+ Args:
701
+ flow: The flow to validate.
702
+
703
+ Raises:
704
+ DuplicateSlotPersistConfigException: If slot persist config is duplicated.
705
+ """
706
+
707
+ def _is_persist_slots_valid(
708
+ persist_slots: List[str], flow_slots: Set[str]
709
+ ) -> ValidationResult:
710
+ """Validates that the slots that should be persisted are used in the flow."""
711
+ invalid_slots = set(persist_slots) - flow_slots
712
+ is_valid = False if invalid_slots else True
713
+
714
+ return ValidationResult(is_valid, invalid_slots)
715
+
716
+ flow_id = flow.id
717
+ persist_slots = flow.persisted_slots
718
+ has_flow_level_persistence = True if persist_slots else False
719
+ flow_slots = set()
720
+
721
+ for step in flow.steps_with_calls_resolved:
722
+ if isinstance(step, SetSlotsFlowStep):
723
+ flow_slots.update([slot["key"] for slot in step.slots])
724
+ elif isinstance(step, CollectInformationFlowStep):
725
+ flow_slots.add(step.collect)
726
+ if not step.reset_after_flow_ends:
727
+ collect_step = step.collect
728
+ warn_deprecated_collect_step_config(flow_id, collect_step)
729
+ if has_flow_level_persistence:
730
+ raise DuplicateSlotPersistConfigException(flow_id, collect_step)
731
+
732
+ if has_flow_level_persistence:
733
+ result = _is_persist_slots_valid(persist_slots, flow_slots)
734
+ if not result.is_valid:
735
+ raise InvalidPersistSlotsException(flow_id, result.invalid_slots)
@@ -1,6 +1,5 @@
1
- import textwrap
2
1
  from pathlib import Path
3
- from typing import Any, Dict, List, Text, Union, Optional
2
+ from typing import Any, ClassVar, Dict, List, Optional, Text, Union
4
3
 
5
4
  import jsonschema
6
5
  import ruamel.yaml.nodes as yaml_nodes
@@ -12,12 +11,11 @@ import rasa.shared.utils.io
12
11
  from rasa.shared.core.flows.flow import Flow
13
12
  from rasa.shared.core.flows.flows_list import FlowsList
14
13
  from rasa.shared.exceptions import RasaException, YamlException
15
- from rasa.shared.importers.importer import FlowSyncImporter
16
14
  from rasa.shared.utils.yaml import (
17
- validate_yaml_with_jsonschema,
18
- read_yaml,
19
15
  dump_obj_as_yaml_to_string,
20
16
  is_key_in_yaml,
17
+ read_yaml,
18
+ validate_yaml_with_jsonschema,
21
19
  )
22
20
 
23
21
  FLOWS_SCHEMA_FILE = "shared/core/flows/flows_yaml_schema.json"
@@ -27,6 +25,8 @@ KEY_FLOWS = "flows"
27
25
  class YAMLFlowsReader:
28
26
  """Class that reads flows information in YAML format."""
29
27
 
28
+ expand_env_vars: ClassVar[bool] = True
29
+
30
30
  @classmethod
31
31
  def read_from_file(
32
32
  cls, filename: Union[Text, Path], add_line_numbers: bool = True
@@ -219,14 +219,21 @@ class YAMLFlowsReader:
219
219
  `Flow`s read from `string`.
220
220
  """
221
221
  validate_yaml_with_jsonschema(
222
- string, FLOWS_SCHEMA_FILE, humanize_error=cls.humanize_flow_error
222
+ string,
223
+ FLOWS_SCHEMA_FILE,
224
+ humanize_error=cls.humanize_flow_error,
225
+ expand_env_vars=cls.expand_env_vars,
223
226
  )
224
227
  if add_line_numbers:
225
- yaml_content = read_yaml(string, custom_constructor=line_number_constructor)
228
+ yaml_content = read_yaml(
229
+ string,
230
+ custom_constructor=line_number_constructor,
231
+ expand_env_vars=cls.expand_env_vars,
232
+ )
226
233
  yaml_content = process_yaml_content(yaml_content)
227
234
 
228
235
  else:
229
- yaml_content = read_yaml(string)
236
+ yaml_content = read_yaml(string, expand_env_vars=cls.expand_env_vars)
230
237
 
231
238
  return FlowsList.from_json(yaml_content.get(KEY_FLOWS, {}), file_path=file_path)
232
239
 
@@ -262,25 +269,6 @@ class YamlFlowsWriter:
262
269
  rasa.shared.utils.io.write_text_file(YamlFlowsWriter.dumps(flows), filename)
263
270
 
264
271
 
265
- def flows_from_str(yaml_str: str) -> FlowsList:
266
- """Reads flows from a YAML string."""
267
- flows = YAMLFlowsReader.read_from_string(
268
- textwrap.dedent(yaml_str), add_line_numbers=False
269
- )
270
- flows.validate()
271
- return flows
272
-
273
-
274
- def flows_from_str_including_defaults(yaml_str: str) -> FlowsList:
275
- """Reads flows from a YAML string and combine them with default flows."""
276
- flows = YAMLFlowsReader.read_from_string(
277
- textwrap.dedent(yaml_str), add_line_numbers=False
278
- )
279
- all_flows = FlowSyncImporter.merge_with_default_flows(flows)
280
- all_flows.validate()
281
- return all_flows
282
-
283
-
284
272
  def is_flows_file(file_path: Union[Text, Path]) -> bool:
285
273
  """Check if file contains Flow training data.
286
274
 
rasa/shared/core/slots.py CHANGED
@@ -193,6 +193,11 @@ class Slot(ABC):
193
193
  data.update(self.persistence_info())
194
194
  return rasa.shared.utils.io.get_dictionary_fingerprint(data)
195
195
 
196
+ def __eq__(self, other: Any) -> bool:
197
+ if not isinstance(other, Slot):
198
+ return False
199
+ return self.name == other.name and self.value == other.value
200
+
196
201
 
197
202
  class FloatSlot(Slot):
198
203
  """A slot storing a float value."""
@@ -1,9 +1,18 @@
1
- from __future__ import annotations
2
-
3
1
  import logging
4
2
  from abc import ABC, abstractmethod
5
3
  from functools import reduce
6
- from typing import Any, Dict, List, Optional, Set, Text, Tuple, Type, Union, cast
4
+ from typing import (
5
+ Any,
6
+ Dict,
7
+ List,
8
+ Optional,
9
+ Set,
10
+ Text,
11
+ Tuple,
12
+ Type,
13
+ Union,
14
+ cast,
15
+ )
7
16
 
8
17
  import importlib_resources
9
18
 
@@ -25,6 +34,7 @@ from rasa.shared.core.training_data.structures import StoryGraph
25
34
  from rasa.shared.nlu.constants import ACTION_NAME, ENTITIES
26
35
  from rasa.shared.nlu.training_data.message import Message
27
36
  from rasa.shared.nlu.training_data.training_data import TrainingData
37
+ from rasa.shared.utils.common import cached_method
28
38
  from rasa.shared.utils.yaml import read_config_file
29
39
 
30
40
  logger = logging.getLogger(__name__)
@@ -115,8 +125,8 @@ class TrainingDataImporter(ABC):
115
125
  config_path: Text,
116
126
  domain_path: Optional[Text] = None,
117
127
  training_data_paths: Optional[List[Text]] = None,
118
- args: Optional[Dict[Text, Any]] = {},
119
- ) -> TrainingDataImporter:
128
+ args: Optional[Dict[Text, Any]] = None,
129
+ ) -> "TrainingDataImporter":
120
130
  """Loads a `TrainingDataImporter` instance from a configuration file."""
121
131
  config = read_config_file(config_path)
122
132
  return TrainingDataImporter.load_from_dict(
@@ -128,8 +138,8 @@ class TrainingDataImporter(ABC):
128
138
  config_path: Text,
129
139
  domain_path: Optional[Text] = None,
130
140
  training_data_paths: Optional[List[Text]] = None,
131
- args: Optional[Dict[Text, Any]] = {},
132
- ) -> TrainingDataImporter:
141
+ args: Optional[Dict[Text, Any]] = None,
142
+ ) -> "TrainingDataImporter":
133
143
  """Loads core `TrainingDataImporter` instance.
134
144
 
135
145
  Instance loaded from configuration file will only read Core training data.
@@ -144,8 +154,8 @@ class TrainingDataImporter(ABC):
144
154
  config_path: Text,
145
155
  domain_path: Optional[Text] = None,
146
156
  training_data_paths: Optional[List[Text]] = None,
147
- args: Optional[Dict[Text, Any]] = {},
148
- ) -> TrainingDataImporter:
157
+ args: Optional[Dict[Text, Any]] = None,
158
+ ) -> "TrainingDataImporter":
149
159
  """Loads nlu `TrainingDataImporter` instance.
150
160
 
151
161
  Instance loaded from configuration file will only read NLU training data.
@@ -168,7 +178,8 @@ class TrainingDataImporter(ABC):
168
178
  domain_path: Optional[Text] = None,
169
179
  training_data_paths: Optional[List[Text]] = None,
170
180
  args: Optional[Dict[Text, Any]] = None,
171
- ) -> TrainingDataImporter:
181
+ expand_env_vars: bool = True,
182
+ ) -> "TrainingDataImporter":
172
183
  """Loads a `TrainingDataImporter` instance from a dictionary."""
173
184
  from rasa.shared.importers.rasa import RasaFileImporter
174
185
 
@@ -183,7 +194,12 @@ class TrainingDataImporter(ABC):
183
194
  importers = [importer for importer in importers if importer]
184
195
  if not importers:
185
196
  importers = [
186
- RasaFileImporter(config_path, domain_path, training_data_paths)
197
+ RasaFileImporter(
198
+ config_path,
199
+ domain_path,
200
+ training_data_paths,
201
+ expand_env_vars=expand_env_vars,
202
+ )
187
203
  ]
188
204
 
189
205
  return E2EImporter(
@@ -197,15 +213,18 @@ class TrainingDataImporter(ABC):
197
213
  domain_path: Optional[Text] = None,
198
214
  training_data_paths: Optional[List[Text]] = None,
199
215
  args: Optional[Dict[Text, Any]] = None,
200
- ) -> Optional[TrainingDataImporter]:
216
+ ) -> Optional["TrainingDataImporter"]:
201
217
  from rasa.shared.importers.multi_project import MultiProjectImporter
202
218
  from rasa.shared.importers.rasa import RasaFileImporter
219
+ from rasa.shared.importers.remote_importer import RemoteTrainingDataImporter
203
220
 
204
221
  module_path = importer_config.pop("name", None)
205
222
  if module_path == RasaFileImporter.__name__:
206
223
  importer_class: Type[TrainingDataImporter] = RasaFileImporter
207
224
  elif module_path == MultiProjectImporter.__name__:
208
225
  importer_class = MultiProjectImporter
226
+ elif module_path == RemoteTrainingDataImporter.__name__:
227
+ importer_class = RemoteTrainingDataImporter
209
228
  else:
210
229
  try:
211
230
  importer_class = rasa.shared.utils.common.class_from_module_path(
@@ -225,7 +244,8 @@ class TrainingDataImporter(ABC):
225
244
  **constructor_arguments,
226
245
  )
227
246
 
228
- def fingerprint(self) -> Text:
247
+ @staticmethod
248
+ def fingerprint() -> Text:
229
249
  """Returns a random fingerprint as data shouldn't be cached."""
230
250
  return rasa.shared.utils.io.random_string(25)
231
251
 
@@ -281,7 +301,6 @@ class NluDataImporter(TrainingDataImporter):
281
301
  """Retrieves NLU training data (see parent class for full docstring)."""
282
302
  return self._importer.get_nlu_data(language)
283
303
 
284
- @rasa.shared.utils.common.cached_method
285
304
  def get_config_file_for_auto_config(self) -> Optional[Text]:
286
305
  """Returns config file path for auto-config only if there is a single one."""
287
306
  return self._importer.get_config_file_for_auto_config()
@@ -297,14 +316,14 @@ class CombinedDataImporter(TrainingDataImporter):
297
316
  def __init__(self, importers: List[TrainingDataImporter]):
298
317
  self._importers = importers
299
318
 
300
- @rasa.shared.utils.common.cached_method
319
+ @cached_method
301
320
  def get_config(self) -> Dict:
302
321
  """Retrieves model config (see parent class for full docstring)."""
303
322
  configs = [importer.get_config() for importer in self._importers]
304
323
 
305
324
  return reduce(lambda merged, other: {**merged, **(other or {})}, configs, {})
306
325
 
307
- @rasa.shared.utils.common.cached_method
326
+ @cached_method
308
327
  def get_domain(self) -> Domain:
309
328
  """Retrieves model domain (see parent class for full docstring)."""
310
329
  domains = [importer.get_domain() for importer in self._importers]
@@ -315,7 +334,7 @@ class CombinedDataImporter(TrainingDataImporter):
315
334
  Domain.empty(),
316
335
  )
317
336
 
318
- @rasa.shared.utils.common.cached_method
337
+ @cached_method
319
338
  def get_stories(self, exclusion_percentage: Optional[int] = None) -> StoryGraph:
320
339
  """Retrieves training stories / rules (see parent class for full docstring)."""
321
340
  stories = [
@@ -326,7 +345,7 @@ class CombinedDataImporter(TrainingDataImporter):
326
345
  lambda merged, other: merged.merge(other), stories, StoryGraph([])
327
346
  )
328
347
 
329
- @rasa.shared.utils.common.cached_method
348
+ @cached_method
330
349
  def get_flows(self) -> FlowsList:
331
350
  """Retrieves training stories / rules (see parent class for full docstring)."""
332
351
  flow_lists = [importer.get_flows() for importer in self._importers]
@@ -337,7 +356,7 @@ class CombinedDataImporter(TrainingDataImporter):
337
356
  FlowsList(underlying_flows=[]),
338
357
  )
339
358
 
340
- @rasa.shared.utils.common.cached_method
359
+ @cached_method
341
360
  def get_conversation_tests(self) -> StoryGraph:
342
361
  """Retrieves conversation test stories (see parent class for full docstring)."""
343
362
  stories = [importer.get_conversation_tests() for importer in self._importers]
@@ -346,7 +365,7 @@ class CombinedDataImporter(TrainingDataImporter):
346
365
  lambda merged, other: merged.merge(other), stories, StoryGraph([])
347
366
  )
348
367
 
349
- @rasa.shared.utils.common.cached_method
368
+ @cached_method
350
369
  def get_nlu_data(self, language: Optional[Text] = "en") -> TrainingData:
351
370
  """Retrieves NLU training data (see parent class for full docstring)."""
352
371
  nlu_data = [importer.get_nlu_data(language) for importer in self._importers]
@@ -355,7 +374,7 @@ class CombinedDataImporter(TrainingDataImporter):
355
374
  lambda merged, other: merged.merge(other), nlu_data, TrainingData()
356
375
  )
357
376
 
358
- @rasa.shared.utils.common.cached_method
377
+ @cached_method
359
378
  def get_config_file_for_auto_config(self) -> Optional[Text]:
360
379
  """Returns config file path for auto-config only if there is a single one."""
361
380
  if len(self._importers) != 1:
@@ -414,26 +433,22 @@ class FlowSyncImporter(PassThroughImporter):
414
433
  """Loads the default flows from the file system."""
415
434
  from rasa.shared.core.flows.yaml_flows_io import YAMLFlowsReader
416
435
 
417
- default_flows_file = str(
418
- importlib_resources.files("rasa.dialogue_understanding.patterns").joinpath(
419
- DEFAULT_PATTERN_FLOWS_FILE_NAME
420
- )
421
- )
422
-
423
- flows = YAMLFlowsReader.read_from_file(default_flows_file)
436
+ flows = YAMLFlowsReader.read_from_file(FlowSyncImporter.default_pattern_path())
424
437
  flows.validate()
425
438
  return flows
426
439
 
427
440
  @staticmethod
428
- def load_default_pattern_flows_domain() -> Domain:
429
- """Loads the default flows from the file system."""
430
- default_flows_file = str(
441
+ def default_pattern_path() -> str:
442
+ return str(
431
443
  importlib_resources.files("rasa.dialogue_understanding.patterns").joinpath(
432
444
  DEFAULT_PATTERN_FLOWS_FILE_NAME
433
445
  )
434
446
  )
435
447
 
436
- return Domain.from_path(default_flows_file)
448
+ @staticmethod
449
+ def load_default_pattern_flows_domain() -> Domain:
450
+ """Loads the default flows from the file system."""
451
+ return Domain.from_path(FlowSyncImporter.default_pattern_path())
437
452
 
438
453
  @classmethod
439
454
  def merge_with_default_flows(cls, flows: FlowsList) -> FlowsList:
@@ -459,7 +474,7 @@ class FlowSyncImporter(PassThroughImporter):
459
474
 
460
475
  return flows.merge(FlowsList(missing_default_flows))
461
476
 
462
- @rasa.shared.utils.common.cached_method
477
+ @cached_method
463
478
  def get_flows(self) -> FlowsList:
464
479
  flows = self._importer.get_flows()
465
480
 
@@ -469,11 +484,11 @@ class FlowSyncImporter(PassThroughImporter):
469
484
 
470
485
  return self.merge_with_default_flows(flows)
471
486
 
472
- @rasa.shared.utils.common.cached_method
487
+ @cached_method
473
488
  def get_user_flows(self) -> FlowsList:
474
489
  return self._importer.get_flows()
475
490
 
476
- @rasa.shared.utils.common.cached_method
491
+ @cached_method
477
492
  def get_domain(self) -> Domain:
478
493
  """Merge existing domain with properties of flows."""
479
494
  # load domain data from user defined domain files
@@ -515,7 +530,7 @@ class ResponsesSyncImporter(PassThroughImporter):
515
530
  back to the Domain.
516
531
  """
517
532
 
518
- @rasa.shared.utils.common.cached_method
533
+ @cached_method
519
534
  def get_domain(self) -> Domain:
520
535
  """Merge existing domain with properties of retrieval intents in NLU data."""
521
536
  existing_domain = self._importer.get_domain()
@@ -597,7 +612,7 @@ class ResponsesSyncImporter(PassThroughImporter):
597
612
  }
598
613
  )
599
614
 
600
- @rasa.shared.utils.common.cached_method
615
+ @cached_method
601
616
  def get_nlu_data(self, language: Optional[Text] = "en") -> TrainingData:
602
617
  """Updates NLU data with responses for retrieval intents from domain."""
603
618
  existing_nlu_data = self._importer.get_nlu_data(language)
@@ -632,7 +647,7 @@ class E2EImporter(PassThroughImporter):
632
647
  - adds potential end-to-end bot messages from stories as actions to the domain
633
648
  """
634
649
 
635
- @rasa.shared.utils.common.cached_method
650
+ @cached_method
636
651
  def get_user_flows(self) -> FlowsList:
637
652
  if not isinstance(self._importer, FlowSyncImporter):
638
653
  raise NotImplementedError(
@@ -641,9 +656,12 @@ class E2EImporter(PassThroughImporter):
641
656
 
642
657
  return self._importer.get_user_flows()
643
658
 
644
- @rasa.shared.utils.common.cached_method
659
+ @cached_method
645
660
  def get_domain(self) -> Domain:
646
- """Retrieves model domain (see parent class for full docstring)."""
661
+ """Merge existing domain with properties of end-to-end actions in stories.
662
+
663
+ Returns: Domain with end-to-end actions added to action names.
664
+ """
647
665
  original = self._importer.get_domain()
648
666
  e2e_domain = self._get_domain_with_e2e_actions()
649
667
 
@@ -673,7 +691,7 @@ class E2EImporter(PassThroughImporter):
673
691
 
674
692
  return Domain.from_dict({KEY_E2E_ACTIONS: list(additional_e2e_action_names)})
675
693
 
676
- @rasa.shared.utils.common.cached_method
694
+ @cached_method
677
695
  def get_nlu_data(self, language: Optional[Text] = "en") -> TrainingData:
678
696
  """Retrieves NLU training data (see parent class for full docstring)."""
679
697
  training_datasets = [
@@ -1,22 +1,23 @@
1
- import logging
2
- from functools import reduce
3
- from typing import Text, Set, Dict, Optional, List, Union, Any
4
1
  import os
2
+ from functools import reduce
3
+ from typing import Any, Dict, List, Optional, Set, Text, Union
4
+
5
+ import structlog
5
6
 
6
7
  import rasa.shared.data
7
8
  import rasa.shared.utils.io
8
9
  from rasa.shared.core.domain import Domain
9
- from rasa.shared.importers.importer import TrainingDataImporter
10
- from rasa.shared.importers import utils
11
- from rasa.shared.nlu.training_data.training_data import TrainingData
12
- from rasa.shared.core.training_data.structures import StoryGraph
13
- from rasa.shared.utils.common import mark_as_experimental_feature
14
10
  from rasa.shared.core.training_data.story_reader.yaml_story_reader import (
15
11
  YAMLStoryReader,
16
12
  )
13
+ from rasa.shared.core.training_data.structures import StoryGraph
14
+ from rasa.shared.importers import utils
15
+ from rasa.shared.importers.importer import TrainingDataImporter
16
+ from rasa.shared.nlu.training_data.training_data import TrainingData
17
+ from rasa.shared.utils.common import cached_method, mark_as_experimental_feature
17
18
  from rasa.shared.utils.yaml import read_config_file, read_model_configuration
18
19
 
19
- logger = logging.getLogger(__name__)
20
+ structlogger = structlog.get_logger()
20
21
 
21
22
 
22
23
  class MultiProjectImporter(TrainingDataImporter):
@@ -50,8 +51,13 @@ class MultiProjectImporter(TrainingDataImporter):
50
51
  self._story_paths += extra_story_files
51
52
  self._nlu_paths += extra_nlu_files
52
53
 
53
- logger.debug(
54
- "Selected projects: {}".format("".join([f"\n-{i}" for i in self._imports]))
54
+ structlogger.debug(
55
+ "multi_project_importer.initialisation",
56
+ event_info=(
57
+ "Selected projects: {}".format(
58
+ "".join([f"\n-{i}" for i in self._imports])
59
+ )
60
+ ),
55
61
  )
56
62
 
57
63
  mark_as_experimental_feature(feature_name="MultiProjectImporter")
@@ -135,6 +141,7 @@ class MultiProjectImporter(TrainingDataImporter):
135
141
 
136
142
  return training_paths
137
143
 
144
+ @cached_method
138
145
  def is_imported(self, path: Text) -> bool:
139
146
  """Checks whether a path is imported by a skill.
140
147
 
@@ -175,6 +182,7 @@ class MultiProjectImporter(TrainingDataImporter):
175
182
  [rasa.shared.utils.io.is_subdirectory(path, i) for i in self._imports]
176
183
  )
177
184
 
185
+ @cached_method
178
186
  def get_domain(self) -> Domain:
179
187
  """Retrieves model domain (see parent class for full docstring)."""
180
188
  domains = [Domain.load(path) for path in self._domain_paths]
@@ -184,20 +192,24 @@ class MultiProjectImporter(TrainingDataImporter):
184
192
  Domain.empty(),
185
193
  )
186
194
 
195
+ @cached_method
187
196
  def get_stories(self, exclusion_percentage: Optional[int] = None) -> StoryGraph:
188
197
  """Retrieves training stories / rules (see parent class for full docstring)."""
189
198
  return utils.story_graph_from_paths(
190
199
  self._story_paths, self.get_domain(), exclusion_percentage
191
200
  )
192
201
 
202
+ @cached_method
193
203
  def get_conversation_tests(self) -> StoryGraph:
194
204
  """Retrieves conversation test stories (see parent class for full docstring)."""
195
205
  return utils.story_graph_from_paths(self._e2e_story_paths, self.get_domain())
196
206
 
207
+ @cached_method
197
208
  def get_config(self) -> Dict:
198
209
  """Retrieves model config (see parent class for full docstring)."""
199
210
  return self.config
200
211
 
212
+ @cached_method
201
213
  def get_nlu_data(self, language: Optional[Text] = "en") -> TrainingData:
202
214
  """Retrieves NLU training data (see parent class for full docstring)."""
203
215
  return utils.training_data_from_paths(self._nlu_paths, language)