rasa-pro 3.12.21__py3-none-any.whl → 3.13.0__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 (354) hide show
  1. rasa/__main__.py +3 -4
  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 +2 -2
  6. rasa/cli/export.py +5 -3
  7. rasa/cli/inspect.py +7 -0
  8. rasa/cli/llm_fine_tuning.py +1 -1
  9. rasa/cli/project_templates/default/config.yml +5 -32
  10. rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_cancels_during_a_correction.yml +1 -1
  11. rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +1 -1
  12. rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_handle.yml +1 -1
  13. rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_name.yml +1 -1
  14. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +1 -1
  15. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_lists_contacts.yml +1 -1
  16. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact.yml +1 -1
  17. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact_from_list.yml +1 -1
  18. rasa/cli/project_templates/default/endpoints.yml +18 -2
  19. rasa/cli/project_templates/defaults.py +133 -0
  20. rasa/cli/project_templates/tutorial/config.yml +1 -1
  21. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  22. rasa/cli/run.py +1 -1
  23. rasa/cli/scaffold.py +2 -3
  24. rasa/cli/shell.py +6 -1
  25. rasa/cli/studio/download.py +0 -22
  26. rasa/cli/studio/link.py +36 -0
  27. rasa/cli/studio/pull.py +79 -0
  28. rasa/cli/studio/push.py +78 -0
  29. rasa/cli/studio/studio.py +12 -0
  30. rasa/cli/studio/train.py +1 -5
  31. rasa/cli/studio/upload.py +6 -4
  32. rasa/cli/train.py +5 -1
  33. rasa/cli/utils.py +1 -1
  34. rasa/cli/x.py +1 -1
  35. rasa/constants.py +2 -0
  36. rasa/core/__init__.py +0 -16
  37. rasa/core/actions/action.py +43 -29
  38. rasa/core/actions/action_repeat_bot_messages.py +18 -22
  39. rasa/core/actions/action_run_slot_rejections.py +1 -2
  40. rasa/core/agent.py +24 -3
  41. rasa/core/available_endpoints.py +146 -0
  42. rasa/core/brokers/kafka.py +4 -0
  43. rasa/core/brokers/pika.py +5 -2
  44. rasa/core/brokers/sql.py +1 -1
  45. rasa/core/channels/__init__.py +3 -0
  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-371401b1.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
  56. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
  58. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
  61. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-f837ca8a.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-8717ac54.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-94f38b83.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
  67. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-0d0a2c10.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-58ea0305.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-cce6f8a1.js} +123 -123
  73. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-95be5545.js} +1 -1
  75. rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-da885b9b.js} +1 -1
  76. rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-f1c817d3.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-d42801e6.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
  82. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
  84. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-e53a2028.js} +1 -1
  85. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-d0226ca5.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-0e21dc00.js} +1 -1
  88. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-9588494e.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-74631749.js} +1 -1
  91. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-a043552f.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 +329 -68
  141. rasa/core/channels/vier_cvg.py +1 -2
  142. rasa/core/channels/voice_ready/audiocodes.py +4 -11
  143. rasa/core/channels/voice_ready/jambonz.py +5 -6
  144. rasa/core/channels/voice_ready/twilio_voice.py +13 -12
  145. rasa/core/channels/voice_ready/utils.py +22 -0
  146. rasa/core/channels/voice_stream/audiocodes.py +13 -16
  147. rasa/core/channels/voice_stream/browser_audio.py +1 -1
  148. rasa/core/channels/voice_stream/genesys.py +37 -18
  149. rasa/core/channels/voice_stream/jambonz.py +232 -0
  150. rasa/core/channels/voice_stream/tts/__init__.py +8 -0
  151. rasa/core/channels/voice_stream/twilio_media_streams.py +15 -12
  152. rasa/core/channels/voice_stream/voice_channel.py +71 -27
  153. rasa/core/concurrent_lock_store.py +24 -10
  154. rasa/core/evaluation/marker_tracker_loader.py +1 -1
  155. rasa/core/exporter.py +37 -1
  156. rasa/core/http_interpreter.py +3 -7
  157. rasa/core/information_retrieval/faiss.py +18 -11
  158. rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
  159. rasa/core/jobs.py +2 -1
  160. rasa/core/lock_store.py +151 -60
  161. rasa/core/nlg/contextual_response_rephraser.py +17 -7
  162. rasa/core/nlg/generator.py +5 -22
  163. rasa/core/nlg/interpolator.py +2 -3
  164. rasa/core/nlg/response.py +6 -43
  165. rasa/core/nlg/summarize.py +1 -1
  166. rasa/core/nlg/translate.py +0 -8
  167. rasa/core/policies/enterprise_search_policy.py +305 -189
  168. rasa/core/policies/enterprise_search_policy_config.py +241 -0
  169. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +67 -0
  170. rasa/core/policies/flow_policy.py +1 -1
  171. rasa/core/policies/flows/flow_executor.py +102 -17
  172. rasa/core/policies/intentless_policy.py +56 -17
  173. rasa/core/processor.py +70 -49
  174. rasa/core/run.py +33 -11
  175. rasa/core/tracker_stores/__init__.py +0 -0
  176. rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +66 -1
  177. rasa/core/tracker_stores/dynamo_tracker_store.py +256 -0
  178. rasa/core/tracker_stores/mongo_tracker_store.py +223 -0
  179. rasa/core/tracker_stores/redis_tracker_store.py +252 -0
  180. rasa/core/tracker_stores/sql_tracker_store.py +582 -0
  181. rasa/core/tracker_stores/tracker_store.py +839 -0
  182. rasa/core/training/interactive.py +1 -1
  183. rasa/core/utils.py +24 -95
  184. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
  185. rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -11
  186. rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
  187. rasa/dialogue_understanding/commands/cancel_flow_command.py +3 -1
  188. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
  189. rasa/dialogue_understanding/commands/clarify_command.py +6 -2
  190. rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
  191. rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
  192. rasa/dialogue_understanding/commands/error_command.py +1 -1
  193. rasa/dialogue_understanding/commands/human_handoff_command.py +3 -3
  194. rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
  195. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
  196. rasa/dialogue_understanding/commands/set_slot_command.py +8 -4
  197. rasa/dialogue_understanding/commands/skip_question_command.py +3 -3
  198. rasa/dialogue_understanding/commands/start_flow_command.py +7 -3
  199. rasa/dialogue_understanding/generator/__init__.py +7 -1
  200. rasa/dialogue_understanding/generator/command_generator.py +4 -2
  201. rasa/dialogue_understanding/generator/command_parser.py +2 -2
  202. rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
  203. rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -2
  204. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -2
  205. rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
  206. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
  207. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
  208. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
  209. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
  210. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +79 -0
  211. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +26 -461
  212. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
  213. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +461 -0
  214. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +20 -64
  215. rasa/dialogue_understanding/patterns/cancel.py +1 -2
  216. rasa/dialogue_understanding/patterns/clarify.py +1 -1
  217. rasa/dialogue_understanding/patterns/correction.py +2 -2
  218. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +42 -27
  219. rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
  220. rasa/dialogue_understanding/processor/command_processor.py +6 -7
  221. rasa/dialogue_understanding_test/command_metric_calculation.py +7 -40
  222. rasa/dialogue_understanding_test/command_metrics.py +38 -0
  223. rasa/dialogue_understanding_test/du_test_case.py +58 -25
  224. rasa/dialogue_understanding_test/du_test_result.py +228 -132
  225. rasa/dialogue_understanding_test/du_test_runner.py +11 -2
  226. rasa/dialogue_understanding_test/du_test_schema.yml +3 -3
  227. rasa/dialogue_understanding_test/io.py +35 -8
  228. rasa/e2e_test/constants.py +1 -1
  229. rasa/e2e_test/e2e_test_runner.py +1 -1
  230. rasa/e2e_test/e2e_test_schema.yml +3 -3
  231. rasa/engine/constants.py +1 -1
  232. rasa/engine/graph.py +2 -2
  233. rasa/engine/recipes/default_recipe.py +1 -1
  234. rasa/engine/validation.py +3 -2
  235. rasa/hooks.py +2 -30
  236. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +2 -6
  237. rasa/model_manager/model_api.py +89 -1
  238. rasa/model_manager/runner_service.py +20 -4
  239. rasa/model_manager/socket_bridge.py +0 -7
  240. rasa/model_manager/trainer_service.py +10 -4
  241. rasa/plugin.py +2 -15
  242. rasa/privacy/__init__.py +0 -0
  243. rasa/privacy/constants.py +83 -0
  244. rasa/privacy/event_broker_utils.py +77 -0
  245. rasa/privacy/privacy_config.py +281 -0
  246. rasa/privacy/privacy_config_schema.json +86 -0
  247. rasa/privacy/privacy_filter.py +393 -0
  248. rasa/privacy/privacy_manager.py +594 -0
  249. rasa/server.py +23 -2
  250. rasa/shared/constants.py +17 -0
  251. rasa/shared/core/command_payload_reader.py +1 -5
  252. rasa/shared/core/constants.py +4 -3
  253. rasa/shared/core/domain.py +172 -11
  254. rasa/shared/core/events.py +100 -6
  255. rasa/shared/core/flows/flow.py +30 -5
  256. rasa/shared/core/flows/flow_step.py +19 -3
  257. rasa/shared/core/flows/flow_step_links.py +15 -0
  258. rasa/shared/core/flows/flow_step_sequence.py +6 -0
  259. rasa/shared/core/flows/flows_yaml_schema.json +3 -0
  260. rasa/shared/core/flows/nlu_trigger.py +13 -0
  261. rasa/shared/core/flows/steps/action.py +7 -4
  262. rasa/shared/core/flows/steps/call.py +11 -4
  263. rasa/shared/core/flows/steps/collect.py +71 -6
  264. rasa/shared/core/flows/steps/internal.py +6 -1
  265. rasa/shared/core/flows/steps/link.py +7 -4
  266. rasa/shared/core/flows/steps/no_operation.py +7 -4
  267. rasa/shared/core/flows/steps/set_slots.py +8 -4
  268. rasa/shared/core/flows/validation.py +25 -5
  269. rasa/shared/core/flows/yaml_flows_io.py +106 -5
  270. rasa/shared/core/slots.py +29 -1
  271. rasa/shared/core/trackers.py +21 -10
  272. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
  273. rasa/shared/importers/importer.py +8 -0
  274. rasa/shared/providers/_configs/azure_openai_client_config.py +2 -2
  275. rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
  276. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
  277. rasa/shared/providers/_configs/openai_client_config.py +1 -1
  278. rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
  279. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
  280. rasa/shared/providers/_configs/utils.py +0 -99
  281. rasa/shared/providers/llm/default_litellm_llm_client.py +2 -2
  282. rasa/shared/utils/common.py +43 -1
  283. rasa/shared/utils/configs.py +110 -0
  284. rasa/shared/utils/constants.py +0 -3
  285. rasa/shared/utils/llm.py +245 -8
  286. rasa/shared/utils/pykwalify_extensions.py +0 -9
  287. rasa/shared/utils/yaml.py +32 -0
  288. rasa/studio/constants.py +1 -0
  289. rasa/studio/data_handler.py +33 -12
  290. rasa/studio/download.py +117 -435
  291. rasa/studio/link.py +211 -0
  292. rasa/studio/prompts.py +221 -0
  293. rasa/studio/pull/__init__.py +0 -0
  294. rasa/studio/pull/data.py +222 -0
  295. rasa/studio/pull/domains.py +60 -0
  296. rasa/studio/pull/pull.py +239 -0
  297. rasa/studio/push.py +138 -0
  298. rasa/studio/results_logger.py +6 -1
  299. rasa/studio/train.py +1 -1
  300. rasa/studio/upload.py +243 -72
  301. rasa/studio/utils.py +33 -0
  302. rasa/telemetry.py +83 -26
  303. rasa/tracing/config.py +4 -5
  304. rasa/tracing/constants.py +19 -1
  305. rasa/tracing/instrumentation/attribute_extractors.py +68 -16
  306. rasa/tracing/instrumentation/instrumentation.py +54 -3
  307. rasa/tracing/instrumentation/metrics.py +98 -15
  308. rasa/tracing/metric_instrument_provider.py +75 -3
  309. rasa/utils/common.py +43 -22
  310. rasa/utils/endpoints.py +22 -1
  311. rasa/utils/licensing.py +2 -3
  312. rasa/utils/log_utils.py +1 -45
  313. rasa/validator.py +2 -8
  314. rasa/version.py +1 -1
  315. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/METADATA +13 -14
  316. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/RECORD +333 -309
  317. rasa/anonymization/__init__.py +0 -2
  318. rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
  319. rasa/anonymization/anonymization_pipeline.py +0 -286
  320. rasa/anonymization/anonymization_rule_executor.py +0 -266
  321. rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
  322. rasa/anonymization/schemas/config.yml +0 -47
  323. rasa/anonymization/utils.py +0 -118
  324. rasa/cli/project_templates/calm/config.yml +0 -10
  325. rasa/cli/project_templates/calm/credentials.yml +0 -33
  326. rasa/cli/project_templates/calm/endpoints.yml +0 -58
  327. rasa/cli/project_templates/default/actions/actions.py +0 -27
  328. rasa/cli/project_templates/default/data/nlu.yml +0 -91
  329. rasa/cli/project_templates/default/data/rules.yml +0 -13
  330. rasa/cli/project_templates/default/data/stories.yml +0 -30
  331. rasa/cli/project_templates/default/domain.yml +0 -34
  332. rasa/cli/project_templates/default/tests/test_stories.yml +0 -91
  333. rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
  334. rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
  335. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
  336. rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
  337. rasa/core/tracker_store.py +0 -1792
  338. /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
  339. /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
  340. /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
  341. /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
  342. /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
  343. /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
  344. /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
  345. /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
  346. /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
  347. /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
  348. /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
  349. /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
  350. /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
  351. /rasa/{cli/project_templates/calm/actions → core/information_retrieval/ingestion}/__init__.py +0 -0
  352. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/NOTICE +0 -0
  353. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/WHEEL +0 -0
  354. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,594 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import copy
