rasa-pro 3.12.18.dev1__py3-none-any.whl → 3.13.0a1.dev1__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 (341) hide show
  1. rasa/__init__.py +0 -6
  2. rasa/__main__.py +3 -4
  3. rasa/api.py +1 -1
  4. rasa/builder/create_openai_vector_store.py +69 -0
  5. rasa/builder/llm-helper-schema.json +69 -0
  6. rasa/builder/prompt_to_bot.py +645 -0
  7. rasa/builder/scrape_rasa_docs.py +97 -0
  8. rasa/builder/skill_to_bot_prompt.jinja +158 -0
  9. rasa/cli/dialogue_understanding_test.py +1 -1
  10. rasa/cli/e2e_test.py +1 -1
  11. rasa/cli/evaluate.py +2 -2
  12. rasa/cli/export.py +3 -3
  13. rasa/cli/llm_fine_tuning.py +1 -1
  14. rasa/cli/project_templates/default/config.yml +5 -32
  15. rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_cancels_during_a_correction.yml +1 -1
  16. rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +1 -1
  17. rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_handle.yml +1 -1
  18. rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_name.yml +1 -1
  19. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +1 -1
  20. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_lists_contacts.yml +1 -1
  21. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact.yml +1 -1
  22. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact_from_list.yml +1 -1
  23. rasa/cli/project_templates/default/endpoints.yml +18 -2
  24. rasa/cli/project_templates/defaults.py +133 -0
  25. rasa/cli/run.py +1 -1
  26. rasa/cli/scaffold.py +2 -3
  27. rasa/cli/studio/download.py +1 -1
  28. rasa/cli/studio/link.py +53 -0
  29. rasa/cli/studio/pull.py +78 -0
  30. rasa/cli/studio/push.py +78 -0
  31. rasa/cli/studio/studio.py +12 -0
  32. rasa/cli/studio/upload.py +5 -3
  33. rasa/cli/train.py +1 -1
  34. rasa/cli/utils.py +1 -1
  35. rasa/cli/x.py +1 -1
  36. rasa/constants.py +2 -0
  37. rasa/core/__init__.py +0 -16
  38. rasa/core/actions/action.py +42 -31
  39. rasa/core/actions/action_repeat_bot_messages.py +18 -22
  40. rasa/core/actions/action_run_slot_rejections.py +1 -2
  41. rasa/core/agent.py +18 -3
  42. rasa/core/available_endpoints.py +146 -0
  43. rasa/core/brokers/kafka.py +4 -0
  44. rasa/core/brokers/pika.py +5 -2
  45. rasa/core/brokers/sql.py +1 -1
  46. rasa/core/channels/botframework.py +2 -2
  47. rasa/core/channels/channel.py +2 -2
  48. rasa/core/channels/development_inspector.py +1 -1
  49. rasa/core/channels/facebook.py +1 -4
  50. rasa/core/channels/hangouts.py +8 -5
  51. rasa/core/channels/inspector/.eslintrc.cjs +12 -6
  52. rasa/core/channels/inspector/.prettierrc +5 -0
  53. rasa/core/channels/inspector/README.md +11 -5
  54. rasa/core/channels/inspector/dist/assets/{arc-9f75cc3b.js → arc-02053cc1.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-008b6289.js} +1 -1
  56. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-fb2597be.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/channel-078dada8.js +1 -0
  58. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-7f847e00.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-ba1d689b.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/clone-5b4516de.js +1 -0
  61. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-dd8e67c4.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-10784939.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-24947ae6.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-a9ced505.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-afda9c7c.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-f9613071.js +1 -0
  67. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-6ef530b8.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-0c7dd39a.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-b57239d6.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-9ed57cec.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-233090de.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-72184470.js} +123 -123
  73. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-aa116649.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-e51877cc.js} +1 -1
  75. rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-3ca3798c.js} +1 -1
  76. rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-26ee10d3.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-aedded32.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-d8957261.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-d771f885.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-09fdf50c.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-9f0af02e.js} +1 -1
  82. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-84415b37.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-8dec4055.js} +1 -1
  84. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-c5431d07.js} +1 -1
  85. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-274e77d9.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-e364a1d7.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-0dae36f6.js} +1 -1
  88. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-c4641675.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-831fe9a1.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-c3304b3a.js} +1 -1
  91. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-da799369.js} +1 -1
  92. rasa/core/channels/inspector/dist/index.html +1 -1
  93. rasa/core/channels/inspector/package.json +3 -1
  94. rasa/core/channels/inspector/src/App.tsx +91 -90
  95. rasa/core/channels/inspector/src/components/Chat.tsx +45 -41
  96. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +40 -40
  97. rasa/core/channels/inspector/src/components/DialogueInformation.tsx +57 -57
  98. rasa/core/channels/inspector/src/components/DialogueStack.tsx +36 -27
  99. rasa/core/channels/inspector/src/components/ExpandIcon.tsx +4 -4
  100. rasa/core/channels/inspector/src/components/FullscreenButton.tsx +7 -7
  101. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +28 -12
  102. rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +9 -9
  103. rasa/core/channels/inspector/src/components/RasaLogo.tsx +5 -5
  104. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +55 -60
  105. rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +5 -5
  106. rasa/core/channels/inspector/src/components/Slots.tsx +22 -22
  107. rasa/core/channels/inspector/src/components/Welcome.tsx +28 -31
  108. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +245 -0
  109. rasa/core/channels/inspector/src/helpers/audio/microphone-processor.js +12 -0
  110. rasa/core/channels/inspector/src/helpers/audio/playback-processor.js +36 -0
  111. rasa/core/channels/inspector/src/helpers/conversation.ts +7 -7
  112. rasa/core/channels/inspector/src/helpers/formatters.test.ts +181 -181
  113. rasa/core/channels/inspector/src/helpers/formatters.ts +111 -111
  114. rasa/core/channels/inspector/src/helpers/utils.ts +78 -61
  115. rasa/core/channels/inspector/src/main.tsx +8 -8
  116. rasa/core/channels/inspector/src/theme/Button/Button.ts +8 -8
  117. rasa/core/channels/inspector/src/theme/Heading/Heading.ts +7 -7
  118. rasa/core/channels/inspector/src/theme/Input/Input.ts +9 -9
  119. rasa/core/channels/inspector/src/theme/Link/Link.ts +6 -6
  120. rasa/core/channels/inspector/src/theme/Modal/Modal.ts +13 -13
  121. rasa/core/channels/inspector/src/theme/Table/Table.tsx +10 -10
  122. rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +5 -5
  123. rasa/core/channels/inspector/src/theme/base/breakpoints.ts +7 -7
  124. rasa/core/channels/inspector/src/theme/base/colors.ts +64 -64
  125. rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +21 -18
  126. rasa/core/channels/inspector/src/theme/base/radii.ts +8 -8
  127. rasa/core/channels/inspector/src/theme/base/shadows.ts +5 -5
  128. rasa/core/channels/inspector/src/theme/base/sizes.ts +5 -5
  129. rasa/core/channels/inspector/src/theme/base/space.ts +12 -12
  130. rasa/core/channels/inspector/src/theme/base/styles.ts +5 -5
  131. rasa/core/channels/inspector/src/theme/base/typography.ts +12 -12
  132. rasa/core/channels/inspector/src/theme/base/zIndices.ts +3 -3
  133. rasa/core/channels/inspector/src/theme/index.ts +38 -38
  134. rasa/core/channels/inspector/src/types.ts +56 -50
  135. rasa/core/channels/inspector/yarn.lock +5 -0
  136. rasa/core/channels/mattermost.py +1 -1
  137. rasa/core/channels/rasa_chat.py +2 -4
  138. rasa/core/channels/rest.py +5 -4
  139. rasa/core/channels/socketio.py +56 -41
  140. rasa/core/channels/studio_chat.py +337 -71
  141. rasa/core/channels/vier_cvg.py +1 -2
  142. rasa/core/channels/voice_ready/audiocodes.py +4 -11
  143. rasa/core/channels/voice_stream/audiocodes.py +8 -5
  144. rasa/core/channels/voice_stream/browser_audio.py +1 -1
  145. rasa/core/channels/voice_stream/genesys.py +2 -2
  146. rasa/core/channels/voice_stream/tts/__init__.py +8 -0
  147. rasa/core/channels/voice_stream/twilio_media_streams.py +10 -5
  148. rasa/core/channels/voice_stream/voice_channel.py +65 -23
  149. rasa/core/concurrent_lock_store.py +24 -10
  150. rasa/core/evaluation/marker_tracker_loader.py +1 -1
  151. rasa/core/exporter.py +1 -1
  152. rasa/core/http_interpreter.py +3 -7
  153. rasa/core/information_retrieval/faiss.py +18 -11
  154. rasa/core/information_retrieval/ingestion/__init__.py +0 -0
  155. rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
  156. rasa/core/jobs.py +2 -1
  157. rasa/core/lock_store.py +151 -60
  158. rasa/core/nlg/contextual_response_rephraser.py +17 -7
  159. rasa/core/nlg/generator.py +5 -22
  160. rasa/core/nlg/interpolator.py +2 -3
  161. rasa/core/nlg/response.py +6 -43
  162. rasa/core/nlg/summarize.py +1 -1
  163. rasa/core/nlg/translate.py +0 -8
  164. rasa/core/policies/enterprise_search_policy.py +262 -62
  165. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +63 -0
  166. rasa/core/policies/flow_policy.py +1 -1
  167. rasa/core/policies/flows/flow_executor.py +96 -17
  168. rasa/core/policies/intentless_policy.py +57 -20
  169. rasa/core/processor.py +114 -54
  170. rasa/core/run.py +33 -11
  171. rasa/core/tracker_stores/__init__.py +0 -0
  172. rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +5 -1
  173. rasa/core/tracker_stores/dynamo_tracker_store.py +218 -0
  174. rasa/core/tracker_stores/mongo_tracker_store.py +206 -0
  175. rasa/core/tracker_stores/redis_tracker_store.py +219 -0
  176. rasa/core/tracker_stores/sql_tracker_store.py +555 -0
  177. rasa/core/tracker_stores/tracker_store.py +805 -0
  178. rasa/core/training/interactive.py +1 -1
  179. rasa/core/utils.py +24 -95
  180. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
  181. rasa/dialogue_understanding/coexistence/llm_based_router.py +10 -6
  182. rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
  183. rasa/dialogue_understanding/commands/cancel_flow_command.py +5 -1
  184. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
  185. rasa/dialogue_understanding/commands/clarify_command.py +4 -0
  186. rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
  187. rasa/dialogue_understanding/commands/correct_slots_command.py +1 -3
  188. rasa/dialogue_understanding/commands/human_handoff_command.py +2 -0
  189. rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
  190. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
  191. rasa/dialogue_understanding/commands/set_slot_command.py +10 -0
  192. rasa/dialogue_understanding/commands/skip_question_command.py +2 -0
  193. rasa/dialogue_understanding/commands/start_flow_command.py +4 -0
  194. rasa/dialogue_understanding/commands/utils.py +26 -2
  195. rasa/dialogue_understanding/generator/__init__.py +7 -1
  196. rasa/dialogue_understanding/generator/command_generator.py +4 -2
  197. rasa/dialogue_understanding/generator/command_parser.py +2 -2
  198. rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
  199. rasa/dialogue_understanding/generator/llm_based_command_generator.py +5 -17
  200. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -3
  201. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +4 -44
  202. rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
  203. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +78 -0
  204. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +26 -474
  205. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
  206. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +477 -0
  207. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -64
  208. rasa/dialogue_understanding/patterns/cancel.py +1 -2
  209. rasa/dialogue_understanding/patterns/clarify.py +1 -1
  210. rasa/dialogue_understanding/patterns/correction.py +2 -2
  211. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
  212. rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
  213. rasa/dialogue_understanding/processor/command_processor.py +6 -7
  214. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
  215. rasa/dialogue_understanding/stack/utils.py +3 -1
  216. rasa/dialogue_understanding/utils.py +68 -12
  217. rasa/dialogue_understanding_test/command_metric_calculation.py +7 -40
  218. rasa/dialogue_understanding_test/command_metrics.py +38 -0
  219. rasa/dialogue_understanding_test/du_test_case.py +58 -25
  220. rasa/dialogue_understanding_test/du_test_result.py +228 -132
  221. rasa/dialogue_understanding_test/du_test_runner.py +11 -2
  222. rasa/dialogue_understanding_test/io.py +35 -8
  223. rasa/e2e_test/e2e_test_runner.py +1 -1
  224. rasa/engine/constants.py +1 -1
  225. rasa/engine/graph.py +2 -2
  226. rasa/engine/recipes/default_recipe.py +1 -1
  227. rasa/engine/validation.py +3 -2
  228. rasa/hooks.py +2 -85
  229. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +1 -5
  230. rasa/llm_fine_tuning/utils.py +2 -4
  231. rasa/model_manager/model_api.py +90 -2
  232. rasa/model_manager/socket_bridge.py +0 -7
  233. rasa/model_manager/trainer_service.py +15 -12
  234. rasa/plugin.py +2 -15
  235. rasa/privacy/__init__.py +0 -0
  236. rasa/privacy/constants.py +83 -0
  237. rasa/privacy/event_broker_utils.py +77 -0
  238. rasa/privacy/privacy_config.py +281 -0
  239. rasa/privacy/privacy_config_schema.json +86 -0
  240. rasa/privacy/privacy_filter.py +340 -0
  241. rasa/privacy/privacy_manager.py +576 -0
  242. rasa/server.py +23 -2
  243. rasa/shared/constants.py +13 -4
  244. rasa/shared/core/command_payload_reader.py +1 -5
  245. rasa/shared/core/constants.py +4 -3
  246. rasa/shared/core/domain.py +172 -11
  247. rasa/shared/core/events.py +100 -6
  248. rasa/shared/core/flows/flow.py +35 -8
  249. rasa/shared/core/flows/flow_step.py +26 -4
  250. rasa/shared/core/flows/flow_step_links.py +15 -0
  251. rasa/shared/core/flows/flow_step_sequence.py +6 -0
  252. rasa/shared/core/flows/flows_yaml_schema.json +3 -0
  253. rasa/shared/core/flows/nlu_trigger.py +13 -0
  254. rasa/shared/core/flows/steps/action.py +7 -4
  255. rasa/shared/core/flows/steps/call.py +11 -4
  256. rasa/shared/core/flows/steps/collect.py +71 -6
  257. rasa/shared/core/flows/steps/internal.py +6 -1
  258. rasa/shared/core/flows/steps/link.py +7 -4
  259. rasa/shared/core/flows/steps/no_operation.py +7 -4
  260. rasa/shared/core/flows/steps/set_slots.py +8 -4
  261. rasa/shared/core/flows/validation.py +16 -3
  262. rasa/shared/core/flows/yaml_flows_io.py +106 -5
  263. rasa/shared/core/slots.py +33 -1
  264. rasa/shared/core/trackers.py +4 -10
  265. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
  266. rasa/shared/importers/importer.py +14 -0
  267. rasa/shared/importers/static.py +63 -0
  268. rasa/shared/providers/constants.py +0 -9
  269. rasa/shared/providers/llm/_base_litellm_client.py +4 -14
  270. rasa/shared/providers/llm/default_litellm_llm_client.py +2 -2
  271. rasa/shared/providers/llm/litellm_router_llm_client.py +7 -17
  272. rasa/shared/providers/llm/llm_client.py +15 -24
  273. rasa/shared/providers/llm/self_hosted_llm_client.py +2 -10
  274. rasa/shared/utils/common.py +43 -1
  275. rasa/shared/utils/llm.py +155 -3
  276. rasa/shared/utils/yaml.py +32 -0
  277. rasa/studio/data_handler.py +3 -3
  278. rasa/studio/download/__init__.py +0 -0
  279. rasa/studio/download/domains.py +49 -0
  280. rasa/studio/download/download.py +416 -0
  281. rasa/studio/download/flows.py +351 -0
  282. rasa/studio/link.py +200 -0
  283. rasa/studio/pull.py +94 -0
  284. rasa/studio/push.py +131 -0
  285. rasa/studio/results_logger.py +6 -1
  286. rasa/studio/upload.py +185 -71
  287. rasa/telemetry.py +83 -26
  288. rasa/tracing/config.py +4 -5
  289. rasa/tracing/constants.py +19 -1
  290. rasa/tracing/instrumentation/attribute_extractors.py +49 -11
  291. rasa/tracing/instrumentation/instrumentation.py +54 -3
  292. rasa/tracing/instrumentation/metrics.py +98 -15
  293. rasa/tracing/metric_instrument_provider.py +75 -3
  294. rasa/utils/common.py +37 -27
  295. rasa/utils/endpoints.py +22 -1
  296. rasa/utils/licensing.py +2 -3
  297. rasa/utils/log_utils.py +1 -45
  298. rasa/validator.py +9 -11
  299. rasa/version.py +1 -1
  300. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/METADATA +12 -14
  301. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/RECORD +318 -294
  302. rasa/anonymization/__init__.py +0 -2
  303. rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
  304. rasa/anonymization/anonymization_pipeline.py +0 -286
  305. rasa/anonymization/anonymization_rule_executor.py +0 -266
  306. rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
  307. rasa/anonymization/schemas/config.yml +0 -47
  308. rasa/anonymization/utils.py +0 -118
  309. rasa/cli/project_templates/calm/config.yml +0 -10
  310. rasa/cli/project_templates/calm/credentials.yml +0 -33
  311. rasa/cli/project_templates/calm/endpoints.yml +0 -58
  312. rasa/cli/project_templates/default/actions/actions.py +0 -27
  313. rasa/cli/project_templates/default/data/nlu.yml +0 -91
  314. rasa/cli/project_templates/default/data/rules.yml +0 -13
  315. rasa/cli/project_templates/default/data/stories.yml +0 -30
  316. rasa/cli/project_templates/default/domain.yml +0 -34
  317. rasa/cli/project_templates/default/tests/test_stories.yml +0 -91
  318. rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
  319. rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
  320. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
  321. rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
  322. rasa/core/tracker_store.py +0 -1792
  323. rasa/monkey_patches.py +0 -91
  324. rasa/studio/download.py +0 -489
  325. /rasa/{cli/project_templates/calm/actions → builder}/__init__.py +0 -0
  326. /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
  327. /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
  328. /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
  329. /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
  330. /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
  331. /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
  332. /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
  333. /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
  334. /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
  335. /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
  336. /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
  337. /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
  338. /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
  339. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/NOTICE +0 -0
  340. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/WHEEL +0 -0
  341. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.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
  )
