rasa-pro 3.11.4__py3-none-any.whl → 3.12.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 (580) hide show
  1. README.md +10 -13
  2. rasa/__main__.py +7 -7
  3. rasa/anonymization/anonymisation_rule_yaml_reader.py +1 -1
  4. rasa/anonymization/anonymization_pipeline.py +3 -3
  5. rasa/anonymization/anonymization_rule_executor.py +17 -11
  6. rasa/anonymization/anonymization_rule_orchestrator.py +2 -3
  7. rasa/cli/arguments/data.py +2 -2
  8. rasa/cli/arguments/default_arguments.py +1 -1
  9. rasa/cli/arguments/evaluate.py +2 -1
  10. rasa/cli/arguments/interactive.py +1 -1
  11. rasa/cli/arguments/run.py +1 -1
  12. rasa/cli/arguments/test.py +7 -5
  13. rasa/cli/arguments/train.py +3 -3
  14. rasa/cli/arguments/visualize.py +2 -2
  15. rasa/cli/arguments/x.py +1 -0
  16. rasa/cli/data.py +20 -3
  17. rasa/cli/dialogue_understanding_test.py +386 -0
  18. rasa/cli/evaluate.py +1 -1
  19. rasa/cli/export.py +6 -6
  20. rasa/cli/inspect.py +20 -1
  21. rasa/cli/interactive.py +4 -5
  22. rasa/cli/llm_fine_tuning.py +51 -16
  23. rasa/cli/markers.py +1 -2
  24. rasa/cli/project_templates/calm/actions/add_contact.py +1 -1
  25. rasa/cli/project_templates/calm/config.yml +2 -2
  26. rasa/cli/project_templates/calm/domain/list_contacts.yml +1 -2
  27. rasa/cli/project_templates/calm/domain/remove_contact.yml +1 -2
  28. rasa/cli/project_templates/calm/domain/shared.yml +1 -4
  29. rasa/cli/project_templates/calm/endpoints.yml +2 -2
  30. rasa/cli/project_templates/tutorial/actions/actions.py +3 -2
  31. rasa/cli/shell.py +5 -6
  32. rasa/cli/studio/download.py +1 -2
  33. rasa/cli/studio/studio.py +2 -3
  34. rasa/cli/studio/train.py +0 -1
  35. rasa/cli/telemetry.py +2 -2
  36. rasa/cli/test.py +11 -11
  37. rasa/cli/train.py +3 -0
  38. rasa/cli/utils.py +25 -5
  39. rasa/constants.py +0 -1
  40. rasa/core/__init__.py +0 -1
  41. rasa/core/actions/action.py +137 -208
  42. rasa/core/actions/action_handle_digressions.py +164 -0
  43. rasa/core/actions/action_hangup.py +1 -1
  44. rasa/core/actions/action_repeat_bot_messages.py +2 -2
  45. rasa/core/actions/action_run_slot_rejections.py +18 -6
  46. rasa/core/actions/action_trigger_chitchat.py +1 -1
  47. rasa/core/actions/action_trigger_flow.py +5 -5
  48. rasa/core/actions/action_trigger_search.py +1 -1
  49. rasa/core/actions/custom_action_executor.py +1 -1
  50. rasa/core/actions/direct_custom_actions_executor.py +1 -0
  51. rasa/core/actions/forms.py +22 -15
  52. rasa/core/actions/http_custom_action_executor.py +8 -1
  53. rasa/core/actions/loops.py +3 -3
  54. rasa/core/actions/two_stage_fallback.py +13 -13
  55. rasa/core/auth_retry_tracker_store.py +1 -2
  56. rasa/core/brokers/broker.py +2 -1
  57. rasa/core/brokers/file.py +1 -1
  58. rasa/core/brokers/kafka.py +8 -8
  59. rasa/core/brokers/pika.py +8 -9
  60. rasa/core/brokers/sql.py +4 -3
  61. rasa/core/channels/__init__.py +7 -0
  62. rasa/core/channels/botframework.py +2 -2
  63. rasa/core/channels/callback.py +4 -4
  64. rasa/core/channels/channel.py +11 -11
  65. rasa/core/channels/console.py +0 -1
  66. rasa/core/channels/development_inspector.py +80 -24
  67. rasa/core/channels/facebook.py +5 -5
  68. rasa/core/channels/hangouts.py +7 -8
  69. rasa/core/channels/inspector/dist/assets/Tableau10-1b767f5e.js +1 -0
  70. rasa/core/channels/inspector/dist/assets/arc-9f1365dc.js +1 -0
  71. rasa/core/channels/inspector/dist/assets/blockDiagram-38ab4fdb-e0f81b12.js +118 -0
  72. rasa/core/channels/inspector/dist/assets/c4Diagram-3d4e48cf-9deaee1c.js +10 -0
  73. rasa/core/channels/inspector/dist/assets/channel-44956714.js +1 -0
  74. rasa/core/channels/inspector/dist/assets/classDiagram-70f12bd4-20450a96.js +2 -0
  75. rasa/core/channels/inspector/dist/assets/classDiagram-v2-f2320105-749d2abf.js +2 -0
  76. rasa/core/channels/inspector/dist/assets/clone-a9475142.js +1 -0
  77. rasa/core/channels/inspector/dist/assets/{createText-62fc7601-89c73b31.js → createText-2e5e7dd3-bef0b38c.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/edges-e0da2a9e-943801a7.js +4 -0
  79. rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-907e0440.js → erDiagram-9861fffd-d523a948.js} +4 -4
  80. rasa/core/channels/inspector/dist/assets/flowDb-956e92f1-54e4cf19.js +10 -0
  81. rasa/core/channels/inspector/dist/assets/flowDiagram-66a62f08-48bfbbe8.js +4 -0
  82. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-43fa749a.js +1 -0
  83. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-4a651766-17c30827.js +139 -0
  84. rasa/core/channels/inspector/dist/assets/ganttDiagram-c361ad54-43086f2d.js +257 -0
  85. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-72cf32ee-5c8b693e.js +70 -0
  86. rasa/core/channels/inspector/dist/assets/graph-41a90d26.js +1 -0
  87. rasa/core/channels/inspector/dist/assets/index-3862675e-b43eeae9.js +1 -0
  88. rasa/core/channels/inspector/dist/assets/{index-e793d777.js → index-e8affe45.js} +201 -196
  89. rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-8ceba4db.js → infoDiagram-f8f76790-0b20676b.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-960d3809.js → journeyDiagram-49397b02-39bce7b5.js} +4 -4
  91. rasa/core/channels/inspector/dist/assets/katex-498eb57e.js +261 -0
  92. rasa/core/channels/inspector/dist/assets/layout-dc8eeea4.js +1 -0
  93. rasa/core/channels/inspector/dist/assets/{line-eeccc4e2.js → line-c4d2e756.js} +1 -1
  94. rasa/core/channels/inspector/dist/assets/linear-86f6f2d9.js +1 -0
  95. rasa/core/channels/inspector/dist/assets/mindmap-definition-fc14e90a-4216f771.js +312 -0
  96. rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-dc9b5e1b.js → pieDiagram-8a3498a8-1a0cfa96.js} +7 -7
  97. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-a08cba6d.js → quadrantDiagram-120e2f19-f91e67cf.js} +1 -1
  98. rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-87242b9e.js → requirementDiagram-deff3bca-d4046bed.js} +2 -2
  99. rasa/core/channels/inspector/dist/assets/sankeyDiagram-04a897e0-2cf6d1d7.js +8 -0
  100. rasa/core/channels/inspector/dist/assets/sequenceDiagram-704730f1-751ac4f5.js +122 -0
  101. rasa/core/channels/inspector/dist/assets/stateDiagram-587899a1-f734f4d4.js +1 -0
  102. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-d93cdb3a-91c65710.js +1 -0
  103. rasa/core/channels/inspector/dist/assets/{styles-9c745c82-cef936a6.js → styles-6aaf32cf-e0cff7be.js} +1 -1
  104. rasa/core/channels/inspector/dist/assets/styles-9a916d00-c8029e5d.js +160 -0
  105. rasa/core/channels/inspector/dist/assets/styles-c10674c1-114f312a.js +116 -0
  106. rasa/core/channels/inspector/dist/assets/svgDrawCommon-08f97a94-b7b9dc00.js +1 -0
  107. rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-0d39bdb2.js → timeline-definition-85554ec2-9536d189.js} +3 -3
  108. rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-a03fa445.js → xychartDiagram-e933f94c-bf3b0f36.js} +3 -3
  109. rasa/core/channels/inspector/dist/index.html +1 -1
  110. rasa/core/channels/inspector/package.json +11 -3
  111. rasa/core/channels/inspector/src/App.tsx +15 -2
  112. rasa/core/channels/inspector/src/components/RasaLogo.tsx +31 -0
  113. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +68 -0
  114. rasa/core/channels/inspector/src/components/Welcome.tsx +19 -13
  115. rasa/core/channels/inspector/yarn.lock +94 -99
  116. rasa/core/channels/mattermost.py +4 -4
  117. rasa/core/channels/rasa_chat.py +4 -4
  118. rasa/core/channels/rest.py +11 -12
  119. rasa/core/channels/rocketchat.py +4 -3
  120. rasa/core/channels/slack.py +6 -5
  121. rasa/core/channels/socketio.py +8 -28
  122. rasa/core/channels/studio_chat.py +212 -0
  123. rasa/core/channels/telegram.py +105 -55
  124. rasa/core/channels/twilio.py +3 -3
  125. rasa/core/channels/vier_cvg.py +2 -2
  126. rasa/core/channels/voice_ready/audiocodes.py +51 -32
  127. rasa/core/channels/voice_ready/jambonz.py +5 -5
  128. rasa/core/channels/voice_ready/jambonz_protocol.py +3 -4
  129. rasa/core/channels/voice_ready/twilio_voice.py +9 -8
  130. rasa/core/channels/voice_ready/utils.py +2 -2
  131. rasa/core/channels/voice_stream/asr/asr_engine.py +12 -6
  132. rasa/core/channels/voice_stream/asr/asr_event.py +5 -0
  133. rasa/core/channels/voice_stream/asr/azure.py +16 -3
  134. rasa/core/channels/voice_stream/asr/deepgram.py +76 -19
  135. rasa/core/channels/voice_stream/audiocodes.py +292 -0
  136. rasa/core/channels/voice_stream/browser_audio.py +14 -7
  137. rasa/core/channels/voice_stream/call_state.py +6 -2
  138. rasa/core/channels/voice_stream/genesys.py +320 -0
  139. rasa/core/channels/voice_stream/tts/azure.py +13 -5
  140. rasa/core/channels/voice_stream/tts/cartesia.py +34 -14
  141. rasa/core/channels/voice_stream/tts/tts_cache.py +3 -2
  142. rasa/core/channels/voice_stream/tts/tts_engine.py +1 -1
  143. rasa/core/channels/voice_stream/twilio_media_streams.py +12 -8
  144. rasa/core/channels/voice_stream/util.py +1 -1
  145. rasa/core/channels/voice_stream/voice_channel.py +100 -56
  146. rasa/core/channels/webexteams.py +3 -4
  147. rasa/core/constants.py +2 -0
  148. rasa/core/evaluation/marker.py +7 -6
  149. rasa/core/evaluation/marker_base.py +15 -16
  150. rasa/core/evaluation/marker_stats.py +3 -4
  151. rasa/core/evaluation/marker_tracker_loader.py +5 -4
  152. rasa/core/exporter.py +4 -4
  153. rasa/core/featurizers/precomputation.py +8 -8
  154. rasa/core/featurizers/single_state_featurizer.py +7 -7
  155. rasa/core/featurizers/tracker_featurizers.py +13 -13
  156. rasa/core/http_interpreter.py +3 -4
  157. rasa/core/information_retrieval/__init__.py +1 -1
  158. rasa/core/information_retrieval/faiss.py +4 -4
  159. rasa/core/information_retrieval/information_retrieval.py +2 -2
  160. rasa/core/information_retrieval/milvus.py +3 -3
  161. rasa/core/information_retrieval/qdrant.py +3 -3
  162. rasa/core/jobs.py +1 -0
  163. rasa/core/lock.py +2 -3
  164. rasa/core/lock_store.py +3 -3
  165. rasa/core/migrate.py +12 -9
  166. rasa/core/nlg/__init__.py +1 -1
  167. rasa/core/nlg/callback.py +2 -3
  168. rasa/core/nlg/contextual_response_rephraser.py +82 -14
  169. rasa/core/nlg/generator.py +85 -17
  170. rasa/core/nlg/interpolator.py +4 -3
  171. rasa/core/nlg/response.py +9 -7
  172. rasa/core/nlg/summarize.py +1 -0
  173. rasa/core/nlg/translate.py +55 -0
  174. rasa/core/persistor.py +3 -3
  175. rasa/core/policies/ensemble.py +10 -9
  176. rasa/core/policies/enterprise_search_policy.py +87 -21
  177. rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
  178. rasa/core/policies/flow_policy.py +13 -14
  179. rasa/core/policies/flows/flow_executor.py +85 -55
  180. rasa/core/policies/intentless_policy.py +6 -7
  181. rasa/core/policies/memoization.py +22 -20
  182. rasa/core/policies/policy.py +24 -22
  183. rasa/core/policies/rule_policy.py +37 -36
  184. rasa/core/policies/ted_policy.py +87 -85
  185. rasa/core/policies/unexpected_intent_policy.py +77 -75
  186. rasa/core/processor.py +167 -74
  187. rasa/core/run.py +5 -4
  188. rasa/core/secrets_manager/endpoints.py +2 -3
  189. rasa/core/secrets_manager/factory.py +2 -3
  190. rasa/core/secrets_manager/secret_manager.py +2 -3
  191. rasa/core/secrets_manager/vault.py +2 -2
  192. rasa/core/test.py +30 -30
  193. rasa/core/tracker_store.py +138 -49
  194. rasa/core/train.py +1 -1
  195. rasa/core/training/__init__.py +2 -2
  196. rasa/core/training/converters/responses_prefix_converter.py +1 -2
  197. rasa/core/training/interactive.py +13 -13
  198. rasa/core/training/story_conflict.py +4 -5
  199. rasa/core/training/training.py +3 -5
  200. rasa/core/utils.py +5 -5
  201. rasa/core/visualize.py +1 -1
  202. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -2
  203. rasa/dialogue_understanding/coexistence/llm_based_router.py +5 -5
  204. rasa/dialogue_understanding/commands/__init__.py +22 -22
  205. rasa/dialogue_understanding/commands/can_not_handle_command.py +38 -1
  206. rasa/dialogue_understanding/commands/cancel_flow_command.py +96 -9
  207. rasa/dialogue_understanding/commands/change_flow_command.py +36 -2
  208. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +36 -4
  209. rasa/dialogue_understanding/commands/clarify_command.py +46 -4
  210. rasa/dialogue_understanding/commands/command.py +3 -2
  211. rasa/dialogue_understanding/commands/command_syntax_manager.py +55 -0
  212. rasa/dialogue_understanding/commands/correct_slots_command.py +14 -5
  213. rasa/dialogue_understanding/commands/error_command.py +1 -1
  214. rasa/dialogue_understanding/commands/free_form_answer_command.py +2 -1
  215. rasa/dialogue_understanding/commands/handle_code_change_command.py +2 -2
  216. rasa/dialogue_understanding/commands/handle_digressions_command.py +144 -0
  217. rasa/dialogue_understanding/commands/human_handoff_command.py +34 -4
  218. rasa/dialogue_understanding/commands/knowledge_answer_command.py +36 -4
  219. rasa/dialogue_understanding/commands/noop_command.py +2 -1
  220. rasa/dialogue_understanding/commands/prompt_command.py +94 -0
  221. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +34 -4
  222. rasa/dialogue_understanding/commands/restart_command.py +2 -5
  223. rasa/dialogue_understanding/commands/session_end_command.py +3 -5
  224. rasa/dialogue_understanding/commands/session_start_command.py +3 -5
  225. rasa/dialogue_understanding/commands/set_slot_command.py +55 -16
  226. rasa/dialogue_understanding/commands/skip_question_command.py +34 -4
  227. rasa/dialogue_understanding/commands/start_flow_command.py +78 -2
  228. rasa/dialogue_understanding/commands/user_silence_command.py +3 -5
  229. rasa/dialogue_understanding/commands/utils.py +126 -43
  230. rasa/dialogue_understanding/constants.py +2 -0
  231. rasa/dialogue_understanding/generator/__init__.py +2 -0
  232. rasa/dialogue_understanding/generator/command_generator.py +120 -79
  233. rasa/dialogue_understanding/generator/command_parser.py +245 -0
  234. rasa/dialogue_understanding/generator/constants.py +12 -4
  235. rasa/dialogue_understanding/generator/flow_retrieval.py +7 -7
  236. rasa/dialogue_understanding/generator/llm_based_command_generator.py +187 -59
  237. rasa/dialogue_understanding/generator/llm_command_generator.py +6 -3
  238. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +106 -110
  239. rasa/dialogue_understanding/generator/nlu_command_adapter.py +53 -11
  240. rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
  241. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +58 -0
  242. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +57 -0
  243. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +574 -0
  244. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +41 -386
  245. rasa/dialogue_understanding/generator/utils.py +76 -0
  246. rasa/dialogue_understanding/patterns/cancel.py +2 -1
  247. rasa/dialogue_understanding/patterns/cannot_handle.py +1 -0
  248. rasa/dialogue_understanding/patterns/chitchat.py +1 -1
  249. rasa/dialogue_understanding/patterns/clarify.py +2 -1
  250. rasa/dialogue_understanding/patterns/code_change.py +2 -0
  251. rasa/dialogue_understanding/patterns/collect_information.py +7 -4
  252. rasa/dialogue_understanding/patterns/completed.py +1 -1
  253. rasa/dialogue_understanding/patterns/continue_interrupted.py +1 -1
  254. rasa/dialogue_understanding/patterns/correction.py +17 -3
  255. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +78 -2
  256. rasa/dialogue_understanding/patterns/handle_digressions.py +81 -0
  257. rasa/dialogue_understanding/patterns/human_handoff.py +1 -1
  258. rasa/dialogue_understanding/patterns/internal_error.py +1 -0
  259. rasa/dialogue_understanding/patterns/search.py +1 -1
  260. rasa/dialogue_understanding/patterns/session_start.py +1 -1
  261. rasa/dialogue_understanding/patterns/skip_question.py +1 -0
  262. rasa/dialogue_understanding/patterns/user_silence.py +1 -1
  263. rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
  264. rasa/dialogue_understanding/processor/command_processor.py +193 -43
  265. rasa/dialogue_understanding/processor/command_processor_component.py +1 -1
  266. rasa/dialogue_understanding/stack/dialogue_stack.py +4 -3
  267. rasa/dialogue_understanding/stack/frames/__init__.py +2 -2
  268. rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +4 -1
  269. rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +2 -3
  270. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +5 -2
  271. rasa/dialogue_understanding/stack/frames/search_frame.py +4 -1
  272. rasa/dialogue_understanding/stack/utils.py +56 -10
  273. rasa/dialogue_understanding/utils.py +164 -0
  274. rasa/dialogue_understanding_test/README.md +429 -0
  275. rasa/dialogue_understanding_test/__init__.py +0 -0
  276. rasa/dialogue_understanding_test/command_comparison.py +60 -0
  277. rasa/dialogue_understanding_test/command_metric_calculation.py +122 -0
  278. rasa/dialogue_understanding_test/constants.py +22 -0
  279. rasa/dialogue_understanding_test/du_test_case.py +448 -0
  280. rasa/dialogue_understanding_test/du_test_result.py +390 -0
  281. rasa/dialogue_understanding_test/du_test_runner.py +322 -0
  282. rasa/dialogue_understanding_test/du_test_schema.yml +161 -0
  283. rasa/dialogue_understanding_test/io.py +443 -0
  284. rasa/dialogue_understanding_test/test_case_simulation/__init__.py +0 -0
  285. rasa/dialogue_understanding_test/test_case_simulation/exception.py +28 -0
  286. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +336 -0
  287. rasa/dialogue_understanding_test/utils.py +70 -0
  288. rasa/dialogue_understanding_test/validation.py +77 -0
  289. rasa/e2e_test/aggregate_test_stats_calculator.py +1 -1
  290. rasa/e2e_test/assertions.py +202 -175
  291. rasa/e2e_test/assertions_schema.yml +6 -0
  292. rasa/e2e_test/constants.py +16 -1
  293. rasa/e2e_test/e2e_config.py +102 -41
  294. rasa/e2e_test/e2e_config_schema.yml +28 -10
  295. rasa/e2e_test/e2e_test_case.py +5 -5
  296. rasa/e2e_test/e2e_test_converter.py +2 -3
  297. rasa/e2e_test/e2e_test_coverage_report.py +6 -6
  298. rasa/e2e_test/e2e_test_result.py +1 -1
  299. rasa/e2e_test/e2e_test_runner.py +143 -38
  300. rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +93 -0
  301. rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2 +169 -0
  302. rasa/e2e_test/stub_custom_action.py +1 -1
  303. rasa/e2e_test/utils/generative_assertions.py +243 -0
  304. rasa/e2e_test/utils/io.py +123 -93
  305. rasa/e2e_test/utils/validation.py +101 -3
  306. rasa/engine/caching.py +5 -7
  307. rasa/engine/constants.py +1 -1
  308. rasa/engine/graph.py +3 -2
  309. rasa/engine/language.py +182 -0
  310. rasa/engine/recipes/config_files/default_config.yml +4 -0
  311. rasa/engine/recipes/default_components.py +13 -15
  312. rasa/engine/recipes/default_recipe.py +65 -49
  313. rasa/engine/recipes/graph_recipe.py +10 -7
  314. rasa/engine/recipes/recipe.py +2 -2
  315. rasa/engine/runner/dask.py +2 -2
  316. rasa/engine/runner/interface.py +1 -0
  317. rasa/engine/storage/local_model_storage.py +6 -4
  318. rasa/engine/storage/resource.py +2 -1
  319. rasa/engine/storage/storage.py +8 -3
  320. rasa/engine/training/components.py +2 -1
  321. rasa/engine/training/fingerprinting.py +4 -2
  322. rasa/engine/training/graph_trainer.py +4 -4
  323. rasa/engine/training/hooks.py +2 -2
  324. rasa/engine/validation.py +36 -33
  325. rasa/exceptions.py +3 -2
  326. rasa/graph_components/converters/nlu_message_converter.py +3 -3
  327. rasa/graph_components/providers/domain_for_core_training_provider.py +3 -3
  328. rasa/graph_components/providers/domain_provider.py +3 -2
  329. rasa/graph_components/providers/flows_provider.py +2 -3
  330. rasa/graph_components/providers/forms_provider.py +4 -4
  331. rasa/graph_components/providers/nlu_training_data_provider.py +5 -3
  332. rasa/graph_components/providers/responses_provider.py +4 -4
  333. rasa/graph_components/providers/rule_only_provider.py +3 -2
  334. rasa/graph_components/providers/story_graph_provider.py +8 -8
  335. rasa/graph_components/providers/training_tracker_provider.py +3 -2
  336. rasa/graph_components/validators/default_recipe_validator.py +16 -16
  337. rasa/graph_components/validators/finetuning_validator.py +10 -8
  338. rasa/hooks.py +19 -14
  339. rasa/jupyter.py +2 -2
  340. rasa/llm_fine_tuning/annotation_module.py +4 -4
  341. rasa/llm_fine_tuning/conversations.py +5 -33
  342. rasa/llm_fine_tuning/llm_data_preparation_module.py +6 -4
  343. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -4
  344. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +18 -13
  345. rasa/llm_fine_tuning/paraphrasing_module.py +6 -2
  346. rasa/llm_fine_tuning/storage.py +3 -3
  347. rasa/llm_fine_tuning/train_test_split_module.py +27 -27
  348. rasa/llm_fine_tuning/utils.py +7 -0
  349. rasa/markers/marker.py +2 -3
  350. rasa/markers/marker_base.py +1 -2
  351. rasa/markers/upload.py +2 -2
  352. rasa/markers/validate.py +2 -3
  353. rasa/model.py +3 -5
  354. rasa/model_manager/config.py +1 -1
  355. rasa/model_manager/model_api.py +5 -4
  356. rasa/model_manager/runner_service.py +13 -10
  357. rasa/model_manager/socket_bridge.py +15 -9
  358. rasa/model_manager/studio_jwt_auth.py +1 -0
  359. rasa/model_manager/trainer_service.py +9 -7
  360. rasa/model_manager/utils.py +1 -1
  361. rasa/model_manager/warm_rasa_process.py +14 -9
  362. rasa/model_service.py +5 -6
  363. rasa/model_testing.py +13 -15
  364. rasa/model_training.py +29 -29
  365. rasa/nlu/classifiers/diet_classifier.py +72 -73
  366. rasa/nlu/classifiers/fallback_classifier.py +9 -8
  367. rasa/nlu/classifiers/keyword_intent_classifier.py +7 -6
  368. rasa/nlu/classifiers/logistic_regression_classifier.py +3 -3
  369. rasa/nlu/classifiers/mitie_intent_classifier.py +5 -4
  370. rasa/nlu/classifiers/regex_message_handler.py +3 -2
  371. rasa/nlu/classifiers/sklearn_intent_classifier.py +2 -2
  372. rasa/nlu/convert.py +2 -2
  373. rasa/nlu/emulators/dialogflow.py +3 -3
  374. rasa/nlu/emulators/luis.py +5 -5
  375. rasa/nlu/emulators/no_emulator.py +1 -0
  376. rasa/nlu/emulators/wit.py +4 -4
  377. rasa/nlu/extractors/crf_entity_extractor.py +11 -11
  378. rasa/nlu/extractors/duckling_entity_extractor.py +7 -6
  379. rasa/nlu/extractors/entity_synonyms.py +10 -9
  380. rasa/nlu/extractors/extractor.py +16 -16
  381. rasa/nlu/extractors/mitie_entity_extractor.py +10 -9
  382. rasa/nlu/extractors/regex_entity_extractor.py +11 -10
  383. rasa/nlu/extractors/spacy_entity_extractor.py +2 -2
  384. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +15 -14
  385. rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +2 -1
  386. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +10 -9
  387. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +9 -7
  388. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +13 -12
  389. rasa/nlu/featurizers/featurizer.py +5 -4
  390. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +6 -6
  391. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -4
  392. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +4 -4
  393. rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +2 -0
  394. rasa/nlu/model.py +0 -1
  395. rasa/nlu/selectors/response_selector.py +67 -68
  396. rasa/nlu/test.py +38 -38
  397. rasa/nlu/tokenizers/jieba_tokenizer.py +1 -2
  398. rasa/nlu/tokenizers/mitie_tokenizer.py +2 -2
  399. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -3
  400. rasa/nlu/tokenizers/tokenizer.py +6 -7
  401. rasa/nlu/tokenizers/whitespace_tokenizer.py +1 -1
  402. rasa/nlu/utils/bilou_utils.py +7 -7
  403. rasa/nlu/utils/hugging_face/registry.py +22 -22
  404. rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +2 -1
  405. rasa/nlu/utils/mitie_utils.py +2 -1
  406. rasa/nlu/utils/pattern_utils.py +1 -1
  407. rasa/nlu/utils/spacy_utils.py +3 -3
  408. rasa/plugin.py +12 -1
  409. rasa/server.py +6 -3
  410. rasa/shared/constants.py +45 -18
  411. rasa/shared/core/command_payload_reader.py +15 -7
  412. rasa/shared/core/constants.py +34 -4
  413. rasa/shared/core/conversation.py +1 -2
  414. rasa/shared/core/domain.py +19 -20
  415. rasa/shared/core/events.py +60 -39
  416. rasa/shared/core/flows/__init__.py +0 -1
  417. rasa/shared/core/flows/constants.py +11 -0
  418. rasa/shared/core/flows/flow.py +107 -26
  419. rasa/shared/core/flows/flow_step.py +4 -3
  420. rasa/shared/core/flows/flow_step_links.py +1 -2
  421. rasa/shared/core/flows/flow_step_sequence.py +1 -1
  422. rasa/shared/core/flows/flows_list.py +3 -3
  423. rasa/shared/core/flows/flows_yaml_schema.json +69 -3
  424. rasa/shared/core/flows/nlu_trigger.py +1 -1
  425. rasa/shared/core/flows/steps/__init__.py +2 -2
  426. rasa/shared/core/flows/steps/action.py +1 -1
  427. rasa/shared/core/flows/steps/call.py +1 -1
  428. rasa/shared/core/flows/steps/collect.py +22 -40
  429. rasa/shared/core/flows/steps/internal.py +1 -1
  430. rasa/shared/core/flows/steps/link.py +1 -1
  431. rasa/shared/core/flows/steps/no_operation.py +2 -2
  432. rasa/shared/core/flows/steps/set_slots.py +1 -1
  433. rasa/shared/core/flows/utils.py +44 -4
  434. rasa/shared/core/flows/validation.py +4 -6
  435. rasa/shared/core/generator.py +20 -21
  436. rasa/shared/core/slot_mappings.py +360 -121
  437. rasa/shared/core/slots.py +163 -6
  438. rasa/shared/core/trackers.py +108 -33
  439. rasa/shared/core/training_data/loading.py +1 -1
  440. rasa/shared/core/training_data/story_reader/story_reader.py +3 -3
  441. rasa/shared/core/training_data/story_reader/story_step_builder.py +4 -4
  442. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +29 -31
  443. rasa/shared/core/training_data/story_writer/yaml_story_writer.py +22 -24
  444. rasa/shared/core/training_data/structures.py +11 -12
  445. rasa/shared/core/training_data/visualization.py +10 -10
  446. rasa/shared/data.py +6 -6
  447. rasa/shared/engine/caching.py +0 -1
  448. rasa/shared/exceptions.py +2 -2
  449. rasa/shared/importers/importer.py +58 -2
  450. rasa/shared/importers/rasa.py +5 -6
  451. rasa/shared/importers/utils.py +1 -1
  452. rasa/shared/nlu/constants.py +9 -0
  453. rasa/shared/nlu/training_data/entities_parser.py +6 -6
  454. rasa/shared/nlu/training_data/features.py +3 -3
  455. rasa/shared/nlu/training_data/formats/__init__.py +1 -1
  456. rasa/shared/nlu/training_data/formats/dialogflow.py +4 -5
  457. rasa/shared/nlu/training_data/formats/luis.py +7 -8
  458. rasa/shared/nlu/training_data/formats/rasa.py +4 -5
  459. rasa/shared/nlu/training_data/formats/rasa_yaml.py +17 -16
  460. rasa/shared/nlu/training_data/formats/readerwriter.py +8 -11
  461. rasa/shared/nlu/training_data/formats/wit.py +3 -4
  462. rasa/shared/nlu/training_data/loading.py +4 -4
  463. rasa/shared/nlu/training_data/lookup_tables_parser.py +1 -1
  464. rasa/shared/nlu/training_data/message.py +13 -14
  465. rasa/shared/nlu/training_data/schemas/data_schema.py +1 -1
  466. rasa/shared/nlu/training_data/schemas/responses.yml +19 -11
  467. rasa/shared/nlu/training_data/synonyms_parser.py +3 -3
  468. rasa/shared/nlu/training_data/training_data.py +12 -13
  469. rasa/shared/nlu/training_data/util.py +11 -10
  470. rasa/shared/providers/_configs/azure_entra_id_config.py +541 -0
  471. rasa/shared/providers/_configs/azure_openai_client_config.py +150 -15
  472. rasa/shared/providers/_configs/client_config.py +3 -1
  473. rasa/shared/providers/_configs/default_litellm_client_config.py +9 -7
  474. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +13 -11
  475. rasa/shared/providers/_configs/litellm_router_client_config.py +12 -10
  476. rasa/shared/providers/_configs/model_group_config.py +8 -5
  477. rasa/shared/providers/_configs/oauth_config.py +33 -0
  478. rasa/shared/providers/_configs/openai_client_config.py +14 -12
  479. rasa/shared/providers/_configs/rasa_llm_client_config.py +5 -3
  480. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +12 -11
  481. rasa/shared/providers/_configs/utils.py +1 -0
  482. rasa/shared/providers/_ssl_verification_utils.py +5 -6
  483. rasa/shared/providers/_utils.py +5 -5
  484. rasa/shared/providers/constants.py +6 -0
  485. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -1
  486. rasa/shared/providers/embedding/azure_openai_embedding_client.py +32 -7
  487. rasa/shared/providers/embedding/embedding_client.py +1 -1
  488. rasa/shared/providers/embedding/litellm_router_embedding_client.py +5 -2
  489. rasa/shared/providers/llm/_base_litellm_client.py +43 -18
  490. rasa/shared/providers/llm/azure_openai_llm_client.py +90 -34
  491. rasa/shared/providers/llm/default_litellm_llm_client.py +4 -2
  492. rasa/shared/providers/llm/litellm_router_llm_client.py +32 -9
  493. rasa/shared/providers/llm/llm_client.py +24 -8
  494. rasa/shared/providers/llm/llm_response.py +61 -2
  495. rasa/shared/providers/llm/openai_llm_client.py +11 -5
  496. rasa/shared/providers/llm/rasa_llm_client.py +17 -14
  497. rasa/shared/providers/llm/self_hosted_llm_client.py +35 -15
  498. rasa/shared/providers/mappings.py +18 -19
  499. rasa/shared/providers/router/_base_litellm_router_client.py +48 -15
  500. rasa/shared/providers/router/router_client.py +3 -1
  501. rasa/shared/utils/cli.py +1 -1
  502. rasa/shared/utils/common.py +15 -1
  503. rasa/shared/utils/constants.py +3 -0
  504. rasa/shared/utils/health_check/embeddings_health_check_mixin.py +1 -1
  505. rasa/shared/utils/health_check/health_check.py +3 -3
  506. rasa/shared/utils/health_check/llm_health_check_mixin.py +1 -1
  507. rasa/shared/utils/io.py +1 -1
  508. rasa/shared/utils/llm.py +100 -18
  509. rasa/shared/utils/pykwalify_extensions.py +25 -1
  510. rasa/shared/utils/schemas/domain.yml +26 -1
  511. rasa/shared/utils/schemas/events.py +1 -1
  512. rasa/shared/utils/yaml.py +24 -20
  513. rasa/studio/auth.py +3 -3
  514. rasa/studio/config.py +1 -2
  515. rasa/studio/data_handler.py +3 -3
  516. rasa/studio/download.py +1 -1
  517. rasa/studio/results_logger.py +3 -3
  518. rasa/studio/upload.py +21 -5
  519. rasa/telemetry.py +127 -48
  520. rasa/tracing/config.py +5 -3
  521. rasa/tracing/constants.py +12 -0
  522. rasa/tracing/instrumentation/attribute_extractors.py +92 -14
  523. rasa/tracing/instrumentation/instrumentation.py +61 -5
  524. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +1 -1
  525. rasa/tracing/instrumentation/metrics.py +52 -11
  526. rasa/tracing/metric_instrument_provider.py +54 -14
  527. rasa/utils/common.py +12 -24
  528. rasa/utils/endpoints.py +1 -1
  529. rasa/utils/io.py +7 -7
  530. rasa/utils/licensing.py +3 -4
  531. rasa/utils/log_utils.py +7 -6
  532. rasa/utils/ml_utils.py +1 -0
  533. rasa/utils/plotting.py +3 -3
  534. rasa/utils/sanic_error_handler.py +1 -1
  535. rasa/utils/tensorflow/callback.py +2 -2
  536. rasa/utils/tensorflow/crf.py +2 -2
  537. rasa/utils/tensorflow/data_generator.py +5 -5
  538. rasa/utils/tensorflow/environment.py +3 -3
  539. rasa/utils/tensorflow/feature_array.py +2 -3
  540. rasa/utils/tensorflow/layers.py +18 -12
  541. rasa/utils/tensorflow/layers_utils.py +2 -1
  542. rasa/utils/tensorflow/metrics.py +2 -2
  543. rasa/utils/tensorflow/model_data.py +7 -7
  544. rasa/utils/tensorflow/model_data_utils.py +10 -9
  545. rasa/utils/tensorflow/models.py +31 -32
  546. rasa/utils/tensorflow/rasa_layers.py +20 -19
  547. rasa/utils/tensorflow/types.py +2 -1
  548. rasa/utils/train_utils.py +23 -21
  549. rasa/utils/url_tools.py +1 -1
  550. rasa/validator.py +594 -115
  551. rasa/version.py +1 -1
  552. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/METADATA +23 -26
  553. rasa_pro-3.12.0.dist-info/RECORD +829 -0
  554. rasa/core/channels/inspector/dist/assets/arc-632a63ec.js +0 -1
  555. rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-081e0df4.js +0 -10
  556. rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-3df0afc2.js +0 -2
  557. rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-8c5ed31e.js +0 -2
  558. rasa/core/channels/inspector/dist/assets/edges-f2ad444c-4fc48c3e.js +0 -4
  559. rasa/core/channels/inspector/dist/assets/flowDb-1972c806-9ec53a3c.js +0 -6
  560. rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-41da787a.js +0 -4
  561. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-8bea338b.js +0 -1
  562. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-ce370633.js +0 -139
  563. rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-90a36523.js +0 -266
  564. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-41e1aa3f.js +0 -70
  565. rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-e6f2af62.js +0 -1
  566. rasa/core/channels/inspector/dist/assets/layout-498807d8.js +0 -1
  567. rasa/core/channels/inspector/dist/assets/linear-8a078617.js +0 -1
  568. rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-396d17dd.js +0 -109
  569. rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-53f6f391.js +0 -8
  570. rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-715c9c20.js +0 -122
  571. rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-2e8fb31f.js +0 -1
  572. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-7e2d2aa0.js +0 -1
  573. rasa/core/channels/inspector/dist/assets/styles-080da4f6-4420cea6.js +0 -110
  574. rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-28676cf4.js +0 -159
  575. rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-151251e9.js +0 -1
  576. rasa_pro-3.11.4.dist-info/RECORD +0 -779
  577. /rasa/dialogue_understanding/generator/{single_step → prompt_templates}/command_prompt_template.jinja2 +0 -0
  578. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/NOTICE +0 -0
  579. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/WHEEL +0 -0
  580. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,212 @@