5
+ import datetime
6
+ import os
7
+ import queue
8
+ import time
9
+ from typing import TYPE_CHECKING, Any, Callable, List, Optional, Tuple
10
+
11
+ import structlog
12
+ from apscheduler.schedulers.background import BackgroundScheduler
13
+
14
+ import rasa.shared.core.trackers
15
+ from rasa.core.tracker_stores.tracker_store import TrackerStore
16
+ from rasa.privacy.constants import (
17
+ TEXT_KEY,
18
+ USER_CHAT_INACTIVITY_IN_MINUTES_ENV_VAR_NAME,
19
+ )
20
+ from rasa.privacy.event_broker_utils import create_event_brokers
21
+ from rasa.privacy.privacy_config import (
22
+ PrivacyConfig,
23
+ PrivacyPolicy,
24
+ validate_sensitive_slots,
25
+ )
26
+ from rasa.privacy.privacy_filter import PrivacyFilter
27
+ from rasa.shared.core.events import Event, SlotSet, UserUttered, split_events
28
+ from rasa.shared.core.trackers import DialogueStateTracker, EventVerbosity
29
+
30
+ if TYPE_CHECKING:
31
+ from asyncio import AbstractEventLoop
32
+
33
+ from rasa.core.available_endpoints import AvailableEndpoints
34
+ from rasa.core.brokers.broker import EventBroker
35
+ from rasa.shared.core.domain import Domain
36
+
37
+
38
+ structlogger = structlog.get_logger(__name__)
39
+
40
+
41
+ def wrap_async(func: Callable) -> Callable:
42
+ """Wraps a function to be used as an async job in the background scheduler."""
43
+
44
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
45
+ return asyncio.run(func(*args, **kwargs))
46
+
47
+ return wrapper
48
+
49
+
50
+ class BackgroundPrivacyManager:
51
+ """Manages privacy-related tasks in the background.
52
+
53
+ This class handles the anonymization and deletion of sensitive information
54
+ in dialogue state trackers, as well as the streaming of anonymized events
55
+ to event brokers. It uses background schedulers to periodically run these
56
+ tasks and processes trackers from a queue to ensure that sensitive information
57
+ is handled in a timely manner.
58
+ """
59
+
60
+ TRACKER_QUEUE_PROCESSING_TIMEOUT_IN_SECONDS = 2.0
61
+
62
+ def __init__(
63
+ self,
64
+ endpoints: Optional["AvailableEndpoints"],
65
+ event_loop: Optional["AbstractEventLoop"] = None,
66
+ in_memory_tracker_store: Optional[TrackerStore] = None,
67
+ ):
68
+ self.config = (
69
+ PrivacyConfig.from_dict(endpoints.privacy)
70
+ if endpoints and endpoints.privacy
71
+ else None
72
+ )
73
+ self.privacy_filter = (
74
+ PrivacyFilter(self.config.anonymization_rules) if self.config else None
75
+ )
76
+ self.user_chat_inactivity_in_minutes = int(
77
+ os.getenv(USER_CHAT_INACTIVITY_IN_MINUTES_ENV_VAR_NAME, 30)
78
+ )
79
+
80
+ if in_memory_tracker_store is not None:
81
+ # if an in-memory tracker store is provided,
82
+ # we need to keep the reference to it
83
+ # so that the background jobs can access it.
84
+ # We also set the event broker to None
85
+ # to prevent it from publishing events
86
+ # during the tracker store background jobs
87
+ in_memory_tracker_store.event_broker = None
88
+ tracker_store = in_memory_tracker_store
89
+ else:
90
+ # we recreate the tracker store here to ensure
91
+ # that this instance has no event brokers
92
+ # that could publish events during the tracker store
93
+ # background jobs
94
+ tracker_store = (
95
+ TrackerStore.create(endpoints.tracker_store)
96
+ if endpoints
97
+ else TrackerStore.create(None)
98
+ )
99
+
100
+ self.tracker_store = tracker_store
101
+
102
+ self.event_brokers: List["EventBroker"] = []
103
+ self.event_loop = event_loop
104
+
105
+ # Order of the initialisation is important
106
+ # The tracker queue must be created before the scheduler
107
+ # The can_consume_tracker_queue must be set to True before the scheduler starts
108
+ self.tracker_queue: queue.Queue = queue.Queue()
109
+
110
+ # This flag is used to stop the scheduler
111
+ self.can_consume_from_tracker_queue = True
112
+ self.background_scheduler = BackgroundScheduler()
113
+ self.background_scheduler.add_job(
114
+ self._consumer_queue, max_instances=1, id="event_broker_job"
115
+ )
116
+
117
+ self.previous_fire_time_deletion = datetime.datetime.now(
118
+ tz=datetime.timezone.utc
119
+ )
120
+ self._configure_background_scheduler()
121
+ self.background_scheduler.start()
122
+
123
+ async def initialize(
124
+ self, endpoints: Optional["AvailableEndpoints"]
125
+ ) -> BackgroundPrivacyManager:
126
+ """Initialize async attributes of the BackgroundPrivacyManager."""
127
+ event_broker_endpoints = endpoints.event_broker if endpoints else None
128
+ self.event_brokers = (
129
+ await create_event_brokers(event_broker_endpoints, self.event_loop)
130
+ if event_broker_endpoints
131
+ else []
132
+ )
133
+
134
+ return self
135
+
136
+ @classmethod
137
+ async def create_instance(
138
+ cls,
139
+ endpoints: Optional["AvailableEndpoints"],
140
+ event_loop: Optional["AbstractEventLoop"] = None,
141
+ in_memory_tracker_store: Optional[TrackerStore] = None,
142
+ ) -> BackgroundPrivacyManager:
143
+ """Create an instance of BackgroundPrivacyManager."""
144
+ instance = cls(endpoints, event_loop, in_memory_tracker_store)
145
+ return await instance.initialize(endpoints)
146
+
147
+ def stop(self) -> None:
148
+ structlogger.debug("rasa.privacy_manager.stop_schedulers")
149
+ self.can_consume_from_tracker_queue = False
150
+ self.background_scheduler.shutdown(wait=False)
151
+
152
+ def run(self, tracker: "DialogueStateTracker") -> None:
153
+ self.tracker_queue.put(tracker)
154
+
155
+ def process(
156
+ self, tracker: "DialogueStateTracker", process_all: bool = False
157
+ ) -> None:
158
+ """Process the tracker to identify and anonymize sensitive information.
159
+
160
+ Args:
161
+ tracker: The tracker to process.
162
+ process_all: If True, process all events in the tracker.
163
+ """
164
+ events = self.process_events(tracker, process_all=process_all)
165
+ events_to_stream = events if events else tracker.events
166
+ self.stream_events(events_to_stream, tracker.sender_id)
167
+
168
+ def process_events(
169
+ self, tracker: DialogueStateTracker, process_all: bool = False
170
+ ) -> List[Event]:
171
+ """Anonymize tracker events."""
172
+ if (latest_message := self._get_latest_user_message(tracker)) is None:
173
+ return []
174
+
175
+ processed_events = list(tracker.events)
176
+ prior_sensitive_slot_events: List[Event] = []
177
+
178
+ if not process_all:
179
+ additional_splitting_conditions = {
180
+ TEXT_KEY: latest_message.text,
181
+ "timestamp": latest_message.timestamp,
182
+ }
183
+
184
+ resulting_events = split_events(
185
+ processed_events,
186
+ UserUttered,
187
+ additional_splitting_conditions=additional_splitting_conditions,
188
+ include_splitting_event=True,
189
+ )
190
+
191
+ processed_events = resulting_events[1]
192
+ prior_events = resulting_events[0]
193
+ prior_tracker = DialogueStateTracker.from_events(
194
+ sender_id=tracker.sender_id, evts=prior_events
195
+ )
196
+ prior_sensitive_slot_events = [
197
+ event
198
+ for event in prior_tracker.applied_events()
199
+ if isinstance(event, SlotSet)
200
+ and event.key in self.config.anonymization_rules # type: ignore[union-attr]
201
+ ]
202
+
203
+ return self.privacy_filter.anonymize( # type: ignore[union-attr]
204
+ processed_events, prior_sensitive_slot_events
205
+ )
206
+
207
+ def stream_events(
208
+ self,
209
+ anonymized_events: List[Event],
210
+ sender_id: str,
211
+ ) -> None:
212
+ """Stream anonymized events to the event broker."""
213
+ if not self.event_brokers:
214
+ structlogger.debug(
215
+ "rasa.privacy_manager.no_event_broker_configured",
216
+ )
217
+ return None
218
+
219
+ for event in anonymized_events:
220
+ body = {"sender_id": sender_id}
221
+ body.update(event.as_dict())
222
+ for broker in self.event_brokers:
223
+ broker.publish(body)
224
+
225
+ return None
226
+
227
+ def validate_sensitive_slots_in_domain(self, domain: "Domain") -> None:
228
+ """Validate the sensitive slots defined in the privacy config against the domain.""" # noqa: E501
229
+ if not self.config:
230
+ structlogger.debug(
231
+ "rasa.privacy_manager.no_sensitive_slots_configured",
232
+ )
233
+ return None
234
+
235
+ # we need to set the domain in the tracker store
236
+ # to prevent errors being raised about slots not found in the domain
237
+ # during the background jobs
238
+ self.tracker_store.domain = domain
239
+ sensitive_slots = list(self.config.anonymization_rules.keys())
240
+ return validate_sensitive_slots(sensitive_slots, domain)
241
+
242
+ def _consumer_queue(self) -> None:
243
+ while self.can_consume_from_tracker_queue:
244
+ try:
245
+ # Wait for 2 seconds for an event to be added to the queue
246
+ # If no event is added to the queue, continue
247
+ # This is done to avoid the scheduler to be stuck in the while loop
248
+ # when we want to stop the scheduler
249
+ tracker = self.tracker_queue.get(
250
+ timeout=self.TRACKER_QUEUE_PROCESSING_TIMEOUT_IN_SECONDS
251
+ )
252
+ self.process(tracker)
253
+ self.tracker_queue.task_done()
254
+ except queue.Empty:
255
+ continue
256
+
257
+ def _get_latest_user_message(
258
+ self, tracker: DialogueStateTracker
259
+ ) -> Optional[UserUttered]:
260
+ """Check if a tracker should be processed."""
261
+ if self.privacy_filter is None:
262
+ structlogger.debug(
263
+ "rasa.privacy_manager.no_privacy_rules_configured",
264
+ )
265
+ return None
266
+
267
+ latest_user_message = tracker.get_last_event_for(
268
+ UserUttered, event_verbosity=EventVerbosity.ALL
269
+ )
270
+ if latest_user_message is None or not latest_user_message.text:
271
+ structlogger.debug(
272
+ "rasa.privacy_manager.no_user_message.skipping_processing",
273
+ )
274
+ return None
275
+
276
+ return latest_user_message
277
+
278
+ @staticmethod
279
+ def _has_session_been_anonymized(events: List[Event]) -> bool:
280
+ """Check if the session has already been anonymized."""
281
+ if not events:
282
+ return False
283
+ for event in reversed(events):
284
+ if (
285
+ hasattr(event, "anonymized_at")
286
+ and getattr(event, "anonymized_at") is not None
287
+ ):
288
+ return True
289
+
290
+ return False
291
+
292
+ async def _run_tracker_store_anonymization(self) -> None:
293
+ """Anonymize eligible tracker sessions in the tracker store."""
294
+ structlogger.info(
295
+ "rasa.privacy_manager.starting_tracker_store_anonymization",
296
+ triggered_by="anonymization_cron_job",
297
+ )
298
+
299
+ keys = await self.tracker_store.keys()
300
+ keys_copy = copy.deepcopy(list(keys))
301
+
302
+ for key in keys_copy:
303
+ full_tracker = await self.tracker_store.retrieve_full_tracker(key)
304
+
305
+ if not full_tracker:
306
+ structlogger.debug(
307
+ "rasa.privacy_manager.no_tracker_found_for_sender_id",
308
+ sender_id=key,
309
+ )
310
+ continue
311
+
312
+ processed_events, already_anonymized_events, uneligible_events = (
313
+ self._get_processed_events_after_anonymization(full_tracker)
314
+ )
315
+
316
+ if not processed_events:
317
+ structlogger.debug(
318
+ "rasa.privacy_manager.no_events_to_anonymize_for_tracker",
319
+ sender_id=key,
320
+ )
321
+ continue
322
+
323
+ all_events = (
324
+ already_anonymized_events + processed_events + uneligible_events
325
+ )
326
+ updated_tracker = DialogueStateTracker.from_events(
327
+ sender_id=key,
328
+ evts=all_events,
329
+ slots=full_tracker.slots.values(),
330
+ )
331
+ await self.tracker_store.delete(sender_id=key)
332
+ await self.tracker_store.save(updated_tracker)
333
+
334
+ structlogger.info(
335
+ "rasa.privacy_manager.saved_tracker_after_anonymization",
336
+ sender_id=key,
337
+ )
338
+
339
+ async def _run_tracker_store_deletion(self) -> None:
340
+ """Delete eligible tracker sessions from the tracker store."""
341
+ structlogger.info(
342
+ "rasa.privacy_manager.starting_tracker_store_deletion",
343
+ triggered_by="deletion_cron_job",
344
+ )
345
+ keys = await self.tracker_store.keys()
346
+
347
+ # Make a copy of the keys to avoid modifying the list while iterating
348
+ keys_copy = copy.deepcopy(list(keys))
349
+
350
+ for key in keys_copy:
351
+ full_tracker = await self.tracker_store.retrieve_full_tracker(key)
352
+
353
+ if not full_tracker:
354
+ structlogger.debug(
355
+ "rasa.privacy_manager.no_tracker_found_for_sender_id",
356
+ sender_id=key,
357
+ )
358
+ continue
359
+
360
+ events_to_be_retained = self._get_events_to_be_retained_after_deletion(
361
+ full_tracker
362
+ )
363
+
364
+ if not events_to_be_retained:
365
+ await self.tracker_store.delete(sender_id=key)
366
+ structlogger.info(
367
+ "rasa.privacy_manager.tracker_session_deleted",
368
+ sender_id=full_tracker.sender_id,
369
+ triggered_by="deletion_cron_job",
370
+ )
371
+ continue
372
+
373
+ tracker = DialogueStateTracker.from_events(
374
+ sender_id=key,
375
+ evts=events_to_be_retained,
376
+ slots=full_tracker.slots.values(),
377
+ )
378
+ await self.tracker_store.update(tracker)
379
+
380
+ structlogger.info(
381
+ "rasa.privacy_manager.overwritten_tracker",
382
+ sender_id=key,
383
+ event_info="Deleted eligible events and saved "
384
+ "tracker with events not scheduled "
385
+ "for deletion yet.",
386
+ )
387
+
388
+ async def _run_tracker_store_background_jobs_sequentially(self) -> None:
389
+ """Run the tracker store background jobs.
390
+
391
+ If both anonymization and deletion policies are configured,
392
+ we need to ensure that the background job timings do not
393
+ overlap to prevent race conditions when accessing the
394
+ tracker store.
395
+
396
+ The scheduler will run the anonymization job first,
397
+ and then the deletion job if the current time is past
398
+ the next scheduled time for deletion.
399
+ """
400
+ await self._run_tracker_store_anonymization()
401
+
402
+ now = datetime.datetime.now(tz=datetime.timezone.utc)
403
+ next_fire_time = (
404
+ self.config.tracker_store_settings.deletion_policy.cron.get_next_fire_time( # type: ignore[union-attr]
405
+ self.previous_fire_time_deletion,
406
+ now=now,
407
+ )
408
+ )
409
+
410
+ if next_fire_time and now >= next_fire_time:
411
+ await self._run_tracker_store_deletion()
412
+ self.previous_fire_time_deletion = next_fire_time
413
+
414
+ return None
415
+
416
+ def _add_anonymization_job(self) -> None:
417
+ wrapped_anonymization = wrap_async(self._run_tracker_store_anonymization)
418
+ self.background_scheduler.add_job(
419
+ wrapped_anonymization,
420
+ trigger=self.config.tracker_store_settings.anonymization_policy.cron, # type: ignore[union-attr]
421
+ max_instances=1,
422
+ id="anonymization_cron_job",
423
+ )
424
+
425
+ def _add_deletion_job(self) -> None:
426
+ wrapped_deletion = wrap_async(self._run_tracker_store_deletion)
427
+ self.background_scheduler.add_job(
428
+ wrapped_deletion,
429
+ trigger=self.config.tracker_store_settings.deletion_policy.cron, # type: ignore[union-attr]
430
+ max_instances=1,
431
+ id="deletion_cron_job",
432
+ )
433
+
434
+ def _add_sequential_job(self) -> None:
435
+ sequential_dispatcher = wrap_async(
436
+ self._run_tracker_store_background_jobs_sequentially
437
+ )
438
+ self.background_scheduler.add_job(
439
+ sequential_dispatcher,
440
+ trigger=self.config.tracker_store_settings.anonymization_policy.cron, # type: ignore[union-attr]
441
+ max_instances=1,
442
+ id="anonymization_and_deletion_cron_job",
443
+ )
444
+
445
+ def _configure_background_scheduler(self) -> None:
446
+ """Configure the background scheduler."""
447
+ tracker_store_settings_configured = (
448
+ self.config is not None and self.config.tracker_store_settings is not None
449
+ )
450
+ anonymization_policy = (
451
+ self.config.tracker_store_settings.anonymization_policy # type: ignore[union-attr]
452
+ if tracker_store_settings_configured
453
+ else None
454
+ )
455
+ deletion_policy = (
456
+ self.config.tracker_store_settings.deletion_policy # type: ignore[union-attr]
457
+ if tracker_store_settings_configured
458
+ else None
459
+ )
460
+
461
+ if (
462
+ tracker_store_settings_configured
463
+ and anonymization_policy is not None
464
+ and deletion_policy is not None
465
+ ):
466
+ next_fire_time_anonymization = get_next_fire_time(anonymization_policy)
467
+ next_fire_time_deletion = get_next_fire_time(deletion_policy)
468
+
469
+ # If both anonymization and deletion policies are configured
470
+ # to start on the same date,
471
+ # we need to run them sequentially to avoid race conditions
472
+ if (
473
+ next_fire_time_anonymization is not None
474
+ and next_fire_time_deletion is not None
475
+ and next_fire_time_anonymization.date()
476
+ == next_fire_time_deletion.date()
477
+ ):
478
+ self._add_sequential_job()
479
+ else:
480
+ self._add_anonymization_job()
481
+ self._add_deletion_job()
482
+
483
+ elif tracker_store_settings_configured and anonymization_policy is not None:
484
+ self._add_anonymization_job()
485
+
486
+ elif tracker_store_settings_configured and deletion_policy is not None:
487
+ self._add_deletion_job()
488
+
489
+ def _get_processed_events_after_anonymization(
490
+ self,
491
+ full_tracker: DialogueStateTracker,
492
+ ) -> Tuple[List[Event], List[Event], List[Event]]:
493
+ """Get processed events after anonymization job."""
494
+ multiple_tracker_sessions = (
495
+ rasa.shared.core.trackers.get_trackers_for_conversation_sessions(
496
+ full_tracker
497
+ )
498
+ )
499
+
500
+ processed_events = []
501
+ already_anonymized_events = []
502
+ uneligible_events = []
503
+
504
+ for session in multiple_tracker_sessions:
505
+ has_session_been_anonymized = self._has_session_been_anonymized(
506
+ list(session.events)
507
+ )
508
+
509
+ if has_session_been_anonymized:
510
+ structlogger.debug(
511
+ "rasa.privacy_manager.session_already_anonymized",
512
+ session_id=session.sender_id,
513
+ )
514
+ already_anonymized_events.extend(list(session.events))
515
+ continue
516
+
517
+ current_time = time.time()
518
+
519
+ last_event_timestamp = (
520
+ str(datetime.datetime.fromtimestamp(session.events[-1].timestamp))
521
+ if session.events
522
+ else "N/A"
523
+ )
524
+
525
+ if session.events and current_time - session.events[-1].timestamp > (
526
+ self.user_chat_inactivity_in_minutes * 60
527
+ + self.config.tracker_store_settings.anonymization_policy.min_after_session_end # type: ignore[union-attr] # noqa: E501
528
+ * 60
529
+ ):
530
+ structlogger.info(
531
+ "rasa.privacy_manager.anonymizing_tracker_session",
532
+ sender_id=session.sender_id,
533
+ last_event_timestamp=last_event_timestamp,
534
+ triggered_by="anonymization_cron_job",
535
+ )
536
+ events = self.process_events(session, process_all=True)
537
+ processed_events.extend(events)
538
+ else:
539
+ # If the session is not valid for anonymization,
540
+ # we still want to write them back to the tracker store
541
+ events = list(session.events)
542
+ uneligible_events.extend(events)
543
+ structlogger.debug(
544
+ "rasa.privacy_manager.session_not_valid_for_anonymization",
545
+ sender_id=session.sender_id,
546
+ session_id=session.sender_id,
547
+ last_event_timestamp=last_event_timestamp,
548
+ )
549
+ return processed_events, already_anonymized_events, uneligible_events
550
+
551
+ def _get_events_to_be_retained_after_deletion(
552
+ self, full_tracker: DialogueStateTracker
553
+ ) -> List[Event]:
554
+ """Get the events to be retained after deletion."""
555
+ multiple_tracker_sessions = (
556
+ rasa.shared.core.trackers.get_trackers_for_conversation_sessions(
557
+ full_tracker
558
+ )
559
+ )
560
+ events_to_be_retained: List[Event] = []
561
+ for session in multiple_tracker_sessions:
562
+ current_time = time.time()
563
+ if session.events and (
564
+ current_time - session.events[-1].timestamp
565
+ <= (
566
+ self.user_chat_inactivity_in_minutes * 60
567
+ + self.config.tracker_store_settings.deletion_policy.min_after_session_end # type: ignore[union-attr] # noqa: E501
568
+ * 60
569
+ )
570
+ ):
571
+ events_to_be_retained.extend(session.events)
572
+ else:
573
+ last_event_timestamp = (
574
+ str(datetime.datetime.fromtimestamp(session.events[-1].timestamp))
575
+ if session.events
576
+ else "N/A"
577
+ )
578
+
579
+ structlogger.info(
580
+ "rasa.privacy_manager.tracker_session_scheduled_for_deletion",
581
+ sender_id=full_tracker.sender_id,
582
+ last_event_timestamp=last_event_timestamp,
583
+ triggered_by="deletion_cron_job",
584
+ )
585
+
586
+ return events_to_be_retained
587
+
588
+
589
+ def get_next_fire_time(
590
+ privacy_policy: PrivacyPolicy,
591
+ ) -> Optional[datetime.datetime]:
592
+ """Get the next fire time for the privacy policy."""
593
+ now = datetime.datetime.now(tz=datetime.timezone.utc)
594
+ return privacy_policy.cron.get_next_fire_time(None, now=now)
rasa/server.py CHANGED
@@ -44,6 +44,7 @@ import rasa.utils.endpoints
44
44
  import rasa.utils.io
