rasa-pro 3.11.0a4.dev2__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 +17 -3
  102. rasa/model_manager/model_api.py +16 -8
  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 +7 -5
  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.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/METADATA +10 -10
  159. {rasa_pro-3.11.0a4.dev2.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.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/NOTICE +0 -0
  162. {rasa_pro-3.11.0a4.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/WHEEL +0 -0
  163. {rasa_pro-3.11.0a4.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/entry_points.txt +0 -0
@@ -24,6 +24,8 @@ from rasa.dialogue_understanding.generator.constants import (
24
24
  LLM_CONFIG_KEY,
25
25
  USER_INPUT_CONFIG_KEY,
26
26
  FLOW_RETRIEVAL_KEY,
27
+ TRAINED_MODEL_NAME_CONFIG_KEY,
28
+ DEFAULT_LLM_CONFIG,
27
29
  )
28
30
  from rasa.dialogue_understanding.generator.flow_retrieval import FlowRetrieval
29
31
  from rasa.dialogue_understanding.generator.llm_based_command_generator import (
@@ -39,7 +41,10 @@ from rasa.engine.graph import ExecutionContext
39
41
  from rasa.engine.recipes.default_recipe import DefaultV1Recipe
40
42
  from rasa.engine.storage.resource import Resource
41
43
  from rasa.engine.storage.storage import ModelStorage
42
- from rasa.shared.constants import RASA_PATTERN_CANNOT_HANDLE_NOT_SUPPORTED
44
+ from rasa.shared.constants import (
45
+ RASA_PATTERN_CANNOT_HANDLE_NOT_SUPPORTED,
46
+ EMBEDDINGS_CONFIG_KEY,
47
+ )
43
48
  from rasa.shared.constants import ROUTE_TO_CALM_SLOT
44
49
  from rasa.shared.core.flows import FlowStep, Flow, FlowsList
45
50
  from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
@@ -53,7 +58,9 @@ from rasa.shared.utils.llm import (
53
58
  tracker_as_readable_transcript,
54
59
  sanitize_message_for_prompt,
55
60
  allowed_values_for_slot,
61
+ resolve_model_client_config,
56
62
  )
63
+ from rasa.shared.utils.health_check import perform_inference_time_llm_health_check
57
64
 
58
65
  # multistep template keys
59
66
  HANDLE_FLOWS_KEY = "handle_flows"
@@ -139,6 +146,14 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
139
146
  ) -> "MultiStepLLMCommandGenerator":
140
147
  """Loads trained component (see parent class for full docstring)."""
141
148
  prompts = cls._load_prompt_templates(model_storage, resource)
149
+
150
+ persisted_config = cls.load_config_from_model_storage(model_storage, resource)
151
+ train_model_name = (
152
+ persisted_config.get(TRAINED_MODEL_NAME_CONFIG_KEY, None)
153
+ if persisted_config
154
+ else None
155
+ )
156
+
142
157
  # init base command generator
143
158
  command_generator = cls(config, model_storage, resource, prompts)
144
159
  # load flow retrieval if enabled
@@ -146,10 +161,21 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
146
161
  command_generator.flow_retrieval = cls.load_flow_retrival(
147
162
  command_generator.config, model_storage, resource
148
163
  )
164
+
165
+ perform_inference_time_llm_health_check(
166
+ command_generator.config.get(LLM_CONFIG_KEY),
167
+ DEFAULT_LLM_CONFIG,
168
+ train_model_name,
169
+ "multi_step_llm_command_generator.load",
170
+ MultiStepLLMCommandGenerator.__name__,
171
+ )
172
+
149
173
  return command_generator
150
174
 
151
175
  def persist(self) -> None:
152
176
  """Persist this component to disk for future loading."""
177
+ super().persist()
178
+
153
179
  # persist prompt template
154
180
  self._persist_prompt_templates()
155
181
  # persist flow retrieval
@@ -229,9 +255,9 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
229
255
  commands: List[Command] = []
230
256
 
231
257
  slot_set_re = re.compile(
232
- r"""SetSlot\((\"?[a-zA-Z_][a-zA-Z0-9_-]*?\"?), ?(.*)\)"""
258
+ r"""SetSlot\(['"]?([a-zA-Z_][a-zA-Z0-9_-]*)['"]?, ?['"]?(.*)['"]?\)"""
233
259
  )
234
- start_flow_re = re.compile(r"StartFlow\(([a-zA-Z0-9_-]+?)\)")
260
+ start_flow_re = re.compile(r"StartFlow\(['\"]?([a-zA-Z0-9_-]+)['\"]?\)")
235
261
  change_flow_re = re.compile(r"ChangeFlow\(\)")
236
262
  cancel_flow_re = re.compile(r"CancelFlow\(\)")
237
263
  chitchat_re = re.compile(r"ChitChat\(\)")
@@ -280,9 +306,19 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
280
306
  commands.append(HumanHandoffCommand())
281
307
  elif match := clarify_re.search(action):
282
308
  options = sorted([opt.strip() for opt in match.group(1).split(",")])
309
+ # Remove surrounding quotes if present
310
+ cleaned_options = []
311
+ for flow in options:
312
+ if (flow.startswith('"') and flow.endswith('"')) or (
313
+ flow.startswith("'") and flow.endswith("'")
314
+ ):
315
+ cleaned_options.append(flow[1:-1])
316
+ else:
317
+ cleaned_options.append(flow)
318
+ # check if flow is valid
283
319
  valid_options = [
284
320
  flow
285
- for flow in options
321
+ for flow in cleaned_options
286
322
  if flow in flows.user_flow_ids
287
323
  and flow not in user_flows_on_the_stack(tracker.stack)
288
324
  ]
@@ -293,6 +329,13 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
293
329
  elif change_flow_re.search(action):
294
330
  commands.append(ChangeFlowCommand())
295
331
 
332
+ if not commands:
333
+ structlogger.debug(
334
+ "multi_step_llm_command_generator.parse_commands",
335
+ message="No commands were parsed from the LLM actions.",
336
+ actions=actions,
337
+ )
338
+
296
339
  return commands
297
340
 
298
341
  ### Helper methods
@@ -761,11 +804,17 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
761
804
  .get(FILE_PATH_KEY),
762
805
  DEFAULT_FILL_SLOTS_TEMPLATE,
763
806
  )
807
+
808
+ llm_config = resolve_model_client_config(
809
+ config.get(LLM_CONFIG_KEY), MultiStepLLMCommandGenerator.__name__
810
+ )
811
+ embedding_config = resolve_model_client_config(
812
+ config.get(FLOW_RETRIEVAL_KEY, {}).get(EMBEDDINGS_CONFIG_KEY),
813
+ FlowRetrieval.__name__,
814
+ )
815
+
764
816
  return deep_container_fingerprint(
765
- [
766
- handle_flows_template,
767
- fill_slots_template,
768
- ]
817
+ [handle_flows_template, fill_slots_template, llm_config, embedding_config]
769
818
  )
770
819
 
771
820
  @staticmethod
@@ -22,6 +22,8 @@ from rasa.dialogue_understanding.generator.constants import (
22
22
  LLM_CONFIG_KEY,
23
23
  USER_INPUT_CONFIG_KEY,
24
24
  FLOW_RETRIEVAL_KEY,
25
+ DEFAULT_LLM_CONFIG,
26
+ TRAINED_MODEL_NAME_CONFIG_KEY,
25
27
  )
26
28
  from rasa.dialogue_understanding.generator.flow_retrieval import (
27
29
  FlowRetrieval,
@@ -38,6 +40,7 @@ from rasa.shared.constants import (
38
40
  ROUTE_TO_CALM_SLOT,
39
41
  PROMPT_CONFIG_KEY,
40
42
  PROMPT_TEMPLATE_CONFIG_KEY,
43
+ EMBEDDINGS_CONFIG_KEY,
41
44
  )
42
45
  from rasa.shared.core.flows import FlowsList
43
46
  from rasa.shared.core.trackers import DialogueStateTracker
@@ -49,9 +52,11 @@ from rasa.shared.utils.llm import (
49
52
  get_prompt_template,
50
53
  tracker_as_readable_transcript,
51
54
  sanitize_message_for_prompt,
55
+ resolve_model_client_config,
52
56
  )
53
- from rasa.utils.log_utils import log_llm
57
+ from rasa.shared.utils.health_check import perform_inference_time_llm_health_check
54
58
  from rasa.utils.beta import ensure_beta_feature_is_enabled, BetaNotEnabledException
59
+ from rasa.utils.log_utils import log_llm
55
60
 
56
61
  COMMAND_PROMPT_FILE_NAME = "command_prompt.jinja2"
57
62
 
@@ -136,6 +141,7 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
136
141
  prompt_template = cls.load_prompt_template_from_model_storage(
137
142
  model_storage, resource, COMMAND_PROMPT_FILE_NAME
138
143
  )
144
+
139
145
  # init base command generator
140
146
  command_generator = cls(config, model_storage, resource, prompt_template)
141
147
  # load flow retrieval if enabled
@@ -143,11 +149,28 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
143
149
  command_generator.flow_retrieval = cls.load_flow_retrival(
144
150
  command_generator.config, model_storage, resource
145
151
  )
152
+
153
+ persisted_config = cls.load_config_from_model_storage(model_storage, resource)
154
+ train_model_name = (
155
+ persisted_config.get(TRAINED_MODEL_NAME_CONFIG_KEY, None)
156
+ if persisted_config
157
+ else None
158
+ )
159
+ perform_inference_time_llm_health_check(
160
+ command_generator.config.get(LLM_CONFIG_KEY),
161
+ DEFAULT_LLM_CONFIG,
162
+ train_model_name,
163
+ "single_step_llm_command_generator.load",
164
+ SingleStepLLMCommandGenerator.__name__,
165
+ )
166
+
146
167
  return command_generator
147
168
 
148
169
  def persist(self) -> None:
149
170
  """Persist this component to disk for future loading."""
150
171
  # persist prompt template
172
+ super().persist()
173
+
151
174
  with self._model_storage.write_to(self._resource) as path:
152
175
  rasa.shared.utils.io.write_text_file(
153
176
  self.prompt_template, path / COMMAND_PROMPT_FILE_NAME
@@ -187,6 +210,12 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
187
210
 
188
211
  if not commands:
189
212
  # no commands are parsed or there's an invalid command
213
+ structlogger.warning(
214
+ "single_step_llm_command_generator.predict_commands",
215
+ message="No commands were predicted as the LLM response could "
216
+ "not be parsed or the LLM responded with an invalid command."
217
+ "Returning a CannotHandleCommand instead.",
218
+ )
190
219
  commands = [CannotHandleCommand()]
191
220
 
192
221
  if tracker.has_coexistence_routing_slot:
@@ -287,14 +316,16 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
287
316
 
288
317
  commands: List[Command] = []
289
318
 
290
- slot_set_re = re.compile(r"""SetSlot\(([a-zA-Z_][a-zA-Z0-9_-]*?), ?(.*)\)""")
291
- start_flow_re = re.compile(r"StartFlow\(([a-zA-Z0-9_-]+?)\)")
319
+ slot_set_re = re.compile(
320
+ r"""SetSlot\(['"]?([a-zA-Z_][a-zA-Z0-9_-]*)['"]?, ?['"]?(.*)['"]?\)"""
321
+ )
322
+ start_flow_re = re.compile(r"StartFlow\(['\"]?([a-zA-Z0-9_-]+)['\"]?\)")
292
323
  cancel_flow_re = re.compile(r"CancelFlow\(\)")
293
324
  chitchat_re = re.compile(r"ChitChat\(\)")
294
325
  skip_question_re = re.compile(r"SkipQuestion\(\)")
295
326
  knowledge_re = re.compile(r"SearchAndReply\(\)")
296
327
  humand_handoff_re = re.compile(r"HumanHandoff\(\)")
297
- clarify_re = re.compile(r"Clarify\(([a-zA-Z0-9_, ]+)\)")
328
+ clarify_re = re.compile(r"Clarify\(([\"\'a-zA-Z0-9_, ]+)\)")
298
329
  repeat_re = re.compile(r"RepeatLastBotMessages\(\)")
299
330
 
300
331
  for action in actions.strip().splitlines():
@@ -326,19 +357,36 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
326
357
  commands.append(RepeatBotMessagesCommand())
327
358
  elif match := clarify_re.search(action):
328
359
  options = sorted([opt.strip() for opt in match.group(1).split(",")])
360
+ # Remove surrounding quotes if present
361
+ cleaned_options = []
362
+ for flow in options:
363
+ if (flow.startswith('"') and flow.endswith('"')) or (
364
+ flow.startswith("'") and flow.endswith("'")
365
+ ):
366
+ cleaned_options.append(flow[1:-1])
367
+ else:
368
+ cleaned_options.append(flow)
369
+ # check if flow is valid
329
370
  valid_options = [
330
- flow for flow in options if flow in flows.user_flow_ids
371
+ flow for flow in cleaned_options if flow in flows.user_flow_ids
331
372
  ]
332
373
  if len(set(valid_options)) == 1:
333
374
  commands.extend(cls.start_flow_by_name(valid_options[0], flows))
334
375
  elif len(valid_options) > 1:
335
376
  commands.append(ClarifyCommand(valid_options))
336
377
 
378
+ if not commands:
379
+ structlogger.debug(
380
+ "single_step_llm_command_generator.parse_commands",
381
+ message="No commands were parsed from the LLM actions.",
382
+ actions=actions,
383
+ )
384
+
337
385
  return commands
338
386
 
339
387
  @classmethod
340
388
  def fingerprint_addon(cls: Any, config: Dict[str, Any]) -> Optional[str]:
341
- """Add a fingerprint of the knowledge base for the graph."""
389
+ """Add a fingerprint for the graph."""
342
390
  config_prompt = (
343
391
  config.get(PROMPT_CONFIG_KEY)
344
392
  or config.get(PROMPT_TEMPLATE_CONFIG_KEY)
@@ -348,7 +396,16 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
348
396
  config_prompt,
349
397
  DEFAULT_COMMAND_PROMPT_TEMPLATE,
350
398
  )
351
- return deep_container_fingerprint(prompt_template)
399
+ llm_config = resolve_model_client_config(
400
+ config.get(LLM_CONFIG_KEY), SingleStepLLMCommandGenerator.__name__
401
+ )
402
+ embedding_config = resolve_model_client_config(
403
+ config.get(FLOW_RETRIEVAL_KEY, {}).get(EMBEDDINGS_CONFIG_KEY),
404
+ FlowRetrieval.__name__,
405
+ )
406
+ return deep_container_fingerprint(
407
+ [prompt_template, llm_config, embedding_config]
408
+ )
352
409
 
353
410
  ### Helper methods
354
411
  def render_template(
@@ -4,6 +4,11 @@ responses:
4
4
  utter_ask_rephrase:
5
5
  - text: I’m sorry I am unable to understand you, could you please rephrase?
6
6
 
7
+ utter_ask_still_there:
8
+ - text: "Hello, are you still there?"
9
+ metadata:
10
+ rephrase: True
11
+
7
12
  utter_boolean_slot_rejection:
8
13
  - text: "Sorry, the value you provided, `{{value}}`, is not valid. Please respond with a valid value."
9
14
  metadata:
@@ -75,6 +80,11 @@ responses:
75
80
  metadata:
76
81
  rephrase: True
77
82
 
83
+ utter_inform_hangup:
84
+ - text: It seems you are not there anymore. I will hang up shortly.
85
+ metadata:
86
+ rephrase: True
87
+
78
88
  utter_internal_error_rasa:
79
89
  - text: Sorry, I am having trouble with that. Please try again in a few minutes.
80
90
 
@@ -251,3 +261,32 @@ flows:
251
261
  name: pattern skip question
252
262
  steps:
253
263
  - action: utter_skip_question_answer
264
+
265
+ pattern_user_silence:
266
+ description: Reacting to user silence in voice bots
267
+ name: pattern react to silence
268
+ nlu_trigger:
269
+ - intent: silence_timeout
270
+ persisted_slots:
271
+ - consecutive_silence_timeouts
272
+ steps:
273
+ - noop: true
274
+ next:
275
+ - if: "slots.consecutive_silence_timeouts = 0.0"
276
+ then:
277
+ - set_slots:
278
+ - consecutive_silence_timeouts: 1.0
279
+ - action: action_repeat_bot_messages
280
+ next: END
281
+ - if: "slots.consecutive_silence_timeouts = 1.0"
282
+ then:
283
+ - set_slots:
284
+ - consecutive_silence_timeouts: 2.0
285
+ - action: utter_ask_still_there
286
+ next: END
287
+ - if: "slots.consecutive_silence_timeouts > 1.0"
288
+ then:
289
+ - action: utter_inform_hangup
290
+ - action: action_hangup
291
+ next: END
292
+ - else: END
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from typing import Any, Dict
4
+
5
+ from rasa.dialogue_understanding.stack.frames import PatternFlowStackFrame
6
+ from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
7
+
8
+
9
+ FLOW_PATTERN_USER_SILENCE = RASA_DEFAULT_FLOW_PATTERN_PREFIX + "user_silence"
10
+
11
+
12
+ @dataclass
13
+ class UserSilencePatternFlowStackFrame(PatternFlowStackFrame):
14
+ """A flow stack frame that can get added when the silence timeout trips."""
15
+
16
+ flow_id: str = FLOW_PATTERN_USER_SILENCE
17
+ """The ID of the flow."""
18
+
19
+ @classmethod
20
+ def type(cls) -> str:
21
+ """Returns the type of the frame."""
22
+ return FLOW_PATTERN_USER_SILENCE
23
+
24
+ @staticmethod
25
+ def from_dict(data: Dict[str, Any]) -> UserSilencePatternFlowStackFrame:
26
+ """Creates a `DialogueStackFrame` from a dictionary.
27
+
28
+ Args:
29
+ data: The dictionary to create the `DialogueStackFrame` from.
30
+
31
+ Returns:
32
+ The created `DialogueStackFrame`.
33
+ """
34
+ return UserSilencePatternFlowStackFrame(
35
+ frame_id=data["frame_id"],
36
+ step_id=data["step_id"],
37
+ )
@@ -190,11 +190,11 @@ class E2ETestRunner:
190
190
  error=f"Message handling timed out for user message '{step.text}'.",
191
191
  exc_info=True,
192
192
  )
193
- except Exception:
193
+ except Exception as exc:
194
194
  structlogger.error(
195
195
  "e2e_test_runner.run_prediction_loop",
196
196
  error=f"An exception occurred while handling "
197
- f"user message '{step.text}'.",
197
+ f"user message '{step.text}'. Error: {exc}",
198
198
  )
199
199
  tracker = await self.agent.tracker_store.retrieve(sender_id) # type: ignore[assignment]
200
200
  turns[position], event_cursor = self.get_actual_step_output(
@@ -1155,6 +1155,8 @@ class E2ETestRunner:
1155
1155
  flow_paths_stack
1156
1156
  and self.agent.domain
1157
1157
  and self.agent.domain.is_custom_action(event.action_name)
1158
+ and STEP_ID_METADATA_KEY in event.metadata
1159
+ and ACTIVE_FLOW_METADATA_KEY in event.metadata
1158
1160
  ):
1159
1161
  flow_paths_stack[-1].nodes.append(self._create_path_node(event))
1160
1162
 
rasa/e2e_test/utils/io.py CHANGED
@@ -346,7 +346,7 @@ def read_test_cases(path: str) -> TestSuite:
346
346
  beta_flag_verified = False
347
347
 
348
348
  for test_file in test_files:
349
- test_file_content = parse_raw_yaml(Path(test_file).read_text())
349
+ test_file_content = parse_raw_yaml(Path(test_file).read_text(encoding="utf-8"))
350
350
 
351
351
  validate_yaml_data_using_schema_with_assertions(
352
352
  yaml_data=test_file_content, schema_content=e2e_test_schema