rasa-pro 3.14.0.dev20250825__py3-none-any.whl → 3.14.0.dev20250922__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 (351) hide show
  1. rasa/builder/README.md +120 -0
  2. rasa/builder/__init__.py +0 -0
  3. rasa/builder/auth.py +176 -0
  4. rasa/builder/config.py +92 -0
  5. rasa/builder/copilot/__init__.py +0 -0
  6. rasa/builder/copilot/constants.py +31 -0
  7. rasa/builder/copilot/copilot.py +450 -0
  8. rasa/builder/copilot/copilot_response_handler.py +522 -0
  9. rasa/builder/copilot/copilot_templated_message_provider.py +58 -0
  10. rasa/builder/copilot/exceptions.py +32 -0
  11. rasa/builder/copilot/models.py +500 -0
  12. rasa/builder/copilot/prompts/__init__.py +0 -0
  13. rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +766 -0
  14. rasa/builder/copilot/prompts/latest_user_message_context_prompt.jinja2 +61 -0
  15. rasa/builder/copilot/signing.py +305 -0
  16. rasa/builder/copilot/telemetry.py +226 -0
  17. rasa/builder/copilot/templated_messages/__init__.py +0 -0
  18. rasa/builder/copilot/templated_messages/copilot_internal_messages_templates.yml +16 -0
  19. rasa/builder/copilot/templated_messages/copilot_templated_responses.yml +38 -0
  20. rasa/builder/document_retrieval/__init__.py +0 -0
  21. rasa/builder/document_retrieval/constants.py +15 -0
  22. rasa/builder/document_retrieval/inkeep-rag-response-schema.json +64 -0
  23. rasa/builder/document_retrieval/inkeep_document_retrieval.py +238 -0
  24. rasa/builder/document_retrieval/models.py +62 -0
  25. rasa/builder/download.py +140 -0
  26. rasa/builder/exceptions.py +91 -0
  27. rasa/builder/guardrails/__init__.py +1 -0
  28. rasa/builder/guardrails/constants.py +9 -0
  29. rasa/builder/guardrails/exceptions.py +4 -0
  30. rasa/builder/guardrails/lakera.py +206 -0
  31. rasa/builder/guardrails/models.py +231 -0
  32. rasa/builder/guardrails/store.py +238 -0
  33. rasa/builder/guardrails/utils.py +328 -0
  34. rasa/builder/job_manager.py +87 -0
  35. rasa/builder/jobs.py +282 -0
  36. rasa/builder/llm_service.py +246 -0
  37. rasa/builder/logging_utils.py +265 -0
  38. rasa/builder/main.py +234 -0
  39. rasa/builder/models.py +216 -0
  40. rasa/builder/project_generator.py +458 -0
  41. rasa/builder/project_info.py +72 -0
  42. rasa/builder/scrape_rasa_docs.py +97 -0
  43. rasa/builder/service.py +1350 -0
  44. rasa/builder/shared/tracker_context.py +212 -0
  45. rasa/builder/skill_to_bot_prompt.jinja2 +164 -0
  46. rasa/builder/template_cache.py +69 -0
  47. rasa/builder/training_service.py +194 -0
  48. rasa/builder/validation_service.py +97 -0
  49. rasa/cli/project_templates/basic/README.md +23 -0
  50. rasa/cli/project_templates/basic/actions/__init__ +0 -0
  51. rasa/cli/project_templates/basic/actions/action_human_handoff.py +40 -0
  52. rasa/cli/project_templates/basic/actions/actions.md +10 -0
  53. rasa/cli/project_templates/basic/config.yml +29 -0
  54. rasa/cli/project_templates/basic/credentials.yml +33 -0
  55. rasa/cli/project_templates/basic/data/data.md +8 -0
  56. rasa/cli/project_templates/basic/data/general/feedback.yml +21 -0
  57. rasa/cli/project_templates/basic/data/general/goodbye.yml +6 -0
  58. rasa/cli/project_templates/basic/data/general/hello.yml +6 -0
  59. rasa/cli/project_templates/basic/data/general/help.yml +6 -0
  60. rasa/cli/project_templates/basic/data/general/human_handoff.yml +16 -0
  61. rasa/cli/project_templates/basic/data/general/show_faqs.yml +6 -0
  62. rasa/cli/project_templates/basic/data/system/patterns/pattern_cannot_handle.yml +7 -0
  63. rasa/cli/project_templates/basic/data/system/patterns/pattern_completed.yml +7 -0
  64. rasa/cli/project_templates/basic/data/system/patterns/pattern_correction.yml +7 -0
  65. rasa/cli/project_templates/basic/data/system/patterns/pattern_search.yml +8 -0
  66. rasa/cli/project_templates/basic/data/system/patterns/pattern_session_start.yml +8 -0
  67. rasa/cli/project_templates/basic/docs/docs.md +5 -0
  68. rasa/cli/project_templates/basic/docs/template.txt +28 -0
  69. rasa/cli/project_templates/basic/domain/domain.md +11 -0
  70. rasa/cli/project_templates/basic/domain/general/feedback.yml +25 -0
  71. rasa/cli/project_templates/basic/domain/general/goodbye.yml +9 -0
  72. rasa/cli/project_templates/basic/domain/general/hello.yml +7 -0
  73. rasa/cli/project_templates/basic/domain/general/help.yml +21 -0
  74. rasa/cli/project_templates/basic/domain/general/human_handoff.yml +32 -0
  75. rasa/cli/project_templates/basic/domain/general/show_faqs.yml +14 -0
  76. rasa/cli/project_templates/basic/domain/system/patterns/pattern_cannot_handle.yml +5 -0
  77. rasa/cli/project_templates/basic/domain/system/patterns/pattern_session_start.yml +19 -0
  78. rasa/cli/project_templates/basic/endpoints.yml +67 -0
  79. rasa/cli/project_templates/basic/prompts/rephraser_demo_personality_prompt.jinja2 +38 -0
  80. rasa/cli/project_templates/default/config.yml +4 -0
  81. rasa/cli/project_templates/default/endpoints.yml +4 -0
  82. rasa/cli/project_templates/finance/README.md +26 -0
  83. rasa/cli/project_templates/finance/actions/__init__.py +0 -0
  84. rasa/cli/project_templates/finance/actions/accounts/__init__.py +0 -0
  85. rasa/cli/project_templates/finance/actions/accounts/check_balance.py +18 -0
  86. rasa/cli/project_templates/finance/actions/actions.md +15 -0
  87. rasa/cli/project_templates/finance/actions/cards/__init__.py +0 -0
  88. rasa/cli/project_templates/finance/actions/cards/check_that_card_exists.py +21 -0
  89. rasa/cli/project_templates/finance/actions/cards/list_cards.py +22 -0
  90. rasa/cli/project_templates/finance/actions/contacts/__init__.py +0 -0
  91. rasa/cli/project_templates/finance/actions/contacts/add_contact.py +30 -0
  92. rasa/cli/project_templates/finance/actions/contacts/list_contacts.py +22 -0
  93. rasa/cli/project_templates/finance/actions/contacts/remove_contact.py +35 -0
  94. rasa/cli/project_templates/finance/actions/db.py +117 -0
  95. rasa/cli/project_templates/finance/actions/general/__init__.py +0 -0
  96. rasa/cli/project_templates/finance/actions/general/action_human_handoff.py +49 -0
  97. rasa/cli/project_templates/finance/actions/transfers/__init__.py +0 -0
  98. rasa/cli/project_templates/finance/actions/transfers/check_transfer_funds.py +27 -0
  99. rasa/cli/project_templates/finance/actions/transfers/check_transfer_limit.py +36 -0
  100. rasa/cli/project_templates/finance/actions/transfers/execute_recurrent_payment.py +20 -0
  101. rasa/cli/project_templates/finance/actions/transfers/execute_transfer.py +45 -0
  102. rasa/cli/project_templates/finance/actions/transfers/list_transactions.py +32 -0
  103. rasa/cli/project_templates/finance/config.yml +29 -0
  104. rasa/cli/project_templates/finance/credentials.yml +33 -0
  105. rasa/cli/project_templates/finance/data/accounts/check_balance.yml +9 -0
  106. rasa/cli/project_templates/finance/data/accounts/download_statements.yml +26 -0
  107. rasa/cli/project_templates/finance/data/bills/bill_pay_reminder.yml +25 -0
  108. rasa/cli/project_templates/finance/data/cards/activate_card.yml +35 -0
  109. rasa/cli/project_templates/finance/data/cards/block_card.yml +45 -0
  110. rasa/cli/project_templates/finance/data/cards/list_cards.yml +14 -0
  111. rasa/cli/project_templates/finance/data/cards/replace_card.yml +16 -0
  112. rasa/cli/project_templates/finance/data/cards/replace_eligible_card.yml +29 -0
  113. rasa/cli/project_templates/finance/data/contacts/add_contact.yml +33 -0
  114. rasa/cli/project_templates/finance/data/contacts/list_contacts.yml +14 -0
  115. rasa/cli/project_templates/finance/data/contacts/remove_contact.yml +31 -0
  116. rasa/cli/project_templates/finance/data/data.md +14 -0
  117. rasa/cli/project_templates/finance/data/general/bot_challenge.yml +6 -0
  118. rasa/cli/project_templates/finance/data/general/feedback.yml +20 -0
  119. rasa/cli/project_templates/finance/data/general/goodbye.yml +6 -0
  120. rasa/cli/project_templates/finance/data/general/hello.yml +6 -0
  121. rasa/cli/project_templates/finance/data/general/help.yml +9 -0
  122. rasa/cli/project_templates/finance/data/general/human_handoff.yml +16 -0
  123. rasa/cli/project_templates/finance/data/general/welcome.yml +9 -0
  124. rasa/cli/project_templates/finance/data/system/patterns/pattern_completed.yml +7 -0
  125. rasa/cli/project_templates/finance/data/system/patterns/pattern_correction.yml +7 -0
  126. rasa/cli/project_templates/finance/data/system/patterns/pattern_search.yml +8 -0
  127. rasa/cli/project_templates/finance/data/system/patterns/pattern_session_start.yml +8 -0
  128. rasa/cli/project_templates/finance/data/transfers/check_transfer_limit.yml +18 -0
  129. rasa/cli/project_templates/finance/data/transfers/list_transactions.yml +46 -0
  130. rasa/cli/project_templates/finance/data/transfers/move_money_between_accounts.yml +51 -0
  131. rasa/cli/project_templates/finance/data/transfers/transfer_money.yml +34 -0
  132. rasa/cli/project_templates/finance/data/transfers/transfer_money_to_a_third_party.yml +175 -0
  133. rasa/cli/project_templates/finance/db/cards.json +18 -0
  134. rasa/cli/project_templates/finance/db/contacts.json +10 -0
  135. rasa/cli/project_templates/finance/db/my_account.json +6 -0
  136. rasa/cli/project_templates/finance/db/transactions.json +22 -0
  137. rasa/cli/project_templates/finance/docs/docs.md +8 -0
  138. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/budgeting_analytics.txt +22 -0
  139. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/multi_currency_accounts.txt +19 -0
  140. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/premium_benefits.txt +19 -0
  141. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/contactless_limits.txt +16 -0
  142. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/freeze_unfreeze_card.txt +16 -0
  143. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/lost_stolen_card.txt +19 -0
  144. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/money_transfers/instant_payments.txt +19 -0
  145. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/money_transfers/international_transfers.txt +19 -0
  146. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/security_fraud/fraud_protection.txt +22 -0
  147. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/security_fraud/secure_payments.txt +22 -0
  148. rasa/cli/project_templates/finance/domain/accounts/check_balance.yml +15 -0
  149. rasa/cli/project_templates/finance/domain/accounts/download_statements.yml +40 -0
  150. rasa/cli/project_templates/finance/domain/bills/bill_pay_reminder.yml +49 -0
  151. rasa/cli/project_templates/finance/domain/cards/activate_card.yml +24 -0
  152. rasa/cli/project_templates/finance/domain/cards/block_card.yml +44 -0
  153. rasa/cli/project_templates/finance/domain/cards/list_cards.yml +16 -0
  154. rasa/cli/project_templates/finance/domain/cards/replace_card.yml +43 -0
  155. rasa/cli/project_templates/finance/domain/cards/shared.yml +15 -0
  156. rasa/cli/project_templates/finance/domain/contacts/add_contact.yml +37 -0
  157. rasa/cli/project_templates/finance/domain/contacts/list_contacts.yml +16 -0
  158. rasa/cli/project_templates/finance/domain/contacts/remove_contact.yml +32 -0
  159. rasa/cli/project_templates/finance/domain/domain.md +18 -0
  160. rasa/cli/project_templates/finance/domain/general/_shared.yml +39 -0
  161. rasa/cli/project_templates/finance/domain/general/bot_challenge.yml +4 -0
  162. rasa/cli/project_templates/finance/domain/general/cannot_handle.yml +8 -0
  163. rasa/cli/project_templates/finance/domain/general/feedback.yml +25 -0
  164. rasa/cli/project_templates/finance/domain/general/goodbye.yml +7 -0
  165. rasa/cli/project_templates/finance/domain/general/human_handoff.yml +31 -0
  166. rasa/cli/project_templates/finance/domain/general/welcome.yml +39 -0
  167. rasa/cli/project_templates/finance/domain/transfers/check_transfer_limit.yml +32 -0
  168. rasa/cli/project_templates/finance/domain/transfers/list_transactions.yml +44 -0
  169. rasa/cli/project_templates/finance/domain/transfers/shared.yml +17 -0
  170. rasa/cli/project_templates/finance/domain/transfers/transfer_money.yml +221 -0
  171. rasa/cli/project_templates/finance/endpoints.yml +67 -0
  172. rasa/cli/project_templates/finance/prompts/rephraser_demo_personality_prompt.jinja2 +38 -0
  173. rasa/cli/project_templates/finance/tests/e2e_test_cases/accounts/check_balance.yml +9 -0
  174. rasa/cli/project_templates/finance/tests/e2e_test_cases/accounts/download_statements.yml +43 -0
  175. rasa/cli/project_templates/finance/tests/e2e_test_cases/cards/block_card.yml +55 -0
  176. rasa/cli/project_templates/finance/tests/e2e_test_cases/general/bot_challenge.yml +8 -0
  177. rasa/cli/project_templates/finance/tests/e2e_test_cases/general/feedback.yml +46 -0
  178. rasa/cli/project_templates/finance/tests/e2e_test_cases/general/goodbye.yml +9 -0
  179. rasa/cli/project_templates/finance/tests/e2e_test_cases/general/hello.yml +8 -0
  180. rasa/cli/project_templates/finance/tests/e2e_test_cases/general/human_handoff.yml +35 -0
  181. rasa/cli/project_templates/finance/tests/e2e_test_cases/general/patterns.yml +22 -0
  182. rasa/cli/project_templates/finance/tests/e2e_test_cases/transfers/transfer_money.yml +56 -0
  183. rasa/cli/project_templates/telco/README.md +25 -0
  184. rasa/cli/project_templates/telco/actions/__init__.py +0 -0
  185. rasa/cli/project_templates/telco/actions/actions.md +12 -0
  186. rasa/cli/project_templates/telco/actions/billing/__init__.py +0 -0
  187. rasa/cli/project_templates/telco/actions/billing/actions_billing.py +204 -0
  188. rasa/cli/project_templates/telco/actions/general/__init__.py +0 -0
  189. rasa/cli/project_templates/telco/actions/general/action_human_handoff.py +49 -0
  190. rasa/cli/project_templates/telco/actions/network/__init__.py +0 -0
  191. rasa/cli/project_templates/telco/actions/network/actions_get_data_from_db.py +48 -0
  192. rasa/cli/project_templates/telco/actions/network/actions_run_diagnostics.py +28 -0
  193. rasa/cli/project_templates/telco/actions/network/actions_session_start.py +18 -0
  194. rasa/cli/project_templates/telco/config.yml +29 -0
  195. rasa/cli/project_templates/telco/credentials.yml +33 -0
  196. rasa/cli/project_templates/telco/csvs/billing.csv +19 -0
  197. rasa/cli/project_templates/telco/csvs/customers.csv +5 -0
  198. rasa/cli/project_templates/telco/data/billing/flow_understand_bill.yml +45 -0
  199. rasa/cli/project_templates/telco/data/data.md +11 -0
  200. rasa/cli/project_templates/telco/data/general/bot_challenge.yml +6 -0
  201. rasa/cli/project_templates/telco/data/general/feedback.yml +20 -0
  202. rasa/cli/project_templates/telco/data/general/goodbye.yml +6 -0
  203. rasa/cli/project_templates/telco/data/general/hello.yml +6 -0
  204. rasa/cli/project_templates/telco/data/general/human_handoff.yml +16 -0
  205. rasa/cli/project_templates/telco/data/general/patterns.yml +30 -0
  206. rasa/cli/project_templates/telco/data/network/flow_reboot_router.yml +8 -0
  207. rasa/cli/project_templates/telco/data/network/flow_reset_router.yml +7 -0
  208. rasa/cli/project_templates/telco/data/network/flow_solve_internet_issue.yml +73 -0
  209. rasa/cli/project_templates/telco/docs/docs.md +8 -0
  210. rasa/cli/project_templates/telco/docs/network/reset_vs_rboot_router.txt +1 -0
  211. rasa/cli/project_templates/telco/docs/network/restart_router.txt +6 -0
  212. rasa/cli/project_templates/telco/docs/network/run_speed_test.txt +6 -0
  213. rasa/cli/project_templates/telco/domain/billing/understand_bill.yml +102 -0
  214. rasa/cli/project_templates/telco/domain/domain.md +13 -0
  215. rasa/cli/project_templates/telco/domain/general/bot_challenge.yml +4 -0
  216. rasa/cli/project_templates/telco/domain/general/feedback.yml +25 -0
  217. rasa/cli/project_templates/telco/domain/general/goodbye.yml +7 -0
  218. rasa/cli/project_templates/telco/domain/general/hello.yml +5 -0
  219. rasa/cli/project_templates/telco/domain/general/human_handoff.yml +26 -0
  220. rasa/cli/project_templates/telco/domain/general/patterns.yml +33 -0
  221. rasa/cli/project_templates/telco/domain/network/reboot_router.yml +21 -0
  222. rasa/cli/project_templates/telco/domain/network/reset_router.yml +12 -0
  223. rasa/cli/project_templates/telco/domain/network/run_speed_test.yml +25 -0
  224. rasa/cli/project_templates/telco/domain/network/solve_internet_issue.yml +75 -0
  225. rasa/cli/project_templates/telco/domain/shared.yml +129 -0
  226. rasa/cli/project_templates/telco/endpoints.yml +67 -0
  227. rasa/cli/project_templates/telco/prompts/rephraser_demo_personality_prompt.jinja2 +40 -0
  228. rasa/cli/project_templates/telco/tests/e2e_test_cases/billing/understand_bill.yml +67 -0
  229. rasa/cli/project_templates/telco/tests/e2e_test_cases/general/bot_challenge.yml +8 -0
  230. rasa/cli/project_templates/telco/tests/e2e_test_cases/general/feedback.yml +46 -0
  231. rasa/cli/project_templates/telco/tests/e2e_test_cases/general/goodbye.yml +9 -0
  232. rasa/cli/project_templates/telco/tests/e2e_test_cases/general/hello.yml +8 -0
  233. rasa/cli/project_templates/telco/tests/e2e_test_cases/general/human_handoff.yml +35 -0
  234. rasa/cli/project_templates/telco/tests/e2e_test_cases/general/patterns.yml +23 -0
  235. rasa/cli/project_templates/telco/tests/e2e_test_cases/network/solve_internet_issue.yml +57 -0
  236. rasa/cli/project_templates/tutorial/config.yml +2 -1
  237. rasa/cli/scaffold.py +46 -2
  238. rasa/core/actions/action.py +0 -1
  239. rasa/core/actions/action_run_slot_rejections.py +1 -1
  240. rasa/core/actions/direct_custom_actions_executor.py +9 -2
  241. rasa/core/brokers/broker.py +1 -1
  242. rasa/core/brokers/kafka.py +52 -8
  243. rasa/core/channels/development_inspector.py +1 -21
  244. rasa/core/channels/hangouts.py +2 -2
  245. rasa/core/channels/inspector/dist/assets/{arc-1ddec37b.js → arc-35222594.js} +1 -1
  246. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-18af387c.js → blockDiagram-38ab4fdb-a0efbfd3.js} +1 -1
  247. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-250127a3.js → c4Diagram-3d4e48cf-0584c0f2.js} +1 -1
  248. rasa/core/channels/inspector/dist/assets/channel-8e08bed9.js +1 -0
  249. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-c3388b34.js → classDiagram-70f12bd4-39f40dbe.js} +1 -1
  250. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-9c893a82.js → classDiagram-v2-f2320105-1ad755f3.js} +1 -1
  251. rasa/core/channels/inspector/dist/assets/clone-78c82dea.js +1 -0
  252. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-c111213b.js → createText-2e5e7dd3-b0f4f0fe.js} +1 -1
  253. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-812a729d.js → edges-e0da2a9e-9039bff9.js} +1 -1
  254. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-fd5051bc.js → erDiagram-9861fffd-65c9b127.js} +1 -1
  255. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-3287ac02.js → flowDb-956e92f1-4f08b38e.js} +1 -1
  256. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-692fb0b2.js → flowDiagram-66a62f08-e95c362a.js} +1 -1
  257. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b08f601.js +1 -0
  258. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-008376f1.js → flowchart-elk-definition-4a651766-703c3015.js} +1 -1
  259. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-df330a69.js → ganttDiagram-c361ad54-699328ea.js} +1 -1
  260. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-e03676fb.js → gitGraphDiagram-72cf32ee-04cf4b05.js} +1 -1
  261. rasa/core/channels/inspector/dist/assets/{graph-46fad2ba.js → graph-ee94449e.js} +1 -1
  262. rasa/core/channels/inspector/dist/assets/{index-3862675e-a484ac55.js → index-3862675e-940162b4.js} +1 -1
  263. rasa/core/channels/inspector/dist/assets/{index-a003633f.js → index-c941dcb3.js} +239 -238
  264. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-3f9e6ec2.js → infoDiagram-f8f76790-c79c2866.js} +1 -1
  265. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-79f72383.js → journeyDiagram-49397b02-84489d30.js} +1 -1
  266. rasa/core/channels/inspector/dist/assets/{layout-aad098e5.js → layout-a9aa9858.js} +1 -1
  267. rasa/core/channels/inspector/dist/assets/{line-219ab7ae.js → line-eb73cf26.js} +1 -1
  268. rasa/core/channels/inspector/dist/assets/{linear-2cddbe62.js → linear-b3399f9a.js} +1 -1
  269. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-1d41ed99.js → mindmap-definition-fc14e90a-b095bf1a.js} +1 -1
  270. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-cc496ee8.js → pieDiagram-8a3498a8-07644b66.js} +1 -1
  271. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-84d32884.js → quadrantDiagram-120e2f19-573a3f9c.js} +1 -1
  272. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-c0deb984.js → requirementDiagram-deff3bca-d457e1e1.js} +1 -1
  273. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-b9d7fd62.js → sankeyDiagram-04a897e0-9d26e1a2.js} +1 -1
  274. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-7d517565.js → sequenceDiagram-704730f1-3a9cde10.js} +1 -1
  275. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-98ef9b27.js → stateDiagram-587899a1-4f3e8cec.js} +1 -1
  276. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-cee70748.js → stateDiagram-v2-d93cdb3a-e617e5bf.js} +1 -1
  277. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-3f9d1c96.js → styles-6aaf32cf-eab30d2f.js} +1 -1
  278. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-67471923.js → styles-9a916d00-09994be2.js} +1 -1
  279. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-bd093fb7.js → styles-c10674c1-b7110364.js} +1 -1
  280. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-675794e8.js → svgDrawCommon-08f97a94-3ebc92ad.js} +1 -1
  281. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0ac67617.js → timeline-definition-85554ec2-7d13d2f2.js} +1 -1
  282. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-c018dc37.js → xychartDiagram-e933f94c-488385e1.js} +1 -1
  283. rasa/core/channels/inspector/dist/index.html +2 -2
  284. rasa/core/channels/inspector/index.html +1 -1
  285. rasa/core/channels/inspector/src/App.tsx +15 -42
  286. rasa/core/channels/inspector/src/components/Chat.tsx +2 -3
  287. rasa/core/channels/inspector/src/components/DialogueInformation.tsx +20 -3
  288. rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +63 -35
  289. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +14 -0
  290. rasa/core/channels/inspector/src/types.ts +32 -7
  291. rasa/core/channels/studio_chat.py +43 -43
  292. rasa/core/channels/voice_stream/asr/asr_event.py +1 -1
  293. rasa/core/channels/voice_stream/asr/azure.py +6 -3
  294. rasa/core/channels/voice_stream/asr/deepgram.py +1 -1
  295. rasa/core/channels/voice_stream/audiocodes.py +3 -0
  296. rasa/core/channels/voice_stream/browser_audio.py +55 -3
  297. rasa/core/channels/voice_stream/genesys.py +2 -1
  298. rasa/core/channels/voice_stream/jambonz.py +9 -1
  299. rasa/core/channels/voice_stream/twilio_media_streams.py +16 -0
  300. rasa/core/channels/voice_stream/voice_channel.py +61 -0
  301. rasa/core/concurrent_lock_store.py +66 -16
  302. rasa/core/constants.py +7 -0
  303. rasa/core/iam_credentials_providers/__init__.py +0 -0
  304. rasa/core/iam_credentials_providers/aws_iam_credentials_providers.py +226 -0
  305. rasa/core/iam_credentials_providers/credentials_provider_protocol.py +90 -0
  306. rasa/core/lock_store.py +46 -10
  307. rasa/core/nlg/generator.py +1 -1
  308. rasa/core/policies/enterprise_search_policy.py +4 -7
  309. rasa/core/policies/flows/flow_executor.py +9 -2
  310. rasa/core/processor.py +32 -0
  311. rasa/core/redis_connection_factory.py +469 -0
  312. rasa/core/tracker_stores/redis_tracker_store.py +32 -14
  313. rasa/core/tracker_stores/sql_tracker_store.py +57 -1
  314. rasa/dialogue_understanding/generator/flow_retrieval.py +10 -9
  315. rasa/engine/graph.py +5 -1
  316. rasa/engine/loader.py +12 -0
  317. rasa/engine/storage/local_model_storage.py +83 -3
  318. rasa/model_manager/model_api.py +1 -2
  319. rasa/model_manager/runner_service.py +1 -1
  320. rasa/model_manager/socket_bridge.py +1 -2
  321. rasa/model_manager/trainer_service.py +12 -9
  322. rasa/model_manager/utils.py +1 -29
  323. rasa/model_manager/warm_rasa_process.py +13 -3
  324. rasa/shared/core/constants.py +1 -0
  325. rasa/shared/core/domain.py +62 -15
  326. rasa/shared/core/events.py +2 -0
  327. rasa/shared/core/flows/flow.py +1 -1
  328. rasa/shared/core/flows/flow_step.py +7 -1
  329. rasa/shared/core/flows/steps/call.py +8 -1
  330. rasa/shared/core/flows/yaml_flows_io.py +16 -8
  331. rasa/shared/core/slots.py +4 -0
  332. rasa/shared/importers/importer.py +6 -0
  333. rasa/shared/importers/utils.py +77 -1
  334. rasa/shared/nlu/training_data/schemas/responses.yml +3 -0
  335. rasa/studio/upload.py +12 -46
  336. rasa/telemetry.py +97 -23
  337. rasa/utils/io.py +27 -9
  338. rasa/utils/json_utils.py +6 -1
  339. rasa/utils/log_utils.py +5 -1
  340. rasa/utils/openapi.py +144 -0
  341. rasa/utils/pypred.py +38 -0
  342. rasa/validator.py +19 -11
  343. rasa/version.py +1 -1
  344. {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/METADATA +27 -25
  345. {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/RECORD +348 -109
  346. rasa/core/channels/inspector/dist/assets/channel-59f6d54b.js +0 -1
  347. rasa/core/channels/inspector/dist/assets/clone-26177ddb.js +0 -1
  348. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-29c03f5a.js +0 -1
  349. {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/NOTICE +0 -0
  350. {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/WHEEL +0 -0
  351. {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  import os
3
3
  from dataclasses import dataclass
4
- from typing import Any, AsyncIterator, Dict, Optional
4
+ from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, Optional
5
5
 
6
6
  import structlog
7
7
 
@@ -15,6 +15,9 @@ from rasa.core.channels.voice_stream.audio_bytes import HERTZ, RasaAudioBytes
15
15
  from rasa.shared.constants import AZURE_SPEECH_API_KEY_ENV_VAR
16
16
  from rasa.shared.exceptions import ConnectionException
17
17
 
18
+ if TYPE_CHECKING:
19
+ from azure.cognitiveservices.speech import SpeechRecognitionEventArgs
20
+
18
21
  logger = structlog.get_logger(__name__)
19
22
 
20
23
 
@@ -43,9 +46,9 @@ class AzureASR(ASREngine[AzureASRConfig]):
43
46
  )
44
47
  self.main_loop = asyncio.get_running_loop()
45
48
 
46
- def signal_user_is_speaking(self, event: Any) -> None:
49
+ def signal_user_is_speaking(self, event: "SpeechRecognitionEventArgs") -> None:
47
50
  """Replace the azure event with a generic is speaking event."""
48
- self.fill_queue(UserIsSpeaking())
51
+ self.fill_queue(UserIsSpeaking(event.result.text))
49
52
 
50
53
  def fill_queue(self, event: Any) -> None:
51
54
  """Either puts the event or a dedicated ASR Event into the queue."""
@@ -117,7 +117,7 @@ class DeepgramASR(ASREngine[DeepgramASRConfig]):
117
117
  self.accumulated_transcript, transcript
118
118
  )
119
119
  elif transcript:
120
- return UserIsSpeaking()
120
+ return UserIsSpeaking(transcript)
121
121
  # event that comes after utterance_end_ms of no new transcript
122
122
  elif data_type == "UtteranceEnd":
123
123
  if self.accumulated_transcript:
@@ -89,6 +89,7 @@ class AudiocodesVoiceOutputChannel(VoiceOutputChannel):
89
89
  # This is an approximation, as the bot will be sent the audio chunks next
90
90
  # which are played to the user immediately.
91
91
  call_state.is_bot_speaking = True
92
+ VoiceInputChannel._cancel_silence_timeout_watcher()
92
93
 
93
94
  async def send_intermediate_marker(self, recipient_id: str) -> None:
94
95
  """Audiocodes doesn't need intermediate markers, so do nothing."""
@@ -116,6 +117,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
116
117
  server_url: str,
117
118
  asr_config: Dict,
118
119
  tts_config: Dict,
120
+ interruptions: Optional[Dict[str, int]] = None,
119
121
  token: Optional[Text] = None,
120
122
  ):
121
123
  mark_as_beta_feature("Audiocodes (audiocodes_stream) Channel")
@@ -123,6 +125,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
123
125
  server_url=server_url,
124
126
  asr_config=asr_config,
125
127
  tts_config=tts_config,
128
+ interruptions=interruptions,
126
129
  )
127
130
  self.token = token
128
131
 
@@ -3,7 +3,9 @@ from __future__ import annotations
3
3
  import audioop
4
4
  import base64
5
5
  import json
6
+ import os
6
7
  import uuid
8
+ import wave
7
9
  from typing import Any, Awaitable, Callable, Dict, Optional, Tuple
8
10
 
9
11
  import structlog
@@ -69,11 +71,48 @@ class BrowserAudioOutputChannel(VoiceOutputChannel):
69
71
 
70
72
 
71
73
  class BrowserAudioInputChannel(VoiceInputChannel):
74
+ requires_voice_license = False
75
+
72
76
  def __init__(
73
- self, server_url: str, asr_config: Dict[str, Any], tts_config: Dict[str, Any]
77
+ self,
78
+ server_url: str,
79
+ asr_config: Dict[str, Any],
80
+ tts_config: Dict[str, Any],
81
+ recording: bool = False,
82
+ interruptions: Optional[Dict[str, int]] = None,
74
83
  ) -> None:
75
84
  """Initializes the browser audio input channel."""
76
- super().__init__(server_url, asr_config, tts_config)
85
+ super().__init__(server_url, asr_config, tts_config, interruptions)
86
+
87
+ # For debugging, recording of user audio might be useful
88
+ # to identify audio quality issues or transcription errors
89
+ self._recording_enabled = recording
90
+ self._wav_file: Optional[wave.Wave_write] = None
91
+
92
+ def _start_recording(self, call_id: str, user_id: str) -> None:
93
+ os.makedirs("recordings", exist_ok=True)
94
+ filename = f"{user_id}_{call_id}.wav"
95
+ file_path = os.path.join("recordings", filename)
96
+
97
+ if not self._recording_enabled:
98
+ return
99
+
100
+ self._wav_file = wave.open(file_path, "wb")
101
+ self._wav_file.setnchannels(1) # Mono audio
102
+ self._wav_file.setsampwidth(4) # 32-bit audio (4 bytes)
103
+ self._wav_file.setframerate(8000) # 8kHz sample rate
104
+ logger.info("voice_channel.user_audio_recording.started", file_path=file_path)
105
+
106
+ def _append_audio_to_recording(self, audio_bytes: bytes) -> None:
107
+ if self._wav_file and self._recording_enabled:
108
+ self._wav_file.writeframes(audio_bytes)
109
+
110
+ def _stop_recording(self) -> None:
111
+ """Close the recording file if it's open."""
112
+ if self._wav_file:
113
+ self._wav_file.close()
114
+ self._wav_file = None
115
+ logger.debug("voice_channel.user_audio_recording.stopped")
77
116
 
78
117
  @classmethod
79
118
  def name(cls) -> str:
@@ -94,7 +133,7 @@ class BrowserAudioInputChannel(VoiceInputChannel):
94
133
  credentials: Optional[Dict[str, Any]],
95
134
  ) -> BrowserAudioInputChannel:
96
135
  cls.validate_basic_credentials(credentials)
97
- new_creds = repack_voice_credentials(credentials)
136
+ new_creds = repack_voice_credentials(credentials or {})
98
137
  return cls(**new_creds)
99
138
 
100
139
  def map_input_message(
@@ -105,6 +144,7 @@ class BrowserAudioInputChannel(VoiceInputChannel):
105
144
  data = json.loads(message)
106
145
  if "audio" in data:
107
146
  channel_bytes = base64.b64decode(data["audio"])
147
+ self._append_audio_to_recording(channel_bytes)
108
148
  audio_bytes = self.channel_bytes_to_rasa_audio_bytes(channel_bytes)
109
149
  return NewAudioAction(audio_bytes)
110
150
  elif "marker" in data:
@@ -120,6 +160,13 @@ class BrowserAudioInputChannel(VoiceInputChannel):
120
160
  call_state.is_bot_speaking = True
121
161
  return ContinueConversationAction()
122
162
 
163
+ async def interrupt_playback(
164
+ self, ws: Websocket, call_parameters: CallParameters
165
+ ) -> None:
166
+ """Interrupt the current playback of audio."""
167
+ logger.debug("browser_audio.interrupt_playback")
168
+ await ws.send(json.dumps({"interruptPlayback": True}))
169
+
123
170
  def create_output_channel(
124
171
  self, voice_websocket: Websocket, tts_engine: TTSEngine
125
172
  ) -> VoiceOutputChannel:
@@ -142,8 +189,13 @@ class BrowserAudioInputChannel(VoiceInputChannel):
142
189
  @blueprint.websocket("/websocket") # type: ignore
143
190
  async def handle_message(request: Request, ws: Websocket) -> None:
144
191
  try:
192
+ call_parameters = await self.collect_call_parameters(ws)
193
+ if call_parameters and call_parameters.call_id:
194
+ self._start_recording(call_parameters.call_id, "local")
145
195
  await self.run_audio_streaming(on_new_message, ws)
146
196
  except Exception as e:
147
197
  logger.error("browser_audio.handle_message.error", error=e)
198
+ finally:
199
+ self._stop_recording()
148
200
 
149
201
  return blueprint
@@ -99,10 +99,11 @@ class GenesysInputChannel(VoiceInputChannel):
99
99
  server_url: str,
100
100
  asr_config: Dict,
101
101
  tts_config: Dict,
102
+ interruptions: Optional[Dict[str, int]] = None,
102
103
  api_key: Optional[Text] = None,
103
104
  client_secret: Optional[Text] = None,
104
105
  ) -> None:
105
- super().__init__(server_url, asr_config, tts_config)
106
+ super().__init__(server_url, asr_config, tts_config, interruptions)
106
107
  self.api_key = api_key
107
108
  self.client_secret = client_secret
108
109
 
@@ -81,6 +81,7 @@ class JambonzStreamInputChannel(VoiceInputChannel):
81
81
  server_url: str,
82
82
  asr_config: Dict,
83
83
  tts_config: Dict,
84
+ interruptions: Optional[Dict[str, int]] = None,
84
85
  username: Optional[Text] = None,
85
86
  password: Optional[Text] = None,
86
87
  ) -> None:
@@ -90,7 +91,7 @@ class JambonzStreamInputChannel(VoiceInputChannel):
90
91
  username: Optional username for basic auth
91
92
  password: Optional password for basic auth
92
93
  """
93
- super().__init__(server_url, asr_config, tts_config)
94
+ super().__init__(server_url, asr_config, tts_config, interruptions)
94
95
  self.username = username
95
96
  self.password = password
96
97
 
@@ -185,6 +186,13 @@ class JambonzStreamInputChannel(VoiceInputChannel):
185
186
  self.tts_cache,
186
187
  )
187
188
 
189
+ async def interrupt_playback(
190
+ self, ws: Websocket, call_parameters: CallParameters
191
+ ) -> None:
192
+ """Interrupt the current playback of audio."""
193
+ logger.debug("jambonz.interrupt_playback")
194
+ await ws.send(json.dumps({"type": "killAudio"}))
195
+
188
196
  def blueprint(
189
197
  self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
190
198
  ) -> Blueprint:
@@ -105,6 +105,7 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
105
105
  server_url: str,
106
106
  asr_config: Dict,
107
107
  tts_config: Dict,
108
+ interruptions: Optional[Dict[str, int]] = None,
108
109
  username: Optional[Text] = None,
109
110
  password: Optional[Text] = None,
110
111
  ):
@@ -112,6 +113,7 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
112
113
  server_url=server_url,
113
114
  asr_config=asr_config,
114
115
  tts_config=tts_config,
116
+ interruptions=interruptions,
115
117
  )
116
118
  self.username = username
117
119
  self.password = password
@@ -195,6 +197,20 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
195
197
  self.tts_cache,
196
198
  )
197
199
 
200
+ async def interrupt_playback(
201
+ self, ws: Websocket, call_parameters: CallParameters
202
+ ) -> None:
203
+ """Interrupt the current playback of audio."""
204
+ logger.debug("twilio_media_streams.interrupt_playback")
205
+ await ws.send(
206
+ json.dumps(
207
+ {
208
+ "event": "clear",
209
+ "streamSid": call_parameters.stream_id,
210
+ }
211
+ )
212
+ )
213
+
198
214
  def blueprint(
199
215
  self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
200
216
  ) -> Blueprint:
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import copy
5
+ import string
5
6
  import time
6
7
  from dataclasses import asdict, dataclass
7
8
  from typing import Any, AsyncIterator, Awaitable, Callable, Dict, List, Optional, Tuple
@@ -53,6 +54,13 @@ from rasa.utils.io import remove_emojis
53
54
  logger = structlog.get_logger(__name__)
54
55
 
55
56
  # define constants for the voice channel
57
+ DEFAULT_INTERRUPTION_MIN_WORDS = 3
58
+
59
+
60
+ @dataclass
61
+ class InterruptionConfig:
62
+ enabled: bool = False
63
+ min_words: int = DEFAULT_INTERRUPTION_MIN_WORDS
56
64
 
57
65
 
58
66
  @dataclass
@@ -270,6 +278,10 @@ class VoiceOutputChannel(OutputChannel):
270
278
  except (WebsocketClosed, ServerError):
271
279
  call_state.connection_failed = True
272
280
 
281
+ # Is the response interruptible?
282
+ allow_interruptions = kwargs.get("allow_interruptions", True)
283
+ call_state.channel_data["allow_interruptions"] = allow_interruptions
284
+
273
285
  if cached_audio_bytes:
274
286
  audio_stream = self.chunk_audio(cached_audio_bytes)
275
287
  else:
@@ -368,6 +380,7 @@ class VoiceInputChannel(InputChannel):
368
380
  server_url: str,
369
381
  asr_config: Dict,
370
382
  tts_config: Dict,
383
+ interruptions: Optional[Dict[str, Any]] = None,
371
384
  ):
372
385
  if self.requires_voice_license:
373
386
  validate_voice_license_scope()
@@ -376,12 +389,21 @@ class VoiceInputChannel(InputChannel):
376
389
  self.asr_config = asr_config
377
390
  self.tts_config = tts_config
378
391
  self.tts_cache = TTSCache(tts_config.get("cache_size", 1000))
392
+ if interruptions:
393
+ self.interruption_config = InterruptionConfig(**interruptions)
394
+ else:
395
+ self.interruption_config = InterruptionConfig()
396
+
397
+ if self.interruption_config.enabled:
398
+ mark_as_beta_feature(f"Interruption Handling in {self.name()}")
379
399
 
380
400
  logger.info(
381
401
  "voice_channel.initialized",
402
+ name=self.name(),
382
403
  server_url=self.server_url,
383
404
  asr_config=self.asr_config,
384
405
  tts_config=self.tts_config,
406
+ interruption_config=self.interruption_config,
385
407
  )
386
408
 
387
409
  def get_sender_id(self, call_parameters: CallParameters) -> str:
@@ -463,6 +485,43 @@ class VoiceInputChannel(InputChannel):
463
485
  """Map a channel input message to a voice channel action."""
464
486
  raise NotImplementedError
465
487
 
488
+ def should_interrupt(self, e: ASREvent) -> bool:
489
+ """Determine if the current ASR event should interrupt playback.
490
+ Returns True if the bot response is interruptible
491
+ And if the user spoke more than 3 words.
492
+
493
+ Arguments:
494
+ e: The ASR event to evaluate.
495
+
496
+ Returns:
497
+ True if the event should interrupt playback, False otherwise.
498
+ """
499
+ # Are interruptions are enabled for the channel?
500
+ if not self.interruption_config.enabled:
501
+ return False
502
+
503
+ # Is the bot response interruptible?
504
+ if not call_state.channel_data.get("allow_interruptions", True):
505
+ return False
506
+
507
+ # Did the user speak more than 3 words?
508
+ min_words = self.interruption_config.min_words
509
+ if isinstance(e, UserIsSpeaking):
510
+ translator = str.maketrans("", "", string.punctuation)
511
+ words = e.text.translate(translator).split()
512
+ return len(words) >= min_words
513
+ return False
514
+
515
+ async def interrupt_playback(
516
+ self, ws: Websocket, call_parameters: CallParameters
517
+ ) -> None:
518
+ """Interrupt the current playback of audio.
519
+
520
+ This function is used for interruption handling.
521
+ As not all channels support flushing bot audio buffer,
522
+ if a channel does not implement it. It has no effect."""
523
+ pass
524
+
466
525
  async def run_audio_streaming(
467
526
  self,
468
527
  on_new_message: Callable[[UserMessage], Awaitable[Any]],
@@ -598,6 +657,8 @@ class VoiceInputChannel(InputChannel):
598
657
  call_state.user_speech_start_time = time.time()
599
658
  self._cancel_silence_timeout_watcher()
600
659
  call_state.is_user_speaking = True
660
+ if self.should_interrupt(e):
661
+ await self.interrupt_playback(voice_websocket, call_parameters)
601
662
  elif isinstance(e, UserSilence):
602
663
  output_channel = self.create_output_channel(voice_websocket, tts_engine)
603
664
  message = UserMessage(
@@ -4,6 +4,7 @@ from collections import deque
4
4
  from typing import Deque, Optional, Text
5
5
 
6
6
  import structlog
7
+ from pydantic import ValidationError
7
8
 
8
9
  from rasa.core.lock import Ticket, TicketLock
9
10
  from rasa.core.lock_store import (
@@ -12,6 +13,12 @@ from rasa.core.lock_store import (
12
13
  LockError,
13
14
  LockStore,
14
15
  )
16
+ from rasa.core.redis_connection_factory import (
17
+ DeploymentMode,
18
+ RedisConfig,
19
+ RedisConnectionFactory,
20
+ )
21
+ from rasa.shared.exceptions import RasaException
15
22
  from rasa.utils.endpoints import EndpointConfig
16
23
 
17
24
  DEFAULT_REDIS_DB = 1
@@ -74,9 +81,10 @@ class ConcurrentRedisLockStore(LockStore):
74
81
  alphanumeric.
75
82
  socket_timeout - Timeout in seconds after which an exception will be raised
76
83
  in case Redis doesn't respond within `socket_timeout` seconds.
84
+ deployment_mode - Redis deployment mode: standard, cluster, or sentinel.
85
+ endpoints - List of endpoints for cluster/sentinel mode in host:port format.
86
+ sentinel_service - Sentinel service name.
77
87
  """