45
45
  from rasa.constants import MINIMUM_COMPATIBLE_VERSION
46
46
  from rasa.core.agent import Agent
47
+ from rasa.core.available_endpoints import AvailableEndpoints
47
48
  from rasa.core.channels.channel import (
48
49
  CollectingOutputChannel,
49
50
  OutputChannel,
@@ -52,7 +53,6 @@ from rasa.core.channels.channel import (
52
53
  from rasa.core.constants import DEFAULT_RESPONSE_TIMEOUT
53
54
  from rasa.core.persistor import parse_remote_storage
54
55
  from rasa.core.test import test
55
- from rasa.core.utils import AvailableEndpoints
56
56
  from rasa.nlu.emulators.emulator import Emulator
57
57
  from rasa.nlu.emulators.no_emulator import NoEmulator
58
58
  from rasa.nlu.test import CVEvaluationResult
@@ -75,7 +75,9 @@ from rasa.shared.core.training_data.story_writer.yaml_story_writer import (
75
75
  YAMLStoryWriter,
76
76
  )
77
77
  from rasa.shared.exceptions import RasaException, YamlException
78
- from rasa.shared.importers.importer import TrainingDataImporter
78
+ from rasa.shared.importers.importer import (
79
+ TrainingDataImporter,
80
+ )
79
81
  from rasa.shared.nlu.training_data.formats import RasaYAMLReader
80
82
  from rasa.shared.utils.schemas.events import EVENTS_SCHEMA
81
83
  from rasa.shared.utils.yaml import validate_training_data
@@ -797,6 +799,25 @@ def create_app(
797
799
  f"An unexpected error occurred. Error: {e}",
798
800
  )
799
801
 
802
+ @app.delete("/conversations/<conversation_id:path>/tracker")
803
+ @requires_auth(app, auth_token)
804
+ @ensure_loaded_agent(app)
805
+ @ensure_conversation_exists()
806
+ async def delete_tracker(request: Request, conversation_id: Text) -> HTTPResponse:
807
+ """Delete a conversation's tracker."""
808
+ try:
809
+ async with app.ctx.agent.lock_store.lock(conversation_id):
810
+ await app.ctx.agent.tracker_store.delete(conversation_id)
811
+ logger.info(f"Tracker for conversation '{conversation_id}' deleted.")
812
+ return response.empty(status=HTTPStatus.NO_CONTENT)
813
+ except Exception as e:
814
+ logger.debug(traceback.format_exc())
815
+ raise ErrorResponse(
816
+ HTTPStatus.INTERNAL_SERVER_ERROR,
817
+ "ConversationError",
818
+ f"An unexpected error occurred. Error: {e}",
819
+ )
820
+
800
821
  @app.post("/conversations/<conversation_id:path>/tracker/events")
801
822
  @requires_auth(app, auth_token)
802
823
  @ensure_loaded_agent(app)
rasa/shared/constants.py CHANGED
@@ -104,6 +104,8 @@ UTTER_FREE_CHITCHAT_RESPONSE = "utter_free_chitchat_response"
104
104
  ASSISTANT_ID_KEY = "assistant_id"
105
105
  ASSISTANT_ID_DEFAULT_VALUE = "placeholder_default"
106
106
 
107
+ ENDPOINTS_NLG_KEY = "nlg"
108
+
107
109
  CONFIG_MANDATORY_COMMON_KEYS = [ASSISTANT_ID_KEY]
108
110
  CONFIG_NAME_KEY = "name"
109
111
  CONFIG_POLICIES_KEY = "policies"
@@ -144,6 +146,7 @@ DEFAULT_ACTIONS_PATH = "actions"
144
146
  DEFAULT_MODELS_PATH = "models"
145
147
  DEFAULT_CONVERTED_DATA_PATH = "converted_data"
146
148
  DEFAULT_DATA_PATH = "data"
149
+ DEFAULT_PROMPTS_PATH = "prompts"
147
150
  DEFAULT_RESULTS_PATH = "results"
148
151
  DEFAULT_NLU_RESULTS_PATH = "nlu_comparison_results"
149
152
  DEFAULT_CORE_SUBDIRECTORY_NAME = "core"
@@ -295,6 +298,7 @@ CONTEXT = "context"
295
298
 
296
299
  RASA_PATTERN_INTERNAL_ERROR = "pattern_internal_error"
297
300
  RASA_PATTERN_HUMAN_HANDOFF = "pattern_human_handoff"
301
+ RASA_PATTERN_CHITCHAT = "pattern_chitchat"
298
302
 
299
303
  RASA_INTERNAL_ERROR_PREFIX = "rasa_internal_error_"
300
304
  RASA_PATTERN_INTERNAL_ERROR_DEFAULT = RASA_INTERNAL_ERROR_PREFIX + "default"
@@ -314,6 +318,9 @@ RASA_PATTERN_CANNOT_HANDLE_NOT_SUPPORTED = (
314
318
  RASA_PATTERN_CANNOT_HANDLE_INVALID_INTENT = (
315
319
  RASA_PATTERN_CANNOT_HANDLE_PREFIX + "invalid_intent"
316
320
  )
321
+ RASA_PATTERN_CANNOT_HANDLE_NO_RELEVANT_ANSWER = (
322
+ RASA_PATTERN_CANNOT_HANDLE_PREFIX + "no_relevant_answer"
323
+ )
317
324
 
318
325
  ROUTE_TO_CALM_SLOT = "route_session_to_calm"
319
326
 
@@ -342,3 +349,13 @@ ROLE_SYSTEM = "system"
342
349
  # Used for key values in ValidateSlotPatternFlowStackFrame
343
350
  REFILL_UTTER = "refill_utter"
344
351
  REJECTIONS = "rejections"
352
+
353
+ # Constants for extractive search FAQ parsing (QA pairs from input documents)
354
+ FAQ_DOCUMENT_METADATA_TITLE = "title"
355
+ FAQ_DOCUMENT_METADATA_ANSWER = "answer"
356
+ FAQ_DOCUMENT_METADATA_TYPE = "type"
357
+ DOCUMENT_TYPE_FAQ = "faq"
358
+ FAQ_INPUT_DATA_QUESTION_LINE_PREFIX = "Q:"
359
+ FAQ_INPUT_DATA_ANSWER_LINE_PREFIX = "A:"
360
+ FAQ_DOCUMENT_ENTRY_SEPARATOR = "\n\n"
361
+ FAQ_DOCUMENT_LINE_SEPARATOR = "\n"