1
+ import asyncio
2
+ import json
3
+ from functools import partial
4
+ from typing import (
5
+ TYPE_CHECKING,
6
+ Any,
7
+ Awaitable,
8
+ Callable,
9
+ Dict,
10
+ List,
11
+ Optional,
12
+ Text,
13
+ )
14
+
15
+ import structlog
16
+ from sanic import Sanic
17
+
18
+ from rasa.core.channels.socketio import SocketBlueprint, SocketIOInput
19
+ from rasa.hooks import hookimpl
20
+ from rasa.plugin import plugin_manager
21
+ from rasa.shared.core.constants import ACTION_LISTEN_NAME
22
+ from rasa.shared.core.events import ActionExecuted
23
+ from rasa.shared.core.trackers import EventVerbosity
24
+
25
+ if TYPE_CHECKING:
26
+ from rasa.core.channels.channel import UserMessage
27
+ from rasa.shared.core.trackers import DialogueStateTracker
28
+
29
+
30
+ structlogger = structlog.get_logger()
31
+
32
+
33
+ def tracker_as_dump(tracker: "DialogueStateTracker") -> str:
34
+ """Create a dump of the tracker state."""
35
+ from rasa.shared.core.trackers import get_trackers_for_conversation_sessions
36
+
37
+ multiple_tracker_sessions = get_trackers_for_conversation_sessions(tracker)
38
+
39
+ if 0 <= len(multiple_tracker_sessions) <= 1:
40
+ last_tracker = tracker
41
+ else:
42
+ last_tracker = multiple_tracker_sessions[-1]
43
+
44
+ state = last_tracker.current_state(EventVerbosity.AFTER_RESTART)
45
+ return json.dumps(state)
46
+
47
+
48
+ def does_need_action_prediction(tracker: "DialogueStateTracker") -> bool:
49
+ """Check if the tracker needs an action prediction."""
50
+ return (
51
+ len(tracker.events) == 0
52
+ or not isinstance(tracker.events[-1], ActionExecuted)
53
+ or tracker.events[-1].action_name != ACTION_LISTEN_NAME
54
+ )
55
+
56
+
57
+ class StudioTrackerUpdatePlugin:
58
+ """Plugin for publishing tracker updates a socketio channel."""
59
+
60
+ def __init__(self, socket_channel: "StudioChatInput") -> None:
61
+ self.socket_channel = socket_channel
62
+ self.tasks: List[asyncio.Task] = []
63
+
64
+ def _cancel_tasks(self) -> None:
65
+ """Cancel all remaining tasks."""
66
+ for task in self.tasks:
67
+ task.cancel()
68
+ self.tasks = []
69
+
70
+ def _cleanup_tasks(self) -> None:
71
+ """Remove tasks that have already completed."""
72
+ self.tasks = [task for task in self.tasks if not task.done()]
73
+
74
+ @hookimpl # type: ignore[misc]
75
+ def after_new_user_message(self, tracker: "DialogueStateTracker") -> None:
76
+ """Triggers a tracker update notification after a new user message."""
77
+ self.handle_tracker_update(tracker)
78
+
79
+ @hookimpl # type: ignore[misc]
80
+ def after_action_executed(self, tracker: "DialogueStateTracker") -> None:
81
+ """Triggers a tracker update notification after an action is executed."""
82
+ self.handle_tracker_update(tracker)
83
+
84
+ def handle_tracker_update(self, tracker: "DialogueStateTracker") -> None:
85
+ """Handles a tracker update when triggered by a hook."""
86
+ structlogger.info("studio_chat.after_tracker_update", tracker=tracker)
87
+ # directly create a dump to avoid the tracker getting modified by another
88
+ # function before it gets published (since the publishing is scheduled
89
+ # as an async task)
90
+ tracker_dump = tracker_as_dump(tracker)
91
+ task = asyncio.create_task(
92
+ self.socket_channel.publish_tracker_update(tracker.sender_id, tracker_dump)
93
+ )
94
+ self.tasks.append(task)
95
+ self._cleanup_tasks()
96
+
97
+ @hookimpl # type: ignore[misc]
98
+ def after_server_stop(self) -> None:
99
+ """Cancels all remaining tasks when the server stops."""
100
+ self._cancel_tasks()
101
+
102
+
103
+ class StudioChatInput(SocketIOInput):
104
+ """Input channel for the communication between Rasa Studio and Rasa Pro."""
105
+
106
+ @classmethod
107
+ def name(cls) -> Text:
108
+ return "studio_chat"
109
+
110
+ def __init__(
111
+ self,
112
+ *args: Any,
113
+ **kwargs: Any,
114
+ ) -> None:
115
+ """Creates a ``SocketIOInput`` object."""
116
+ from rasa.core.agent import Agent
117
+
118
+ super().__init__(*args, **kwargs)
119
+ self.agent: Optional[Agent] = None
120
+
121
+ self._register_tracker_update_hook()
122
+
123
+ def _register_tracker_update_hook(self) -> None:
124
+ plugin_manager().register(StudioTrackerUpdatePlugin(self))
125
+
126
+ async def on_tracker_updated(self, tracker: "DialogueStateTracker") -> None:
127
+ """Triggers a tracker update notification after a change to the tracker."""
128
+ await self.publish_tracker_update(tracker.sender_id, tracker_as_dump(tracker))
129
+
130
+ async def publish_tracker_update(self, sender_id: str, tracker_dump: Dict) -> None:
131
+ """Publishes a tracker update notification to the websocket."""
132
+ if not self.sio:
133
+ structlogger.error("studio_chat.on_tracker_updated.sio_not_initialized")
134
+ return
135
+ await self.sio.emit("tracker", tracker_dump, room=sender_id)
136
+
137
+ async def on_message_proxy(
138
+ self,
139
+ on_new_message: Callable[["UserMessage"], Awaitable[Any]],
140
+ message: "UserMessage",
141
+ ) -> None:
142
+ """Proxies the on_new_message call to the underlying channel.
143
+
144
+ Triggers a tracker update notification after processing the message.
145
+ """
146
+ await on_new_message(message)
147
+
148
+ if not self.agent:
149
+ structlogger.error("studio_chat.on_message_proxy.agent_not_initialized")
150
+ return
151
+
152
+ tracker = await self.agent.tracker_store.retrieve(message.sender_id)
153
+ if tracker is None:
154
+ structlogger.error("studio_chat.on_message_proxy.tracker_not_found")
155
+ return
156
+
157
+ await self.on_tracker_updated(tracker)
158
+
159
+ async def handle_tracker_update(self, sid: str, data: Dict) -> None:
160
+ from rasa.shared.core.trackers import DialogueStateTracker
161
+
162
+ structlogger.debug(
163
+ "studio_chat.sio.handle_tracker_update",
164
+ sid=sid,
165
+ sender_id=data["sender_id"],
166
+ )
167
+ if self.agent is None:
168
+ structlogger.error("studio_chat.sio.agent_not_initialized")
169
+ return None
170
+
171
+ if not (domain := self.agent.domain):
172
+ structlogger.error("studio_chat.sio.domain_not_initialized")
173
+ return None
174
+
175
+ async with self.agent.lock_store.lock(data["sender_id"]):
176
+ tracker = DialogueStateTracker.from_dict(
177
+ data["sender_id"], data["events"], domain.slots
178
+ )
179
+
180
+ # will override an existing tracker with the same id!
181
+ await self.agent.tracker_store.save(tracker)
182
+
183
+ processor = self.agent.processor
184
+ if processor and does_need_action_prediction(tracker):
185
+ output_channel = self.get_output_channel()
186
+
187
+ await processor._run_prediction_loop(output_channel, tracker)
188
+ await processor.run_anonymization_pipeline(tracker)
189
+ await self.agent.tracker_store.save(tracker)
190
+
191
+ await self.on_tracker_updated(tracker)
192
+
193
+ def blueprint(
194
+ self, on_new_message: Callable[["UserMessage"], Awaitable[Any]]
195
+ ) -> SocketBlueprint:
196
+ socket_blueprint = super().blueprint(
197
+ partial(self.on_message_proxy, on_new_message)
198
+ )
199
+
200
+ if not self.sio:
201
+ structlogger.error("studio_chat.blueprint.sio_not_initialized")
202
+ return socket_blueprint
203
+
204
+ @socket_blueprint.listener("after_server_start") # type: ignore[misc]
205
+ async def after_server_start(app: Sanic, _: asyncio.AbstractEventLoop) -> None:
206
+ self.agent = app.ctx.agent
207
+
208
+ @self.sio.on("update_tracker", namespace=self.namespace)
209
+ async def on_update_tracker(sid: Text, data: Dict) -> None:
210
+ await self.handle_tracker_update(sid, data)
211
+
212
+ return socket_blueprint
@@ -1,31 +1,25 @@
1
- import asyncio
2
1
  import json