78
- import redis
79
-
80
88
  host = endpoint_config.kwargs.get("host", DEFAULT_HOSTNAME)
81
89
  port = endpoint_config.kwargs.get("port", DEFAULT_PORT)
82
90
  db = endpoint_config.kwargs.get("db", DEFAULT_REDIS_DB)
@@ -90,20 +98,33 @@ class ConcurrentRedisLockStore(LockStore):
90
98
  socket_timeout = endpoint_config.kwargs.get(
91
99
  "socket_timeout", DEFAULT_SOCKET_TIMEOUT_IN_SECONDS
92
100
  )
93
-
94
- self.red = redis.StrictRedis(
95
- host=host,
96
- port=int(port),
97
- db=int(db),
98
- username=username,
99
- password=password,
100
- ssl=use_ssl,
101
- ssl_certfile=ssl_certfile,
102
- ssl_keyfile=ssl_keyfile,
103
- ssl_ca_certs=ssl_ca_certs,
104
- socket_timeout=socket_timeout,
101
+ deployment_mode = endpoint_config.kwargs.get(
102
+ "deployment_mode", DeploymentMode.STANDARD.value
105
103
  )
104
+ endpoints = endpoint_config.kwargs.get("endpoints", [])
105
+ sentinel_service = endpoint_config.kwargs.get("sentinel_service")
106
106
 
107
+ try:
108
+ redis_config = RedisConfig(
109
+ host=host,
110
+ port=port,
111
+ db=db,
112
+ username=username,
113
+ password=password,
114
+ use_ssl=use_ssl,
115
+ ssl_certfile=ssl_certfile,
116
+ ssl_keyfile=ssl_keyfile,
117
+ ssl_ca_certs=ssl_ca_certs,
118
+ socket_timeout=socket_timeout,
119
+ deployment_mode=deployment_mode,
120
+ endpoints=endpoints,
121
+ sentinel_service=sentinel_service,
122
+ )
123
+ self.red = RedisConnectionFactory.create_connection(redis_config)
124
+ except ValidationError as e:
125
+ raise RasaException(f"Invalid Redis configuration: {e}")
126
+
127
+ self.deployment_mode = deployment_mode
107
128
  self.key_prefix = DEFAULT_CONCURRENT_REDIS_LOCK_STORE_KEY_PREFIX
108
129
  if key_prefix:
109
130
  structlogger.debug(
@@ -129,6 +150,32 @@ class ConcurrentRedisLockStore(LockStore):
129
150
  ),
130
151
  )
