rasa-pro 3.13.0.dev20250612__py3-none-any.whl → 3.13.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 (252) hide show
  1. rasa/__main__.py +0 -3
  2. rasa/api.py +1 -1
  3. rasa/cli/dialogue_understanding_test.py +1 -1
  4. rasa/cli/e2e_test.py +1 -8
  5. rasa/cli/evaluate.py +1 -1
  6. rasa/cli/export.py +3 -1
  7. rasa/cli/llm_fine_tuning.py +12 -11
  8. rasa/cli/project_templates/defaults.py +133 -0
  9. rasa/cli/project_templates/tutorial/config.yml +1 -1
  10. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  11. rasa/cli/run.py +1 -1
  12. rasa/cli/studio/download.py +1 -23
  13. rasa/cli/studio/link.py +52 -0
  14. rasa/cli/studio/pull.py +79 -0
  15. rasa/cli/studio/push.py +78 -0
  16. rasa/cli/studio/studio.py +12 -0
  17. rasa/cli/studio/train.py +0 -1
  18. rasa/cli/studio/upload.py +8 -0
  19. rasa/cli/train.py +1 -1
  20. rasa/cli/utils.py +1 -1
  21. rasa/cli/x.py +1 -1
  22. rasa/constants.py +2 -0
  23. rasa/core/__init__.py +0 -16
  24. rasa/core/actions/action.py +5 -1
  25. rasa/core/actions/action_repeat_bot_messages.py +18 -22
  26. rasa/core/actions/action_run_slot_rejections.py +0 -1
  27. rasa/core/agent.py +16 -1
  28. rasa/core/available_endpoints.py +146 -0
  29. rasa/core/brokers/pika.py +1 -2
  30. rasa/core/channels/__init__.py +2 -0
  31. rasa/core/channels/botframework.py +2 -2
  32. rasa/core/channels/channel.py +2 -2
  33. rasa/core/channels/development_inspector.py +1 -1
  34. rasa/core/channels/facebook.py +1 -4
  35. rasa/core/channels/hangouts.py +8 -5
  36. rasa/core/channels/inspector/README.md +3 -3
  37. rasa/core/channels/inspector/dist/assets/{arc-c4b064fc.js → arc-371401b1.js} +1 -1
  38. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-215b5026.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
  39. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-2b54a0a3.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
  40. rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
  41. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-daacea5f.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
  42. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-930d4dc2.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
  43. rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
  44. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-83c206ba.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
  45. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-b0eb01d0.js → edges-e0da2a9e-f837ca8a.js} +1 -1
  46. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-17586500.js → erDiagram-9861fffd-8717ac54.js} +1 -1
  47. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-be2a1776.js → flowDb-956e92f1-94f38b83.js} +1 -1
  48. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-c2120ebd.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
  49. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
  50. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-a6ab5c48.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
  51. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-ef613457.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
  52. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-d59185b3.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
  53. rasa/core/channels/inspector/dist/assets/{graph-0f155405.js → graph-0d0a2c10.js} +1 -1
  54. rasa/core/channels/inspector/dist/assets/{index-3862675e-d5f1d1b7.js → index-3862675e-58ea0305.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{index-47737d3a.js → index-cce6f8a1.js} +3 -3
  56. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b07d141f.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-1936d429.js → journeyDiagram-49397b02-95be5545.js} +1 -1
  58. rasa/core/channels/inspector/dist/assets/{layout-dde8d0f3.js → layout-da885b9b.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{line-0c2c7ee0.js → line-f1c817d3.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/{linear-35dd89a4.js → linear-d42801e6.js} +1 -1
  61. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-56192851.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-fc21ed78.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-25e98518.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-546ff1f5.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-02d8b82d.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3ca5a92e.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
  67. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-128ea07c.js → stateDiagram-587899a1-e53a2028.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-95f290af.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-4984898a.js → styles-6aaf32cf-d0226ca5.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1bf266ba.js → styles-9a916d00-0e21dc00.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-60521c63.js → styles-c10674c1-9588494e.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-a25b6e12.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
  73. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0fc086bf.js → timeline-definition-85554ec2-74631749.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-44ee592e.js → xychartDiagram-e933f94c-a043552f.js} +1 -1
  75. rasa/core/channels/inspector/dist/index.html +1 -1
  76. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +1 -1
  77. rasa/core/channels/mattermost.py +1 -1
  78. rasa/core/channels/rasa_chat.py +2 -4
  79. rasa/core/channels/rest.py +5 -4
  80. rasa/core/channels/socketio.py +56 -41
  81. rasa/core/channels/studio_chat.py +314 -10
  82. rasa/core/channels/vier_cvg.py +1 -2
  83. rasa/core/channels/voice_ready/audiocodes.py +2 -9
  84. rasa/core/channels/voice_stream/asr/azure.py +9 -0
  85. rasa/core/channels/voice_stream/audiocodes.py +8 -5
  86. rasa/core/channels/voice_stream/browser_audio.py +1 -1
  87. rasa/core/channels/voice_stream/genesys.py +2 -2
  88. rasa/core/channels/voice_stream/jambonz.py +166 -0
  89. rasa/core/channels/voice_stream/tts/__init__.py +8 -0
  90. rasa/core/channels/voice_stream/twilio_media_streams.py +17 -5
  91. rasa/core/channels/voice_stream/voice_channel.py +44 -24
  92. rasa/core/exporter.py +36 -0
  93. rasa/core/http_interpreter.py +3 -7
  94. rasa/core/information_retrieval/faiss.py +18 -11
  95. rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
  96. rasa/core/jobs.py +2 -1
  97. rasa/core/nlg/contextual_response_rephraser.py +48 -12
  98. rasa/core/nlg/generator.py +0 -1
  99. rasa/core/nlg/interpolator.py +2 -3
  100. rasa/core/nlg/summarize.py +39 -5
  101. rasa/core/policies/enterprise_search_policy.py +298 -184
  102. rasa/core/policies/enterprise_search_policy_config.py +241 -0
  103. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +64 -0
  104. rasa/core/policies/flow_policy.py +1 -1
  105. rasa/core/policies/flows/flow_executor.py +96 -17
  106. rasa/core/policies/intentless_policy.py +71 -26
  107. rasa/core/processor.py +104 -51
  108. rasa/core/run.py +33 -11
  109. rasa/core/tracker_stores/tracker_store.py +1 -1
  110. rasa/core/training/interactive.py +1 -1
  111. rasa/core/utils.py +35 -99
  112. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
  113. rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -17
  114. rasa/dialogue_understanding/commands/__init__.py +4 -0
  115. rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
  116. rasa/dialogue_understanding/commands/cancel_flow_command.py +6 -2
  117. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
  118. rasa/dialogue_understanding/commands/clarify_command.py +7 -3
  119. rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
  120. rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
  121. rasa/dialogue_understanding/commands/error_command.py +1 -1
  122. rasa/dialogue_understanding/commands/human_handoff_command.py +3 -3
  123. rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
  124. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
  125. rasa/dialogue_understanding/commands/set_slot_command.py +15 -5
  126. rasa/dialogue_understanding/commands/skip_question_command.py +3 -3
  127. rasa/dialogue_understanding/commands/start_flow_command.py +7 -3
  128. rasa/dialogue_understanding/commands/utils.py +26 -2
  129. rasa/dialogue_understanding/generator/__init__.py +7 -1
  130. rasa/dialogue_understanding/generator/command_generator.py +15 -3
  131. rasa/dialogue_understanding/generator/command_parser.py +2 -2
  132. rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
  133. rasa/dialogue_understanding/generator/constants.py +2 -2
  134. rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
  135. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
  136. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
  137. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
  138. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
  139. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +79 -0
  140. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +28 -463
  141. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
  142. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +461 -0
  143. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -64
  144. rasa/dialogue_understanding/patterns/cancel.py +1 -2
  145. rasa/dialogue_understanding/patterns/clarify.py +1 -1
  146. rasa/dialogue_understanding/patterns/correction.py +2 -2
  147. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
  148. rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
  149. rasa/dialogue_understanding/processor/command_processor.py +11 -12
  150. rasa/dialogue_understanding/processor/command_processor_component.py +3 -3
  151. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
  152. rasa/dialogue_understanding/stack/utils.py +3 -1
  153. rasa/dialogue_understanding/utils.py +68 -12
  154. rasa/dialogue_understanding_test/du_test_case.py +1 -1
  155. rasa/dialogue_understanding_test/du_test_runner.py +4 -22
  156. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +2 -6
  157. rasa/e2e_test/e2e_test_coverage_report.py +1 -1
  158. rasa/e2e_test/e2e_test_runner.py +1 -1
  159. rasa/engine/constants.py +1 -1
  160. rasa/engine/graph.py +2 -2
  161. rasa/engine/recipes/default_recipe.py +26 -2
  162. rasa/engine/validation.py +3 -2
  163. rasa/hooks.py +0 -28
  164. rasa/llm_fine_tuning/annotation_module.py +39 -9
  165. rasa/llm_fine_tuning/conversations.py +3 -0
  166. rasa/llm_fine_tuning/llm_data_preparation_module.py +66 -49
  167. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +5 -7
  168. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +52 -44
  169. rasa/llm_fine_tuning/paraphrasing_module.py +10 -12
  170. rasa/llm_fine_tuning/storage.py +4 -4
  171. rasa/llm_fine_tuning/utils.py +63 -1
  172. rasa/model_manager/model_api.py +88 -0
  173. rasa/model_manager/trainer_service.py +4 -4
  174. rasa/plugin.py +1 -11
  175. rasa/privacy/__init__.py +0 -0
  176. rasa/privacy/constants.py +83 -0
  177. rasa/privacy/event_broker_utils.py +77 -0
  178. rasa/privacy/privacy_config.py +281 -0
  179. rasa/privacy/privacy_config_schema.json +86 -0
  180. rasa/privacy/privacy_filter.py +340 -0
  181. rasa/privacy/privacy_manager.py +576 -0
  182. rasa/server.py +23 -2
  183. rasa/shared/constants.py +18 -0
  184. rasa/shared/core/command_payload_reader.py +1 -5
  185. rasa/shared/core/constants.py +4 -3
  186. rasa/shared/core/domain.py +7 -0
  187. rasa/shared/core/events.py +38 -10
  188. rasa/shared/core/flows/constants.py +2 -0
  189. rasa/shared/core/flows/flow.py +127 -14
  190. rasa/shared/core/flows/flows_list.py +18 -1
  191. rasa/shared/core/flows/flows_yaml_schema.json +3 -0
  192. rasa/shared/core/flows/steps/collect.py +46 -2
  193. rasa/shared/core/flows/steps/link.py +7 -2
  194. rasa/shared/core/flows/validation.py +25 -5
  195. rasa/shared/core/slots.py +28 -0
  196. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
  197. rasa/shared/exceptions.py +4 -0
  198. rasa/shared/providers/_configs/azure_openai_client_config.py +6 -2
  199. rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
  200. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
  201. rasa/shared/providers/_configs/openai_client_config.py +5 -1
  202. rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
  203. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
  204. rasa/shared/providers/_configs/utils.py +0 -99
  205. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +3 -0
  206. rasa/shared/providers/llm/_base_litellm_client.py +5 -2
  207. rasa/shared/utils/common.py +1 -1
  208. rasa/shared/utils/configs.py +110 -0
  209. rasa/shared/utils/constants.py +0 -3
  210. rasa/shared/utils/llm.py +195 -9
  211. rasa/shared/utils/pykwalify_extensions.py +0 -9
  212. rasa/shared/utils/yaml.py +32 -0
  213. rasa/studio/constants.py +1 -0
  214. rasa/studio/data_handler.py +11 -4
  215. rasa/studio/download.py +167 -0
  216. rasa/studio/link.py +200 -0
  217. rasa/studio/prompts.py +223 -0
  218. rasa/studio/pull/__init__.py +0 -0
  219. rasa/studio/{download/flows.py → pull/data.py} +23 -160
  220. rasa/studio/{download → pull}/domains.py +1 -1
  221. rasa/studio/pull/pull.py +235 -0
  222. rasa/studio/push.py +136 -0
  223. rasa/studio/train.py +1 -1
  224. rasa/studio/upload.py +117 -67
  225. rasa/telemetry.py +82 -25
  226. rasa/tracing/config.py +3 -4
  227. rasa/tracing/constants.py +19 -1
  228. rasa/tracing/instrumentation/attribute_extractors.py +30 -8
  229. rasa/tracing/instrumentation/instrumentation.py +53 -2
  230. rasa/tracing/instrumentation/metrics.py +98 -15
  231. rasa/tracing/metric_instrument_provider.py +75 -3
  232. rasa/utils/common.py +7 -22
  233. rasa/utils/log_utils.py +1 -45
  234. rasa/validator.py +2 -8
  235. rasa/version.py +1 -1
  236. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/METADATA +8 -9
  237. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/RECORD +241 -220
  238. rasa/anonymization/__init__.py +0 -2
  239. rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
  240. rasa/anonymization/anonymization_pipeline.py +0 -286
  241. rasa/anonymization/anonymization_rule_executor.py +0 -266
  242. rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
  243. rasa/anonymization/schemas/config.yml +0 -47
  244. rasa/anonymization/utils.py +0 -118
  245. rasa/core/channels/inspector/dist/assets/channel-3730f5fd.js +0 -1
  246. rasa/core/channels/inspector/dist/assets/clone-e847561e.js +0 -1
  247. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +0 -1
  248. rasa/studio/download/download.py +0 -439
  249. /rasa/{studio/download → core/information_retrieval/ingestion}/__init__.py +0 -0
  250. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/NOTICE +0 -0
  251. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/WHEEL +0 -0
  252. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/entry_points.txt +0 -0
@@ -113,10 +113,11 @@ FLOW_HASHES_SLOT = "flow_hashes"
113
113
  FLOW_SLOT_NAMES = [FLOW_HASHES_SLOT]
114
114
 
115
115
  # slots for audio timeout
116
- SLOT_SILENCE_TIMEOUT = "silence_timeout"
116
+ GLOBAL_SILENCE_TIMEOUT_KEY = "global_silence_timeout"
117
+ SILENCE_TIMEOUT_SLOT = "silence_timeout"
117
118
  SLOT_CONSECUTIVE_SILENCE_TIMEOUTS = "consecutive_silence_timeouts"
118
- SILENCE_TIMEOUT_DEFAULT_VALUE = 6.0
119
- SILENCE_SLOTS = [SLOT_SILENCE_TIMEOUT, SLOT_CONSECUTIVE_SILENCE_TIMEOUTS]
119
+ GLOBAL_SILENCE_TIMEOUT_DEFAULT_VALUE = 7.0
120
+ SILENCE_SLOTS = [SILENCE_TIMEOUT_SLOT, SLOT_CONSECUTIVE_SILENCE_TIMEOUTS]
120
121
  # slots for knowledge base
121
122
  SLOT_LISTED_ITEMS = "knowledge_base_listed_objects"
122
123
  SLOT_LAST_OBJECT = "knowledge_base_last_object"
@@ -32,6 +32,7 @@ from ruamel.yaml.scalarstring import DoubleQuotedScalarString
32
32
  import rasa.shared.core.slot_mappings
33
33
  import rasa.shared.utils.common
34
34
  import rasa.shared.utils.io
35
+ from rasa.core.available_endpoints import AvailableEndpoints
35
36
  from rasa.shared.constants import (
36
37
  DEFAULT_CARRY_OVER_SLOTS_TO_NEW_SESSION,
37
38
  DEFAULT_SESSION_EXPIRATION_TIME_IN_MINUTES,
@@ -48,6 +49,7 @@ from rasa.shared.core.constants import (
48
49
  ACTION_SHOULD_SEND_DOMAIN,
49
50
  KEY_MAPPING_TYPE,
50
51
  KNOWLEDGE_BASE_SLOT_NAMES,
52
+ SILENCE_TIMEOUT_SLOT,
51
53
  SLOT_MAPPINGS,
52
54
  SlotMappingType,
53
55
  )
@@ -306,6 +308,11 @@ class Domain:
306
308
  responses = data.get(KEY_RESPONSES, {})
307
309
 
308
310
  domain_slots = data.get(KEY_SLOTS, {})
311
+ for slot_name, slot in domain_slots.items():
312
+ if slot_name == SILENCE_TIMEOUT_SLOT:
313
+ slot["initial_value"] = (
314
+ AvailableEndpoints.get_instance().interaction_handling.global_silence_timeout
315
+ )
309
316
  slots = cls.collect_slots(domain_slots)
310
317
  domain_actions = data.get(KEY_ACTIONS, [])
311
318
  actions = cls._collect_action_names(domain_actions)
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import abc
2
4
  import copy
3
5
  import json
@@ -6,7 +8,7 @@ import re
6
8
  import time
7
9
  import uuid
8
10
  from abc import ABC
9
- from datetime import datetime
11
+ from datetime import datetime, timezone
10
12
  from typing import (
11
13
  TYPE_CHECKING,
12
14
  Any,
@@ -124,9 +126,7 @@ def deserialise_events(serialized_events: List[Dict[Text, Any]]) -> List["Event"
124
126
  if event:
125
127
  deserialised.append(event)
126
128
  else:
127
- structlogger.warning(
128
- "event.deserialization.failed", rasa_event=copy.deepcopy(event)
129
- )
129
+ structlogger.warning("event.deserialization.failed")
130
130
 
131
131
  return deserialised
132
132
 
@@ -453,6 +453,7 @@ class UserUttered(Event):
453
453
  message_id: Optional[Text] = None,
454
454
  metadata: Optional[Dict] = None,
455
455
  use_text_for_featurization: Optional[bool] = None,
456
+ anonymized_at: Optional[float] = None,
456
457
  ) -> None:
457
458
  """Creates event for incoming user message.
458
459
 
@@ -467,6 +468,7 @@ class UserUttered(Event):
467
468
  message_id: Unique ID for message.
468
469
  use_text_for_featurization: `True` if the message's text was used to predict
469
470
  next action. `False` if the message's intent was used.
471
+ anonymized_at: When the event was anonymized in the tracker store.
470
472
 
471
473
  """
472
474
  self.text = text
@@ -500,7 +502,11 @@ class UserUttered(Event):
500
502
  if parse_data:
501
503
  self.parse_data.update(**parse_data)
502
504
 
503
- self._anonymized_at: Optional[datetime] = None
505
+ self._anonymized_at: Optional[datetime] = (
506
+ datetime.fromtimestamp(anonymized_at, tz=timezone.utc)
507
+ if anonymized_at is not None
508
+ else None
509
+ )
504
510
 
505
511
  @property
506
512
  def anonymized_at(self) -> Optional[datetime]:
@@ -525,6 +531,7 @@ class UserUttered(Event):
525
531
  input_channel: Optional[Text] = None,
526
532
  message_id: Optional[Text] = None,
527
533
  metadata: Optional[Dict] = None,
534
+ anonymized_at: Optional[float] = None,
528
535
  ) -> "UserUttered":
529
536
  return UserUttered(
530
537
  text,
@@ -535,6 +542,7 @@ class UserUttered(Event):
535
542
  input_channel,
536
543
  message_id,
537
544
  metadata,
545
+ anonymized_at,
538
546
  )
539
547
 
540
548
  def __hash__(self) -> int:
@@ -633,7 +641,9 @@ class UserUttered(Event):
633
641
  "input_channel": getattr(self, "input_channel", None),
634
642
  "message_id": getattr(self, "message_id", None),
635
643
  "metadata": self.metadata,
636
- "anonymized_at": self.anonymized_at,
644
+ "anonymized_at": self.anonymized_at.timestamp()
645
+ if self.anonymized_at
646
+ else None,
637
647
  }
638
648
  )