3
2
  import logging
3
+ import typing
4
4
  from copy import deepcopy
5
+ from typing import Any, Awaitable, Callable, Dict, List, Optional, Text
6
+
5
7
  from sanic import Blueprint, response
6
8
  from sanic.request import Request
7
9
  from sanic.response import HTTPResponse
8
- from aiogram import Bot
9
- from aiogram.types import (
10
- InlineKeyboardButton,
11
- Update,
12
- InlineKeyboardMarkup,
13
- KeyboardButton,
14
- ReplyKeyboardMarkup,
15
- Message,
16
- )
17
- from aiogram.utils.exceptions import TelegramAPIError
18
- from typing import Dict, Text, Any, List, Optional, Callable, Awaitable
19
-
20
- from rasa.core.channels.channel import InputChannel, UserMessage, OutputChannel
10
+
11
+ from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
21
12
  from rasa.shared.constants import INTENT_MESSAGE_PREFIX
22
13
  from rasa.shared.core.constants import USER_INTENT_RESTART
23
14
  from rasa.shared.exceptions import RasaException
24
15
 
25
16
  logger = logging.getLogger(__name__)
26
17
 
18
+ if typing.TYPE_CHECKING:
19
+ from aiogram.types import Message, Update
20
+
27
21
 
28
- class TelegramOutput(Bot, OutputChannel):
22
+ class TelegramOutput(OutputChannel):
29
23
  """Output channel for Telegram."""