@@ -134,6 +136,22 @@ ALL_DOMAIN_KEYS = [
134
136
 
135
137
  PREV_PREFIX = "prev_"
136
138
 
139
+ MERGE_FUNC_MAPPING: Dict[Text, Callable[..., Any]] = {
140
+ KEY_ACTIONS: rasa.shared.utils.common.merge_lists_of_dicts,
141
+ KEY_RESPONSES: rasa.shared.utils.common.merge_dicts,
142
+ KEY_SLOTS: rasa.shared.utils.common.merge_dicts,
143
+ KEY_INTENTS: rasa.shared.utils.common.merge_lists_of_dicts,
144
+ KEY_ENTITIES: rasa.shared.utils.common.merge_lists_of_dicts,
145
+ KEY_E2E_ACTIONS: rasa.shared.utils.common.merge_lists,
146
+ KEY_FORMS: rasa.shared.utils.common.merge_dicts,
147
+ }
148
+
149
+ DICT_DATA_KEYS = [
150
+ key
151
+ for key, value in MERGE_FUNC_MAPPING.items()
152
+ if value == rasa.shared.utils.common.merge_dicts
153
+ ]
154
+
137
155
  # State is a dictionary with keys (USER, PREVIOUS_ACTION, SLOTS, ACTIVE_LOOP)
138
156
  # representing the origin of a SubState;
139
157
  # the values are SubStates, that contain the information needed for featurization
@@ -290,6 +308,11 @@ class Domain:
290
308
  responses = data.get(KEY_RESPONSES, {})
291
309
 
292
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
+ )
293
316
  slots = cls.collect_slots(domain_slots)