639
649
  return _dict
@@ -693,6 +703,7 @@ class UserUttered(Event):
693
703
  parameters.get("input_channel"),
694
704
  parameters.get("message_id"),
695
705
  parameters.get("metadata"),
706
+ parameters.get("anonymized_at"),
696
707
  )
697
708
  ]
698
709
  except KeyError as e:
@@ -920,6 +931,7 @@ class BotUttered(SkipEventInMDStoryMixin):
920
931
  data: Optional[Dict] = None,
921
932
  metadata: Optional[Dict[Text, Any]] = None,
922
933
  timestamp: Optional[float] = None,
934
+ anonymized_at: Optional[float] = None,
923
935
  ) -> None:
924
936
  """Creates event for a bot response.
925
937
 
@@ -928,10 +940,15 @@ class BotUttered(SkipEventInMDStoryMixin):
928
940
  data: Additional data for more complex utterances (e.g. buttons).
929
941
  timestamp: When the event was created.
930
942
  metadata: Additional event metadata.
943
+ anonymized_at: When the event was anonymized in the tracker store.
931
944
  """
932
945
  self.text = text
933
946
  self.data = data or {}
934
- self._anonymized_at: Optional[datetime] = None
947
+ self._anonymized_at: Optional[datetime] = (
948
+ datetime.fromtimestamp(anonymized_at, tz=timezone.utc)
949
+ if anonymized_at is not None
950
+ else None
951
+ )
935
952
  super().__init__(timestamp, metadata)