30
24
 
31
25
  # skipcq: PYL-W0236
@@ -34,20 +28,28 @@ class TelegramOutput(Bot, OutputChannel):
34
28
  return "telegram"
35
29
 
36
30
  def __init__(self, access_token: Optional[Text]) -> None:
37
- Bot.__init__(self, access_token)
31
+ try:
32
+ from aiogram import Bot
33
+
34
+ self.bot = Bot(access_token)
35
+ except ImportError:
36
+ raise ImportError(
37
+ "To use the Telegram channel, please install the aiogram package "
38
+ "with 'pip install aiogram'"
39
+ )
38
40
 
39
41
  async def send_text_message(
40
42
  self, recipient_id: Text, text: Text, **kwargs: Any
41
43
  ) -> None:
42
44
  """Sends text message."""
43
45
  for message_part in text.strip().split("\n\n"):
44
- await self.send_message(recipient_id, message_part)
46
+ await self.bot.send_message(recipient_id, message_part)
45
47
 
46
48
  async def send_image_url(
47
49
  self, recipient_id: Text, image: Text, **kwargs: Any
48
50
  ) -> None:
49
51
  """Sends an image."""
50
- await self.send_photo(recipient_id, image)
52
+ await self.bot.send_photo(recipient_id, image)
51
53
 
