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
@@ -1,16 +1,21 @@
1
+ from __future__ import annotations
2
+
1
3
  import collections
2
4
  import copy
3
5
  import json
4
6
  import os
5
7
  from dataclasses import dataclass
8
+ from functools import cached_property
6
9
  from pathlib import Path
7
10
  from typing import (
8
11
  TYPE_CHECKING,
9
12
  Any,
10
13
  Callable,
14
+ ClassVar,
11
15
  Dict,
12
16
  Iterable,
13
17
  List,
18
+ MutableMapping,
14
19
  NamedTuple,
15
20
  NoReturn,
16
21
  Optional,
@@ -19,7 +24,6 @@ from typing import (
19
24
  Tuple,
20
25
  Union,
21
26
  cast,
22
- MutableMapping,
23
27
  )
24
28
 
25
29
  import structlog
@@ -51,11 +55,11 @@ from rasa.shared.core.constants import (
51
55
  )
52
56
  from rasa.shared.core.events import SlotSet, UserUttered
53
57
  from rasa.shared.core.slots import (
54
- Slot,
55
- CategoricalSlot,
56
- TextSlot,
57
58
  AnySlot,
59
+ CategoricalSlot,
58
60
  ListSlot,
61
+ Slot,
62
+ TextSlot,
59
63
  )
60
64
  from rasa.shared.exceptions import (
61
65
  RasaException,
@@ -63,21 +67,21 @@ from rasa.shared.exceptions import (
63
67
  YamlSyntaxException,
64
68
  )
65
69
  from rasa.shared.nlu.constants import (
66
- ENTITY_ATTRIBUTE_TYPE,
67
- ENTITY_ATTRIBUTE_ROLE,
70
+ ENTITIES,
68
71
  ENTITY_ATTRIBUTE_GROUP,
69
- RESPONSE_IDENTIFIER_DELIMITER,
72
+ ENTITY_ATTRIBUTE_ROLE,
73
+ ENTITY_ATTRIBUTE_TYPE,
70
74
  INTENT_NAME_KEY,
71
- ENTITIES,
75
+ RESPONSE_IDENTIFIER_DELIMITER,
72
76
  )
73
77
  from rasa.shared.utils.cli import print_error_and_exit
74
78
  from rasa.shared.utils.yaml import (
75
79
  KEY_TRAINING_DATA_FORMAT_VERSION,
80
+ dump_obj_as_yaml_to_string,
76
81
  read_yaml,
77
- validate_training_data_format_version,
78
82
  read_yaml_file,
79
- dump_obj_as_yaml_to_string,
80
83
  validate_raw_yaml_using_schema_file_with_responses,
84
+ validate_training_data_format_version,
81
85
  )
82
86
 
83
87
  if TYPE_CHECKING:
@@ -155,7 +159,7 @@ class SessionConfig(NamedTuple):
155
159
  carry_over_slots: bool
156
160
 
157
161
  @staticmethod
158
- def default() -> "SessionConfig":
162
+ def default() -> SessionConfig:
159
163
  """Returns the SessionConfig with the default values."""
160
164
  return SessionConfig(
161
165
  DEFAULT_SESSION_EXPIRATION_TIME_IN_MINUTES,
@@ -191,13 +195,16 @@ class Domain:
191
195
  and entities it can recognise.
192
196
  """
193
197
 
198
+ validate_yaml: ClassVar[bool] = True
199
+ expand_env_vars: ClassVar[bool] = True
200
+
194
201
  @classmethod
195
- def empty(cls) -> "Domain":
202
+ def empty(cls) -> Domain:
196
203
  """Returns empty Domain."""
197
204
  return Domain.from_dict({})
198
205
 
199
206
  @classmethod
200
- def load(cls, paths: Union[List[Union[Path, Text]], Text, Path]) -> "Domain":
207
+ def load(cls, paths: Union[List[Union[Path, Text]], Text, Path]) -> Domain:
201
208
  """Returns loaded Domain after merging all domain files."""
202
209
  if not paths:
203
210
  raise InvalidDomain(
@@ -215,8 +222,15 @@ class Domain:
215
222
  return domain
216
223
 
217
224
  @classmethod
218
- def from_path(cls, path: Union[Text, Path]) -> "Domain":
219
- """Loads the `Domain` from a path."""
225
+ def from_path(cls, path: Union[Text, Path]) -> Domain:
226
+ """Loads the `Domain` from a path.
227
+
228
+ Args:
229
+ path: Path to the domain file.
230
+
231
+ Returns:
232
+ The instantiated `Domain` object.
233
+ """
220
234
  path = os.path.abspath(path)
221
235
 
222
236
  if os.path.isfile(path):
@@ -232,17 +246,30 @@ class Domain:
232
246
  return domain
233
247
 
234
248
  @classmethod
235
- def from_file(cls, path: Text) -> "Domain":
236
- """Loads the `Domain` from a YAML file."""
249
+ def from_file(cls, path: Text) -> Domain:
250
+ """Loads the `Domain` from a YAML file.
251
+
252
+ Args:
253
+ path: Path to the domain file.
254
+
255
+ Returns:
256
+ The instantiated `Domain` object.
257
+ """
237
258
  return cls.from_yaml(rasa.shared.utils.io.read_file(path), path)
238
259
 
239
260
  @classmethod
240
- def from_yaml(cls, yaml: Text, original_filename: Text = "") -> "Domain":
241
- """Loads the `Domain` from YAML text after validating it."""
242
- try:
243
- validate_raw_yaml_using_schema_file_with_responses(yaml, DOMAIN_SCHEMA_FILE)
261
+ def from_yaml(cls, yaml: Text, original_filename: Text = "") -> Domain:
262
+ """Loads the `Domain` from YAML text after validating it.
244
263
 
245
- data = read_yaml(yaml)
264
+ Args:
265
+ yaml: The YAML string to load the domain from.
266
+ original_filename: The filename of the original YAML file.
267
+
268
+ Returns:
269
+ The instantiated `Domain` object.
270
+ """
271
+ try:
272
+ data = cls._dict_from_raw_yaml_content(yaml)
246
273
  if not validate_training_data_format_version(data, original_filename):
247
274
  return Domain.empty()
248
275
  return cls.from_dict(data)
@@ -251,7 +278,7 @@ class Domain:
251
278
  raise e
252
279
 
253
280
  @classmethod
254
- def from_dict(cls, data: Dict) -> "Domain":
281
+ def from_dict(cls, data: Dict) -> Domain:
255
282
  """Deserializes and creates domain.
256
283
 
257
284
  Args:
@@ -282,8 +309,8 @@ class Domain:
282
309
  _validate_forms(forms)
283
310
 
284
311
  return cls(
285
- intents=intents,
286
- entities=data.get(KEY_ENTITIES, {}),
312
+ intents=intents or [],
313
+ entities=data.get(KEY_ENTITIES, []),
287
314
  slots=slots,
288
315
  responses=responses,
289
316
  action_names=actions,
@@ -308,8 +335,15 @@ class Domain:
308
335
  return SessionConfig(session_expiration_time_min, carry_over_slots)
309
336
 
310
337
  @classmethod
311
- def from_directory(cls, path: Text) -> "Domain":
312
- """Loads and merges multiple domain files recursively from a directory tree."""
338
+ def from_directory(cls, path: Text) -> Domain:
339
+ """Loads and merges multiple domain files recursively from a directory tree.
340
+
341
+ Args:
342
+ path: Path to the root directory.
343
+
344
+ Returns:
345
+ The instantiated `Domain` object.
346
+ """
313
347
  combined: Dict[Text, Any] = {}
314
348
  duplicates: List[Dict[Text, List[Text]]] = []
315
349
 
@@ -319,10 +353,10 @@ class Domain:
319
353
  if not Domain.is_domain_file(full_path):
320
354
  continue
321
355
 
322
- # does the validation here only
323
- _ = Domain.from_file(full_path)
356
+ other_dict = cls._dict_from_raw_yaml_content(
357
+ rasa.shared.utils.io.read_file(full_path)
358
+ )
324
359
 
325
- other_dict = read_yaml(rasa.shared.utils.io.read_file(full_path))
326
360
  combined = Domain.merge_domain_dicts(other_dict, combined)
327
361
  duplicates.append(combined.pop("duplicates", {}))
328
362
 
@@ -368,10 +402,10 @@ class Domain:
368
402
 
369
403
  def merge(
370
404
  self,
371
- domain: Optional["Domain"],
405
+ domain: Optional[Domain],
372
406
  override: bool = False,
373
407
  ignore_warnings_about_duplicates: bool = False,
374
- ) -> "Domain":
408
+ ) -> Domain:
375
409
  """Merges this domain dict with another one, combining their attributes.
376
410
 
377
411
  This method merges domain dicts, and ensures all attributes (like ``intents``,
@@ -674,7 +708,7 @@ class Domain:
674
708
 
675
709
  return intent
676
710
 
677
- @rasa.shared.utils.common.lazy_property
711
+ @cached_property
678
712
  def retrieval_intents(self) -> List[Text]:
679
713
  """List retrieval intents present in the domain."""
680
714
  return [
@@ -899,7 +933,7 @@ class Domain:
899
933
  self.store_entities_as_slots = store_entities_as_slots
900
934
  self._check_domain_sanity()
901
935
 
902
- def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> "Domain":
936
+ def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> Domain:
903
937
  """Enables making a deep copy of the `Domain` using `copy.deepcopy`.
904
938
 
905
939
  See https://docs.python.org/3/library/copy.html#copy.deepcopy
@@ -1003,23 +1037,23 @@ class Domain:
1003
1037
  sorted_intents = sorted(intents, key=sort)
1004
1038
  return sorted_intents
1005
1039
 
1006
- @rasa.shared.utils.common.lazy_property
1040
+ @cached_property
1007
1041
  def user_actions_and_forms(self) -> List[Text]:
1008
1042
  """Returns combination of user actions and forms."""
1009
1043
  return self.user_actions + self.form_names
1010
1044
 
1011
- @rasa.shared.utils.common.lazy_property
1045
+ @cached_property
1012
1046
  def num_actions(self) -> int:
1013
1047
  """Returns the number of available actions."""
1014
1048
  # noinspection PyTypeChecker
1015
1049
  return len(self.action_names_or_texts)
1016
1050
 
1017
- @rasa.shared.utils.common.lazy_property
1051
+ @cached_property
1018
1052
  def num_states(self) -> int:
1019
1053
  """Number of used input states for the action prediction."""
1020
1054
  return len(self.input_states)
1021
1055
 
1022
- @rasa.shared.utils.common.lazy_property
1056
+ @cached_property
1023
1057
  def retrieval_intent_responses(self) -> Dict[Text, List[Dict[Text, Any]]]:
1024
1058
  """Return only the responses which are defined for retrieval intents."""
1025
1059
  return dict(
@@ -1171,8 +1205,7 @@ class Domain:
1171
1205
  f"Available actions are: \n{action_names}"
1172
1206
  )
1173
1207
 
1174
- # noinspection PyTypeChecker
1175
- @rasa.shared.utils.common.lazy_property
1208
+ @cached_property
1176
1209
  def slot_states(self) -> List[Text]:
1177
1210
  """Returns all available slot state strings."""
1178
1211
  return [
@@ -1181,8 +1214,7 @@ class Domain:
1181
1214
  for feature_index in range(0, slot.feature_dimensionality())
1182
1215
  ]
1183
1216
 
1184
- # noinspection PyTypeChecker
1185
- @rasa.shared.utils.common.lazy_property
1217
+ @cached_property
1186
1218
  def entity_states(self) -> List[Text]:
1187
1219
  """Returns all available entity state strings."""
1188
1220
  entity_states = copy.deepcopy(self.entities)
@@ -1230,12 +1262,12 @@ class Domain:
1230
1262
  for entity_sub_label in entity_sub_labels
1231
1263
  ]
1232
1264
 
1233
- @rasa.shared.utils.common.lazy_property
1265
+ @cached_property
1234
1266
  def input_state_map(self) -> Dict[Text, int]:
1235
1267
  """Provide a mapping from state names to indices."""
1236
1268
  return {f: i for i, f in enumerate(self.input_states)}
1237
1269
 
1238
- @rasa.shared.utils.common.lazy_property
1270
+ @cached_property
1239
1271
  def input_states(self) -> List[Text]:
1240
1272
  """Returns all available states."""
1241
1273
  return (
@@ -1465,7 +1497,7 @@ class Domain:
1465
1497
  ignore_rule_only_turns: bool = False,
1466
1498
  rule_only_data: Optional[Dict[Text, Any]] = None,
1467
1499
  ) -> List[State]:
1468
- """List of states for each state of the trackers history.
1500
+ """List of states for each state of the tracker's history.
1469
1501
 
1470
1502
  Args:
1471
1503
  tracker: Dialogue state tracker containing the dialogue so far.
@@ -1682,12 +1714,12 @@ class Domain:
1682
1714
  """Return the configuration for an intent."""
1683
1715
  return self.intent_properties.get(intent_name, {})
1684
1716
 
1685
- @rasa.shared.utils.common.lazy_property
1717
+ @cached_property
1686
1718
  def intents(self) -> List[Text]:
1687
1719
  """Returns sorted list of intents."""
1688
1720
  return sorted(self.intent_properties.keys())
1689
1721
 
1690
- @rasa.shared.utils.common.lazy_property
1722
+ @cached_property
1691
1723
  def entities(self) -> List[Text]:
1692
1724
  """Returns sorted list of entities."""
1693
1725
  return sorted(self.entity_properties.entities)
@@ -1924,8 +1956,8 @@ class Domain:
1924
1956
  """Check whether the domain is empty."""
1925
1957
  return self.as_dict() == Domain.empty().as_dict()
1926
1958
 
1927
- @staticmethod
1928
- def is_domain_file(filename: Union[Text, Path]) -> bool:
1959
+ @classmethod
1960
+ def is_domain_file(cls, filename: Union[Text, Path]) -> bool:
1929
1961
  """Checks whether the given file path is a Rasa domain file.
1930
1962
 
1931
1963
  Args:
@@ -1944,7 +1976,7 @@ class Domain:
1944
1976
  return False
1945
1977
 
1946
1978
  try:
1947
- content = read_yaml_file(filename)
1979
+ content = read_yaml_file(filename, expand_env_vars=cls.expand_env_vars)
1948
1980
  except (RasaException, YamlSyntaxException):
1949
1981
  structlogger.warning(
1950
1982
  "domain.cannot_load_domain_file",
@@ -2055,6 +2087,31 @@ class Domain:
2055
2087
  def is_custom_action(self, action_name: str) -> bool:
2056
2088
  return action_name in self._custom_actions
2057
2089
 
2090
+ @classmethod
2091
+ def _dict_from_raw_yaml_content(cls, raw_yaml_content: Text) -> Any:
2092
+ """Loads the Domain dict from raw YAML content.
2093
+
2094
+ Validates the raw YAML content using the schema file if `validate_yaml` is set
2095
+ to `True`.
2096
+
2097
+ Args:
2098
+ raw_yaml_content: The raw YAML content of the domain file.
2099
+
2100
+ Returns:
2101
+ The Domain dict.
2102
+ """
2103
+ if cls.validate_yaml:
2104
+ structlogger.info(
2105
+ "domain.from_yaml.validating",
2106
+ )
2107
+ validate_raw_yaml_using_schema_file_with_responses(
2108
+ raw_yaml_content,
2109
+ DOMAIN_SCHEMA_FILE,
2110
+ expand_env_vars=cls.expand_env_vars,
2111
+ )
2112
+
2113
+ return read_yaml(raw_yaml_content, expand_env_vars=cls.expand_env_vars)
2114
+
2058
2115
 
2059
2116
  def warn_about_duplicates_found_during_domain_merging(
2060
2117
  duplicates: Dict[Text, List[Text]],
@@ -2528,3 +2528,32 @@ class FlowCancelled(SkipEventInMDStoryMixin):
2528
2528
  )
2529
2529
  except KeyError as e:
2530
2530
  raise ValueError(f"Failed to parse flow_cancelled event. {e}")
2531
+
2532
+
2533
+ class SessionEnded(AlwaysEqualEventMixin):
2534
+ """Mark the end of a conversation session."""
2535
+
2536
+ type_name = "session_ended"
2537
+
2538
+ def __hash__(self) -> int:
2539
+ """Returns unique hash for event."""
2540
+ return hash(32143124321)
2541
+
2542
+ def __repr__(self) -> Text:
2543
+ """Returns event as string for debugging."""
2544
+ return f"SessionEnded(type_name: {self.type_name})"
2545
+
2546
+ def __str__(self) -> Text:
2547
+ """Returns event as human-readable string."""
2548
+ return f"{self.__class__.__name__}({self.type_name})"
2549
+
2550
+ def as_story_string(self) -> None:
2551
+ """Skips representing event in stories."""
2552
+ logger.warning(
2553
+ f"'{self.type_name}' events cannot be serialised as story strings."
2554
+ )
2555
+
2556
+ def apply_to(self, tracker: "DialogueStateTracker") -> None:
2557
+ """Applies event to current conversation state."""
2558
+ # noinspection PyProtectedMember
2559
+ tracker._reset()
@@ -60,6 +60,8 @@ class Flow:
60
60
  """
61
61
  file_path: Optional[str] = None
62
62
  """The path to the file where the flow is stored."""
63
+ persisted_slots: List[str] = field(default_factory=list)
64
+ """The list of slots that should be persisted after the flow ends."""
63
65
 
64
66
  @staticmethod
65
67
  def from_json(
@@ -95,6 +97,7 @@ class Flow:
95
97
  # If we are reading the flows in after training the file_path is part of
96
98
  # data. When the model is trained, take the provided file_path.
97
99
  file_path=data.get("file_path") if "file_path" in data else file_path,
100
+ persisted_slots=data.get("persisted_slots", []),
98
101
  )
99
102
 
100
103
  def get_full_name(self) -> str:
@@ -167,6 +170,8 @@ class Flow:
167
170
  data["nlu_trigger"] = self.nlu_triggers.as_json()
168
171
  if self.file_path:
169
172
  data["file_path"] = self.file_path
173
+ if self.persisted_slots:
174
+ data["persisted_slots"] = self.persisted_slots
170
175
 
171
176
  return data
172
177
 
@@ -16,6 +16,7 @@ from rasa.shared.core.flows.validation import (
16
16
  validate_patterns_are_not_called_or_linked,
17
17
  validate_patterns_are_not_calling_or_linking_other_flows,
18
18
  validate_step_ids_are_unique,
19
+ DuplicatedFlowIdException,
19
20
  )
20
21
  from rasa.shared.core.slots import Slot
21
22
 
@@ -49,21 +50,31 @@ class FlowsList:
49
50
  return len(self.underlying_flows) == 0
50
51
 
51
52
  @classmethod
52
- def from_multiple_flows_lists(cls, *other: FlowsList) -> FlowsList:
53
+ def from_multiple_flows_lists(
54
+ cls, *other: FlowsList, ignore_duplicates: bool = True
55
+ ) -> FlowsList:
53
56
  """Merges multiple lists of flows into a single flow ensuring each flow is
54
57
  unique, based on its ID.
55
58
 
56
59
  Args:
57
60
  other: Variable number of flow lists instances to be merged.
61
+ ignore_duplicates: Whether to ignore duplicate flow ids, or raise an error.
58
62
 
59
63
  Returns:
60
64
  Merged flow list.
61
65
  """
62
- merged_flows = dict()
66
+ merged_flows: Dict[Text, Flow] = dict()
63
67
  for flow_list in other:
64
68
  for flow in flow_list:
65
- if flow.id not in merged_flows:
66
- merged_flows[flow.id] = flow
69
+ if flow.id in merged_flows:
70
+ if ignore_duplicates:
71
+ continue
72
+ current_flow_path = flow.file_path
73
+ other_flow_path = merged_flows[flow.id].file_path
74
+ raise DuplicatedFlowIdException(
75
+ flow.id, current_flow_path, other_flow_path
76
+ )
77
+ merged_flows[flow.id] = flow
67
78
  return FlowsList(list(merged_flows.values()))
68
79
 
69
80
  @classmethod
@@ -118,9 +129,11 @@ class FlowsList:
118
129
  flow_dicts = [flow.as_json() for flow in self.underlying_flows]
119
130
  return rasa.shared.utils.io.get_list_fingerprint(flow_dicts)
120
131
 
121
- def merge(self, other: FlowsList) -> FlowsList:
132
+ def merge(self, other: FlowsList, ignore_duplicates: bool = True) -> FlowsList:
122
133
  """Merges two lists of flows together."""
123
- return FlowsList.from_multiple_flows_lists(self, other)
134
+ return FlowsList.from_multiple_flows_lists(
135
+ self, other, ignore_duplicates=ignore_duplicates
136
+ )
124
137
 
125
138
  def flow_by_id(self, flow_id: Text) -> Optional[Flow]:
126
139
  """Return the flow with the given id."""
@@ -279,6 +279,9 @@
279
279
  },
280
280
  "steps": {
281
281
  "$ref": "#/$defs/steps"
282
+ },
283
+ "persisted_slots": {
284
+ "$ref": "#/$defs/persisted_slots"
282
285
  }
283
286
  }