936
953
 
937
954
  @property
@@ -1040,7 +1057,9 @@ class BotUttered(SkipEventInMDStoryMixin):
1040
1057
  "text": self.text,
1041
1058
  "data": self.data,
1042
1059
  "metadata": self.metadata,
1043
- "anonymized_at": self.anonymized_at,
1060
+ "anonymized_at": self.anonymized_at.timestamp()
1061
+ if self.anonymized_at
1062
+ else None,
1044
1063
  }
1045
1064
  )
1046
1065
  return d
@@ -1053,6 +1072,7 @@ class BotUttered(SkipEventInMDStoryMixin):
1053
1072
  parameters.get("data"),
1054
1073
  parameters.get("metadata"),
1055
1074
  parameters.get("timestamp"),
1075
+ parameters.get("anonymized_at"),
1056
1076
  )
1057
1077
  except KeyError as e:
1058
1078
  raise ValueError(f"Failed to parse bot uttered event. {e}")
@@ -1077,6 +1097,7 @@ class SlotSet(Event):
1077
1097
  timestamp: Optional[float] = None,
1078
1098
  metadata: Optional[Dict[Text, Any]] = None,
1079
1099
  filled_by: Optional[str] = None,
1100
+ anonymized_at: Optional[float] = None,
1080
1101
  ) -> None:
1081
1102
  """Creates event to set slot.
1082
1103
 
@@ -1089,7 +1110,11 @@ class SlotSet(Event):
1089
1110
  self.key = key
1090
1111
  self.value = value
1091
1112
  self._filled_by = filled_by
1092
- self._anonymized_at: Optional[datetime] = None
1113
+ self._anonymized_at: Optional[datetime] = (
1114
+ datetime.fromtimestamp(anonymized_at, tz=timezone.utc)
1115
+ if anonymized_at is not None
1116
+ else None
1117
+ )
1093
1118
  super().__init__(timestamp, metadata)
1094
1119
 
1095
1120
  @property
@@ -1156,7 +1181,9 @@ class SlotSet(Event):
1156
1181
  "name": self.key,
1157
1182
  "value": self.value,
1158
1183
  "filled_by": self.filled_by,
1159
- "anonymized_at": self.anonymized_at,
1184
+ "anonymized_at": self.anonymized_at.timestamp()
1185
+ if self.anonymized_at
1186
+ else None,
1160
1187
  }
1161
1188
  )
1162
1189
  return d
@@ -1170,6 +1197,7 @@ class SlotSet(Event):
1170
1197
  parameters.get("timestamp"),
1171
1198
  parameters.get("metadata"),
1172
1199
  filled_by=parameters.get("filled_by"),
1200
+ anonymized_at=parameters.get("anonymized_at"),
1173
1201
  )
1174
1202
  except KeyError as e:
1175
1203
  raise ValueError(f"Failed to parse set slot event. {e}")
@@ -9,3 +9,5 @@ KEY_FILE_PATH = "file_path"
9
9
  KEY_PERSISTED_SLOTS = "persisted_slots"
10
10
  KEY_RUN_PATTERN_COMPLETED = "run_pattern_completed"
11
11
  KEY_TRANSLATION = "translation"
12
+ KEY_CALLED_FLOW = "called_flow"
13
+ KEY_LINKED_FLOW = "linked_flow"
@@ -4,7 +4,7 @@ import copy
4
4
  from dataclasses import dataclass, field
5
5
  from functools import cached_property
6
6
  from pathlib import Path
7
- from typing import Any, Dict, List, Optional, Set, Text, Union
7
+ from typing import Any, Dict, List, Optional, Set, Text, Tuple, Union
8
8
 
9
9
  import structlog
10
10
  from pydantic import BaseModel
@@ -15,10 +15,12 @@ from rasa.engine.language import Language
15
15
  from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
16
16
  from rasa.shared.core.flows.constants import (
17
17
  KEY_ALWAYS_INCLUDE_IN_PROMPT,
18
+ KEY_CALLED_FLOW,
18
19
  KEY_DESCRIPTION,
19
20
  KEY_FILE_PATH,
20
21
  KEY_ID,
21
22
  KEY_IF,
23
+ KEY_LINKED_FLOW,
22
24
  KEY_NAME,
23
25
  KEY_NLU_TRIGGER,
24
26
  KEY_PERSISTED_SLOTS,
@@ -41,6 +43,7 @@ from rasa.shared.core.flows.steps import (
41
43
  CallFlowStep,
42
44
  CollectInformationFlowStep,
43
45
  EndFlowStep,
46
+ LinkFlowStep,
44
47
  StartFlowStep,
45
48
  )
46
49
  from rasa.shared.core.flows.steps.constants import (
@@ -63,7 +66,7 @@ class FlowLanguageTranslation(BaseModel):
63
66
  """The human-readable name of the flow."""
64
67
 
65
68
  class Config:
66
- """Config for the FlowLanguageTranslation class."""
69
+ """Configuration for the FlowLanguageTranslation model."""
67
70
 
68
71
  extra = "ignore"
69
72
 
@@ -262,7 +265,7 @@ class Flow:
262
265
  def readable_name(self, language: Optional[Language] = None) -> str:
263
266
  """Returns the flow's name in the specified language if available.