294
317
  domain_actions = data.get(KEY_ACTIONS, [])
295
318
  actions = cls._collect_action_names(domain_actions)
@@ -466,17 +489,7 @@ class Domain:
466
489
 
467
490
  duplicates: Dict[Text, List[Text]] = {}
468
491
 
469
- merge_func_mappings: Dict[Text, Callable[..., Any]] = {
470
- KEY_INTENTS: rasa.shared.utils.common.merge_lists_of_dicts,
471
- KEY_ENTITIES: rasa.shared.utils.common.merge_lists_of_dicts,
472
- KEY_ACTIONS: rasa.shared.utils.common.merge_lists_of_dicts,
473
- KEY_E2E_ACTIONS: rasa.shared.utils.common.merge_lists,
474
- KEY_FORMS: rasa.shared.utils.common.merge_dicts,
475
- KEY_RESPONSES: rasa.shared.utils.common.merge_dicts,
476
- KEY_SLOTS: rasa.shared.utils.common.merge_dicts,
477
- }
478
-
479
- for key, merge_func in merge_func_mappings.items():
492
+ for key, merge_func in MERGE_FUNC_MAPPING.items():
480
493
  duplicates[key] = rasa.shared.utils.common.extract_duplicates(
481
494
  combined.get(key, []), domain_dict.get(key, [])
482
495
  )