284
287
  },
@@ -288,6 +291,13 @@
288
291
  "items": {
289
292
  "type": "object"
290
293
  }
294
+ },
295
+ "persisted_slots": {
296
+ "type": "array",
297
+ "schema_name": "list of slots",
298
+ "items": {
299
+ "type": "string"
300
+ }
291
301
  }
292
302
  }
293
303
  }
@@ -0,0 +1,39 @@
1
+ from typing import Set
2
+ from rasa.shared.utils.io import raise_deprecation_warning
3
+
4
+ RESET_PROPERTY_NAME = "reset_after_flow_ends"
5
+ PERSIST_PROPERTY_NAME = "persisted_slots"
6
+
7
+
8
+ def warn_deprecated_collect_step_config(flow_id: str, collect_step: str) -> None:
9
+ """Warns about deprecated reset_after_flow_ends usage in collect steps."""
10
+ raise_deprecation_warning(
11
+ f"Configuring '{RESET_PROPERTY_NAME}' in collect step '{collect_step}' is "
12
+ f"deprecated and will be removed in Rasa Pro 4.0.0. In flow id '{flow_id}', "
13
+ f"please use the '{PERSIST_PROPERTY_NAME}' "
14
+ "property at the flow level instead."
15
+ )
16
+
17
+
18
+ def get_duplicate_slot_persistence_config_error_message(
19
+ flow_id: str, collect_step: str
20
+ ) -> str:
21
+ """Returns an error message for duplicate slot persistence configuration."""
22
+ return (
23
+ f"Flow with id '{flow_id}' uses the '{RESET_PROPERTY_NAME}' property "
24
+ f"in collect step '{collect_step}' and also the "
25
+ f"'{PERSIST_PROPERTY_NAME}' property at the flow level. "
26
+ "Please use only one of the two configuration methods."
27
+ )
28
+
29
+
30
+ def get_invalid_slot_persistence_config_error_message(
31
+ flow_id: str, invalid_slots: Set[str]
32
+ ) -> str:
33
+ """Returns an error message for invalid slot persistence configuration."""
34
+ return (
35
+ f"Flow with id '{flow_id}' lists slot(s) '{invalid_slots}' in the "
36
+ f"'{PERSIST_PROPERTY_NAME}' property. However these slots "
37
+ f"are neither used in a collect step nor a set_slot step of the flow. "
38
+ f"Please remove such slots from the '{PERSIST_PROPERTY_NAME}' property."
39
+ )