264
267
 
265
- Otherwise falls back to the flow's name, and finally the flow's ID.
268
+ Otherwise, falls back to the flow's name, and finally the flow's ID.
266
269
 
267
270
  Args:
268
271
  language: Preferred language code.
@@ -406,8 +409,7 @@ class Flow:
406
409
  structlogger.error(
407
410
  "command_generator.validate_flow_starting_conditions.error",
408
411
  predicate=self.guard_condition,
409
- context=context,
410
- slots=slots,
412
+ flow_id=self.id,
411
413
  error=str(e),
412
414
  )
413
415
  return False
@@ -516,6 +518,9 @@ class Flow:
516
518
  current_path: FlowPath,
517
519
  all_paths: FlowPathsList,
518
520
  visited_step_ids: Set[str],
521
+ call_stack: Optional[
522
+ List[Tuple[Optional[FlowStep], Optional[Flow], str]]
523
+ ] = None,
519
524
  ) -> None:
520
525
  """Processes the flow steps recursively.
521
526
 
@@ -524,19 +529,25 @@ class Flow:
524
529
  current_path: The current path being constructed.
525
530
  all_paths: The list where completed paths are added.
526
531
  visited_step_ids: A set of steps that have been visited to avoid cycles.
532
+ call_stack: Tuple list of (flow, path, flow_type) to track path when \
533
+ calling flows through call and link steps.
527
534
 
528
535
  Returns:
529
536
  None: This function modifies all_paths in place by appending new paths
530
537
  as they are found.
531
538
  """