@@ -494,6 +507,74 @@ class Domain:
494
507
 
495
508
  return combined
496
509
 
510
+ def partial_merge(self, other: Domain) -> Domain:
511
+ """
512
+ Returns a new Domain with intersection-based merging:
513
+ - For each domain section only overwrite items that already exist in self.
514
+ - Brand-new items in `other` are ignored.
515
+
516
+ Args:
517
+ other: The domain to merge with.
518
+
519
+ Returns:
520
+ A new Domain object with the merged content.
521
+ """
522
+ updated_self = copy.deepcopy(self.as_dict())
523
+ other_dict = other.as_dict()
524
+
525
+ keys_to_merge = MERGE_FUNC_MAPPING.keys()
526
+ for key in keys_to_merge:
527
+ if key in DICT_DATA_KEYS:
528
+ # Merge dictionaries
529
+ self_val = updated_self.get(key, {})
530
+ other_val = other_dict.get(key, {})
531
+ updated_self[key] = rasa.shared.utils.common.partial_merge_dict(
532
+ self_val, other_val
533
+ )
534
+ else:
535
+ # Merge lists
536
+ self_val = updated_self.get(key, [])
537
+ other_val = other_dict.get(key, [])
538
+ is_same_item_fn = SAME_ITEM_FUNCTIONS.get(key, default_is_same_item)
539
+ updated_self[key] = rasa.shared.utils.common.partial_merge_list(
540
+ self_val, other_val, is_same_item_fn
541
+ )
542
+
543
+ return Domain.from_dict(updated_self)
544
+
545
+ def difference(self, other: Domain) -> Domain:
546
+ """
547
+ Returns a new Domain containing items in `self` that are NOT in `other`,
548
+ using simple equality checks for dict/list items.
549
+
550
+ Args:
551
+ other: The domain to compare with.
552
+
553
+ Returns:
554
+ A new Domain object with the difference content.
555
+ """
556
+ self_dict = self.as_dict()
557
+ other_dict = other.as_dict()
558
+
559
+ difference_dict = {}
560
+ for key in MERGE_FUNC_MAPPING.keys():
561
+ is_dict = key in DICT_DATA_KEYS
562
+ self_val = self_dict.get(key, {} if is_dict else [])
563
+ other_val = other_dict.get(key, {} if is_dict else [])
564
+
565
+ if is_dict and isinstance(self_val, dict) and isinstance(other_val, dict):
566
+ difference_dict[key] = {
567
+ k: v
568
+ for k, v in self_val.items()
569
+ if k not in other_val or v != other_val[k]
570
+ }
571
+ else:
572
+ difference_dict[key] = [
573
+ item for item in self_val if item not in other_val
574
+ ] # type: ignore[assignment]
575
+
576
+ return Domain.from_dict(difference_dict)
577
+
497
578
  def _preprocess_domain_dict(
498
579
  self,
499
580
  data: Dict,
@@ -2120,6 +2201,11 @@ class Domain:
2120
2201
  """Remove all builtin slots from the domain."""
2121
2202
  self.slots = [slot for slot in self.slots if not slot.is_builtin]
2122
2203
 
2204
+ def __eq__(self, other: object) -> bool:
2205
+ if isinstance(other, Domain):
2206
+ return self.as_dict() == other.as_dict()
2207
+ return False
2208
+
2123
2209
 
2124
2210
  def warn_about_duplicates_found_during_domain_merging(
2125
2211
  duplicates: Dict[Text, List[Text]],
@@ -2178,3 +2264,78 @@ def _validate_forms(forms: Union[Dict, List]) -> None:
2178
2264
  f"the keyword `{REQUIRED_SLOTS_KEY}` is required. "
2179
2265
  f"Please see {DOCS_URL_FORMS} for more information."
2180
2266
  )
2267
+
2268
+
2269
+ def is_same_entity(e1: Any, e2: Any) -> bool:
2270
+ """Check if two entities are the 'same' (string or dict).
2271
+
2272
+ Args:
2273
+ e1: First entity to compare.
2274
+ e2: Second entity to compare.
2275
+
2276
+ Returns:
2277
+ True if the entities are the same, False otherwise.
2278
+ """
2279
+ if isinstance(e1, str) and isinstance(e2, str):
2280
+ return e1 == e2
2281
+
2282
+ if isinstance(e1, dict) and isinstance(e2, dict):
2283
+ return (
2284
+ e1.get(ENTITY_ATTRIBUTE_TYPE) == e2.get(ENTITY_ATTRIBUTE_TYPE)
2285
+ and e1.get(ENTITY_ATTRIBUTE_ROLE) == e2.get(ENTITY_ATTRIBUTE_ROLE)
2286
+ and e1.get(ENTITY_ATTRIBUTE_GROUP) == e2.get(ENTITY_ATTRIBUTE_GROUP)
2287
+ )
2288
+
2289
+ return False
2290
+
2291
+
2292
+ def is_same_intent(i1: Any, i2: Any) -> bool:
2293
+ """Check if two intents are the 'same' (string or dict).
2294
+
2295
+ Args:
2296
+ i1: First intent to compare.
2297
+ i2: Second intent to compare.
2298
+
2299
+ Returns:
2300
+ True if the intents are the same, False otherwise.
2301
+ """
2302
+ if isinstance(i1, str) and isinstance(i2, str):
2303
+ return i1 == i2
2304
+
2305
+ if isinstance(i1, dict) and isinstance(i2, dict):
2306
+ key1, key2 = next(iter(i1.keys())), next(iter((i2.keys())))
2307
+ return key1 == key2
2308
+
2309
+ return False
2310
+
2311
+
2312
+ def is_same_action(a1: Any, a2: Any) -> bool:
2313
+ """Check if two actions are the 'same' (string or dict).
2314
+
2315
+ Args:
2316
+ a1: First action to compare.
2317
+ a2: Second action to compare.
2318
+
2319
+ Returns:
2320
+ True if the actions are the same, False otherwise.
2321
+ """
2322
+ if isinstance(a1, str) and isinstance(a2, str):
2323
+ return a1 == a2
2324
+
2325
+ if isinstance(a1, dict) and isinstance(a2, dict):
2326
+ key1, key2 = next(iter((a1.keys()))), next(iter((a2.keys())))
2327
+ return key1 == key2
2328
+
2329
+ return False
2330
+
2331
+
2332
+ def default_is_same_item(a: Any, b: Any) -> bool:
2333
+ """Fallback exact equality check if a key doesn't need special handling."""
2334
+ return a == b
2335
+
2336
+
2337
+ SAME_ITEM_FUNCTIONS: Dict[Text, Callable[[Any, Any], bool]] = {
2338
+ KEY_ENTITIES: is_same_entity,
2339
+ KEY_INTENTS: is_same_intent,
2340
+ KEY_ACTIONS: is_same_action,
2341
+ }
@@ -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,
@@ -107,6 +109,8 @@ if TYPE_CHECKING:
107
109
  logger = logging.getLogger(__name__)
108
110
  structlogger = structlog.get_logger()
109
111
 
112
+ INVALID_DATETIME_ERROR_MESSAGE = "`anonymized_at` must be a datetime object."
113
+
110
114
 
111
115
  def deserialise_events(serialized_events: List[Dict[Text, Any]]) -> List["Event"]:
112
116
  """Convert a list of dictionaries to a list of corresponding events.
@@ -122,9 +126,7 @@ def deserialise_events(serialized_events: List[Dict[Text, Any]]) -> List["Event"
122
126
  if event:
123
127
  deserialised.append(event)
124
128
  else:
125
- structlogger.warning(
126
- "event.deserialization.failed", rasa_event=copy.deepcopy(event)
127
- )
129
+ structlogger.warning("event.deserialization.failed")
128
130
 
129
131
  return deserialised
130
132
 
@@ -451,6 +453,7 @@ class UserUttered(Event):
451
453
  message_id: Optional[Text] = None,
452
454
  metadata: Optional[Dict] = None,
453
455
  use_text_for_featurization: Optional[bool] = None,
456
+ anonymized_at: Optional[float] = None,
454
457
  ) -> None:
455
458
  """Creates event for incoming user message.
456
459
 
@@ -465,6 +468,7 @@ class UserUttered(Event):
465
468
  message_id: Unique ID for message.
466
469
  use_text_for_featurization: `True` if the message's text was used to predict
467
470
  next action. `False` if the message's intent was used.
471
+ anonymized_at: When the event was anonymized in the tracker store.
468
472
 
469
473
  """
470
474
  self.text = text
@@ -498,6 +502,27 @@ class UserUttered(Event):
498
502
  if parse_data:
499
503
  self.parse_data.update(**parse_data)
500
504
 
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
+ )
510
+
511
+ @property
512
+ def anonymized_at(self) -> Optional[datetime]:
513
+ """Returns the time when the event was anonymized in the tracker store.
514
+
515
+ If the event was not anonymized, it returns None.
516
+ """
517
+ return self._anonymized_at
518
+
519
+ @anonymized_at.setter
520
+ def anonymized_at(self, value: Optional[datetime]) -> None:
521
+ """Sets the time when the event was anonymized in the tracker store."""
522
+ if value is not None and not isinstance(value, datetime):
523
+ raise ValueError(INVALID_DATETIME_ERROR_MESSAGE)
524
+ self._anonymized_at = value
525
+
501
526
  @staticmethod
502
527
  def _from_parse_data(
503
528
  text: Text,
@@ -506,6 +531,7 @@ class UserUttered(Event):
506
531
  input_channel: Optional[Text] = None,
507
532
  message_id: Optional[Text] = None,
508
533
  metadata: Optional[Dict] = None,
534
+ anonymized_at: Optional[float] = None,
509
535
  ) -> "UserUttered":
510
536
  return UserUttered(
511
537
  text,
@@ -516,6 +542,7 @@ class UserUttered(Event):
516
542
  input_channel,
517
543
  message_id,
518
544
  metadata,
545
+ anonymized_at,
519
546
  )
520
547
 
521
548
  def __hash__(self) -> int:
@@ -614,6 +641,9 @@ class UserUttered(Event):
614
641
  "input_channel": getattr(self, "input_channel", None),
615
642
  "message_id": getattr(self, "message_id", None),
616
643
  "metadata": self.metadata,
644
+ "anonymized_at": self.anonymized_at.timestamp()
645
+ if self.anonymized_at
646
+ else None,
617
647
  }
618
648
  )
619
649
  return _dict
@@ -673,6 +703,7 @@ class UserUttered(Event):
673
703
  parameters.get("input_channel"),
674
704
  parameters.get("message_id"),
675
705
  parameters.get("metadata"),
706
+ parameters.get("anonymized_at"),
676
707
  )
677
708
  ]
678
709
  except KeyError as e:
@@ -900,6 +931,7 @@ class BotUttered(SkipEventInMDStoryMixin):
900
931
  data: Optional[Dict] = None,
901
932
  metadata: Optional[Dict[Text, Any]] = None,
902
933
  timestamp: Optional[float] = None,
934
+ anonymized_at: Optional[float] = None,
903
935
  ) -> None:
904
936
  """Creates event for a bot response.
905
937
 
@@ -908,11 +940,32 @@ class BotUttered(SkipEventInMDStoryMixin):
908
940
  data: Additional data for more complex utterances (e.g. buttons).
909
941
  timestamp: When the event was created.
910
942
  metadata: Additional event metadata.
943
+ anonymized_at: When the event was anonymized in the tracker store.
911
944
  """
912
945
  self.text = text
913
946
  self.data = data or {}
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
+ )
914
952
  super().__init__(timestamp, metadata)
915
953
 
954
+ @property
955
+ def anonymized_at(self) -> Optional[datetime]:
956
+ """Returns the time when the event was anonymized in the tracker store.
957
+
958
+ If the event was not anonymized, it returns None.
959
+ """
960
+ return self._anonymized_at
961
+
962
+ @anonymized_at.setter
963
+ def anonymized_at(self, value: Optional[datetime]) -> None:
964
+ """Sets the time when the event was anonymized in the tracker store."""
965
+ if value is not None and not isinstance(value, datetime):
966
+ raise ValueError(INVALID_DATETIME_ERROR_MESSAGE)
967
+ self._anonymized_at = value
968
+
916
969
  def __members(self) -> Tuple[Optional[Text], Text, Text]:
917
970
  data_no_nones = {k: v for k, v in self.data.items() if v is not None}
918
971
  meta_no_nones = {k: v for k, v in self.metadata.items() if v is not None}
@@ -999,7 +1052,16 @@ class BotUttered(SkipEventInMDStoryMixin):
999
1052
  def as_dict(self) -> Dict[Text, Any]:
1000
1053
  """Returns serialized event."""
1001
1054
  d = super().as_dict()
1002
- d.update({"text": self.text, "data": self.data, "metadata": self.metadata})
1055
+ d.update(
1056
+ {
1057
+ "text": self.text,
1058
+ "data": self.data,
1059
+ "metadata": self.metadata,
1060
+ "anonymized_at": self.anonymized_at.timestamp()
1061
+ if self.anonymized_at
1062
+ else None,
1063
+ }
1064
+ )
1003
1065
  return d
1004
1066
 
1005
1067
  @classmethod
@@ -1010,6 +1072,7 @@ class BotUttered(SkipEventInMDStoryMixin):
1010
1072
  parameters.get("data"),
1011
1073
  parameters.get("metadata"),
1012
1074
  parameters.get("timestamp"),
1075
+ parameters.get("anonymized_at"),
1013
1076
  )
1014
1077
  except KeyError as e:
1015
1078
  raise ValueError(f"Failed to parse bot uttered event. {e}")
@@ -1034,6 +1097,7 @@ class SlotSet(Event):
1034
1097
  timestamp: Optional[float] = None,
1035
1098
  metadata: Optional[Dict[Text, Any]] = None,
1036
1099
  filled_by: Optional[str] = None,
1100
+ anonymized_at: Optional[float] = None,
1037
1101
  ) -> None:
1038
1102
  """Creates event to set slot.
1039
1103
 
@@ -1046,8 +1110,28 @@ class SlotSet(Event):
1046
1110
  self.key = key
1047
1111
  self.value = value
1048
1112
  self._filled_by = filled_by
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
+ )
1049
1118
  super().__init__(timestamp, metadata)