131
152
 
153
+ def _get_keys_by_pattern(self, pattern: Text) -> list:
154
+ """Get keys by pattern, using SCAN for cluster mode and KEYS for others."""
155
+ if self.deployment_mode == DeploymentMode.CLUSTER.value:
156
+ # In cluster mode, use SCAN to get keys more reliably
157
+ keys = []
158
+ cursor = 0
159
+
160
+ while True:
161
+ try:
162
+ cursor, batch_keys = self.red.scan(cursor, match=pattern, count=100)
163
+ keys.extend(batch_keys)
164
+ if cursor == 0:
165
+ break
166
+ except Exception as e:
167
+ structlogger.warning(
168
+ "concurrent_redis_lock_store._get_keys_by_pattern.scan_interrupted",
169
+ event_info=f"SCAN interrupted in cluster mode: {e}. "
170
+ f"Returning {len(keys)} keys found so far.",
171
+ )
172
+ break
173
+ else:
174
+ # Standard and sentinel modes use KEYS
175
+ keys = self.red.keys(pattern)
176
+
177
+ return keys
178
+
132
179
  def issue_ticket(
133
180
  self, conversation_id: Text, lock_lifetime: float = LOCK_LIFETIME
134
181
  ) -> int:
@@ -157,11 +204,14 @@ class ConcurrentRedisLockStore(LockStore):
157
204
  tickets: Deque[Ticket] = deque()