539
+ if call_stack is None:
540
+ call_stack = []
541
+
532
542
  # Check if the step is relevant for testable_paths extraction.
533
- # We only create new path nodes for ActionFlowStep, CallFlowStep and
534
- # CollectInformationFlowStep because these are externally visible
535
- # changes in the assistant's behaviour (trackable in the e2e tests).
543
+ # We only create new path nodes for CollectInformationFlowStep,
544
+ # ActionFlowStep, CallFlowStep and LinkFlowStep,
545
+ # because these are externally visible changes
546
+ # in the assistant's behaviour (trackable in the e2e tests).
536
547
  # For other flow steps, we only follow their links.
537
- # We decided to ignore calls to other flows in our coverage analysis.
538
548
  should_add_node = isinstance(
539
- current_step, (CollectInformationFlowStep, ActionFlowStep, CallFlowStep)
549
+ current_step,
550
+ (CollectInformationFlowStep, ActionFlowStep, CallFlowStep, LinkFlowStep),
540
551
  )
541
552
  if should_add_node:
542
553
  # Add current step to the current path that is being constructed.
@@ -548,10 +559,45 @@ class Flow:
548
559
  )
549
560
  )
550
561
 
562
+ # Check if the current step has already been visited or
563
+ # if the end of the path has been reached.
564
+ # If so, and we’re not within a called flow, we terminate the current path.
565
+ # This also applies for when we're inside a linked flow and reach its end.
566
+ # If we're inside a called flow and reach its end,
567
+ # continue with the next steps in its parent flow.
551
568
  if current_step.id in visited_step_ids or self.is_end_of_path(current_step):
552
- # Found a cycle, or reached an end step, do not proceed further.
553
- all_paths.paths.append(copy.deepcopy(current_path))
554
- # Remove the last node from the path if it was added.
569
+ # Shallow copy is sufficient, since we only pop from the list and
570
+ # don't mutate the objects inside the tuples.
571
+ # The state of FlowStep and Flow does not change during the traversal.
572
+ call_stack_copy = call_stack.copy()
573
+ # parent_flow_type could be any of: None, i.e. main flow,
574
+ # KEY_CALLED_FLOW(=called_flow) or KEY_LINKED_FLOW(=linked_flow)
575
+ parent_step, parent_flow, parent_flow_type = (
576
+ call_stack_copy.pop() if call_stack_copy else (None, None, None)
577
+ )
578
+
579
+ # Check if within a called flow.
580
+ # If within linked flow, stop the traversal as this takes precedence.
581
+ if parent_step and parent_flow_type == KEY_CALLED_FLOW:
582
+ # As we have reached the END step of a called flow, we need to
583
+ # continue with the next links of the parent step.
584
+ if parent_flow is not None:
585
+ for link in parent_step.next.links:
586
+ parent_flow._handle_link(
587
+ current_path,
588
+ all_paths,
589
+ visited_step_ids,
590
+ link,
591
+ call_stack_copy,
592
+ )
593
+
594
+ else:
595
+ # Found a cycle, or reached an end step, do not proceed further.
596
+ all_paths.paths.append(copy.deepcopy(current_path))
597
+
598
+ # Backtrack: remove the last node after reaching a terminal step.
599
+ # Ensures the path is correctly backtracked, after a path ends or
600
+ # a cycle is detected.
555
601
  if should_add_node:
556
602
  current_path.nodes.pop()
557
603
  return
@@ -559,6 +605,62 @@ class Flow:
559
605
  # Mark current step as visited in this path.
560
606
  visited_step_ids.add(current_step.id)
561
607
 
