rasa-pro 3.10.16__py3-none-any.whl → 3.11.0a1__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 (185) hide show
  1. README.md +396 -17
  2. rasa/api.py +9 -3
  3. rasa/cli/arguments/default_arguments.py +23 -2
  4. rasa/cli/arguments/run.py +15 -0
  5. rasa/cli/arguments/train.py +3 -9
  6. rasa/cli/e2e_test.py +1 -1
  7. rasa/cli/evaluate.py +1 -1
  8. rasa/cli/inspect.py +8 -4
  9. rasa/cli/llm_fine_tuning.py +12 -15
  10. rasa/cli/run.py +8 -1
  11. rasa/cli/studio/studio.py +8 -18
  12. rasa/cli/train.py +11 -53
  13. rasa/cli/utils.py +8 -10
  14. rasa/cli/x.py +1 -1
  15. rasa/constants.py +1 -1
  16. rasa/core/actions/action.py +2 -0
  17. rasa/core/actions/action_hangup.py +29 -0
  18. rasa/core/agent.py +2 -2
  19. rasa/core/brokers/kafka.py +3 -1
  20. rasa/core/brokers/pika.py +3 -1
  21. rasa/core/channels/__init__.py +8 -6
  22. rasa/core/channels/channel.py +21 -4
  23. rasa/core/channels/development_inspector.py +143 -46
  24. rasa/core/channels/inspector/README.md +1 -1
  25. rasa/core/channels/inspector/dist/assets/{arc-b6e548fe.js → arc-86942a71.js} +1 -1
  26. rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-fa03ac9e.js → c4Diagram-d0fbc5ce-b0290676.js} +1 -1
  27. rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-ee67392a.js → classDiagram-936ed81e-f6405f6e.js} +1 -1
  28. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-9b283fae.js → classDiagram-v2-c3cb15f1-ef61ac77.js} +1 -1
  29. rasa/core/channels/inspector/dist/assets/{createText-62fc7601-8b6fcc2a.js → createText-62fc7601-f0411e58.js} +1 -1
  30. rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-22e77f4f.js → edges-f2ad444c-7dcc4f3b.js} +1 -1
  31. rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-60ffc87f.js → erDiagram-9d236eb7-e0c092d7.js} +1 -1
  32. rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-9dd802e4.js → flowDb-1972c806-fba2e3ce.js} +1 -1
  33. rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-5fa1912f.js → flowDiagram-7ea5b25a-7a70b71a.js} +1 -1
  34. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-24a5f41a.js +1 -0
  35. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-622a1fd2.js → flowchart-elk-definition-abe16c3d-00a59b68.js} +1 -1
  36. rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-e285a63a.js → ganttDiagram-9b5ea136-293c91fa.js} +1 -1
  37. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-f237bdca.js → gitGraphDiagram-99d0ae7c-07b2d68c.js} +1 -1
  38. rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-4b03d70e.js → index-2c4b9a3b-bc959fbd.js} +1 -1
  39. rasa/core/channels/inspector/dist/assets/index-3a8a5a28.js +1317 -0
  40. rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-72a0fa5f.js → infoDiagram-736b4530-4a350f72.js} +1 -1
  41. rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-82218c41.js → journeyDiagram-df861f2b-af464fb7.js} +1 -1
  42. rasa/core/channels/inspector/dist/assets/{layout-78cff630.js → layout-0071f036.js} +1 -1
  43. rasa/core/channels/inspector/dist/assets/{line-5038b469.js → line-2f73cc83.js} +1 -1
  44. rasa/core/channels/inspector/dist/assets/{linear-c4fc4098.js → linear-f014b4cc.js} +1 -1
  45. rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-c33c8ea6.js → mindmap-definition-beec6740-d2426fb6.js} +1 -1
  46. rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-a8d03059.js → pieDiagram-dbbf0591-776f01a2.js} +1 -1
  47. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-6a0e56b2.js → quadrantDiagram-4d7f4fd6-82e00b57.js} +1 -1
  48. rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-2dc7c7bd.js → requirementDiagram-6fc4c22a-ea13c6bb.js} +1 -1
  49. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-2360fe39.js → sankeyDiagram-8f13d901-1feca7e9.js} +1 -1
  50. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-41b9f9ad.js → sequenceDiagram-b655622a-070c61d2.js} +1 -1
  51. rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-0aad326f.js → stateDiagram-59f0c015-24f46263.js} +1 -1
  52. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-9847d984.js → stateDiagram-v2-2b26beab-c9056051.js} +1 -1
  53. rasa/core/channels/inspector/dist/assets/{styles-080da4f6-564d890e.js → styles-080da4f6-08abc34a.js} +1 -1
  54. rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-38957613.js → styles-3dcbcfbf-bc74c25a.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{styles-9c745c82-f0fc6921.js → styles-9c745c82-4e5d66de.js} +1 -1
  56. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-ef3c5a77.js → svgDrawCommon-4835440b-849c4517.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-bf3e91c1.js → timeline-definition-5b62e21b-d0fb1598.js} +1 -1
  58. rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-4d4026c0.js → xychartDiagram-2b33534f-04d115e2.js} +1 -1
  59. rasa/core/channels/inspector/dist/index.html +18 -17
  60. rasa/core/channels/inspector/index.html +17 -16
  61. rasa/core/channels/inspector/package.json +5 -1
  62. rasa/core/channels/inspector/src/App.tsx +117 -67
  63. rasa/core/channels/inspector/src/components/Chat.tsx +95 -0
  64. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +11 -10
  65. rasa/core/channels/inspector/src/components/DialogueStack.tsx +10 -25
  66. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +1 -1
  67. rasa/core/channels/inspector/src/helpers/formatters.test.ts +10 -0
  68. rasa/core/channels/inspector/src/helpers/formatters.ts +107 -41
  69. rasa/core/channels/inspector/src/helpers/utils.ts +92 -7
  70. rasa/core/channels/inspector/src/types.ts +21 -1
  71. rasa/core/channels/inspector/yarn.lock +94 -1
  72. rasa/core/channels/rest.py +51 -46
  73. rasa/core/channels/socketio.py +22 -0
  74. rasa/core/channels/{audiocodes.py → voice_ready/audiocodes.py} +110 -68
  75. rasa/core/channels/{voice_aware → voice_ready}/jambonz.py +11 -4
  76. rasa/core/channels/{voice_aware → voice_ready}/jambonz_protocol.py +57 -5
  77. rasa/core/channels/{twilio_voice.py → voice_ready/twilio_voice.py} +58 -7
  78. rasa/core/channels/{voice_aware → voice_ready}/utils.py +16 -0
  79. rasa/core/channels/voice_stream/asr/__init__.py +0 -0
  80. rasa/core/channels/voice_stream/asr/asr_engine.py +71 -0
  81. rasa/core/channels/voice_stream/asr/asr_event.py +13 -0
  82. rasa/core/channels/voice_stream/asr/deepgram.py +77 -0
  83. rasa/core/channels/voice_stream/audio_bytes.py +7 -0
  84. rasa/core/channels/voice_stream/tts/__init__.py +0 -0
  85. rasa/core/channels/voice_stream/tts/azure.py +100 -0
  86. rasa/core/channels/voice_stream/tts/cartesia.py +114 -0
  87. rasa/core/channels/voice_stream/tts/tts_cache.py +27 -0
  88. rasa/core/channels/voice_stream/tts/tts_engine.py +48 -0
  89. rasa/core/channels/voice_stream/twilio_media_streams.py +164 -0
  90. rasa/core/channels/voice_stream/util.py +57 -0
  91. rasa/core/channels/voice_stream/voice_channel.py +247 -0
  92. rasa/core/featurizers/single_state_featurizer.py +1 -22
  93. rasa/core/featurizers/tracker_featurizers.py +18 -115
  94. rasa/core/nlg/contextual_response_rephraser.py +11 -2
  95. rasa/{nlu → core}/persistor.py +16 -38
  96. rasa/core/policies/enterprise_search_policy.py +12 -15
  97. rasa/core/policies/flows/flow_executor.py +8 -18
  98. rasa/core/policies/intentless_policy.py +10 -15
  99. rasa/core/policies/ted_policy.py +33 -58
  100. rasa/core/policies/unexpected_intent_policy.py +7 -15
  101. rasa/core/processor.py +13 -64
  102. rasa/core/run.py +11 -1
  103. rasa/core/secrets_manager/constants.py +4 -0
  104. rasa/core/secrets_manager/factory.py +8 -0
  105. rasa/core/secrets_manager/vault.py +11 -1
  106. rasa/core/training/interactive.py +1 -1
  107. rasa/core/utils.py +1 -11
  108. rasa/dialogue_understanding/coexistence/llm_based_router.py +10 -10
  109. rasa/dialogue_understanding/commands/__init__.py +2 -0
  110. rasa/dialogue_understanding/commands/change_flow_command.py +0 -6
  111. rasa/dialogue_understanding/commands/session_end_command.py +61 -0
  112. rasa/dialogue_understanding/generator/flow_retrieval.py +0 -7
  113. rasa/dialogue_understanding/generator/llm_based_command_generator.py +12 -3
  114. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
  115. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -28
  116. rasa/dialogue_understanding/generator/nlu_command_adapter.py +1 -19
  117. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +4 -37
  118. rasa/e2e_test/aggregate_test_stats_calculator.py +1 -11
  119. rasa/e2e_test/assertions.py +6 -48
  120. rasa/e2e_test/e2e_test_runner.py +6 -9
  121. rasa/e2e_test/utils/e2e_yaml_utils.py +1 -1
  122. rasa/e2e_test/utils/io.py +1 -3
  123. rasa/engine/graph.py +3 -10
  124. rasa/engine/recipes/config_files/default_config.yml +0 -3
  125. rasa/engine/recipes/default_recipe.py +0 -1
  126. rasa/engine/recipes/graph_recipe.py +0 -1
  127. rasa/engine/runner/dask.py +2 -2
  128. rasa/engine/storage/local_model_storage.py +12 -42
  129. rasa/engine/storage/storage.py +1 -5
  130. rasa/engine/validation.py +1 -78
  131. rasa/keys +1 -0
  132. rasa/model_training.py +13 -16
  133. rasa/nlu/classifiers/diet_classifier.py +25 -38
  134. rasa/nlu/classifiers/logistic_regression_classifier.py +9 -22
  135. rasa/nlu/classifiers/sklearn_intent_classifier.py +16 -37
  136. rasa/nlu/extractors/crf_entity_extractor.py +50 -93
  137. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +16 -45
  138. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +17 -52
  139. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +3 -5
  140. rasa/server.py +1 -1
  141. rasa/shared/constants.py +3 -12
  142. rasa/shared/core/constants.py +4 -0
  143. rasa/shared/core/domain.py +101 -47
  144. rasa/shared/core/events.py +29 -0
  145. rasa/shared/core/flows/flows_list.py +20 -11
  146. rasa/shared/core/flows/validation.py +25 -0
  147. rasa/shared/core/flows/yaml_flows_io.py +3 -24
  148. rasa/shared/importers/importer.py +40 -39
  149. rasa/shared/importers/multi_project.py +23 -11
  150. rasa/shared/importers/rasa.py +7 -2
  151. rasa/shared/importers/remote_importer.py +196 -0
  152. rasa/shared/importers/utils.py +3 -1
  153. rasa/shared/nlu/training_data/features.py +2 -120
  154. rasa/shared/nlu/training_data/training_data.py +18 -19
  155. rasa/shared/providers/_configs/azure_openai_client_config.py +3 -5
  156. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -6
  157. rasa/shared/providers/llm/_base_litellm_client.py +11 -31
  158. rasa/shared/providers/llm/self_hosted_llm_client.py +3 -15
  159. rasa/shared/utils/common.py +3 -22
  160. rasa/shared/utils/io.py +0 -1
  161. rasa/shared/utils/llm.py +30 -27
  162. rasa/shared/utils/schemas/events.py +2 -0
  163. rasa/shared/utils/schemas/model_config.yml +0 -10
  164. rasa/shared/utils/yaml.py +44 -0
  165. rasa/studio/auth.py +5 -3
  166. rasa/studio/config.py +4 -13
  167. rasa/studio/constants.py +0 -1
  168. rasa/studio/data_handler.py +3 -10
  169. rasa/studio/upload.py +8 -17
  170. rasa/tracing/instrumentation/attribute_extractors.py +1 -1
  171. rasa/utils/io.py +66 -0
  172. rasa/utils/tensorflow/model_data.py +193 -2
  173. rasa/validator.py +0 -12
  174. rasa/version.py +1 -1
  175. rasa_pro-3.11.0a1.dist-info/METADATA +576 -0
  176. {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/RECORD +181 -164
  177. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-1844e5a5.js +0 -1
  178. rasa/core/channels/inspector/dist/assets/index-a5d3e69d.js +0 -1040
  179. rasa/utils/tensorflow/feature_array.py +0 -366
  180. rasa_pro-3.10.16.dist-info/METADATA +0 -196
  181. /rasa/core/channels/{voice_aware → voice_ready}/__init__.py +0 -0
  182. /rasa/core/channels/{voice_native → voice_stream}/__init__.py +0 -0
  183. {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/NOTICE +0 -0
  184. {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/WHEEL +0 -0
  185. {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.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,15 @@ class Domain:
191
195
  and entities it can recognise.
192
196
  """
193
197
 
198
+ validate_yaml: ClassVar[bool] = True
199
+
194
200
  @classmethod
195
- def empty(cls) -> "Domain":
201
+ def empty(cls) -> Domain:
196
202
  """Returns empty Domain."""
197
203
  return Domain.from_dict({})
198
204
 
199
205
  @classmethod
200
- def load(cls, paths: Union[List[Union[Path, Text]], Text, Path]) -> "Domain":
206
+ def load(cls, paths: Union[List[Union[Path, Text]], Text, Path]) -> Domain:
201
207
  """Returns loaded Domain after merging all domain files."""
202
208
  if not paths:
203
209
  raise InvalidDomain(
@@ -215,8 +221,15 @@ class Domain:
215
221
  return domain
216
222
 
217
223
  @classmethod
218
- def from_path(cls, path: Union[Text, Path]) -> "Domain":
219
- """Loads the `Domain` from a path."""
224
+ def from_path(cls, path: Union[Text, Path]) -> Domain:
225
+ """Loads the `Domain` from a path.
226
+
227
+ Args:
228
+ path: Path to the domain file.
229
+
230
+ Returns:
231
+ The instantiated `Domain` object.
232
+ """
220
233
  path = os.path.abspath(path)
221
234
 
222
235
  if os.path.isfile(path):
@@ -232,17 +245,30 @@ class Domain:
232
245
  return domain
233
246
 
234
247
  @classmethod
235
- def from_file(cls, path: Text) -> "Domain":
236
- """Loads the `Domain` from a YAML file."""
248
+ def from_file(cls, path: Text) -> Domain:
249
+ """Loads the `Domain` from a YAML file.
250
+
251
+ Args:
252
+ path: Path to the domain file.
253
+
254
+ Returns:
255
+ The instantiated `Domain` object.
256
+ """
237
257
  return cls.from_yaml(rasa.shared.utils.io.read_file(path), path)
238
258
 
239
259
  @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)
260
+ def from_yaml(cls, yaml: Text, original_filename: Text = "") -> Domain:
261
+ """Loads the `Domain` from YAML text after validating it.
262
+
263
+ Args:
264
+ yaml: The YAML string to load the domain from.
265
+ original_filename: The filename of the original YAML file.
244
266
 
245
- data = read_yaml(yaml)
267
+ Returns:
268
+ The instantiated `Domain` object.
269
+ """
270
+ try:
271
+ data = cls._dict_from_raw_yaml_content(yaml)
246
272
  if not validate_training_data_format_version(data, original_filename):
247
273
  return Domain.empty()
248
274
  return cls.from_dict(data)
@@ -251,7 +277,7 @@ class Domain:
251
277
  raise e
252
278
 
253
279
  @classmethod
254
- def from_dict(cls, data: Dict) -> "Domain":
280
+ def from_dict(cls, data: Dict) -> Domain:
255
281
  """Deserializes and creates domain.
256
282
 
257
283
  Args:
@@ -282,8 +308,8 @@ class Domain:
282
308
  _validate_forms(forms)
283
309
 
284
310
  return cls(
285
- intents=intents,
286
- entities=data.get(KEY_ENTITIES, {}),
311
+ intents=intents or [],
312
+ entities=data.get(KEY_ENTITIES, []),
287
313
  slots=slots,
288
314
  responses=responses,
289
315
  action_names=actions,
@@ -308,8 +334,15 @@ class Domain:
308
334
  return SessionConfig(session_expiration_time_min, carry_over_slots)
309
335
 
310
336
  @classmethod
311
- def from_directory(cls, path: Text) -> "Domain":
312
- """Loads and merges multiple domain files recursively from a directory tree."""
337
+ def from_directory(cls, path: Text) -> Domain:
338
+ """Loads and merges multiple domain files recursively from a directory tree.
339
+
340
+ Args:
341
+ path: Path to the root directory.
342
+
343
+ Returns:
344
+ The instantiated `Domain` object.
345
+ """
313
346
  combined: Dict[Text, Any] = {}
314
347
  duplicates: List[Dict[Text, List[Text]]] = []
315
348
 
@@ -319,10 +352,10 @@ class Domain:
319
352
  if not Domain.is_domain_file(full_path):
320
353
  continue
321
354
 
322
- # does the validation here only
323
- _ = Domain.from_file(full_path)
355
+ other_dict = cls._dict_from_raw_yaml_content(
356
+ rasa.shared.utils.io.read_file(full_path)
357
+ )
324
358
 
325
- other_dict = read_yaml(rasa.shared.utils.io.read_file(full_path))
326
359
  combined = Domain.merge_domain_dicts(other_dict, combined)
327
360
  duplicates.append(combined.pop("duplicates", {}))
328
361
 
@@ -368,10 +401,10 @@ class Domain:
368
401
 
369
402
  def merge(
370
403
  self,
371
- domain: Optional["Domain"],
404
+ domain: Optional[Domain],
372
405
  override: bool = False,
373
406
  ignore_warnings_about_duplicates: bool = False,
374
- ) -> "Domain":
407
+ ) -> Domain:
375
408
  """Merges this domain dict with another one, combining their attributes.
376
409
 
377
410
  This method merges domain dicts, and ensures all attributes (like ``intents``,
@@ -674,7 +707,7 @@ class Domain:
674
707
 
675
708
  return intent
676
709
 
677
- @rasa.shared.utils.common.lazy_property
710
+ @cached_property
678
711
  def retrieval_intents(self) -> List[Text]:
679
712
  """List retrieval intents present in the domain."""
680
713
  return [
@@ -899,7 +932,7 @@ class Domain:
899
932
  self.store_entities_as_slots = store_entities_as_slots
900
933
  self._check_domain_sanity()
901
934
 
902
- def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> "Domain":
935
+ def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> Domain:
903
936
  """Enables making a deep copy of the `Domain` using `copy.deepcopy`.
904
937
 
905
938
  See https://docs.python.org/3/library/copy.html#copy.deepcopy
@@ -1003,23 +1036,23 @@ class Domain:
1003
1036
  sorted_intents = sorted(intents, key=sort)
1004
1037
  return sorted_intents
1005
1038
 
1006
- @rasa.shared.utils.common.lazy_property
1039
+ @cached_property
1007
1040
  def user_actions_and_forms(self) -> List[Text]:
1008
1041
  """Returns combination of user actions and forms."""
1009
1042
  return self.user_actions + self.form_names
1010
1043
 
1011
- @rasa.shared.utils.common.lazy_property
1044
+ @cached_property
1012
1045
  def num_actions(self) -> int:
1013
1046
  """Returns the number of available actions."""
1014
1047
  # noinspection PyTypeChecker
1015
1048
  return len(self.action_names_or_texts)
1016
1049
 
1017
- @rasa.shared.utils.common.lazy_property
1050
+ @cached_property
1018
1051
  def num_states(self) -> int:
1019
1052
  """Number of used input states for the action prediction."""
1020
1053
  return len(self.input_states)
1021
1054
 
1022
- @rasa.shared.utils.common.lazy_property
1055
+ @cached_property
1023
1056
  def retrieval_intent_responses(self) -> Dict[Text, List[Dict[Text, Any]]]:
1024
1057
  """Return only the responses which are defined for retrieval intents."""
1025
1058
  return dict(
@@ -1171,8 +1204,7 @@ class Domain:
1171
1204
  f"Available actions are: \n{action_names}"
1172
1205
  )
1173
1206
 
1174
- # noinspection PyTypeChecker
1175
- @rasa.shared.utils.common.lazy_property
1207
+ @cached_property
1176
1208
  def slot_states(self) -> List[Text]:
1177
1209
  """Returns all available slot state strings."""
1178
1210
  return [
@@ -1181,8 +1213,7 @@ class Domain:
1181
1213
  for feature_index in range(0, slot.feature_dimensionality())
1182
1214
  ]
1183
1215
 
1184
- # noinspection PyTypeChecker
1185
- @rasa.shared.utils.common.lazy_property
1216
+ @cached_property
1186
1217
  def entity_states(self) -> List[Text]:
1187
1218
  """Returns all available entity state strings."""
1188
1219
  entity_states = copy.deepcopy(self.entities)
@@ -1230,12 +1261,12 @@ class Domain:
1230
1261
  for entity_sub_label in entity_sub_labels
1231
1262
  ]
1232
1263
 
1233
- @rasa.shared.utils.common.lazy_property
1264
+ @cached_property
1234
1265
  def input_state_map(self) -> Dict[Text, int]:
1235
1266
  """Provide a mapping from state names to indices."""
1236
1267
  return {f: i for i, f in enumerate(self.input_states)}
1237
1268
 
1238
- @rasa.shared.utils.common.lazy_property
1269
+ @cached_property
1239
1270
  def input_states(self) -> List[Text]:
1240
1271
  """Returns all available states."""
1241
1272
  return (
@@ -1465,7 +1496,7 @@ class Domain:
1465
1496
  ignore_rule_only_turns: bool = False,
1466
1497
  rule_only_data: Optional[Dict[Text, Any]] = None,
1467
1498
  ) -> List[State]:
1468
- """List of states for each state of the trackers history.
1499
+ """List of states for each state of the tracker's history.
1469
1500
 
1470
1501
  Args:
1471
1502
  tracker: Dialogue state tracker containing the dialogue so far.
@@ -1682,12 +1713,12 @@ class Domain:
1682
1713
  """Return the configuration for an intent."""
1683
1714
  return self.intent_properties.get(intent_name, {})
1684
1715
 
1685
- @rasa.shared.utils.common.lazy_property
1716
+ @cached_property
1686
1717
  def intents(self) -> List[Text]:
1687
1718
  """Returns sorted list of intents."""
1688
1719
  return sorted(self.intent_properties.keys())
1689
1720
 
1690
- @rasa.shared.utils.common.lazy_property
1721
+ @cached_property
1691
1722
  def entities(self) -> List[Text]:
1692
1723
  """Returns sorted list of entities."""
1693
1724
  return sorted(self.entity_properties.entities)
@@ -2055,6 +2086,29 @@ class Domain:
2055
2086
  def is_custom_action(self, action_name: str) -> bool:
2056
2087
  return action_name in self._custom_actions
2057
2088
 
2089
+ @classmethod
2090
+ def _dict_from_raw_yaml_content(cls, raw_yaml_content: Text) -> Any:
2091
+ """Loads the Domain dict from raw YAML content.
2092
+
2093
+ Validates the raw YAML content using the schema file if `validate_yaml` is set
2094
+ to `True`.
2095
+
2096
+ Args:
2097
+ raw_yaml_content: The raw YAML content of the domain file.
2098
+
2099
+ Returns:
2100
+ The Domain dict.
2101
+ """
2102
+ if cls.validate_yaml:
2103
+ structlogger.info(
2104
+ "domain.from_yaml.validating",
2105
+ )
2106
+ validate_raw_yaml_using_schema_file_with_responses(
2107
+ raw_yaml_content, DOMAIN_SCHEMA_FILE
2108
+ )
2109
+
2110
+ return read_yaml(raw_yaml_content)
2111
+
2058
2112
 
2059
2113
  def warn_about_duplicates_found_during_domain_merging(
2060
2114
  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()
@@ -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."""
@@ -221,16 +234,12 @@ class FlowsList:
221
234
  [f for f in self.underlying_flows if not f.is_startable_only_via_link()]
222
235
  )
223
236
 
224
- def available_slot_names(
225
- self, ask_before_filling: Optional[bool] = None
226
- ) -> Set[str]:
237
+ def available_slot_names(self) -> Set[str]:
227
238
  """Get all slot names collected by flows."""
228
239
  return {
229
240
  step.collect
230
241
  for flow in self.underlying_flows
231
242
  for step in flow.get_collect_steps()
232
- if ask_before_filling is None
233
- or step.ask_before_filling == ask_before_filling
234
243
  }
235
244
 
236
245
  def available_custom_actions(self) -> Set[str]:
@@ -101,6 +101,31 @@ class DuplicatedStepIdException(RasaException):
101
101
  )
102
102
 
103
103
 
104
+ class DuplicatedFlowIdException(RasaException):
105
+ """Raised when a flow is using the same id as another flow."""
106
+
107
+ def __init__(
108
+ self, flow_id: str, first_file_path: str, second_file_path: str
109
+ ) -> None:
110
+ """Initializes the exception."""
111
+ self.flow_id = flow_id
112
+ self.first_file_path = first_file_path
113
+ self.second_file_path = second_file_path
114
+
115
+ def __str__(self) -> str:
116
+ """Return a string representation of the exception."""
117
+ if self.first_file_path == self.second_file_path:
118
+ return (
119
+ f"Flow '{self.flow_id}' is used twice in `{self.first_file_path}`. "
120
+ f"Please make sure flow IDs are unique across all files."
121
+ )
122
+ return (
123
+ f"Flow '{self.flow_id}' is used in both "
124
+ f"`{self.first_file_path}` and `{self.second_file_path}`. "
125
+ f"Please make sure flow IDs are unique across all files."
126
+ )
127
+
128
+
104
129
  class MissingElseBranchException(RasaException):
105
130
  """Raised when a flow step is missing an else branch."""
106
131
 
@@ -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, 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"
@@ -262,25 +260,6 @@ class YamlFlowsWriter:
262
260
  rasa.shared.utils.io.write_text_file(YamlFlowsWriter.dumps(flows), filename)
263
261
 
264
262
 
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
263
  def is_flows_file(file_path: Union[Text, Path]) -> bool:
285
264
  """Check if file contains Flow training data.
286
265