1050
1119
 
1120
+ @property
1121
+ def anonymized_at(self) -> Optional[datetime]:
1122
+ """Returns the time when the event was anonymized in the tracker store.
1123
+
1124
+ If the event was not anonymized, it returns None.
1125
+ """
1126
+ return self._anonymized_at
1127
+
1128
+ @anonymized_at.setter
1129
+ def anonymized_at(self, value: Optional[datetime]) -> None:
1130
+ """Sets the time when the event was anonymized in the tracker store."""
1131
+ if value is not None and not isinstance(value, datetime):
1132
+ raise ValueError(INVALID_DATETIME_ERROR_MESSAGE)
1133
+ self._anonymized_at = value
1134
+
1051
1135
  def __repr__(self) -> Text:
1052
1136
  """Returns text representation of event."""
1053
1137
  return f"SlotSet(key: {self.key}, value: {self.value})"
@@ -1092,7 +1176,16 @@ class SlotSet(Event):
1092
1176
  def as_dict(self) -> Dict[Text, Any]:
1093
1177
  """Returns serialized event."""
1094
1178
  d = super().as_dict()
1095
- d.update({"name": self.key, "value": self.value, "filled_by": self.filled_by})
1179
+ d.update(
1180
+ {
1181
+ "name": self.key,
1182
+ "value": self.value,
1183
+ "filled_by": self.filled_by,
1184
+ "anonymized_at": self.anonymized_at.timestamp()
1185
+ if self.anonymized_at
1186
+ else None,
1187
+ }
1188
+ )
1096
1189
  return d
