rasa-pro 3.11.0a4.dev3__py3-none-any.whl → 3.11.0rc1__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 (163) hide show
  1. rasa/__main__.py +22 -12
  2. rasa/api.py +1 -1
  3. rasa/cli/arguments/default_arguments.py +1 -2
  4. rasa/cli/arguments/shell.py +5 -1
  5. rasa/cli/e2e_test.py +1 -1
  6. rasa/cli/evaluate.py +8 -8
  7. rasa/cli/inspect.py +4 -4
  8. rasa/cli/llm_fine_tuning.py +1 -1
  9. rasa/cli/project_templates/calm/config.yml +5 -7
  10. rasa/cli/project_templates/calm/endpoints.yml +8 -0
  11. rasa/cli/project_templates/tutorial/config.yml +8 -5
  12. rasa/cli/project_templates/tutorial/data/flows.yml +1 -1
  13. rasa/cli/project_templates/tutorial/data/patterns.yml +5 -0
  14. rasa/cli/project_templates/tutorial/domain.yml +14 -0
  15. rasa/cli/project_templates/tutorial/endpoints.yml +7 -7
  16. rasa/cli/run.py +1 -1
  17. rasa/cli/scaffold.py +4 -2
  18. rasa/cli/utils.py +5 -0
  19. rasa/cli/x.py +8 -8
  20. rasa/constants.py +1 -1
  21. rasa/core/channels/channel.py +3 -0
  22. rasa/core/channels/inspector/dist/assets/{arc-6852c607.js → arc-bc141fb2.js} +1 -1
  23. rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-acc952b2.js → c4Diagram-d0fbc5ce-be2db283.js} +1 -1
  24. rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-848a7597.js → classDiagram-936ed81e-55366915.js} +1 -1
  25. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-a73d3e68.js → classDiagram-v2-c3cb15f1-bb529518.js} +1 -1
  26. rasa/core/channels/inspector/dist/assets/{createText-62fc7601-e5ee049d.js → createText-62fc7601-b0ec81d6.js} +1 -1
  27. rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-771e517e.js → edges-f2ad444c-6166330c.js} +1 -1
  28. rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-aa347178.js → erDiagram-9d236eb7-5ccc6a8e.js} +1 -1
  29. rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-651fc57d.js → flowDb-1972c806-fca3bfe4.js} +1 -1
  30. rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-ca67804f.js → flowDiagram-7ea5b25a-4739080f.js} +1 -1
  31. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-736177bf.js +1 -0
  32. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-2dbc568d.js → flowchart-elk-definition-abe16c3d-7c1b0e0f.js} +1 -1
  33. rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-25a65bd8.js → ganttDiagram-9b5ea136-772fd050.js} +1 -1
  34. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-fdc7378d.js → gitGraphDiagram-99d0ae7c-8eae1dc9.js} +1 -1
  35. rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-6f1fd606.js → index-2c4b9a3b-f55afcdf.js} +1 -1
  36. rasa/core/channels/inspector/dist/assets/{index-efdd30c1.js → index-e7cef9de.js} +68 -68
  37. rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-cb1a041a.js → infoDiagram-736b4530-124d4a14.js} +1 -1
  38. rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-14609879.js → journeyDiagram-df861f2b-7c4fae44.js} +1 -1
  39. rasa/core/channels/inspector/dist/assets/{layout-2490f52b.js → layout-b9885fb6.js} +1 -1
  40. rasa/core/channels/inspector/dist/assets/{line-40186f1f.js → line-7c59abb6.js} +1 -1
  41. rasa/core/channels/inspector/dist/assets/{linear-08814e93.js → linear-4776f780.js} +1 -1
  42. rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-1a534584.js → mindmap-definition-beec6740-2332c46c.js} +1 -1
  43. rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-72397b61.js → pieDiagram-dbbf0591-8fb39303.js} +1 -1
  44. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-3bb0b6a3.js → quadrantDiagram-4d7f4fd6-3c7180a2.js} +1 -1
  45. rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-57334f61.js → requirementDiagram-6fc4c22a-e910bcb8.js} +1 -1
  46. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-111e1297.js → sankeyDiagram-8f13d901-ead16c89.js} +1 -1
  47. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-10bcfe62.js → sequenceDiagram-b655622a-29a02a19.js} +1 -1
  48. rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-acaf7513.js → stateDiagram-59f0c015-042b3137.js} +1 -1
  49. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-3ec2a235.js → stateDiagram-v2-2b26beab-2178c0f3.js} +1 -1
  50. rasa/core/channels/inspector/dist/assets/{styles-080da4f6-62730289.js → styles-080da4f6-23ffa4fc.js} +1 -1
  51. rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-5284ee76.js → styles-3dcbcfbf-94f59763.js} +1 -1
  52. rasa/core/channels/inspector/dist/assets/{styles-9c745c82-642435e3.js → styles-9c745c82-78a6bebc.js} +1 -1
  53. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-b250a350.js → svgDrawCommon-4835440b-eae2a6f6.js} +1 -1
  54. rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-c2b147ed.js → timeline-definition-5b62e21b-5c968d92.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-f92cfea9.js → xychartDiagram-2b33534f-fd3db0d5.js} +1 -1
  56. rasa/core/channels/inspector/dist/index.html +1 -1
  57. rasa/core/channels/inspector/src/App.tsx +1 -1
  58. rasa/core/channels/inspector/src/helpers/audiostream.ts +77 -16
  59. rasa/core/channels/socketio.py +2 -1
  60. rasa/core/channels/telegram.py +1 -1
  61. rasa/core/channels/twilio.py +1 -1
  62. rasa/core/channels/voice_ready/jambonz.py +2 -2
  63. rasa/core/channels/voice_stream/asr/asr_event.py +5 -0
  64. rasa/core/channels/voice_stream/asr/azure.py +122 -0
  65. rasa/core/channels/voice_stream/asr/deepgram.py +16 -6
  66. rasa/core/channels/voice_stream/audio_bytes.py +1 -0
  67. rasa/core/channels/voice_stream/browser_audio.py +31 -8
  68. rasa/core/channels/voice_stream/call_state.py +23 -0
  69. rasa/core/channels/voice_stream/tts/azure.py +6 -2
  70. rasa/core/channels/voice_stream/tts/cartesia.py +10 -6
  71. rasa/core/channels/voice_stream/tts/tts_engine.py +1 -0
  72. rasa/core/channels/voice_stream/twilio_media_streams.py +27 -18
  73. rasa/core/channels/voice_stream/util.py +4 -4
  74. rasa/core/channels/voice_stream/voice_channel.py +177 -39
  75. rasa/core/featurizers/single_state_featurizer.py +22 -1
  76. rasa/core/featurizers/tracker_featurizers.py +115 -18
  77. rasa/core/nlg/contextual_response_rephraser.py +16 -22
  78. rasa/core/persistor.py +86 -39
  79. rasa/core/policies/enterprise_search_policy.py +159 -60
  80. rasa/core/policies/flows/flow_executor.py +7 -4
  81. rasa/core/policies/intentless_policy.py +120 -22
  82. rasa/core/policies/ted_policy.py +58 -33
  83. rasa/core/policies/unexpected_intent_policy.py +15 -7
  84. rasa/core/processor.py +25 -0
  85. rasa/core/training/interactive.py +34 -35
  86. rasa/core/utils.py +8 -3
  87. rasa/dialogue_understanding/coexistence/llm_based_router.py +58 -16
  88. rasa/dialogue_understanding/commands/change_flow_command.py +6 -0
  89. rasa/dialogue_understanding/commands/user_silence_command.py +59 -0
  90. rasa/dialogue_understanding/commands/utils.py +5 -0
  91. rasa/dialogue_understanding/generator/constants.py +4 -0
  92. rasa/dialogue_understanding/generator/flow_retrieval.py +65 -3
  93. rasa/dialogue_understanding/generator/llm_based_command_generator.py +68 -26
  94. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +57 -8
  95. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +64 -7
  96. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +39 -0
  97. rasa/dialogue_understanding/patterns/user_silence.py +37 -0
  98. rasa/e2e_test/e2e_test_runner.py +4 -2
  99. rasa/e2e_test/utils/io.py +1 -1
  100. rasa/engine/validation.py +297 -7
  101. rasa/model_manager/config.py +15 -3
  102. rasa/model_manager/model_api.py +15 -7
  103. rasa/model_manager/runner_service.py +8 -6
  104. rasa/model_manager/socket_bridge.py +6 -3
  105. rasa/model_manager/trainer_service.py +7 -5
  106. rasa/model_manager/utils.py +28 -7
  107. rasa/model_service.py +6 -2
  108. rasa/model_training.py +2 -0
  109. rasa/nlu/classifiers/diet_classifier.py +38 -25
  110. rasa/nlu/classifiers/logistic_regression_classifier.py +22 -9
  111. rasa/nlu/classifiers/sklearn_intent_classifier.py +37 -16
  112. rasa/nlu/extractors/crf_entity_extractor.py +93 -50
  113. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +45 -16
  114. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +52 -17
  115. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +5 -3
  116. rasa/shared/constants.py +36 -3
  117. rasa/shared/core/constants.py +7 -0
  118. rasa/shared/core/domain.py +26 -0
  119. rasa/shared/core/flows/flow.py +5 -0
  120. rasa/shared/core/flows/flows_yaml_schema.json +10 -0
  121. rasa/shared/core/flows/utils.py +39 -0
  122. rasa/shared/core/flows/validation.py +96 -0
  123. rasa/shared/core/slots.py +5 -0
  124. rasa/shared/nlu/training_data/features.py +120 -2
  125. rasa/shared/providers/_configs/azure_openai_client_config.py +5 -3
  126. rasa/shared/providers/_configs/litellm_router_client_config.py +200 -0
  127. rasa/shared/providers/_configs/model_group_config.py +167 -0
  128. rasa/shared/providers/_configs/openai_client_config.py +1 -1
  129. rasa/shared/providers/_configs/rasa_llm_client_config.py +73 -0
  130. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -0
  131. rasa/shared/providers/_configs/utils.py +16 -0
  132. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +12 -15
  133. rasa/shared/providers/embedding/azure_openai_embedding_client.py +54 -21
  134. rasa/shared/providers/embedding/litellm_router_embedding_client.py +135 -0
  135. rasa/shared/providers/llm/_base_litellm_client.py +31 -30
  136. rasa/shared/providers/llm/azure_openai_llm_client.py +50 -29
  137. rasa/shared/providers/llm/litellm_router_llm_client.py +127 -0
  138. rasa/shared/providers/llm/rasa_llm_client.py +112 -0
  139. rasa/shared/providers/llm/self_hosted_llm_client.py +1 -1
  140. rasa/shared/providers/mappings.py +19 -0
  141. rasa/shared/providers/router/__init__.py +0 -0
  142. rasa/shared/providers/router/_base_litellm_router_client.py +149 -0
  143. rasa/shared/providers/router/router_client.py +73 -0
  144. rasa/shared/utils/common.py +8 -0
  145. rasa/shared/utils/health_check.py +533 -0
  146. rasa/shared/utils/io.py +28 -6
  147. rasa/shared/utils/llm.py +350 -46
  148. rasa/shared/utils/yaml.py +11 -13
  149. rasa/studio/upload.py +64 -20
  150. rasa/telemetry.py +80 -17
  151. rasa/tracing/instrumentation/attribute_extractors.py +74 -17
  152. rasa/utils/io.py +0 -66
  153. rasa/utils/log_utils.py +9 -2
  154. rasa/utils/tensorflow/feature_array.py +366 -0
  155. rasa/utils/tensorflow/model_data.py +2 -193
  156. rasa/validator.py +70 -0
  157. rasa/version.py +1 -1
  158. {rasa_pro-3.11.0a4.dev3.dist-info → rasa_pro-3.11.0rc1.dist-info}/METADATA +10 -10
  159. {rasa_pro-3.11.0a4.dev3.dist-info → rasa_pro-3.11.0rc1.dist-info}/RECORD +162 -146
  160. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-587d82d8.js +0 -1
  161. {rasa_pro-3.11.0a4.dev3.dist-info → rasa_pro-3.11.0rc1.dist-info}/NOTICE +0 -0
  162. {rasa_pro-3.11.0a4.dev3.dist-info → rasa_pro-3.11.0rc1.dist-info}/WHEEL +0 -0
  163. {rasa_pro-3.11.0a4.dev3.dist-info → rasa_pro-3.11.0rc1.dist-info}/entry_points.txt +0 -0