52
54
  async def send_text_with_buttons(
53
55
  self,
@@ -67,34 +69,45 @@ class TelegramOutput(Bot, OutputChannel):
67
69
 
68
70
  :button_type reply: reply keyboard
69
71
  """
72
+ from aiogram.types import InlineKeyboardButton, KeyboardButton
73
+ from aiogram.utils.keyboard import (
74
+ InlineKeyboardBuilder,
75
+ KeyboardBuilder,
76
+ ReplyKeyboardBuilder,
77
+ )
78
+
70
79
  if button_type == "inline":
71
- reply_markup = InlineKeyboardMarkup()
80
+ reply_markup_builder: "KeyboardBuilder" = InlineKeyboardBuilder()
72
81
  button_list = [
73
- InlineKeyboardButton(s["title"], callback_data=s["payload"])
82
+ InlineKeyboardButton(text=s["title"], callback_data=s["payload"])
74
83
  for s in buttons
75
84
  ]
76
- reply_markup.row(*button_list)
85
+ reply_markup_builder.row(*button_list)
86
+ reply_markup = reply_markup_builder.as_markup()
77
87
 
78
88
  elif button_type == "vertical":
79
- reply_markup = InlineKeyboardMarkup()
89
+ reply_markup_builder = InlineKeyboardBuilder()
80
90
  [
81
- reply_markup.row(
82
- InlineKeyboardButton(s["title"], callback_data=s["payload"])
91
+ reply_markup_builder.row(
92
+ InlineKeyboardButton(text=s["title"], callback_data=s["payload"])
83
93
  )
84
94
  for s in buttons
85
95
  ]
96
+ reply_markup = reply_markup_builder.as_markup()
86
97
 
87
98
  elif button_type == "reply":
88
- reply_markup = ReplyKeyboardMarkup(
89
- resize_keyboard=False, one_time_keyboard=True
90
- )
91
- # drop button_type from button_list
92
- button_list = [b for b in buttons if b.get("title")]
99
+ reply_markup_builder = ReplyKeyboardBuilder()
100
+
93
101
  for idx, button in enumerate(buttons):
94
102
  if isinstance(button, list):
95
- reply_markup.add(KeyboardButton(s["title"]) for s in button)
103
+ reply_markup_builder.add(
104
+ *[KeyboardButton(text=s["title"]) for s in button]
105
+ )
96
106
  else:
97
- reply_markup.add(KeyboardButton(button["title"]))
107
+ reply_markup_builder.add(KeyboardButton(text=button["title"]))
108
+ reply_markup = reply_markup_builder.as_markup(
109
+ resize_keyboard=False, one_time_keyboard=True
110
+ )
98
111
  else:
99
112
  logger.error(
100
113
  "Trying to send text with buttons for unknown button type {}".format(
@@ -103,7 +116,7 @@ class TelegramOutput(Bot, OutputChannel):
103
116
  )
104
117
  return
105
118
 
106
- await self.send_message(recipient_id, text, reply_markup=reply_markup)
119
+ await self.bot.send_message(recipient_id, text, reply_markup=reply_markup)
107
120
 
108
121
  async def send_custom_json(
109
122
  self, recipient_id: Text, json_message: Dict[Text, Any], **kwargs: Any
@@ -143,9 +156,17 @@ class TelegramOutput(Bot, OutputChannel):
143
156
  for params in send_functions.keys():
144
157
  if all(json_message.get(p) is not None for p in params):
145
158
  args = [json_message.pop(p) for p in params]
146
- api_call = getattr(self, send_functions[params])
159
+ api_call = getattr(self.bot, send_functions[params])
147
160
  await api_call(recipient_id, *args, **json_message)
148
161
 
162
+ async def get_me(self) -> Any:
163
+ """Get information about the bot itself."""
164
+ return await self.bot.get_me()
165
+
166
+ async def set_webhook(self, url: Text) -> None:
167
+ """Set the webhook URL for telegram."""
168
+ await self.bot.set_webhook(url=url)
169
+
149
170
 
150
171
  class TelegramInput(InputChannel):
151
172
  """Telegram input channel."""
@@ -178,19 +199,19 @@ class TelegramInput(InputChannel):
178
199
  self.debug_mode = debug_mode
179
200
 
180
201
  @staticmethod
181
- def _is_location(message: Message) -> bool:
202
+ def _is_location(message: "Message") -> bool:
182
203
  return message.location is not None
183
204
 
184
205
  @staticmethod
185
- def _is_user_message(message: Message) -> bool:
206
+ def _is_user_message(message: "Message") -> bool:
186
207
  return message.text is not None
187
208
 
188
209
  @staticmethod
189
- def _is_edited_message(message: Update) -> bool:
210
+ def _is_edited_message(message: "Update") -> bool:
190
211
  return message.edited_message is not None
191
212
 
192
213
  @staticmethod
193
- def _is_button(message: Update) -> bool:
214
+ def _is_button(message: "Update") -> bool:
194
215
  return message.callback_query is not None
195
216
 
196
217
  def blueprint(
@@ -205,16 +226,19 @@ class TelegramInput(InputChannel):
205
226
 
206
227
  @telegram_webhook.route("/set_webhook", methods=["GET", "POST"])
207
228
  async def set_webhook(_: Request) -> HTTPResponse:
208
- s = await out_channel.set_webhook(self.webhook_url)
209
- if s:
210
- logger.info("Webhook Setup Successful")
211
- return response.text("Webhook setup successful")
212
- else:
213
- logger.warning("Webhook Setup Failed")
214
- return response.text("Invalid webhook")
229
+ try:
230
+ await self.set_webhook(out_channel)
231
+ except RasaException as exc:
232
+ logger.error(exc)
233
+ return response.text(str(exc))
234
+
235
+ logger.info("Webhook Setup Successful")
236
+ return response.text("Webhook setup successful")
215
237
 
216
238
  @telegram_webhook.route("/webhook", methods=["GET", "POST"])
217
239
  async def message(request: Request) -> Any:
240
+ from aiogram.types import Update
241
+
218
242
  if request.method == "POST":
219
243
  request_dict = request.json
220
244
  if isinstance(request_dict, Text):
@@ -226,24 +250,49 @@ class TelegramInput(InputChannel):
226
250
  return response.text("failed")
227
251
 
228
252
  if self._is_button(update):
229
- msg = update.callback_query.message
230
- text = update.callback_query.data
253
+ msg = (
254
+ update.callback_query.message
255
+ if update.callback_query is not None
256
+ else None
257
+ )
258
+ text = (
259
+ update.callback_query.data
260
+ if update.callback_query is not None
261
+ else None
262
+ )
231
263
  elif self._is_edited_message(update):
232
264
  msg = update.edited_message
233
- text = update.edited_message.text
265
+ text = (
266
+ update.edited_message.text
267
+ if update.edited_message is not None
268
+ else None
269
+ )
234
270
  else:
235
271
  msg = update.message
236
272
  if self._is_user_message(msg):
237
- text = msg.text.replace("/bot", "")
273
+ text = (
274
+ msg.text.replace("/bot", "")
275
+ if msg is not None and msg.text is not None
276
+ else None
277
+ )
238
278
  elif self._is_location(msg):
239
- text = '{{"lng":{0}, "lat":{1}}}'.format(
240
- msg.location.longitude, msg.location.latitude
279
+ text = (
280
+ '{{"lng":{0}, "lat":{1}}}'.format(
281
+ msg.location.longitude, msg.location.latitude
282
+ )
283
+ if msg is not None and msg.location is not None
284
+ else None
241
285
  )
242
286
  else:
243
287
  return response.text("success")
244
- sender_id = msg.chat.id
288
+
245
289
  metadata = self.get_metadata(request)
246
290
  try:
291
+ if msg is not None:
292
+ sender_id = str(msg.chat.id)
293
+ else:
294
+ raise ValueError("No message found.")
295
+
247
296
  if text == (INTENT_MESSAGE_PREFIX + USER_INTENT_RESTART):
248
297
  await on_new_message(
249
298
  UserMessage(
@@ -286,13 +335,14 @@ class TelegramInput(InputChannel):
286
335
 
287
336
  def get_output_channel(self) -> TelegramOutput:
288
337
  """Loads the telegram channel."""
289
- channel = TelegramOutput(self.access_token)
338
+ return TelegramOutput(self.access_token)
339
+
340
+ async def set_webhook(self, channel: TelegramOutput) -> None:
341
+ from aiogram.exceptions import TelegramAPIError
290
342
 
291
343
  try:
292
- asyncio.run(channel.set_webhook(url=self.webhook_url))
344
+ await channel.set_webhook(url=self.webhook_url)
293
345
  except TelegramAPIError as error:
294
346
  raise RasaException(
295
347
  "Failed to set channel webhook: " + str(error)
296
348
  ) from error
297
-
298
- return channel
@@ -1,13 +1,13 @@
1
1
  import logging
2
+ from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Optional, Text
3
+
2
4
  from sanic import Blueprint, response
3
5
  from sanic.request import Request
4
6
  from sanic.response import HTTPResponse
5
7
  from twilio.base.exceptions import TwilioRestException
6
8
  from twilio.rest import Client
7
- from typing import Dict, Text, Any, Callable, Awaitable, Optional, TYPE_CHECKING
8
9
 
9
- from rasa.core.channels.channel import InputChannel
10
- from rasa.core.channels.channel import UserMessage, OutputChannel
10
+ from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from twilio.rest.api.v2010.account.message import MessageInstance
@@ -8,10 +8,10 @@ from dataclasses import dataclass
8
8
  from functools import wraps
9
9
  from typing import Any, Awaitable, Callable, Dict, Optional, Text
10
10
 
11
- import rasa.shared.utils.io
12
11
  import structlog
13
- from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
14
12
 
13
+ import rasa.shared.utils.io
14
+ from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
15
15
  from rasa.utils.beta import ensure_beta_feature_is_enabled
16
16
 
17
17
  # ignore ResourceWarning, InsecureRequestWarning
@@ -1,26 +1,28 @@
1
+ import asyncio
1
2
  import copy
2
- from datetime import datetime, timezone, timedelta
3
3
  import json
4
4
  import uuid
5
- from typing import Any, Awaitable, Callable, Dict, List, Optional, Text, Union
5
+ from collections import defaultdict
6
6
  from dataclasses import asdict
7
+ from datetime import datetime, timedelta, timezone
8
+ from typing import Any, Awaitable, Callable, Dict, List, Optional, Set, Text, Union
7
9
 
8
10
  import structlog
9
11
  from jsonschema import ValidationError, validate
12
+ from sanic import Blueprint, response
13
+ from sanic.exceptions import NotFound, SanicException, ServerError
14
+ from sanic.request import Request
15
+ from sanic.response import HTTPResponse
16
+
10
17
  from rasa.core import jobs
11
18
  from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
12
19
  from rasa.core.channels.voice_ready.utils import (
13
- validate_voice_license_scope,
14
20
  CallParameters,
21
+ validate_voice_license_scope,
15
22
  )
16
23
  from rasa.shared.constants import INTENT_MESSAGE_PREFIX
17
24
  from rasa.shared.core.constants import USER_INTENT_SESSION_START
18
25
  from rasa.shared.exceptions import RasaException
19
- from sanic import Blueprint, response
20
- from sanic.exceptions import NotFound, SanicException, ServerError
21
- from sanic.request import Request
22
- from sanic.response import HTTPResponse
23
-
24
26
  from rasa.utils.io import remove_emojis
25
27
 
26
28
  structlogger = structlog.get_logger()
@@ -45,8 +47,8 @@ def map_call_params(parameters: Dict[Text, Any]) -> CallParameters:
45
47
  """Map the Audiocodes parameters to the CallParameters dataclass."""
46
48
  return CallParameters(
47
49
  call_id=parameters.get("vaigConversationId"),
48
- user_phone=parameters.get("callee"),
49
- bot_phone=parameters.get("caller"),
50
+ user_phone=parameters.get("caller"),
51
+ bot_phone=parameters.get("callee"),
50
52
  user_name=parameters.get("callerDisplayName"),
51
53
  user_host=parameters.get("callerHost"),
52
54
  bot_host=parameters.get("calleeHost"),
@@ -223,6 +225,16 @@ class AudiocodesInput(InputChannel):
223
225
  self.scheduler_job = None
224
226
  self.keep_alive = keep_alive
225
227
  self.keep_alive_expiration_factor = keep_alive_expiration_factor
228
+ self.background_tasks: Dict[Text, Set[asyncio.Task]] = defaultdict(set)
229
+
230
+ def _create_task(self, conversation_id: Text, coro: Awaitable[Any]) -> asyncio.Task:
231
+ """Create and track an asyncio task for a conversation."""
232
+ task: asyncio.Task = asyncio.create_task(coro)
233
+ self.background_tasks[conversation_id].add(task)
234
+ task.add_done_callback(
235
+ lambda t: self.background_tasks[conversation_id].discard(t)
236
+ )
237
+ return task
226
238
 
227
239
  async def _set_scheduler_job(self) -> None:
228
240
  if self.scheduler_job:
@@ -251,11 +263,20 @@ class AudiocodesInput(InputChannel):
251
263
  )
252
264
  now = datetime.now(timezone.utc)
253
265
  delta = timedelta(seconds=self.keep_alive * self.keep_alive_expiration_factor)
254
- self.conversations = {
255
- k: v
256
- for k, v in self.conversations.items()
257
- if v.is_active_conversation(now, delta)
258
- }
266
+
267
+ # clean up conversations
268
+ inactive = [
269
+ conv_id
270
+ for conv_id, conv in self.conversations.items()
271
+ if not conv.is_active_conversation(now, delta)
272
+ ]
273
+
274
+ # cancel tasks and remove conversations
275
+ for conv_id in inactive:
276
+ for task in self.background_tasks[conv_id]:
277
+ task.cancel()
278
+ self.background_tasks.pop(conv_id, None)
279
+ self.conversations.pop(conv_id, None)
259
280
 
260
281
  def handle_start_conversation(self, body: Dict[Text, Any]) -> Dict[Text, Any]:
261
282
  conversation_id = body["conversation"]
@@ -347,31 +368,29 @@ class AudiocodesInput(InputChannel):
347
368
  structlogger.debug("audiocodes.on_activities", conversation=conversation_id)
348
369
  conversation = self._get_conversation(request.token, conversation_id)
349
370
  if conversation is None:
371
+ structlogger.warning(
372
+ "audiocodes.on_activities.no_conversation", request=request.json
373
+ )
350
374
  return response.json({})
351
375
  elif conversation.ws:
352
376
  ac_output: Union[WebsocketOutput, AudiocodesOutput] = WebsocketOutput(
353
377
  conversation.ws, conversation_id
354
378
  )
355
- await conversation.handle_activities(
356
- request.json,
357
- output_channel=ac_output,
358
- on_new_message=on_new_message,
359
- )
360
- return response.json({})
379
+ response_json = {}
361
380
  else:
362
381
  # handle non websocket case where messages get returned in json
363
382
  ac_output = AudiocodesOutput()
364
- await conversation.handle_activities(
365
- request.json,
366
- output_channel=ac_output,
367
- on_new_message=on_new_message,
368
- )
369
- return response.json(
370
- {
371
- "conversation": conversation_id,
372
- "activities": ac_output.messages,
373
- }
374
- )
383
+ response_json = {
384
+ "conversation": conversation_id,
385
+ "activities": ac_output.messages,
386
+ }
387
+
388
+ # start a background task to handle activities
389
+ self._create_task(
390
+ conversation_id,
391
+ conversation.handle_activities(request.json, ac_output, on_new_message),
392
+ )
393
+ return response.json(response_json)
375
394
 
376
395
  @ac_webhook.route(
377
396
  "/conversation/<conversation_id>/disconnect", methods=["POST"]