1097
1190
 
1098
1191
  @classmethod
@@ -1104,6 +1197,7 @@ class SlotSet(Event):
1104
1197
  parameters.get("timestamp"),
1105
1198
  parameters.get("metadata"),
1106
1199
  filled_by=parameters.get("filled_by"),
1200
+ anonymized_at=parameters.get("anonymized_at"),
1107
1201
  )
1108
1202
  except KeyError as e:
1109
1203
  raise ValueError(f"Failed to parse set slot event. {e}")
@@ -53,6 +53,8 @@ from rasa.shared.core.slots import Slot
53
53
 
54
54
  structlogger = structlog.get_logger()
55
55
 
56
+ DEFAULT_RUN_PATTERN_COMPLETED = True
57
+
56
58
 
57
59
  class FlowLanguageTranslation(BaseModel):
58
60
  """Represents the translation of the flow properties in a specific language."""
@@ -61,8 +63,15 @@ class FlowLanguageTranslation(BaseModel):
61
63
  """The human-readable name of the flow."""
62
64
 
63
65
  class Config:
66
+ """Config for the FlowLanguageTranslation class."""
67
+
64
68
  extra = "ignore"
65
69
 
70
+ def __eq__(self, other: object) -> bool:
71
+ if isinstance(other, FlowLanguageTranslation):
72
+ return self.name == other.name
73
+ return False
74
+
66
75
 