@@ -1,30 +1,32 @@
1
1
  from __future__ import annotations
2
+
2
3
  import logging
3
4
  import re
5
+ from typing import Any, Dict, List, Optional, Text, Tuple, Set, Type, Union
6
+
7
+ import numpy as np
4
8
  import scipy.sparse
5
- from typing import Any, Dict, List, Optional, Text, Tuple, Set, Type
6
- from rasa.nlu.tokenizers.tokenizer import Tokenizer
9
+ from sklearn.exceptions import NotFittedError
10
+ from sklearn.feature_extraction.text import CountVectorizer
7
11
 
8
12
  import rasa.shared.utils.io
9
13
  from rasa.engine.graph import GraphComponent, ExecutionContext
10
14
  from rasa.engine.recipes.default_recipe import DefaultV1Recipe
11
15
  from rasa.engine.storage.resource import Resource
12
16
  from rasa.engine.storage.storage import ModelStorage
13
- from rasa.nlu.featurizers.sparse_featurizer.sparse_featurizer import SparseFeaturizer
14
- from rasa.nlu.utils.spacy_utils import SpacyModel
15
- from rasa.shared.constants import DOCS_URL_COMPONENTS
16
- import rasa.utils.io as io_utils
17
- from sklearn.exceptions import NotFittedError
18
- from sklearn.feature_extraction.text import CountVectorizer
19
- from rasa.shared.nlu.training_data.training_data import TrainingData
20
- from rasa.shared.nlu.training_data.message import Message
21
- from rasa.shared.exceptions import RasaException, FileIOException
22
17
  from rasa.nlu.constants import (
23
18
  TOKENS_NAMES,
24
19
  MESSAGE_ATTRIBUTES,
25
20
  DENSE_FEATURIZABLE_ATTRIBUTES,
26
21
  )