158
205
 
159
206
  pattern = self.key_prefix + conversation_id + ":" + "[0-9]*"
160
- redis_keys = self.red.keys(pattern)
207
+ redis_keys = self._get_keys_by_pattern(pattern)
161
208
 
162
209
  for key in redis_keys:
163
210
  serialised_ticket = self.red.get(key)
164
211
  if serialised_ticket:
212
+ # Handle bytes to string conversion for JSON parsing
213
+ if isinstance(serialised_ticket, bytes):
214
+ serialised_ticket = serialised_ticket.decode("utf-8")
165
215
  ticket = Ticket.from_dict(json.loads(serialised_ticket))
166
216
  tickets.appendleft(ticket)
167
217
 
@@ -172,7 +222,7 @@ class ConcurrentRedisLockStore(LockStore):
172
222
  def delete_lock(self, conversation_id: Text) -> None:
173
223
  """Deletes lock for conversation ID."""
174
224
  pattern = self.key_prefix + conversation_id + ":*"
175
- redis_keys = self.red.keys(pattern)
225
+ redis_keys = self._get_keys_by_pattern(pattern)
176
226
 
177
227
  if not redis_keys:
178
228
  structlogger.debug(
rasa/core/constants.py CHANGED
@@ -112,3 +112,10 @@ ACTIVE_FLOW_METADATA_KEY = "active_flow"
112
112
  STEP_ID_METADATA_KEY = "step_id"
113
113
  KEY_IS_CALM_SYSTEM = "is_calm_system"
114
114
  KEY_IS_COEXISTENCE_ASSISTANT = "is_coexistence_assistant"
115
+
116
+ IAM_CLOUD_PROVIDER_ENV_VAR_NAME = "IAM_CLOUD_PROVIDER"
117
+ SQL_TRACKER_STORE_SSL_MODE_ENV_VAR_NAME = "SQL_TRACKER_STORE_SSL_MODE"
118
+ SQL_TRACKER_STORE_SSL_ROOT_CERTIFICATE_ENV_VAR_NAME = (
119
+ "SQL_TRACKER_STORE_SSL_ROOT_CERTIFICATE"
120
+ )
121
+ AWS_ELASTICACHE_CLUSTER_NAME_ENV_VAR_NAME = "AWS_ELASTICACHE_CLUSTER_NAME"
File without changes