67
76
  @dataclass
68
77
  class Flow:
@@ -90,8 +99,25 @@ class Flow:
90
99
  """The path to the file where the flow is stored."""
91
100
  persisted_slots: List[str] = field(default_factory=list)
92
101
  """The list of slots that should be persisted after the flow ends."""
93
- run_pattern_completed: bool = True
102
+ run_pattern_completed: bool = DEFAULT_RUN_PATTERN_COMPLETED
94
103
  """Whether the pattern_completed flow should be run after the flow ends."""
104
+ metadata: Dict[Text, Any] = field(default_factory=dict)
105
+
106
+ def __eq__(self, other: object) -> bool:
107
+ if isinstance(other, Flow):
108
+ return (
109
+ self.id == other.id
110
+ and self.custom_name == other.custom_name
111
+ and self.description == other.description
112
+ and self.translation == other.translation
113
+ and self.guard_condition == other.guard_condition
114
+ and self.step_sequence == other.step_sequence
115
+ and self.nlu_triggers == other.nlu_triggers
116
+ and self.always_include_in_prompt == other.always_include_in_prompt
117
+ and self.persisted_slots == other.persisted_slots
118
+ and self.run_pattern_completed == other.run_pattern_completed
119
+ )
120
+ return False
95
121
 
96
122
  @staticmethod