22
+ from rasa.nlu.featurizers.sparse_featurizer.sparse_featurizer import SparseFeaturizer
23
+ from rasa.nlu.tokenizers.tokenizer import Tokenizer
24
+ from rasa.nlu.utils.spacy_utils import SpacyModel
25
+ from rasa.shared.constants import DOCS_URL_COMPONENTS
26
+ from rasa.shared.exceptions import RasaException, FileIOException
27
27
  from rasa.shared.nlu.constants import TEXT, INTENT, INTENT_RESPONSE_KEY, ACTION_NAME
28
+ from rasa.shared.nlu.training_data.message import Message
29
+ from rasa.shared.nlu.training_data.training_data import TrainingData
28
30
 
29
31
  BUFFER_SLOTS_PREFIX = "buf_"
30
32
 
@@ -688,6 +690,31 @@ class CountVectorsFeaturizer(SparseFeaturizer, GraphComponent):
688
690
  """Check if any model got trained."""
689
691
  return any(value is not None for value in attribute_vocabularies.values())
690
692
 
693
+ @staticmethod
694
+ def convert_vocab(
695
+ vocab: Dict[str, Union[int, Optional[Dict[str, int]]]], to_int: bool
696
+ ) -> Dict[str, Union[None, int, np.int64, Dict[str, Union[int, np.int64]]]]:
697
+ """Converts numpy integers in the vocabulary to Python integers."""
698
+
699
+ def convert_value(value: int) -> Union[int, np.int64]:
700
+ """Helper function to convert a single value based on to_int flag."""
701
+ return int(value) if to_int else np.int64(value)
702
+
703
+ result_dict: Dict[
704
+ str, Union[None, int, np.int64, Dict[str, Union[int, np.int64]]]
705
+ ] = {}
706
+ for key, sub_dict in vocab.items():
707
+ if isinstance(sub_dict, int):
708
+ result_dict[key] = convert_value(sub_dict)
709
+ elif not sub_dict:
710
+ result_dict[key] = None
711
+ else:
712
+ result_dict[key] = {
713
+ sub_key: convert_value(value) for sub_key, value in sub_dict.items()
714
+ }
715
+
716
+ return result_dict
717
+
691
718
  def persist(self) -> None:
692
719
  """Persist this model into the passed directory.
693
720
 
@@ -701,17 +728,18 @@ class CountVectorsFeaturizer(SparseFeaturizer, GraphComponent):
701
728
  attribute_vocabularies = self._collect_vectorizer_vocabularies()
702
729
  if self._is_any_model_trained(attribute_vocabularies):
703
730
  # Definitely need to persist some vocabularies
704
- featurizer_file = model_dir / "vocabularies.pkl"
731
+ featurizer_file = model_dir / "vocabularies.json"
705
732
 
706
733
  # Only persist vocabulary from one attribute if `use_shared_vocab`.
707
734
  # Can be loaded and distributed to all attributes.
708
- vocab = (
735
+ loaded_vocab = (
709
736
  attribute_vocabularies[TEXT]
710
737
  if self.use_shared_vocab
711
738
  else attribute_vocabularies
712
739
  )
740
+ vocab = self.convert_vocab(loaded_vocab, to_int=True)
713
741
 
714
- io_utils.json_pickle(featurizer_file, vocab)
742
+ rasa.shared.utils.io.dump_obj_as_json_to_file(featurizer_file, vocab)
715
743
 
716
744
  # Dump OOV words separately as they might have been modified during
717
745
  # training
@@ -786,8 +814,9 @@ class CountVectorsFeaturizer(SparseFeaturizer, GraphComponent):
786
814
  """Loads trained component (see parent class for full docstring)."""
787
815
  try:
788
816
  with model_storage.read_from(resource) as model_dir:
789
- featurizer_file = model_dir / "vocabularies.pkl"
790
- vocabulary = io_utils.json_unpickle(featurizer_file)
817
+ featurizer_file = model_dir / "vocabularies.json"
818
+ vocabulary = rasa.shared.utils.io.read_json_file(featurizer_file)
819
+ vocabulary = cls.convert_vocab(vocabulary, to_int=False)
791
820
 
792
821
  share_vocabulary = config["use_shared_vocab"]
793
822
 
@@ -1,9 +1,7 @@
1
1
  from __future__ import annotations
2
+
2
3
  import logging
3
4
  from collections import OrderedDict
4
-
5
- import scipy.sparse
6
- import numpy as np
7
5
  from typing import (
8
6
  Any,
9
7
  Dict,
@@ -17,30 +15,34 @@ from typing import (
17
15
  Union,
18
16
  )
19
17
 
18
+ import numpy as np
19
+ import scipy.sparse
20
+
21
+ import rasa.shared.utils.io
22
+ import rasa.utils.io
20
23
  from rasa.engine.graph import ExecutionContext, GraphComponent
21
24
  from rasa.engine.recipes.default_recipe import DefaultV1Recipe
22
25
  from rasa.engine.storage.resource import Resource
23
26
  from rasa.engine.storage.storage import ModelStorage
27
+ from rasa.nlu.constants import TOKENS_NAMES
28
+ from rasa.nlu.featurizers.sparse_featurizer.sparse_featurizer import SparseFeaturizer
24
29
  from rasa.nlu.tokenizers.spacy_tokenizer import POS_TAG_KEY, SpacyTokenizer
25
30
  from rasa.nlu.tokenizers.tokenizer import Token, Tokenizer
26
- from rasa.nlu.featurizers.sparse_featurizer.sparse_featurizer import SparseFeaturizer
27
- from rasa.nlu.constants import TOKENS_NAMES
28
31
  from rasa.shared.constants import DOCS_URL_COMPONENTS
29
- from rasa.shared.nlu.training_data.training_data import TrainingData
30
- from rasa.shared.nlu.training_data.message import Message
31
- from rasa.shared.nlu.constants import TEXT
32
32
  from rasa.shared.exceptions import InvalidConfigException
33
- import rasa.shared.utils.io
34
- import rasa.utils.io
33
+ from rasa.shared.nlu.constants import TEXT
34
+ from rasa.shared.nlu.training_data.message import Message
35
+ from rasa.shared.nlu.training_data.training_data import TrainingData
35
36
 
36
37
  logger = logging.getLogger(__name__)
37
38
 
38
-
39
39
  END_OF_SENTENCE = "EOS"
40
40
  BEGIN_OF_SENTENCE = "BOS"
41
41
 
42
42
  FEATURES = "features"
43
43
 
44
+ SEPERATOR = "###"
45
+
44
46
 
45
47
  @DefaultV1Recipe.register(
46
48
  DefaultV1Recipe.ComponentType.MESSAGE_FEATURIZER, is_trainable=True
@@ -72,7 +74,7 @@ class LexicalSyntacticFeaturizer(SparseFeaturizer, GraphComponent):
72
74
  of the token at position `t+1`.
73
75
  """