608
+ # If the current step is a call step, we need to resolve the call
609
+ # and continue with the steps of the called flow.
610
+ if isinstance(current_step, CallFlowStep):
611
+ # Get the steps of the called flow and continue with them.
612
+ called_flow = current_step.called_flow_reference
613
+ if called_flow and (
614
+ start_step_in_called_flow := called_flow.first_step_in_flow()
615
+ ):
616
+ call_stack.append((current_step, self, KEY_CALLED_FLOW))
617
+ called_flow._go_over_steps(
618
+ start_step_in_called_flow,
619
+ current_path,
620
+ all_paths,
621
+ visited_step_ids,
622
+ call_stack,
623
+ )
624
+
625
+ # After processing the steps of the called (child) flow,
626
+ # remove them from the visited steps
627
+ # to allow the calling (parent) flow to revisit them later.
628
+ visited_step_ids.remove(current_step.id)
629
+ call_stack.pop()
630
+
631
+ # Backtrack: remove the last node
632
+ # after returning from a called (child) flow.
633
+ # Ensures the parent flow can continue exploring other branches.
634
+ if should_add_node:
635
+ current_path.nodes.pop()
636
+ return
637
+
638
+ # If the current step is a LinkFlowStep, step into the linked flow,
639
+ # process its links, and do not return from that flow anymore.
640
+ if isinstance(current_step, LinkFlowStep):
641
+ # Get the steps of the linked flow and continue with them.
642
+ linked_flow = current_step.linked_flow_reference
643
+ if linked_flow and (
644
+ start_step_in_linked_flow := linked_flow.first_step_in_flow()
645
+ ):
646
+ call_stack.append((current_step, self, KEY_LINKED_FLOW))
647
+ linked_flow._go_over_steps(
648
+ start_step_in_linked_flow,
649
+ current_path,
650
+ all_paths,
651
+ visited_step_ids,
652
+ call_stack,
653
+ )
654
+ visited_step_ids.remove(current_step.id)
655
+ call_stack.pop()
656
+
657
+ # Backtrack: remove the last node
658
+ # after returning from a linked (child) flow.
659
+ # Ensures the parent can continue after the linked flow is processed.
660
+ if should_add_node:
661
+ current_path.nodes.pop()
662
+ return
663
+
562
664
  # Iterate over all links of the current step.
563
665
  for link in current_step.next.links:
564
666
  self._handle_link(
@@ -566,12 +668,15 @@ class Flow:
566
668
  all_paths,
567
669
  visited_step_ids,
568
670
  link,
671
+ call_stack,
569
672
  )
570
673
 
571
674
  # Backtrack the current step and remove it from the path.
572
675
  visited_step_ids.remove(current_step.id)
573
676
 
574
- # Remove the last node from the path if it was added.
677
+ # Backtrack: remove the last node
678
+ # after processing all links of the current step.
679
+ # Ensures the next recursion can start once all links are explored.
575
680
  if should_add_node:
576
681
  current_path.nodes.pop()
577
682
 
@@ -581,6 +686,9 @@ class Flow:
581
686
  all_paths: FlowPathsList,
582
687
  visited_step_ids: Set[str],
583
688
  link: FlowStepLink,
689
+ call_stack: Optional[
690
+ List[Tuple[Optional[FlowStep], Optional[Flow], str]]
691
+ ] = None,
584
692
  ) -> None:
585
693
  """Handles the next step in a flow.
586
694
 
@@ -589,6 +697,8 @@ class Flow:
589
697
  all_paths: The list where completed paths are added.
590
698
  visited_step_ids: A set of steps that have been visited to avoid cycles.
591
699
  link: The link to be followed.
700
+ call_stack: Tuple list of (flow, path, flow_type) to track path when \
701
+ calling flows through call and link steps..
592
702
 
593
703
  Returns:
594
704
  None: This function modifies all_paths in place by appending new paths
@@ -603,6 +713,7 @@ class Flow:
603
713
  current_path,
604
714
  all_paths,
605
715
  visited_step_ids,
716
+ call_stack,
606
717
  )
607
718
  return
608
719
  # IfFlowStepLink and ElseFlowStepLink are conditional links.
@@ -616,6 +727,7 @@ class Flow:
616
727
  current_path,
617
728
  all_paths,
618
729
  visited_step_ids,
730
+ call_stack,
619
731
  )
620
732
  return
621
733
  else:
@@ -626,6 +738,7 @@ class Flow:
626
738
  current_path,
627
739
  all_paths,
628
740
  visited_step_ids,
741
+ call_stack,
629
742
  )
630
743
  return
631
744
 
@@ -36,6 +36,7 @@ class FlowsList:
36
36
  def __post_init__(self) -> None:
37
37
  """Initializes the FlowsList object."""
38
38
  self._resolve_called_flows()
39
+ self._resolve_linked_flows()
39
40
 
40
41
  def __iter__(self) -> Generator[Flow, None, None]:
41
42
  """Iterates over the flows."""
@@ -103,7 +104,10 @@ class FlowsList:
103
104
  )
104
105
 
105
106
  def _resolve_called_flows(self) -> None:
106
- """Resolves the called flows."""
107
+ """Resolves the called flows.
108
+
109
+ `Resolving` here means connecting the step to the actual `Flow` object.
110
+ """
107
111
  from rasa.shared.core.flows.steps import CallFlowStep
108
112
 
109
113
  for flow in self.underlying_flows:
@@ -112,6 +116,19 @@ class FlowsList:
112
116
  # only resolve the reference, if it isn't already resolved
113
117
  step.called_flow_reference = self.flow_by_id(step.call)
114
118
 
119
+ def _resolve_linked_flows(self) -> None:
120
+ """Resolves the linked flows.
121
+
122
+ `Resolving` here means connecting the step to the actual `Flow` object.
123
+ """
124
+ from rasa.shared.core.flows.steps import LinkFlowStep
125
+
126
+ for flow in self.underlying_flows:
127
+ for step in flow.steps:
128
+ if isinstance(step, LinkFlowStep) and not step.linked_flow_reference:
129
+ # only resolve the reference, if it isn't already resolved
130
+ step.linked_flow_reference = self.flow_by_id(step.link)
131
+
115
132
  def as_json_list(self) -> List[Dict[Text, Any]]:
116
133
  """Serialize the FlowsList object to list format and not to the original dict.
117
134
 
@@ -244,6 +244,9 @@
244
244
  }
245
245
  }
246
246
  }
247
+ },
248
+ "silence_timeout": {
249
+ "type": "number"
247
250
  }
248
251
  }
249
252
  }