97
123
  def from_json(
@@ -130,7 +156,9 @@ class Flow:
130
156
  # data. When the model is trained, take the provided file_path.
131
157
  file_path=data.get(KEY_FILE_PATH) if KEY_FILE_PATH in data else file_path,
132
158
  persisted_slots=data.get(KEY_PERSISTED_SLOTS, []),
133
- run_pattern_completed=data.get(KEY_RUN_PATTERN_COMPLETED, True),
159
+ run_pattern_completed=data.get(
160
+ KEY_RUN_PATTERN_COMPLETED, DEFAULT_RUN_PATTERN_COMPLETED
161
+ ),
134
162
  translation=extract_translations(
135
163
  translation_data=data.get(KEY_TRANSLATION, {})
136
164
  ),
@@ -209,7 +237,7 @@ class Flow:
209
237
  if self.persisted_slots:
210
238
  data[KEY_PERSISTED_SLOTS] = self.persisted_slots
211
239
  if self.run_pattern_completed is not None:
212
- data["run_pattern_completed"] = self.run_pattern_completed
240
+ data[KEY_RUN_PATTERN_COMPLETED] = self.run_pattern_completed
213
241
  if self.translation:
214
242
  data[KEY_TRANSLATION] = {
215
243
  language_code: translation.dict()
@@ -232,9 +260,9 @@ class Flow:
232
260
  return translation.name if translation else None
233
261
 
234
262
  def readable_name(self, language: Optional[Language] = None) -> str:
235
- """
236
- Returns the flow's name in the specified language if available; otherwise
237
- falls back to the flow's name, and finally the flow's ID.
263
+ """Returns the flow's name in the specified language if available.
264
+
265
+ Otherwise falls back to the flow's name, and finally the flow's ID.
238
266
 
239
267
  Args:
240
268
  language: Preferred language code.
@@ -378,8 +406,7 @@ class Flow:
378
406
  structlogger.error(
379
407
  "command_generator.validate_flow_starting_conditions.error",
380
408
  predicate=self.guard_condition,
381
- context=context,
382
- slots=slots,
409
+ flow_id=self.id,
383
410
  error=str(e),
384
411
  )
385
412
  return False
@@ -52,7 +52,13 @@ def step_from_json(flow_id: Text, data: Dict[Text, Any]) -> FlowStep:
52
52
  return SetSlotsFlowStep.from_json(flow_id, data)
53
53
  if "noop" in data:
54
54
  return NoOperationFlowStep.from_json(flow_id, data)
55
- raise RasaException(f"Failed to parse step from json. Unknown type for {data}.")
55
+
56
+ required_properties = ["action", "collect", "link", "call", "set_slots", "noop"]
57
+ raise RasaException(
58
+ f"Failed to parse step from json. Unknown type for {data}. "
59
+ f"At lest one of the following properties is required: "
60
+ f"{', '.join(required_properties)}"
61
+ )
56
62
 
57
63
 
58
64
  @dataclass
@@ -100,7 +106,9 @@ class FlowStep:
100
106
  """Most steps allow linking to the next step. But some don't."""
101
107
  return True
102
108
 
103
- def as_json(self) -> Dict[Text, Any]:
109
+ def as_json(
110
+ self, step_properties: Optional[Dict[Text, Any]] = None
111
+ ) -> Dict[Text, Any]:
104
112
  """Serialize the FlowStep object.
105
113
 
106
114
  Returns:
@@ -108,10 +116,13 @@ class FlowStep:
108
116
  """
109
117
  data: Dict[Text, Any] = {"id": self.id}
110
118
 
111
- if dumped_next := self.next.as_json():
112
- data["next"] = dumped_next
119
+ if step_properties:
120
+ data.update(step_properties)
121
+
113
122
  if self.description:
114
123
  data["description"] = self.description
124
+ if dumped_next := self.next.as_json():
125
+ data["next"] = dumped_next
115
126
  if self.metadata:
116
127
  data["metadata"] = self.metadata
117
128
  return data
@@ -143,6 +154,17 @@ class FlowStep:
143
154
  """Return all the utterances used in this step."""
144
155
  return set()
145
156
 
157
+ def __eq__(self, other: object) -> bool:
158
+ if not isinstance(other, FlowStep):
159
+ return False
160
+
161
+ return (
162
+ self.idx == other.idx
163
+ and self.description == other.description
164
+ and self.next == other.next
165
+ and self.flow_id == other.flow_id
166
+ )
167
+
146
168
 
147
169
  @dataclass
148
170
  class FlowStepWithFlowReference:
@@ -74,6 +74,11 @@ class FlowStepLinks:
74
74
  depth = max(depth, link.depth_in_tree())
75
75
  return depth
76
76
 
77
+ def __eq__(self, other: object) -> bool:
78
+ if isinstance(other, FlowStepLinks):
79
+ return self.links == other.links
80
+ return False
81
+
77
82
 
78
83
  class FlowStepLink:
79
84
  """A flow step link that links two steps in a single flow."""
@@ -193,6 +198,11 @@ class BranchingFlowStepLink(FlowStepLink):
193
198
  return depth + 1
194
199
  return 1
195
200
 
201
+ def __eq__(self, other: object) -> bool:
202
+ if isinstance(other, BranchingFlowStepLink):
203
+ return self.target_reference == other.target_reference
204
+ return False
205
+
196
206
 
197
207
  @dataclass
198
208
  class IfFlowStepLink(BranchingFlowStepLink):
@@ -324,3 +334,8 @@ class StaticFlowStepLink(FlowStepLink):
324
334
  def depth_in_tree(self) -> int:
325
335
  """Returns the depth in the tree."""
326
336
  return 0
337
+
338
+ def __eq__(self, other: object) -> bool:
339
+ if isinstance(other, StaticFlowStepLink):
340
+ return self.target_step_id == other.target_step_id
341
+ return False
@@ -70,3 +70,9 @@ class FlowStepSequence:
70
70
  def empty(cls) -> FlowStepSequence:
71
71
  """Create an empty FlowStepSequence object."""
72
72
  return cls(child_steps=[])
73
+
74
+ def __eq__(self, other: object) -> bool:
75
+ return (
76
+ isinstance(other, FlowStepSequence)
77
+ and self.child_steps == other.child_steps
78
+ )
@@ -244,6 +244,9 @@
244
244
  }
245
245
  }
246
246
  }
247
+ },
248
+ "silence_timeout": {
249
+ "type": "number"
247
250
  }
248
251
  }
249
252
  }