74
76
 
75
- FILENAME_FEATURE_TO_IDX_DICT = "feature_to_idx_dict.pkl"
77
+ FILENAME_FEATURE_TO_IDX_DICT = "feature_to_idx_dict.json"
76
78
 
77
79
  # NOTE: "suffix5" of the token "is" will be "is". Hence, when combining multiple
78
80
  # prefixes, short words will be represented/encoded repeatedly.
@@ -488,6 +490,32 @@ class LexicalSyntacticFeaturizer(SparseFeaturizer, GraphComponent):
488
490
  """Creates a new untrained component (see parent class for full docstring)."""
489
491
  return cls(config, model_storage, resource, execution_context)
490
492
 
493
+ @staticmethod
494
+ def _restructure_feature_to_idx_dict(
495
+ loaded_data: Dict[str, Dict[str, int]],
496
+ ) -> Dict[Tuple[int, str], Dict[str, int]]:
497
+ """Reconstructs the feature to idx dict.
498
+
499
+ When storing the feature_to_idx_dict to disk, we need to convert the tuple (key)
500
+ into a string to be able to store it via json. When loading the data
501
+ we need to reconstruct the tuple from the stored string.
502
+
503
+ Args:
504
+ loaded_data: The loaded feature to idx dict from file.
505
+
506
+ Returns:
507
+ The reconstructed feature_to_idx_dict
508
+ """
509
+ feature_to_idx_dict = {}
510
+ for tuple_string, feature_value in loaded_data.items():
511
+ # Example of tuple_string: "1###low"
512
+ index, feature_name = tuple_string.split(SEPERATOR)
513
+
514
+ feature_key = (int(index), feature_name)
515
+ feature_to_idx_dict[feature_key] = feature_value
516
+
517
+ return feature_to_idx_dict
518
+
491
519
  @classmethod