@@ -1,16 +1,23 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import Any, Dict, List, Set, Text
4
+ from typing import Any, Dict, List, Optional, Set, Text, Union
5
+
6
+ import structlog
5
7
 
6
8
  from rasa.shared.constants import ACTION_ASK_PREFIX, UTTER_ASK_PREFIX
7
9
  from rasa.shared.core.flows.flow_step import FlowStep
8
10
  from rasa.shared.core.slots import SlotRejection
11
+ from rasa.shared.exceptions import RasaException
9
12
 
10
13
  DEFAULT_ASK_BEFORE_FILLING = False
11
14
  DEFAULT_RESET_AFTER_FLOW_ENDS = True
12
15
  DEFAULT_FORCE_SLOT_FILLING = False
13
16
 
17
+ logger = structlog.get_logger(__name__)
18
+
19
+ SilenceTimeoutInstructionType = Union[int, float, Dict[str, Any]]
20
+
14
21
 
15
22
  @dataclass
16
23
  class CollectInformationFlowStep(FlowStep):
@@ -30,6 +37,8 @@ class CollectInformationFlowStep(FlowStep):
30
37
  """Whether to reset the slot value at the end of the flow."""
31
38
  force_slot_filling: bool = False
32
39
  """Whether to keep only the SetSlot command for the collected slot."""
40
+ silence_timeout: Optional[float] = None
41
+ """The silence timeout for the collect information step."""
33
42
 
34
43
  @classmethod
35
44
  def from_json(
@@ -44,6 +53,11 @@ class CollectInformationFlowStep(FlowStep):
44
53
  Returns:
45
54
  A CollectInformationFlowStep object
46
55
  """
56
+
57
+ silence_timeout = cls._deserialise_silence_timeout(
58
+ data.get("silence_timeout", None)
59
+ )
60
+
47
61
  base = super().from_json(flow_id, data)
48
62
  return CollectInformationFlowStep(
49
63
  collect=data["collect"],
@@ -58,14 +72,40 @@ class CollectInformationFlowStep(FlowStep):
58
72
  for rejection in data.get("rejections", [])
59
73
  ],
60
74
  force_slot_filling=data.get("force_slot_filling", False),
75
+ silence_timeout=silence_timeout,
61
76
  **base.__dict__,
62
77
  )
63
78
 
79
+ @staticmethod
80
+ def _deserialise_silence_timeout(
81
+ silence_timeout_json: Optional[SilenceTimeoutInstructionType],
82
+ ) -> Optional[float]:
83
+ """Deserialize silence timeout from JSON."""
84
+ if not silence_timeout_json:
85
+ return None
86
+
87
+ if not isinstance(silence_timeout_json, (int, float)):
88
+ raise RasaException(
89
+ f"Invalid silence timeout value: {silence_timeout_json}. "
90
+ "If defined at collect step, silence timeout must be a number."
91
+ )
92
+
93
+ silence_timeout = silence_timeout_json
94
+
95
+ if silence_timeout and silence_timeout < 0:
96
+ raise RasaException(
97
+ f"Invalid silence timeout value: {silence_timeout}. "
98
+ "Silence timeout must be a non-negative number."
99
+ )
100
+ return silence_timeout
101
+
64
102
  @staticmethod
65
103
  def _default_utter(collect: str) -> str:
66
104
  return f"{UTTER_ASK_PREFIX}{collect}"
67
105
 
68
- def as_json(self) -> Dict[str, Any]: # type: ignore[override]
106
+ def as_json(
107
+ self, step_properties: Optional[Dict[Text, Any]] = None
108
+ ) -> Dict[str, Any]:
69
109
  """Serialize the CollectInformationFlowStep object.
70
110
 
71
111
  Returns:
@@ -78,6 +118,9 @@ class CollectInformationFlowStep(FlowStep):
78
118
  data["reset_after_flow_ends"] = self.reset_after_flow_ends
79
119
  data["rejections"] = [rejection.as_dict() for rejection in self.rejections]
80
120
  data["force_slot_filling"] = self.force_slot_filling
121
+ if self.silence_timeout:
122
+ data["silence_timeout"] = self.silence_timeout
123
+
81
124
  return super().as_json(step_properties=data)
82
125
 
83
126
  @property
@@ -100,6 +143,7 @@ class CollectInformationFlowStep(FlowStep):
100
143
  and self.ask_before_filling == other.ask_before_filling
101
144
  and self.reset_after_flow_ends == other.reset_after_flow_ends
102
145
  and self.force_slot_filling == other.force_slot_filling
146
+ and self.silence_timeout == other.silence_timeout
103
147
  and super().__eq__(other)
104
148
  )
105
149
  return False
@@ -1,9 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import Any, Dict, Text
4
+ from typing import TYPE_CHECKING, Any, Dict, Text
5
5
 
6
- from rasa.shared.core.flows.flow_step import FlowStep
6
+ from rasa.shared.core.flows.flow_step import FlowStep, Optional
7
+
8
+ if TYPE_CHECKING:
9
+ from rasa.shared.core.flows.flow import Flow
7
10
 
8
11
 
9
12
  @dataclass
@@ -12,6 +15,8 @@ class LinkFlowStep(FlowStep):
12
15
 
13
16
  link: Text
14
17
  """The id of the flow that should be started subsequently."""
18
+ linked_flow_reference: Optional["Flow"] = None
19
+ """The flow that is linked to by this step."""
15
20
 
16
21
  def does_allow_for_next_step(self) -> bool:
17
22
  """Returns whether this step allows for following steps.