492
520
  def load(
493
521
  cls,
@@ -500,10 +528,13 @@ class LexicalSyntacticFeaturizer(SparseFeaturizer, GraphComponent):
500
528
  """Loads trained component (see parent class for full docstring)."""
501
529
  try:
502
530
  with model_storage.read_from(resource) as model_path:
503
- feature_to_idx_dict = rasa.utils.io.json_unpickle(
531
+ loaded_data = rasa.shared.utils.io.read_json_file(
504
532
  model_path / cls.FILENAME_FEATURE_TO_IDX_DICT,
505
- encode_non_string_keys=True,
506
533
  )
534
+
535
+ # convert the key back into tuple
536
+ feature_to_idx_dict = cls._restructure_feature_to_idx_dict(loaded_data)
537
+
507
538
  return cls(
508
539
  config=config,
509
540
  model_storage=model_storage,
@@ -528,9 +559,13 @@ class LexicalSyntacticFeaturizer(SparseFeaturizer, GraphComponent):
528
559
  if not self._feature_to_idx_dict:
529
560
  return None
530
561
 
562
+ # as we cannot dump tuples, convert the tuple into a string
563
+ restructured_feature_dict = {
564
+ f"{k[0]}{SEPERATOR}{k[1]}": v for k, v in self._feature_to_idx_dict.items()
565
+ }
566
+
531
567
  with self._model_storage.write_to(self._resource) as model_path:
532
- rasa.utils.io.json_pickle(
568
+ rasa.shared.utils.io.dump_obj_as_json_to_file(
533
569
  model_path / self.FILENAME_FEATURE_TO_IDX_DICT,
534
- self._feature_to_idx_dict,
535
- encode_non_string_keys=True,
570
+ restructured_feature_dict,
536
571
  )
@@ -1,11 +1,13 @@
1
1
  from __future__ import annotations
2
+
2
3
  import logging
3
4
  import re
4
5
  from typing import Any, Dict, List, Optional, Text, Tuple, Type
6
+
5
7
  import numpy as np
6
8
  import scipy.sparse
7
- from rasa.nlu.tokenizers.tokenizer import Tokenizer
8
9
 
10
+ from rasa.nlu.tokenizers.tokenizer import Tokenizer
9
11
  import rasa.shared.utils.io
10
12
  import rasa.utils.io
11
13
  import rasa.nlu.utils.pattern_utils as pattern_utils
@@ -240,7 +242,7 @@ class RegexFeaturizer(SparseFeaturizer, GraphComponent):
240
242
 
241
243
  try:
242
244
  with model_storage.read_from(resource) as model_dir:
243
- patterns_file_name = model_dir / "patterns.pkl"
245
+ patterns_file_name = model_dir / "patterns.json"
244
246
  known_patterns = rasa.shared.utils.io.read_json_file(patterns_file_name)
245
247
  except (ValueError, FileNotFoundError):
246
248
  logger.warning(
@@ -258,7 +260,7 @@ class RegexFeaturizer(SparseFeaturizer, GraphComponent):
258
260
 
259
261
  def _persist(self) -> None:
260
262
  with self._model_storage.write_to(self._resource) as model_dir:
261
- regex_file = model_dir / "patterns.pkl"
263
+ regex_file = model_dir / "patterns.json"
262
264
  rasa.shared.utils.io.dump_obj_as_json_to_file(
263
265
  regex_file, self.known_patterns
264
266
  )
rasa/shared/constants.py CHANGED
@@ -183,7 +183,34 @@ STREAM_CONFIG_KEY = "stream"
183
183
  N_REPHRASES_CONFIG_KEY = "n"
184
184
  USE_CHAT_COMPLETIONS_ENDPOINT_CONFIG_KEY = "use_chat_completions_endpoint"
185
185
 
186
+ ROUTER_CONFIG_KEY = "router"
187
+ ROUTER_STRATEGY_CONFIG_KEY = "router_strategy"
188
+ REDIS_HOST_CONFIG_KEY = "redis_host"
189
+ ROUTER_STRATEGIES_REQUIRING_REDIS_CACHE = [
190
+ "cost-based-routing",
191
+ "usage-based-routing",
192
+ ]
193
+ ROUTER_STRATEGIES_NOT_REQUIRING_CACHE = [
194
+ "latency-based-routing",
195
+ "least-busy",
196
+ "simple-shuffle",
197
+ ]
198
+ VALID_ROUTER_STRATEGIES = (
199
+ ROUTER_STRATEGIES_REQUIRING_REDIS_CACHE + ROUTER_STRATEGIES_NOT_REQUIRING_CACHE
200
+ )
201
+
202
+ MODELS_CONFIG_KEY = "models"
203
+ MODEL_GROUPS_CONFIG_KEY = "model_groups"
204
+ MODEL_GROUP_CONFIG_KEY = "model_group"
205
+ MODEL_GROUP_ID_CONFIG_KEY = "id"
206
+
207
+ EXTRA_PARAMETERS_KEY = "extra_parameters"
208
+ MODEL_GROUP_ID_KEY = "model_group_id"
209
+ MODEL_LIST_KEY = "model_list"
210
+ LITELLM_PARAMS_KEY = "litellm_params"
211
+
186
212
  LLM_API_HEALTH_CHECK_ENV_VAR = "LLM_API_HEALTH_CHECK"
213
+ LLM_API_HEALTH_CHECK_DEFAULT_VALUE = "false"
187
214
 
188
215
  AZURE_API_KEY_ENV_VAR = "AZURE_API_KEY"
189
216
  AZURE_AD_TOKEN_ENV_VAR = "AZURE_AD_TOKEN"
@@ -191,6 +218,8 @@ AZURE_API_BASE_ENV_VAR = "AZURE_API_BASE"
191
218
  AZURE_API_VERSION_ENV_VAR = "AZURE_API_VERSION"
192
219
  AZURE_API_TYPE_ENV_VAR = "AZURE_API_TYPE"
193
220
 
221
+ AWS_REGION_NAME_CONFIG_KEY = "aws_region_name"
222
+
194
223
  HUGGINGFACE_MULTIPROCESS_CONFIG_KEY = "multi_process"
195
224
  HUGGINGFACE_CACHE_FOLDER_CONFIG_KEY = "cache_folder"
196
225
  HUGGINGFACE_SHOW_PROGRESS_CONFIG_KEY = "show_progress"
@@ -211,6 +240,13 @@ OPENAI_PROVIDER = "openai"
211
240
  AZURE_OPENAI_PROVIDER = "azure"
212
241
  SELF_HOSTED_PROVIDER = "self-hosted"
213
242
  HUGGINGFACE_LOCAL_EMBEDDING_PROVIDER = "huggingface_local"
243
+ RASA_PROVIDER = "rasa"
244
+
245
+ SELF_HOSTED_VLLM_PREFIX = "hosted_vllm"
246
+ SELF_HOSTED_VLLM_API_KEY_ENV_VAR = "HOSTED_VLLM_API_KEY"
247
+
248
+ SELF_HOSTED_VLLM_PREFIX = "hosted_vllm"
249
+ SELF_HOSTED_VLLM_API_KEY_ENV_VAR = "HOSTED_VLLM_API_KEY"
214
250
 
215
251
  SELF_HOSTED_VLLM_PREFIX = "hosted_vllm"
216
252
  SELF_HOSTED_VLLM_API_KEY_ENV_VAR = "HOSTED_VLLM_API_KEY"
@@ -244,6 +280,3 @@ RASA_PATTERN_CANNOT_HANDLE_INVALID_INTENT = (
244
280
  )
245
281
 
246
282
  ROUTE_TO_CALM_SLOT = "route_session_to_calm"
247
-
248
- ORIGINAL_VALUE = "original_value"
249
- RESOLVED_VALUE = "resolved_value"
@@ -11,6 +11,7 @@ USER_INTENT_BACK = "back"
11
11
  USER_INTENT_OUT_OF_SCOPE = "out_of_scope"
12
12
  USER_INTENT_SESSION_START = "session_start"
13
13
  USER_INTENT_SESSION_END = "session_end"
14
+ USER_INTENT_SILENCE_TIMEOUT = "silence_timeout"
14
15
  SESSION_START_METADATA_SLOT = "session_started_metadata"
15
16
 
16
17
  DEFAULT_INTENTS = [
@@ -19,6 +20,7 @@ DEFAULT_INTENTS = [
19
20
  USER_INTENT_OUT_OF_SCOPE,
20
21
  USER_INTENT_SESSION_START,
21
22
  USER_INTENT_SESSION_END,
23
+ USER_INTENT_SILENCE_TIMEOUT,
22
24
  constants.DEFAULT_NLU_FALLBACK_INTENT_NAME,
23
25
  ]
24
26
 
@@ -106,6 +108,11 @@ FLOW_HASHES_SLOT = "flow_hashes"
106
108
 
107
109
  FLOW_SLOT_NAMES = [FLOW_HASHES_SLOT]
108
110
 
111
+ # slots for audio timeout
112
+ SLOT_SILENCE_TIMEOUT = "silence_timeout"
113
+ SILENCE_TIMEOUT_DEFAULT_VALUE = 6.0
114
+ SLOT_CONSECUTIVE_SILENCE_TIMEOUTS = "consecutive_silence_timeouts"
115
+ SILENCE_SLOTS = [SLOT_SILENCE_TIMEOUT, SLOT_CONSECUTIVE_SILENCE_TIMEOUTS]
109
116
  # slots for knowledge base
110
117
  SLOT_LISTED_ITEMS = "knowledge_base_listed_objects"
111
118
  SLOT_LAST_OBJECT = "knowledge_base_last_object"
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import collections
4
4
  import copy
5
5
  import json
6
+ import math
6
7
  import os
7
8
  from dataclasses import dataclass
8
9
  from functools import cached_property
@@ -57,6 +58,7 @@ from rasa.shared.core.events import SlotSet, UserUttered
57
58
  from rasa.shared.core.slots import (
58
59
  AnySlot,
59
60
  CategoricalSlot,
61
+ FloatSlot,
60
62
  ListSlot,
61
63
  Slot,
62
64
  TextSlot,
@@ -1082,6 +1084,7 @@ class Domain:
1082
1084
  self._add_knowledge_base_slots()
1083
1085
  self._add_categorical_slot_default_value()
1084
1086
  self._add_session_metadata_slot()
1087
+ self._add_audio_slots()
1085
1088
 
1086
1089
  def _add_categorical_slot_default_value(self) -> None:
1087
1090
  """Add a default value to all categorical slots.
@@ -1136,6 +1139,29 @@ class Domain:
1136
1139
  )
1137
1140
  )
1138
1141
 
1142
+ def _add_audio_slots(self) -> None:
1143
+ """Add slots relevant for audio channels."""
1144
+ self.slots.append(
1145
+ FloatSlot(
1146
+ rasa.shared.core.constants.SLOT_SILENCE_TIMEOUT,
1147
+ mappings=[],
1148
+ influence_conversation=False,
1149
+ is_builtin=True,
1150
+ initial_value=rasa.shared.core.constants.SILENCE_TIMEOUT_DEFAULT_VALUE,
1151
+ max_value=math.inf,
1152
+ )
1153
+ )
1154
+ self.slots.append(
1155
+ FloatSlot(
1156
+ rasa.shared.core.constants.SLOT_CONSECUTIVE_SILENCE_TIMEOUTS,
1157
+ mappings=[],
1158
+ influence_conversation=False,
1159
+ is_builtin=True,
1160
+ initial_value=0.0,
1161
+ max_value=math.inf,
1162
+ )
1163
+ )
1164
+
1139
1165
  def _add_knowledge_base_slots(self) -> None:
1140
1166
  """Add slots for the knowledge base action to slots.
1141
1167
 
@@ -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
 
@@ -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
+ )
@@ -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:
@@ -379,6 +386,42 @@ class FlowIdNamingException(RasaException):
379
386
  )
380
387
 
381
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
+
382
425
  def validate_flow(flow: Flow) -> None:
383
426
  """Validates the flow configuration.
384
427
 
@@ -387,6 +430,8 @@ def validate_flow(flow: Flow) -> None:
387
430
  - whether all next links point to existing steps
388
431
  - whether all steps can be reached from the start step
389
432
  """
433
+ from rasa.cli.utils import is_skip_validation_flag_set
434
+
390
435
  validate_flow_not_empty(flow)
391
436
  validate_no_empty_step_sequences(flow)
392
437
  validate_all_steps_next_property(flow)
@@ -397,6 +442,12 @@ def validate_flow(flow: Flow) -> None:
397
442
  validate_slot_names_to_be_collected(flow)
398
443
  validate_flow_id(flow)
399
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
+
400
451
 
401
452
  def validate_flow_not_empty(flow: Flow) -> None:
402
453
  """Validate that the flow is not empty."""
@@ -637,3 +688,48 @@ def validate_flow_id(flow: Flow) -> None:
637
688
  flow_re = re.compile(FLOW_ID_REGEX)
638
689
  if not flow_re.search(flow.id):
639
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)
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."""