rasa-pro 3.13.12__py3-none-any.whl → 3.14.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 (586) hide show
  1. rasa/__main__.py +15 -3
  2. rasa/agents/__init__.py +0 -0
  3. rasa/agents/agent_factory.py +122 -0
  4. rasa/agents/agent_manager.py +213 -0
  5. rasa/agents/constants.py +43 -0
  6. rasa/agents/core/__init__.py +0 -0
  7. rasa/agents/core/agent_protocol.py +107 -0
  8. rasa/agents/core/types.py +81 -0
  9. rasa/agents/exceptions.py +38 -0
  10. rasa/agents/protocol/__init__.py +5 -0
  11. rasa/agents/protocol/a2a/__init__.py +0 -0
  12. rasa/agents/protocol/a2a/a2a_agent.py +889 -0
  13. rasa/agents/protocol/mcp/__init__.py +0 -0
  14. rasa/agents/protocol/mcp/mcp_base_agent.py +778 -0
  15. rasa/agents/protocol/mcp/mcp_open_agent.py +327 -0
  16. rasa/agents/protocol/mcp/mcp_task_agent.py +522 -0
  17. rasa/agents/schemas/__init__.py +13 -0
  18. rasa/agents/schemas/agent_input.py +38 -0
  19. rasa/agents/schemas/agent_output.py +26 -0
  20. rasa/agents/schemas/agent_tool_result.py +65 -0
  21. rasa/agents/schemas/agent_tool_schema.py +186 -0
  22. rasa/agents/templates/__init__.py +0 -0
  23. rasa/agents/templates/mcp_open_agent_prompt_template.jinja2 +20 -0
  24. rasa/agents/templates/mcp_task_agent_prompt_template.jinja2 +22 -0
  25. rasa/agents/utils.py +228 -0
  26. rasa/agents/validation.py +538 -0
  27. rasa/api.py +23 -9
  28. rasa/builder/README.md +120 -0
  29. rasa/builder/__init__.py +0 -0
  30. rasa/builder/auth.py +176 -0
  31. rasa/builder/config.py +96 -0
  32. rasa/builder/copilot/__init__.py +0 -0
  33. rasa/builder/copilot/constants.py +38 -0
  34. rasa/builder/copilot/copilot.py +562 -0
  35. rasa/builder/copilot/copilot_response_handler.py +522 -0
  36. rasa/builder/copilot/copilot_templated_message_provider.py +81 -0
  37. rasa/builder/copilot/exceptions.py +32 -0
  38. rasa/builder/copilot/models.py +690 -0
  39. rasa/builder/copilot/prompts/__init__.py +0 -0
  40. rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +787 -0
  41. rasa/builder/copilot/prompts/copilot_training_error_handler_prompt.jinja2 +53 -0
  42. rasa/builder/copilot/prompts/latest_user_message_context_prompt.jinja2 +91 -0
  43. rasa/builder/copilot/signing.py +305 -0
  44. rasa/builder/copilot/telemetry.py +234 -0
  45. rasa/builder/copilot/templated_messages/__init__.py +0 -0
  46. rasa/builder/copilot/templated_messages/copilot_internal_messages_templates.yml +16 -0
  47. rasa/builder/copilot/templated_messages/copilot_templated_responses.yml +41 -0
  48. rasa/builder/copilot/templated_messages/copilot_welcome_messages.yml +56 -0
  49. rasa/builder/document_retrieval/__init__.py +0 -0
  50. rasa/builder/document_retrieval/constants.py +15 -0
  51. rasa/builder/document_retrieval/inkeep-rag-response-schema.json +64 -0
  52. rasa/builder/document_retrieval/inkeep_document_retrieval.py +238 -0
  53. rasa/builder/document_retrieval/models.py +62 -0
  54. rasa/builder/download.py +140 -0
  55. rasa/builder/exceptions.py +91 -0
  56. rasa/builder/guardrails/__init__.py +1 -0
  57. rasa/builder/guardrails/clients.py +256 -0
  58. rasa/builder/guardrails/constants.py +12 -0
  59. rasa/builder/guardrails/exceptions.py +4 -0
  60. rasa/builder/guardrails/models.py +266 -0
  61. rasa/builder/guardrails/policy_checker.py +324 -0
  62. rasa/builder/guardrails/store.py +238 -0
  63. rasa/builder/guardrails/utils.py +94 -0
  64. rasa/builder/job_manager.py +87 -0
  65. rasa/builder/jobs.py +609 -0
  66. rasa/builder/llm_service.py +273 -0
  67. rasa/builder/logging_utils.py +265 -0
  68. rasa/builder/main.py +234 -0
  69. rasa/builder/models.py +229 -0
  70. rasa/builder/project_generator.py +463 -0
  71. rasa/builder/project_info.py +72 -0
  72. rasa/builder/service.py +1367 -0
  73. rasa/builder/shared/tracker_context.py +212 -0
  74. rasa/builder/skill_to_bot_prompt.jinja2 +164 -0
  75. rasa/builder/template_cache.py +69 -0
  76. rasa/builder/training_service.py +188 -0
  77. rasa/builder/validation_service.py +101 -0
  78. rasa/cli/arguments/data.py +9 -0
  79. rasa/cli/arguments/default_arguments.py +12 -0
  80. rasa/cli/arguments/run.py +2 -0
  81. rasa/cli/arguments/train.py +2 -0
  82. rasa/cli/data.py +78 -10
  83. rasa/cli/dialogue_understanding_test.py +11 -7
  84. rasa/cli/e2e_test.py +10 -6
  85. rasa/cli/evaluate.py +4 -2
  86. rasa/cli/export.py +5 -2
  87. rasa/cli/inspect.py +9 -4
  88. rasa/cli/interactive.py +8 -4
  89. rasa/cli/llm_fine_tuning.py +12 -6
  90. rasa/cli/project_templates/basic/README.md +23 -0
  91. rasa/cli/project_templates/basic/actions/__init__ +0 -0
  92. rasa/cli/project_templates/basic/actions/action_human_handoff.py +40 -0
  93. rasa/cli/project_templates/basic/actions/actions.md +10 -0
  94. rasa/cli/project_templates/basic/config.yml +29 -0
  95. rasa/cli/project_templates/basic/credentials.yml +33 -0
  96. rasa/cli/project_templates/basic/data/data.md +8 -0
  97. rasa/cli/project_templates/basic/data/general/feedback.yml +21 -0
  98. rasa/cli/project_templates/basic/data/general/goodbye.yml +6 -0
  99. rasa/cli/project_templates/basic/data/general/hello.yml +6 -0
  100. rasa/cli/project_templates/basic/data/general/help.yml +6 -0
  101. rasa/cli/project_templates/basic/data/general/human_handoff.yml +16 -0
  102. rasa/cli/project_templates/basic/data/general/show_faqs.yml +6 -0
  103. rasa/cli/project_templates/basic/data/system/patterns/pattern_cannot_handle.yml +7 -0
  104. rasa/cli/project_templates/basic/data/system/patterns/pattern_completed.yml +7 -0
  105. rasa/cli/project_templates/basic/data/system/patterns/pattern_correction.yml +7 -0
  106. rasa/cli/project_templates/basic/data/system/patterns/pattern_search.yml +8 -0
  107. rasa/cli/project_templates/basic/data/system/patterns/pattern_session_start.yml +8 -0
  108. rasa/cli/project_templates/basic/docs/docs.md +5 -0
  109. rasa/cli/project_templates/basic/docs/template.txt +28 -0
  110. rasa/cli/project_templates/basic/domain/domain.md +11 -0
  111. rasa/cli/project_templates/basic/domain/general/feedback.yml +25 -0
  112. rasa/cli/project_templates/basic/domain/general/goodbye.yml +9 -0
  113. rasa/cli/project_templates/basic/domain/general/hello.yml +7 -0
  114. rasa/cli/project_templates/basic/domain/general/help.yml +21 -0
  115. rasa/cli/project_templates/basic/domain/general/human_handoff.yml +32 -0
  116. rasa/cli/project_templates/basic/domain/general/show_faqs.yml +14 -0
  117. rasa/cli/project_templates/basic/domain/system/patterns/pattern_cannot_handle.yml +5 -0
  118. rasa/cli/project_templates/basic/domain/system/patterns/pattern_session_start.yml +19 -0
  119. rasa/cli/project_templates/basic/endpoints.yml +67 -0
  120. rasa/cli/project_templates/basic/prompts/rephraser_demo_personality_prompt.jinja2 +38 -0
  121. rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/feedback.yml +46 -0
  122. rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/goodbye.yml +9 -0
  123. rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/hello.yml +8 -0
  124. rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/help.yml +8 -0
  125. rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/human_handoff.yml +41 -0
  126. rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/patterns.yml +32 -0
  127. rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/show_faqs.yml +8 -0
  128. rasa/cli/project_templates/default/config.yml +4 -0
  129. rasa/cli/project_templates/default/endpoints.yml +4 -0
  130. rasa/cli/project_templates/defaults.py +1 -0
  131. rasa/cli/project_templates/finance/README.md +26 -0
  132. rasa/cli/project_templates/finance/actions/__init__.py +0 -0
  133. rasa/cli/project_templates/finance/actions/accounts/__init__.py +0 -0
  134. rasa/cli/project_templates/finance/actions/accounts/check_balance.py +18 -0
  135. rasa/cli/project_templates/finance/actions/actions.md +15 -0
  136. rasa/cli/project_templates/finance/actions/cards/__init__.py +0 -0
  137. rasa/cli/project_templates/finance/actions/cards/check_that_card_exists.py +21 -0
  138. rasa/cli/project_templates/finance/actions/cards/list_cards.py +22 -0
  139. rasa/cli/project_templates/finance/actions/contacts/__init__.py +0 -0
  140. rasa/cli/project_templates/finance/actions/contacts/add_contact.py +30 -0
  141. rasa/cli/project_templates/finance/actions/contacts/list_contacts.py +22 -0
  142. rasa/cli/project_templates/finance/actions/contacts/remove_contact.py +35 -0
  143. rasa/cli/project_templates/finance/actions/db.py +117 -0
  144. rasa/cli/project_templates/finance/actions/general/__init__.py +0 -0
  145. rasa/cli/project_templates/finance/actions/general/action_human_handoff.py +49 -0
  146. rasa/cli/project_templates/finance/actions/transfers/__init__.py +0 -0
  147. rasa/cli/project_templates/finance/actions/transfers/check_transfer_funds.py +27 -0
  148. rasa/cli/project_templates/finance/actions/transfers/check_transfer_limit.py +36 -0
  149. rasa/cli/project_templates/finance/actions/transfers/execute_recurrent_payment.py +20 -0
  150. rasa/cli/project_templates/finance/actions/transfers/execute_transfer.py +45 -0
  151. rasa/cli/project_templates/finance/actions/transfers/list_transactions.py +32 -0
  152. rasa/cli/project_templates/finance/config.yml +29 -0
  153. rasa/cli/project_templates/finance/credentials.yml +33 -0
  154. rasa/cli/project_templates/finance/data/accounts/check_balance.yml +9 -0
  155. rasa/cli/project_templates/finance/data/accounts/download_statements.yml +26 -0
  156. rasa/cli/project_templates/finance/data/bills/bill_pay_reminder.yml +25 -0
  157. rasa/cli/project_templates/finance/data/cards/activate_card.yml +35 -0
  158. rasa/cli/project_templates/finance/data/cards/block_card.yml +45 -0
  159. rasa/cli/project_templates/finance/data/cards/list_cards.yml +14 -0
  160. rasa/cli/project_templates/finance/data/cards/replace_card.yml +16 -0
  161. rasa/cli/project_templates/finance/data/cards/replace_eligible_card.yml +29 -0
  162. rasa/cli/project_templates/finance/data/contacts/add_contact.yml +33 -0
  163. rasa/cli/project_templates/finance/data/contacts/list_contacts.yml +14 -0
  164. rasa/cli/project_templates/finance/data/contacts/remove_contact.yml +31 -0
  165. rasa/cli/project_templates/finance/data/data.md +14 -0
  166. rasa/cli/project_templates/finance/data/general/bot_challenge.yml +6 -0
  167. rasa/cli/project_templates/finance/data/general/feedback.yml +20 -0
  168. rasa/cli/project_templates/finance/data/general/goodbye.yml +6 -0
  169. rasa/cli/project_templates/finance/data/general/hello.yml +6 -0
  170. rasa/cli/project_templates/finance/data/general/help.yml +9 -0
  171. rasa/cli/project_templates/finance/data/general/human_handoff.yml +16 -0
  172. rasa/cli/project_templates/finance/data/general/welcome.yml +9 -0
  173. rasa/cli/project_templates/finance/data/system/patterns/pattern_completed.yml +7 -0
  174. rasa/cli/project_templates/finance/data/system/patterns/pattern_correction.yml +7 -0
  175. rasa/cli/project_templates/finance/data/system/patterns/pattern_search.yml +8 -0
  176. rasa/cli/project_templates/finance/data/system/patterns/pattern_session_start.yml +8 -0
  177. rasa/cli/project_templates/finance/data/transfers/check_transfer_limit.yml +18 -0
  178. rasa/cli/project_templates/finance/data/transfers/list_transactions.yml +46 -0
  179. rasa/cli/project_templates/finance/data/transfers/move_money_between_accounts.yml +51 -0
  180. rasa/cli/project_templates/finance/data/transfers/transfer_money.yml +34 -0
  181. rasa/cli/project_templates/finance/data/transfers/transfer_money_to_a_third_party.yml +175 -0
  182. rasa/cli/project_templates/finance/db/cards.json +18 -0
  183. rasa/cli/project_templates/finance/db/contacts.json +10 -0
  184. rasa/cli/project_templates/finance/db/my_account.json +6 -0
  185. rasa/cli/project_templates/finance/db/transactions.json +22 -0
  186. rasa/cli/project_templates/finance/docs/docs.md +8 -0
  187. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/budgeting_analytics.txt +22 -0
  188. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/multi_currency_accounts.txt +19 -0
  189. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/premium_benefits.txt +19 -0
  190. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/contactless_limits.txt +16 -0
  191. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/freeze_unfreeze_card.txt +16 -0
  192. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/lost_stolen_card.txt +19 -0
  193. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/money_transfers/instant_payments.txt +19 -0
  194. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/money_transfers/international_transfers.txt +19 -0
  195. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/security_fraud/fraud_protection.txt +22 -0
  196. rasa/cli/project_templates/finance/docs/fenlo_banking_faq/security_fraud/secure_payments.txt +22 -0
  197. rasa/cli/project_templates/finance/domain/accounts/check_balance.yml +15 -0
  198. rasa/cli/project_templates/finance/domain/accounts/download_statements.yml +40 -0
  199. rasa/cli/project_templates/finance/domain/bills/bill_pay_reminder.yml +49 -0
  200. rasa/cli/project_templates/finance/domain/cards/activate_card.yml +24 -0
  201. rasa/cli/project_templates/finance/domain/cards/block_card.yml +44 -0
  202. rasa/cli/project_templates/finance/domain/cards/list_cards.yml +16 -0
  203. rasa/cli/project_templates/finance/domain/cards/replace_card.yml +43 -0
  204. rasa/cli/project_templates/finance/domain/cards/shared.yml +15 -0
  205. rasa/cli/project_templates/finance/domain/contacts/add_contact.yml +37 -0
  206. rasa/cli/project_templates/finance/domain/contacts/list_contacts.yml +16 -0
  207. rasa/cli/project_templates/finance/domain/contacts/remove_contact.yml +32 -0
  208. rasa/cli/project_templates/finance/domain/domain.md +18 -0
  209. rasa/cli/project_templates/finance/domain/general/_shared.yml +39 -0
  210. rasa/cli/project_templates/finance/domain/general/bot_challenge.yml +4 -0
  211. rasa/cli/project_templates/finance/domain/general/cannot_handle.yml +8 -0
  212. rasa/cli/project_templates/finance/domain/general/feedback.yml +25 -0
  213. rasa/cli/project_templates/finance/domain/general/goodbye.yml +7 -0
  214. rasa/cli/project_templates/finance/domain/general/help.yml +0 -0
  215. rasa/cli/project_templates/finance/domain/general/human_handoff.yml +31 -0
  216. rasa/cli/project_templates/finance/domain/general/welcome.yml +39 -0
  217. rasa/cli/project_templates/finance/domain/transfers/check_transfer_limit.yml +32 -0
  218. rasa/cli/project_templates/finance/domain/transfers/list_transactions.yml +44 -0
  219. rasa/cli/project_templates/finance/domain/transfers/shared.yml +17 -0
  220. rasa/cli/project_templates/finance/domain/transfers/transfer_money.yml +221 -0
  221. rasa/cli/project_templates/finance/endpoints.yml +67 -0
  222. rasa/cli/project_templates/finance/prompts/rephraser_demo_personality_prompt.jinja2 +38 -0
  223. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/accounts/check_balance.yml +9 -0
  224. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/accounts/download_statements.yml +43 -0
  225. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/cards/block_card.yml +55 -0
  226. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/bot_challenge.yml +8 -0
  227. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/feedback.yml +46 -0
  228. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/goodbye.yml +9 -0
  229. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/hello.yml +8 -0
  230. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/human_handoff.yml +35 -0
  231. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/patterns.yml +22 -0
  232. rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/transfers/transfer_money.yml +56 -0
  233. rasa/cli/project_templates/telco/README.md +25 -0
  234. rasa/cli/project_templates/telco/actions/__init__.py +0 -0
  235. rasa/cli/project_templates/telco/actions/actions.md +12 -0
  236. rasa/cli/project_templates/telco/actions/billing/__init__.py +0 -0
  237. rasa/cli/project_templates/telco/actions/billing/actions_billing.py +204 -0
  238. rasa/cli/project_templates/telco/actions/general/__init__.py +0 -0
  239. rasa/cli/project_templates/telco/actions/general/action_human_handoff.py +49 -0
  240. rasa/cli/project_templates/telco/actions/network/__init__.py +0 -0
  241. rasa/cli/project_templates/telco/actions/network/actions_get_data_from_db.py +48 -0
  242. rasa/cli/project_templates/telco/actions/network/actions_run_diagnostics.py +28 -0
  243. rasa/cli/project_templates/telco/actions/network/actions_session_start.py +18 -0
  244. rasa/cli/project_templates/telco/config.yml +29 -0
  245. rasa/cli/project_templates/telco/credentials.yml +33 -0
  246. rasa/cli/project_templates/telco/csvs/billing.csv +19 -0
  247. rasa/cli/project_templates/telco/csvs/customers.csv +5 -0
  248. rasa/cli/project_templates/telco/data/billing/flow_understand_bill.yml +45 -0
  249. rasa/cli/project_templates/telco/data/data.md +11 -0
  250. rasa/cli/project_templates/telco/data/general/bot_challenge.yml +6 -0
  251. rasa/cli/project_templates/telco/data/general/feedback.yml +20 -0
  252. rasa/cli/project_templates/telco/data/general/goodbye.yml +6 -0
  253. rasa/cli/project_templates/telco/data/general/hello.yml +6 -0
  254. rasa/cli/project_templates/telco/data/general/human_handoff.yml +16 -0
  255. rasa/cli/project_templates/telco/data/general/patterns.yml +30 -0
  256. rasa/cli/project_templates/telco/data/network/flow_reboot_router.yml +8 -0
  257. rasa/cli/project_templates/telco/data/network/flow_reset_router.yml +7 -0
  258. rasa/cli/project_templates/telco/data/network/flow_solve_internet_issue.yml +73 -0
  259. rasa/cli/project_templates/telco/docs/docs.md +8 -0
  260. rasa/cli/project_templates/telco/docs/network/reset_vs_rboot_router.txt +1 -0
  261. rasa/cli/project_templates/telco/docs/network/restart_router.txt +6 -0
  262. rasa/cli/project_templates/telco/docs/network/run_speed_test.txt +6 -0
  263. rasa/cli/project_templates/telco/domain/billing/understand_bill.yml +102 -0
  264. rasa/cli/project_templates/telco/domain/domain.md +13 -0
  265. rasa/cli/project_templates/telco/domain/general/bot_challenge.yml +4 -0
  266. rasa/cli/project_templates/telco/domain/general/feedback.yml +25 -0
  267. rasa/cli/project_templates/telco/domain/general/goodbye.yml +7 -0
  268. rasa/cli/project_templates/telco/domain/general/hello.yml +5 -0
  269. rasa/cli/project_templates/telco/domain/general/human_handoff.yml +26 -0
  270. rasa/cli/project_templates/telco/domain/general/patterns.yml +33 -0
  271. rasa/cli/project_templates/telco/domain/network/reboot_router.yml +21 -0
  272. rasa/cli/project_templates/telco/domain/network/reset_router.yml +12 -0
  273. rasa/cli/project_templates/telco/domain/network/run_speed_test.yml +25 -0
  274. rasa/cli/project_templates/telco/domain/network/solve_internet_issue.yml +74 -0
  275. rasa/cli/project_templates/telco/domain/shared.yml +129 -0
  276. rasa/cli/project_templates/telco/endpoints.yml +67 -0
  277. rasa/cli/project_templates/telco/prompts/rephraser_demo_personality_prompt.jinja2 +40 -0
  278. rasa/cli/project_templates/telco/tests/e2e_test_cases/with_stub/network/solve_internet_not_slow.yml +33 -0
  279. rasa/cli/project_templates/telco/tests/e2e_test_cases/with_stub/network/solve_internet_slow.yml +47 -0
  280. rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/billing/understand_bill.yml +67 -0
  281. rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/bot_challenge.yml +8 -0
  282. rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/feedback.yml +46 -0
  283. rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/goodbye.yml +9 -0
  284. rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/hello.yml +8 -0
  285. rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/human_handoff.yml +35 -0
  286. rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/patterns.yml +23 -0
  287. rasa/cli/project_templates/tutorial/config.yml +2 -1
  288. rasa/cli/project_templates/tutorial/credentials.yml +10 -0
  289. rasa/cli/run.py +8 -10
  290. rasa/cli/scaffold.py +50 -6
  291. rasa/cli/shell.py +10 -5
  292. rasa/cli/studio/studio.py +1 -1
  293. rasa/cli/test.py +34 -14
  294. rasa/cli/train.py +44 -30
  295. rasa/cli/utils.py +1 -393
  296. rasa/cli/validation/__init__.py +0 -0
  297. rasa/cli/validation/bot_config.py +232 -0
  298. rasa/cli/validation/config_path_validation.py +257 -0
  299. rasa/cli/x.py +8 -4
  300. rasa/constants.py +7 -1
  301. rasa/core/actions/action.py +53 -13
  302. rasa/core/actions/action_exceptions.py +1 -1
  303. rasa/core/actions/action_run_slot_rejections.py +1 -1
  304. rasa/core/actions/grpc_custom_action_executor.py +1 -1
  305. rasa/core/agent.py +22 -2
  306. rasa/core/available_agents.py +239 -0
  307. rasa/core/brokers/broker.py +1 -1
  308. rasa/core/brokers/kafka.py +56 -8
  309. rasa/core/channels/__init__.py +82 -35
  310. rasa/core/channels/channel.py +4 -3
  311. rasa/core/channels/constants.py +3 -0
  312. rasa/core/channels/development_inspector.py +29 -16
  313. rasa/core/channels/hangouts.py +2 -2
  314. rasa/core/channels/inspector/README.md +25 -13
  315. rasa/core/channels/inspector/dist/assets/{arc-0b11fe30.js → arc-6177260a.js} +1 -1
  316. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-9eef30a7.js → blockDiagram-38ab4fdb-b054f038.js} +1 -1
  317. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-03e94f28.js → c4Diagram-3d4e48cf-f25427d5.js} +1 -1
  318. rasa/core/channels/inspector/dist/assets/channel-bf9cbb34.js +1 -0
  319. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-95c09eba.js → classDiagram-70f12bd4-c7a2af53.js} +1 -1
  320. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-38e8446c.js → classDiagram-v2-f2320105-58db65c0.js} +1 -1
  321. rasa/core/channels/inspector/dist/assets/clone-8f9083bb.js +1 -0
  322. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-57dc3038.js → createText-2e5e7dd3-088372e2.js} +1 -1
  323. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-4bac0545.js → edges-e0da2a9e-58676240.js} +1 -1
  324. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-81795c90.js → erDiagram-9861fffd-0c14d7c6.js} +1 -1
  325. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-89489ae6.js → flowDb-956e92f1-ea63f85c.js} +1 -1
  326. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-cd152627.js → flowDiagram-66a62f08-a2af48cd.js} +1 -1
  327. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-9ecd5b59.js +1 -0
  328. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-3da369bc.js → flowchart-elk-definition-4a651766-6937abe7.js} +1 -1
  329. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-85ec16f8.js → ganttDiagram-c361ad54-7473f357.js} +1 -1
  330. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-495bc140.js → gitGraphDiagram-72cf32ee-d0c9405e.js} +1 -1
  331. rasa/core/channels/inspector/dist/assets/{graph-1ec4d266.js → graph-0a6f8466.js} +1 -1
  332. rasa/core/channels/inspector/dist/assets/{index-3862675e-0a0e97c9.js → index-3862675e-7610671a.js} +1 -1
  333. rasa/core/channels/inspector/dist/assets/index-74e01d94.js +1354 -0
  334. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-4d54bcde.js → infoDiagram-f8f76790-be397dc7.js} +1 -1
  335. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-dc097114.js → journeyDiagram-49397b02-4cefbf62.js} +1 -1
  336. rasa/core/channels/inspector/dist/assets/{layout-1a08981e.js → layout-e7fbc2bf.js} +1 -1
  337. rasa/core/channels/inspector/dist/assets/{line-95f7f1d3.js → line-a8aa457c.js} +1 -1
  338. rasa/core/channels/inspector/dist/assets/{linear-97e69543.js → linear-3351e0d2.js} +1 -1
  339. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-8c71ff03.js → mindmap-definition-fc14e90a-b8cbf605.js} +1 -1
  340. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-f14c71c7.js → pieDiagram-8a3498a8-f327f774.js} +1 -1
  341. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-f1d3c9ff.js → quadrantDiagram-120e2f19-2854c591.js} +1 -1
  342. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-bfa2412f.js → requirementDiagram-deff3bca-964985d5.js} +1 -1
  343. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-53f2c97b.js → sankeyDiagram-04a897e0-edeb4f33.js} +1 -1
  344. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-319d7c0e.js → sequenceDiagram-704730f1-fcf70125.js} +1 -1
  345. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-76a09418.js → stateDiagram-587899a1-0e770395.js} +1 -1
  346. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-a67f15d4.js → stateDiagram-v2-d93cdb3a-af8dcd22.js} +1 -1
  347. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-0654e7c3.js → styles-6aaf32cf-36a9e70d.js} +1 -1
  348. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1394bb9d.js → styles-9a916d00-884a8b5b.js} +1 -1
  349. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-e4c5bdae.js → styles-c10674c1-dc097813.js} +1 -1
  350. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-50957104.js → svgDrawCommon-08f97a94-5a2c7eed.js} +1 -1
  351. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-b0885a6a.js → timeline-definition-85554ec2-e89c4f6e.js} +1 -1
  352. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-79e6541a.js → xychartDiagram-e933f94c-afb6fe56.js} +1 -1
  353. rasa/core/channels/inspector/dist/index.html +1 -1
  354. rasa/core/channels/inspector/package.json +18 -18
  355. rasa/core/channels/inspector/src/App.tsx +56 -12
  356. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +1 -1
  357. rasa/core/channels/inspector/src/components/DialogueAgentStack.tsx +108 -0
  358. rasa/core/channels/inspector/src/components/{DialogueStack.tsx → DialogueHistoryStack.tsx} +4 -2
  359. rasa/core/channels/inspector/src/components/DialogueInformation.tsx +20 -3
  360. rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +296 -0
  361. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -2
  362. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +26 -4
  363. rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -0
  364. rasa/core/channels/inspector/src/helpers/formatters.ts +24 -3
  365. rasa/core/channels/inspector/src/helpers/utils.test.ts +127 -0
  366. rasa/core/channels/inspector/src/helpers/utils.ts +66 -1
  367. rasa/core/channels/inspector/src/theme/base/styles.ts +19 -1
  368. rasa/core/channels/inspector/src/types.ts +55 -1
  369. rasa/core/channels/inspector/yarn.lock +336 -189
  370. rasa/core/channels/socketio.py +212 -51
  371. rasa/core/channels/studio_chat.py +82 -32
  372. rasa/core/channels/telegram.py +4 -9
  373. rasa/core/channels/voice_ready/twilio_voice.py +1 -1
  374. rasa/core/channels/voice_stream/asr/asr_event.py +1 -1
  375. rasa/core/channels/voice_stream/asr/azure.py +6 -3
  376. rasa/core/channels/voice_stream/asr/deepgram.py +1 -1
  377. rasa/core/channels/voice_stream/audiocodes.py +11 -6
  378. rasa/core/channels/voice_stream/browser_audio.py +91 -4
  379. rasa/core/channels/voice_stream/call_state.py +13 -2
  380. rasa/core/channels/voice_stream/genesys.py +19 -15
  381. rasa/core/channels/voice_stream/jambonz.py +22 -12
  382. rasa/core/channels/voice_stream/tts/deepgram.py +140 -0
  383. rasa/core/channels/voice_stream/twilio_media_streams.py +35 -14
  384. rasa/core/channels/voice_stream/util.py +11 -1
  385. rasa/core/channels/voice_stream/voice_channel.py +170 -32
  386. rasa/core/concurrent_lock_store.py +83 -16
  387. rasa/core/config/__init__.py +0 -0
  388. rasa/core/{available_endpoints.py → config/available_endpoints.py} +56 -18
  389. rasa/core/config/configuration.py +295 -0
  390. rasa/core/config/credentials.py +19 -0
  391. rasa/core/config/message_procesing_config.py +34 -0
  392. rasa/core/constants.py +17 -0
  393. rasa/core/exceptions.py +1 -1
  394. rasa/core/featurizers/tracker_featurizers.py +3 -2
  395. rasa/core/iam_credentials_providers/__init__.py +0 -0
  396. rasa/core/iam_credentials_providers/aws_iam_credentials_providers.py +291 -0
  397. rasa/core/iam_credentials_providers/credentials_provider_protocol.py +91 -0
  398. rasa/core/lock_store.py +50 -10
  399. rasa/core/nlg/contextual_response_rephraser.py +5 -0
  400. rasa/core/nlg/generator.py +1 -1
  401. rasa/core/persistor.py +7 -7
  402. rasa/core/policies/enterprise_search_policy.py +9 -10
  403. rasa/core/policies/flow_policy.py +4 -4
  404. rasa/core/policies/flows/agent_executor.py +720 -0
  405. rasa/core/policies/flows/flow_exceptions.py +5 -2
  406. rasa/core/policies/flows/flow_executor.py +146 -77
  407. rasa/core/policies/flows/mcp_tool_executor.py +304 -0
  408. rasa/core/policies/intentless_policy.py +1 -1
  409. rasa/core/policies/rule_policy.py +1 -1
  410. rasa/core/policies/ted_policy.py +20 -12
  411. rasa/core/policies/unexpected_intent_policy.py +6 -0
  412. rasa/core/processor.py +100 -44
  413. rasa/core/redis_connection_factory.py +474 -0
  414. rasa/core/run.py +49 -10
  415. rasa/core/test.py +4 -0
  416. rasa/core/tracker_stores/redis_tracker_store.py +36 -14
  417. rasa/core/tracker_stores/sql_tracker_store.py +59 -1
  418. rasa/core/tracker_stores/tracker_store.py +3 -7
  419. rasa/core/train.py +1 -1
  420. rasa/core/training/interactive.py +20 -18
  421. rasa/core/training/story_conflict.py +5 -5
  422. rasa/core/utils.py +22 -23
  423. rasa/dialogue_understanding/commands/__init__.py +8 -0
  424. rasa/dialogue_understanding/commands/cancel_flow_command.py +20 -6
  425. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +21 -2
  426. rasa/dialogue_understanding/commands/clarify_command.py +20 -2
  427. rasa/dialogue_understanding/commands/continue_agent_command.py +91 -0
  428. rasa/dialogue_understanding/commands/knowledge_answer_command.py +21 -2
  429. rasa/dialogue_understanding/commands/restart_agent_command.py +162 -0
  430. rasa/dialogue_understanding/commands/start_flow_command.py +75 -7
  431. rasa/dialogue_understanding/commands/utils.py +135 -2
  432. rasa/dialogue_understanding/generator/command_parser.py +4 -0
  433. rasa/dialogue_understanding/generator/flow_retrieval.py +0 -9
  434. rasa/dialogue_understanding/generator/llm_based_command_generator.py +52 -12
  435. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
  436. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +1 -1
  437. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +66 -0
  438. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +66 -0
  439. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +89 -0
  440. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +88 -0
  441. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +42 -7
  442. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +40 -3
  443. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +20 -3
  444. rasa/dialogue_understanding/patterns/cancel.py +27 -6
  445. rasa/dialogue_understanding/patterns/clarify.py +3 -14
  446. rasa/dialogue_understanding/patterns/continue_interrupted.py +239 -6
  447. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +49 -9
  448. rasa/dialogue_understanding/processor/command_processor.py +136 -15
  449. rasa/dialogue_understanding/stack/dialogue_stack.py +98 -2
  450. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +57 -0
  451. rasa/dialogue_understanding/stack/utils.py +57 -3
  452. rasa/dialogue_understanding/utils.py +24 -4
  453. rasa/dialogue_understanding_test/du_test_runner.py +8 -3
  454. rasa/e2e_test/e2e_test_runner.py +13 -3
  455. rasa/engine/caching.py +2 -2
  456. rasa/engine/constants.py +1 -1
  457. rasa/engine/graph.py +5 -1
  458. rasa/engine/loader.py +12 -0
  459. rasa/engine/recipes/default_components.py +138 -49
  460. rasa/engine/recipes/default_recipe.py +108 -11
  461. rasa/engine/runner/dask.py +8 -5
  462. rasa/engine/validation.py +25 -8
  463. rasa/graph_components/validators/default_recipe_validator.py +86 -28
  464. rasa/hooks.py +5 -5
  465. rasa/llm_fine_tuning/utils.py +2 -2
  466. rasa/model_manager/model_api.py +4 -5
  467. rasa/model_manager/runner_service.py +2 -2
  468. rasa/model_manager/socket_bridge.py +21 -17
  469. rasa/model_manager/trainer_service.py +12 -9
  470. rasa/model_manager/utils.py +1 -29
  471. rasa/model_manager/warm_rasa_process.py +13 -3
  472. rasa/model_training.py +60 -47
  473. rasa/nlu/classifiers/diet_classifier.py +198 -98
  474. rasa/nlu/classifiers/logistic_regression_classifier.py +1 -4
  475. rasa/nlu/classifiers/mitie_intent_classifier.py +3 -0
  476. rasa/nlu/classifiers/sklearn_intent_classifier.py +1 -3
  477. rasa/nlu/extractors/crf_entity_extractor.py +9 -10
  478. rasa/nlu/extractors/mitie_entity_extractor.py +3 -0
  479. rasa/nlu/extractors/spacy_entity_extractor.py +3 -0
  480. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +4 -0
  481. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +5 -0
  482. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +2 -0
  483. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +3 -0
  484. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +4 -2
  485. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -0
  486. rasa/nlu/selectors/response_selector.py +10 -2
  487. rasa/nlu/tokenizers/jieba_tokenizer.py +3 -4
  488. rasa/nlu/tokenizers/mitie_tokenizer.py +3 -2
  489. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -2
  490. rasa/nlu/utils/mitie_utils.py +3 -0
  491. rasa/nlu/utils/spacy_utils.py +3 -2
  492. rasa/plugin.py +8 -8
  493. rasa/privacy/privacy_config.py +1 -1
  494. rasa/privacy/privacy_manager.py +12 -3
  495. rasa/server.py +15 -3
  496. rasa/shared/agents/__init__.py +0 -0
  497. rasa/shared/agents/auth/__init__.py +0 -0
  498. rasa/shared/agents/auth/agent_auth_factory.py +105 -0
  499. rasa/shared/agents/auth/agent_auth_manager.py +92 -0
  500. rasa/shared/agents/auth/auth_strategy/__init__.py +19 -0
  501. rasa/shared/agents/auth/auth_strategy/agent_auth_strategy.py +52 -0
  502. rasa/shared/agents/auth/auth_strategy/api_key_auth_strategy.py +42 -0
  503. rasa/shared/agents/auth/auth_strategy/bearer_token_auth_strategy.py +28 -0
  504. rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +170 -0
  505. rasa/shared/agents/auth/constants.py +13 -0
  506. rasa/shared/agents/auth/types.py +12 -0
  507. rasa/shared/agents/auth/utils.py +85 -0
  508. rasa/shared/agents/utils.py +35 -0
  509. rasa/shared/constants.py +11 -0
  510. rasa/shared/core/constants.py +17 -1
  511. rasa/shared/core/domain.py +62 -22
  512. rasa/shared/core/events.py +329 -0
  513. rasa/shared/core/flows/constants.py +5 -0
  514. rasa/shared/core/flows/flow.py +1 -1
  515. rasa/shared/core/flows/flow_step.py +7 -1
  516. rasa/shared/core/flows/flows_list.py +21 -5
  517. rasa/shared/core/flows/flows_yaml_schema.json +119 -184
  518. rasa/shared/core/flows/steps/call.py +57 -6
  519. rasa/shared/core/flows/steps/collect.py +98 -13
  520. rasa/shared/core/flows/validation.py +372 -8
  521. rasa/shared/core/flows/yaml_flows_io.py +19 -10
  522. rasa/shared/core/slots.py +6 -2
  523. rasa/shared/core/trackers.py +5 -2
  524. rasa/shared/core/training_data/story_reader/story_reader.py +1 -1
  525. rasa/shared/exceptions.py +39 -2
  526. rasa/shared/importers/importer.py +6 -0
  527. rasa/shared/importers/rasa.py +1 -1
  528. rasa/shared/importers/utils.py +86 -4
  529. rasa/shared/nlu/training_data/schemas/responses.yml +3 -0
  530. rasa/shared/providers/llm/_base_litellm_client.py +41 -9
  531. rasa/shared/providers/llm/litellm_router_llm_client.py +10 -6
  532. rasa/shared/providers/llm/llm_client.py +7 -3
  533. rasa/shared/providers/llm/llm_response.py +66 -0
  534. rasa/shared/providers/llm/self_hosted_llm_client.py +8 -4
  535. rasa/shared/utils/common.py +26 -1
  536. rasa/shared/utils/health_check/health_check.py +7 -3
  537. rasa/shared/utils/llm.py +92 -19
  538. rasa/shared/utils/mcp/__init__.py +0 -0
  539. rasa/shared/utils/mcp/server_connection.py +250 -0
  540. rasa/shared/utils/mcp/utils.py +20 -0
  541. rasa/shared/utils/schemas/events.py +42 -0
  542. rasa/shared/utils/yaml.py +3 -1
  543. rasa/studio/download.py +3 -0
  544. rasa/studio/prompts.py +1 -0
  545. rasa/studio/pull/pull.py +3 -2
  546. rasa/studio/train.py +8 -7
  547. rasa/studio/upload.py +19 -52
  548. rasa/telemetry.py +166 -28
  549. rasa/tracing/config.py +45 -12
  550. rasa/tracing/constants.py +14 -0
  551. rasa/tracing/instrumentation/attribute_extractors.py +142 -9
  552. rasa/tracing/instrumentation/instrumentation.py +626 -21
  553. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +4 -4
  554. rasa/tracing/instrumentation/metrics.py +32 -0
  555. rasa/tracing/metric_instrument_provider.py +68 -0
  556. rasa/utils/common.py +92 -1
  557. rasa/utils/endpoints.py +11 -2
  558. rasa/utils/io.py +27 -9
  559. rasa/utils/json_utils.py +6 -1
  560. rasa/utils/log_utils.py +121 -7
  561. rasa/utils/ml_utils.py +1 -1
  562. rasa/utils/openapi.py +144 -0
  563. rasa/utils/plotting.py +1 -1
  564. rasa/utils/pypred.py +45 -0
  565. rasa/utils/tensorflow/__init__.py +7 -0
  566. rasa/utils/tensorflow/callback.py +136 -101
  567. rasa/utils/tensorflow/crf.py +1 -1
  568. rasa/utils/tensorflow/data_generator.py +21 -8
  569. rasa/utils/tensorflow/layers.py +21 -11
  570. rasa/utils/tensorflow/metrics.py +7 -3
  571. rasa/utils/tensorflow/models.py +56 -8
  572. rasa/utils/tensorflow/rasa_layers.py +8 -6
  573. rasa/utils/tensorflow/transformer.py +2 -3
  574. rasa/utils/train_utils.py +54 -24
  575. rasa/validator.py +149 -16
  576. rasa/version.py +1 -1
  577. rasa_pro-3.14.0.dist-info/METADATA +212 -0
  578. {rasa_pro-3.13.12.dist-info → rasa_pro-3.14.0.dist-info}/RECORD +581 -269
  579. rasa/core/channels/inspector/dist/assets/channel-51d02e9e.js +0 -1
  580. rasa/core/channels/inspector/dist/assets/clone-cc738fa6.js +0 -1
  581. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-0c716443.js +0 -1
  582. rasa/core/channels/inspector/dist/assets/index-c804b295.js +0 -1335
  583. rasa_pro-3.13.12.dist-info/METADATA +0 -192
  584. {rasa_pro-3.13.12.dist-info → rasa_pro-3.14.0.dist-info}/NOTICE +0 -0
  585. {rasa_pro-3.13.12.dist-info → rasa_pro-3.14.0.dist-info}/WHEEL +0 -0
  586. {rasa_pro-3.13.12.dist-info → rasa_pro-3.14.0.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import asyncio
2
4
  import copy
5
+ import string
6
+ import time
3
7
  from dataclasses import asdict, dataclass
4
8
  from typing import Any, AsyncIterator, Awaitable, Callable, Dict, List, Optional, Tuple
5
9
 
@@ -8,6 +12,11 @@ from sanic import Websocket # type: ignore
8
12
  from sanic.exceptions import ServerError, WebsocketClosed
9
13
 
10
14
  from rasa.core.channels import InputChannel, OutputChannel, UserMessage
15
+ from rasa.core.channels.constants import (
16
+ USER_CONVERSATION_SESSION_END,
17
+ USER_CONVERSATION_SESSION_START,
18
+ USER_CONVERSATION_SILENCE_TIMEOUT,
19
+ )
11
20
  from rasa.core.channels.voice_ready.utils import (
12
21
  CallParameters,
13
22
  validate_voice_license_scope,
@@ -29,6 +38,7 @@ from rasa.core.channels.voice_stream.call_state import (
29
38
  )
30
39
  from rasa.core.channels.voice_stream.tts.azure import AzureTTS
31
40
  from rasa.core.channels.voice_stream.tts.cartesia import CartesiaTTS
41
+ from rasa.core.channels.voice_stream.tts.deepgram import DeepgramTTS
32
42
  from rasa.core.channels.voice_stream.tts.tts_cache import TTSCache
33
43
  from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine, TTSError
34
44
  from rasa.core.channels.voice_stream.util import (
@@ -45,9 +55,13 @@ from rasa.utils.io import remove_emojis
45
55
  logger = structlog.get_logger(__name__)
46
56
 
47
57
  # define constants for the voice channel
48
- USER_CONVERSATION_SESSION_END = "/session_end"
49
- USER_CONVERSATION_SESSION_START = "/session_start"
50
- USER_CONVERSATION_SILENCE_TIMEOUT = "/silence_timeout"
58
+ DEFAULT_INTERRUPTION_MIN_WORDS = 3
59
+
60
+
61
+ @dataclass
62
+ class InterruptionConfig:
63
+ enabled: bool = False
64
+ min_words: int = DEFAULT_INTERRUPTION_MIN_WORDS
51
65
 
52
66
 
53
67
  @dataclass
@@ -120,6 +134,8 @@ def tts_engine_from_config(tts_config: Dict) -> TTSEngine:
120
134
  return AzureTTS.from_config_dict(tts_config)
121
135
  elif name.lower() == "cartesia":
122
136
  return CartesiaTTS.from_config_dict(tts_config)
137
+ elif name.lower() == "deepgram":
138
+ return DeepgramTTS.from_config_dict(tts_config)
123
139
  else:
124
140
  mark_as_beta_feature("Custom TTS Engine")
125
141
  try:
@@ -189,7 +205,7 @@ class VoiceOutputChannel(OutputChannel):
189
205
  def update_silence_timeout(self) -> None:
190
206
  """Updates the silence timeout for the session."""
191
207
  if self.tracker_state:
192
- call_state.silence_timeout = self.tracker_state["slots"][ # type: ignore[attr-defined]
208
+ call_state.silence_timeout = self.tracker_state["slots"][
193
209
  SILENCE_TIMEOUT_SLOT
194
210
  ]
195
211
  logger.debug(
@@ -207,22 +223,67 @@ class VoiceOutputChannel(OutputChannel):
207
223
  """Uses the concise button output format for voice channels."""
208
224
  await self.send_text_with_buttons_concise(recipient_id, text, buttons, **kwargs)
209
225
 
226
+ def _track_rasa_processing_latency(self) -> None:
227
+ """Track and log Rasa processing completion latency."""
228
+ if call_state.rasa_processing_start_time:
229
+ call_state.rasa_processing_latency_ms = (
230
+ time.time() - call_state.rasa_processing_start_time
231
+ ) * 1000
232
+ logger.debug(
233
+ "voice_channel.rasa_processing_latency",
234
+ latency_ms=call_state.rasa_processing_latency_ms,
235
+ )
236
+
237
+ def _track_tts_first_byte_latency(self) -> None:
238
+ """Track and log TTS first byte latency."""
239
+ if call_state.tts_start_time:
240
+ call_state.tts_first_byte_latency_ms = (
241
+ time.time() - call_state.tts_start_time
242
+ ) * 1000
243
+ logger.debug(
244
+ "voice_channel.tts_first_byte_latency",
245
+ latency_ms=call_state.tts_first_byte_latency_ms,
246
+ )
247
+
248
+ def _track_tts_complete_latency(self) -> None:
249
+ """Track and log TTS completion latency."""
250
+ if call_state.tts_start_time:
251
+ call_state.tts_complete_latency_ms = (
252
+ time.time() - call_state.tts_start_time
253
+ ) * 1000
254
+ logger.debug(
255
+ "voice_channel.tts_complete_latency",
256
+ latency_ms=call_state.tts_complete_latency_ms,
257
+ )
258
+
210
259
  async def send_text_message(
211
260
  self, recipient_id: str, text: str, **kwargs: Any
212
261
  ) -> None:
213
262
  text = remove_emojis(text)
214
263
  self.update_silence_timeout()
264
+
265
+ # Track Rasa processing completion
266
+ self._track_rasa_processing_latency()
267
+
268
+ # Track TTS start time
269
+ call_state.tts_start_time = time.time()
270
+
215
271
  cached_audio_bytes = self.tts_cache.get(text)
216
272
  collected_audio_bytes = RasaAudioBytes(b"")
217
273
  seconds_marker = -1
218
274
  last_sent_offset = 0
275
+ first_audio_sent = False
219
276
  logger.debug("voice_channel.sending_audio", text=text)
220
277
 
221
278
  # Send start marker before first chunk
222
279
  try:
223
280
  await self.send_start_marker(recipient_id)
224
281
  except (WebsocketClosed, ServerError):
225
- call_state.connection_failed = True # type: ignore[attr-defined]
282
+ call_state.connection_failed = True
283
+
284
+ # Is the response interruptible?
285
+ allow_interruptions = kwargs.get("allow_interruptions", True)
286
+ call_state.channel_data["allow_interruptions"] = allow_interruptions
226
287
 
227
288
  if cached_audio_bytes:
228
289
  audio_stream = self.chunk_audio(cached_audio_bytes)
@@ -244,6 +305,11 @@ class VoiceOutputChannel(OutputChannel):
244
305
 
245
306
  if should_send:
246
307
  try:
308
+ # Track TTS first byte time
309
+ if not first_audio_sent:
310
+ self._track_tts_first_byte_latency()
311
+ first_audio_sent = True
312
+
247
313
  # Send only the new bytes since last send
248
314
  new_bytes = RasaAudioBytes(collected_audio_bytes[last_sent_offset:])
249
315
  await self.send_audio_bytes(recipient_id, new_bytes)
@@ -256,24 +322,31 @@ class VoiceOutputChannel(OutputChannel):
256
322
 
257
323
  except (WebsocketClosed, ServerError):
258
324
  # ignore sending error, and keep collecting and caching audio bytes
259
- call_state.connection_failed = True # type: ignore[attr-defined]
325
+ call_state.connection_failed = True
260
326
 
261
327
  # Send any remaining audio not yet sent
262
328
  remaining_bytes = len(collected_audio_bytes) - last_sent_offset
263
329
  if remaining_bytes > 0:
264
330
  try:
331
+ # Track TTS first byte time if not already tracked
332
+ if not first_audio_sent:
333
+ self._track_tts_first_byte_latency()
334
+
265
335
  new_bytes = RasaAudioBytes(collected_audio_bytes[last_sent_offset:])
266
336
  await self.send_audio_bytes(recipient_id, new_bytes)
267
337
  except (WebsocketClosed, ServerError):
268
338
  # ignore sending error
269
- call_state.connection_failed = True # type: ignore[attr-defined]
339
+ call_state.connection_failed = True
340
+
341
+ # Track TTS completion time
342
+ self._track_tts_complete_latency()
270
343
 
271
344
  try:
272
345
  await self.send_end_marker(recipient_id)
273
346
  except (WebsocketClosed, ServerError):
274
347
  # ignore sending error
275
348
  pass
276
- call_state.latest_bot_audio_id = self.latest_message_id # type: ignore[attr-defined]
349
+ call_state.latest_bot_audio_id = self.latest_message_id
277
350
 
278
351
  if not cached_audio_bytes:
279
352
  self.tts_cache.put(text, collected_audio_bytes)
@@ -298,7 +371,7 @@ class VoiceOutputChannel(OutputChannel):
298
371
  return
299
372
 
300
373
  async def hangup(self, recipient_id: str, **kwargs: Any) -> None:
301
- call_state.should_hangup = True # type: ignore[attr-defined]
374
+ call_state.should_hangup = True
302
375
 
303
376
 
304
377
  class VoiceInputChannel(InputChannel):
@@ -310,6 +383,7 @@ class VoiceInputChannel(InputChannel):
310
383
  server_url: str,
311
384
  asr_config: Dict,
312
385
  tts_config: Dict,
386
+ interruptions: Optional[Dict[str, Any]] = None,
313
387
  ):
314
388
  if self.requires_voice_license:
315
389
  validate_voice_license_scope()
@@ -318,12 +392,21 @@ class VoiceInputChannel(InputChannel):
318
392
  self.asr_config = asr_config
319
393
  self.tts_config = tts_config
320
394
  self.tts_cache = TTSCache(tts_config.get("cache_size", 1000))
395
+ if interruptions:
396
+ self.interruption_config = InterruptionConfig(**interruptions)
397
+ else:
398
+ self.interruption_config = InterruptionConfig()
399
+
400
+ if self.interruption_config.enabled:
401
+ mark_as_beta_feature(f"Interruption Handling in {self.name()}")
321
402
 
322
403
  logger.info(
323
404
  "voice_channel.initialized",
405
+ name=self.name(),
324
406
  server_url=self.server_url,
325
407
  asr_config=self.asr_config,
326
408
  tts_config=self.tts_config,
409
+ interruption_config=self.interruption_config,
327
410
  )
328
411
 
329
412
  def get_sender_id(self, call_parameters: CallParameters) -> str:
@@ -345,32 +428,32 @@ class VoiceInputChannel(InputChannel):
345
428
  if call_state.silence_timeout_watcher:
346
429
  logger.debug("voice_channel.cancelling_current_timeout_watcher_task")
347
430
  call_state.silence_timeout_watcher.cancel()
348
- call_state.silence_timeout_watcher = None # type: ignore[attr-defined]
431
+ call_state.silence_timeout_watcher = None
349
432
 
350
433
  @classmethod
351
- def from_credentials(
352
- cls,
353
- credentials: Optional[Dict[str, Any]],
354
- ) -> InputChannel:
434
+ def validate_basic_credentials(cls, credentials: Optional[Dict[str, Any]]) -> None:
435
+ """Validate the basic credentials for the voice channel."""
355
436
  if not credentials:
356
437
  cls.raise_missing_credentials_exception()
357
-
358
- if not credentials.get("server_url"):
359
- raise InvalidConfigException("No server_url provided in credentials.")
360
- if not credentials.get("asr"):
438
+ if not isinstance(credentials, dict):
361
439
  raise InvalidConfigException(
362
- "No ASR configuration provided in credentials."
440
+ "Credentials must be a dictionary for voice channel."
363
441
  )
364
- if not credentials.get("tts"):
442
+
443
+ required_keys = {"server_url", "asr", "tts"}
444
+ credentials_keys = set(credentials.keys())
445
+ if not required_keys.issubset(credentials_keys):
446
+ missing_fields = required_keys - credentials_keys
365
447
  raise InvalidConfigException(
366
- "No TTS configuration provided in credentials."
448
+ f"Missing required fields in credentials: {', '.join(missing_fields)} "
449
+ f"for channel {cls.name()}"
367
450
  )
368
451
 
369
- return cls(
370
- server_url=credentials["server_url"],
371
- asr_config=credentials["asr"],
372
- tts_config=credentials["tts"],
373
- )
452
+ @classmethod
453
+ def from_credentials(
454
+ cls, credentials: Optional[Dict[str, Any]]
455
+ ) -> VoiceInputChannel:
456
+ raise NotImplementedError
374
457
 
375
458
  def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
376
459
  raise NotImplementedError
@@ -405,6 +488,43 @@ class VoiceInputChannel(InputChannel):
405
488
  """Map a channel input message to a voice channel action."""
406
489
  raise NotImplementedError
407
490
 
491
+ def should_interrupt(self, e: ASREvent) -> bool:
492
+ """Determine if the current ASR event should interrupt playback.
493
+ Returns True if the bot response is interruptible
494
+ And if the user spoke more than 3 words.
495
+
496
+ Arguments:
497
+ e: The ASR event to evaluate.
498
+
499
+ Returns:
500
+ True if the event should interrupt playback, False otherwise.
501
+ """
502
+ # Are interruptions are enabled for the channel?
503
+ if not self.interruption_config.enabled:
504
+ return False
505
+
506
+ # Is the bot response interruptible?
507
+ if not call_state.channel_data.get("allow_interruptions", True):
508
+ return False
509
+
510
+ # Did the user speak more than 3 words?
511
+ min_words = self.interruption_config.min_words
512
+ if isinstance(e, UserIsSpeaking):
513
+ translator = str.maketrans("", "", string.punctuation)
514
+ words = e.text.translate(translator).split()
515
+ return len(words) >= min_words
516
+ return False
517
+
518
+ async def interrupt_playback(
519
+ self, ws: Websocket, call_parameters: CallParameters
520
+ ) -> None:
521
+ """Interrupt the current playback of audio.
522
+
523
+ This function is used for interruption handling.
524
+ As not all channels support flushing bot audio buffer,
525
+ if a channel does not implement it. It has no effect."""
526
+ pass
527
+
408
528
  async def run_audio_streaming(
409
529
  self,
410
530
  on_new_message: Callable[[UserMessage], Awaitable[Any]],
@@ -439,10 +559,8 @@ class VoiceInputChannel(InputChannel):
439
559
  if was_bot_speaking_before and not is_bot_speaking_after:
440
560
  logger.debug("voice_channel.bot_stopped_speaking")
441
561
  self._cancel_silence_timeout_watcher()
442
- call_state.silence_timeout_watcher = ( # type: ignore[attr-defined]
443
- asyncio.create_task(
444
- self.monitor_silence_timeout(asr_event_queue)
445
- )
562
+ call_state.silence_timeout_watcher = asyncio.create_task(
563
+ self.monitor_silence_timeout(asr_event_queue)
446
564
  )
447
565
  if isinstance(channel_action, NewAudioAction):
448
566
  await asr_engine.send_audio_chunks(channel_action.audio_bytes)
@@ -498,6 +616,16 @@ class VoiceInputChannel(InputChannel):
498
616
  """Create a matching voice output channel for this voice input channel."""
499
617
  raise NotImplementedError
500
618
 
619
+ def _track_asr_latency(self) -> None:
620
+ """Track and log ASR processing latency."""
621
+ if call_state.user_speech_start_time:
622
+ call_state.asr_latency_ms = (
623
+ time.time() - call_state.user_speech_start_time
624
+ ) * 1000
625
+ logger.debug(
626
+ "voice_channel.asr_latency", latency_ms=call_state.asr_latency_ms
627
+ )
628
+
501
629
  async def handle_asr_event(
502
630
  self,
503
631
  e: ASREvent,
@@ -511,7 +639,12 @@ class VoiceInputChannel(InputChannel):
511
639
  logger.debug(
512
640
  "VoiceInputChannel.handle_asr_event.new_transcript", transcript=e.text
513
641
  )
514
- call_state.is_user_speaking = False # type: ignore[attr-defined]
642
+ call_state.is_user_speaking = False
643
+
644
+ # Track ASR and Rasa latencies
645
+ self._track_asr_latency()
646
+ call_state.rasa_processing_start_time = time.time()
647
+
515
648
  output_channel = self.create_output_channel(voice_websocket, tts_engine)
516
649
  message = UserMessage(
517
650
  text=e.text,
@@ -522,8 +655,13 @@ class VoiceInputChannel(InputChannel):
522
655
  )
523
656
  await on_new_message(message)
524
657
  elif isinstance(e, UserIsSpeaking):
658
+ # Track when user starts speaking for ASR latency calculation
659
+ if not call_state.is_user_speaking:
660
+ call_state.user_speech_start_time = time.time()
525
661
  self._cancel_silence_timeout_watcher()
526
- call_state.is_user_speaking = True # type: ignore[attr-defined]
662
+ call_state.is_user_speaking = True
663
+ if self.should_interrupt(e):
664
+ await self.interrupt_playback(voice_websocket, call_parameters)
527
665
  elif isinstance(e, UserSilence):
528
666
  output_channel = self.create_output_channel(voice_websocket, tts_engine)
529
667
  message = UserMessage(
@@ -4,7 +4,11 @@ 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
 
9
+ from rasa.core.iam_credentials_providers.credentials_provider_protocol import (
10
+ SupportedServiceType,
11
+ )
8
12
  from rasa.core.lock import Ticket, TicketLock
9
13
  from rasa.core.lock_store import (
10
14
  DEFAULT_SOCKET_TIMEOUT_IN_SECONDS,
@@ -12,6 +16,12 @@ from rasa.core.lock_store import (
12
16
  LockError,
13
17
  LockStore,
14
18
  )
19
+ from rasa.core.redis_connection_factory import (
20
+ DeploymentMode,
21
+ RedisConfig,
22
+ RedisConnectionFactory,
23
+ )
24
+ from rasa.shared.exceptions import RasaException
15
25
  from rasa.utils.endpoints import EndpointConfig
16
26
 
17
27
  DEFAULT_REDIS_DB = 1
@@ -74,9 +84,10 @@ class ConcurrentRedisLockStore(LockStore):
74
84
  alphanumeric.
75
85
  socket_timeout - Timeout in seconds after which an exception will be raised
76
86
  in case Redis doesn't respond within `socket_timeout` seconds.
87
+ deployment_mode - Redis deployment mode: standard, cluster, or sentinel.
88
+ endpoints - List of endpoints for cluster/sentinel mode in host:port format.
89
+ sentinel_service - Sentinel service name.
77
90
  """
78
- import redis
79
-
80
91
  host = endpoint_config.kwargs.get("host", DEFAULT_HOSTNAME)
81
92
  port = endpoint_config.kwargs.get("port", DEFAULT_PORT)
82
93
  db = endpoint_config.kwargs.get("db", DEFAULT_REDIS_DB)
@@ -90,20 +101,34 @@ class ConcurrentRedisLockStore(LockStore):
90
101
  socket_timeout = endpoint_config.kwargs.get(
91
102
  "socket_timeout", DEFAULT_SOCKET_TIMEOUT_IN_SECONDS
92
103
  )
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,
104
+ deployment_mode = endpoint_config.kwargs.get(
105
+ "deployment_mode", DeploymentMode.STANDARD.value
105
106
  )
107
+ endpoints = endpoint_config.kwargs.get("endpoints", [])
108
+ sentinel_service = endpoint_config.kwargs.get("sentinel_service")
106
109
 
110
+ try:
111
+ redis_config = RedisConfig(
112
+ host=host,
113
+ port=port,
114
+ service_type=SupportedServiceType.LOCK_STORE,
115
+ db=db,
116
+ username=username,
117
+ password=password,
118
+ use_ssl=use_ssl,
119
+ ssl_certfile=ssl_certfile,
120
+ ssl_keyfile=ssl_keyfile,
121
+ ssl_ca_certs=ssl_ca_certs,
122
+ socket_timeout=socket_timeout,
123
+ deployment_mode=deployment_mode,
124
+ endpoints=endpoints,
125
+ sentinel_service=sentinel_service,
126
+ )
127
+ self.red = RedisConnectionFactory.create_connection(redis_config)
128
+ except ValidationError as e:
129
+ raise RasaException(f"Invalid Redis configuration: {e}")
130
+
131
+ self.deployment_mode = deployment_mode
107
132
  self.key_prefix = DEFAULT_CONCURRENT_REDIS_LOCK_STORE_KEY_PREFIX
108
133
  if key_prefix:
109
134
  structlogger.debug(
@@ -129,6 +154,45 @@ class ConcurrentRedisLockStore(LockStore):
129
154
  ),
130
155
  )
131
156
 
157
+ def _scan_cluster_keys(self, pattern: Text) -> list:
158
+ """Scan keys in cluster mode with proper cursor handling."""
159
+ keys = []
160
+ cursor = 0
161
+
162
+ while True:
163
+ try:
164
+ cursor, batch_keys = self.red.scan(cursor, match=pattern, count=100)
165
+ keys.extend(batch_keys)
166
+
167
+ if isinstance(cursor, dict):
168
+ # cursor is a dict mapping each node to its scan position. e.g
169
+ # {'127.0.0.1:7000': 0, '127.0.0.1:7001': 5, '127.0.0.1:7002': 0}
170
+ # A cursor value of 0 means that node has finished scanning
171
+ # When all nodes show 0, the entire cluster scan is complete
172
+ if all(v == 0 for v in cursor.values()):
173
+ break
174
+ else:
175
+ # if scan is complete
176
+ if cursor == 0:
177
+ break
178
+
179
+ except Exception as e:
180
+ structlogger.warning(
181
+ "concurrent_redis_lock_store._get_keys_by_pattern.scan_interrupted",
182
+ event_info=f"SCAN interrupted in cluster mode: {e}. "
183
+ f"Returning {len(keys)} keys found so far.",
184
+ )
185
+ break
186
+
187
+ return keys
188
+
189
+ def _get_keys_by_pattern(self, pattern: Text) -> list:
190
+ """Get keys by pattern, using SCAN for cluster mode and KEYS for others."""
191
+ if self.deployment_mode == DeploymentMode.CLUSTER.value:
192
+ return self._scan_cluster_keys(pattern)
193
+ else:
194
+ return self.red.keys(pattern)
195
+
132
196
  def issue_ticket(
133
197
  self, conversation_id: Text, lock_lifetime: float = LOCK_LIFETIME
134
198
  ) -> int:
@@ -157,11 +221,14 @@ class ConcurrentRedisLockStore(LockStore):
157
221
  tickets: Deque[Ticket] = deque()
158
222
 
159
223
  pattern = self.key_prefix + conversation_id + ":" + "[0-9]*"
160
- redis_keys = self.red.keys(pattern)
224
+ redis_keys = self._get_keys_by_pattern(pattern)
161
225
 
162
226
  for key in redis_keys:
163
227
  serialised_ticket = self.red.get(key)
164
228
  if serialised_ticket:
229
+ # Handle bytes to string conversion for JSON parsing
230
+ if isinstance(serialised_ticket, bytes):
231
+ serialised_ticket = serialised_ticket.decode("utf-8")
165
232
  ticket = Ticket.from_dict(json.loads(serialised_ticket))
166
233
  tickets.appendleft(ticket)
167
234
 
@@ -172,7 +239,7 @@ class ConcurrentRedisLockStore(LockStore):
172
239
  def delete_lock(self, conversation_id: Text) -> None:
173
240
  """Deletes lock for conversation ID."""
174
241
  pattern = self.key_prefix + conversation_id + ":*"
175
- redis_keys = self.red.keys(pattern)
242
+ redis_keys = self._get_keys_by_pattern(pattern)
176
243
 
177
244
  if not redis_keys:
178
245
  structlogger.debug(
File without changes
@@ -1,9 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import dataclasses
4
+ from pathlib import Path
4
5
  from typing import Any, Dict, List, Optional, Union
5
6
 
6
- from rasa.shared.constants import DEFAULT_ENDPOINTS_PATH
7
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
8
+
9
+ from rasa.core.constants import MCP_SERVERS_KEY
10
+ from rasa.shared.agents.auth.utils import validate_secrets_in_params
7
11
  from rasa.shared.core.constants import (
8
12
  GLOBAL_SILENCE_TIMEOUT_DEFAULT_VALUE,
9
13
  GLOBAL_SILENCE_TIMEOUT_KEY,
@@ -57,13 +61,47 @@ class InteractionHandlingConfig:
57
61
  )
58
62
 
59
63
 
64
+ class MCPServerConfig(BaseModel):
65
+ model_config = ConfigDict(extra="allow")
66
+ name: str = Field(..., description="The name of the MCP server.")
67
+ url: str = Field(..., description="The URL of the MCP server.")
68
+ type: str = Field(..., description="The type of the MCP server.")
69
+ additional_params: Optional[Dict[str, Any]] = Field(
70
+ default_factory=dict, description="Additional parameters for the MCP server."
71
+ )
72
+
73
+ @model_validator(mode="after")
74
+ def validate_type(self) -> MCPServerConfig:
75
+ # validate that type is "http"
76
+ if self.type not in ["http", "https"]:
77
+ raise ValueError(f"Invalid MCP server type: {self.type}")
78
+ # validate that name and url are not empty
79
+ if not self.name or not self.url:
80
+ raise ValueError("Name and URL cannot be empty")
81
+ # validate secrets in additional_params
82
+ if self.additional_params:
83
+ validate_secrets_in_params(
84
+ self.additional_params, f"MCP server - '{self.name}'"
85
+ )
86
+ return self
87
+
88
+ @model_validator(mode="before")
89
+ def collect_additional_params(cls, values: Dict[str, Any]) -> Dict[str, Any]:
90
+ base_fields = {"name", "url", "type"}
91
+ extras = {k: v for k, v in values.items() if k not in base_fields}
92
+ if extras:
93
+ values["additional_params"] = extras
94
+ # remove them from top level so Pydantic doesn’t complain
95
+ for k in extras:
96
+ values.pop(k)
97
+ return values
98
+
99
+
60
100
  class AvailableEndpoints:
61
101
  """Collection of configured endpoints."""
62
102
 
63
- _instance = None
64
-
65
103
  @classmethod
66
- def read_endpoints(cls, endpoint_file: str) -> AvailableEndpoints:
104
+ def read_endpoints(cls, endpoint_file: Path) -> AvailableEndpoints:
67
105
  """Read the different endpoints from a yaml file."""
68
106
  nlg = read_endpoint_config(endpoint_file, endpoint_type="nlg")
69
107
  nlu = read_endpoint_config(endpoint_file, endpoint_type="nlu")
@@ -75,6 +113,14 @@ class AvailableEndpoints:
75
113
  lock_store = read_endpoint_config(endpoint_file, endpoint_type="lock_store")
76
114
  event_broker = read_endpoint_config(endpoint_file, endpoint_type="event_broker")
77
115
  vector_store = read_endpoint_config(endpoint_file, endpoint_type="vector_store")
116
+ raw_mcp_servers = read_property_config_from_endpoints_file(
117
+ endpoint_file, property_name=MCP_SERVERS_KEY
118
+ )
119
+ mcp_servers = (
120
+ [MCPServerConfig(**server) for server in raw_mcp_servers]
121
+ if raw_mcp_servers
122
+ else None
123
+ )
78
124
  model_groups = read_property_config_from_endpoints_file(
79
125
  endpoint_file, property_name="model_groups"
80
126
  )
@@ -89,6 +135,7 @@ class AvailableEndpoints:
89
135
  )
90
136
 
91
137
  return cls(
138
+ endpoint_file,
92
139
  nlg,
93
140
  nlu,
94
141
  action,
@@ -97,6 +144,7 @@ class AvailableEndpoints:
97
144
  lock_store,
98
145
  event_broker,
99
146
  vector_store,
147
+ mcp_servers,
100
148
  model_groups,
101
149
  privacy,
102
150
  interaction_handling,
@@ -104,6 +152,7 @@ class AvailableEndpoints:
104
152
 
105
153
  def __init__(
106
154
  self,
155
+ config_file_path: Optional[Path] = None,
107
156
  nlg: Optional[EndpointConfig] = None,
108
157
  nlu: Optional[EndpointConfig] = None,
109
158
  action: Optional[EndpointConfig] = None,
@@ -112,6 +161,7 @@ class AvailableEndpoints:
112
161
  lock_store: Optional[EndpointConfig] = None,
113
162
  event_broker: Optional[EndpointConfig] = None,
114
163
  vector_store: Optional[EndpointConfig] = None,
164
+ mcp_servers: Optional[List[MCPServerConfig]] = None,
115
165
  model_groups: Optional[List[Dict[str, Any]]] = None,
116
166
  privacy: Optional[Dict[str, Any]] = None,
117
167
  interaction_handling: InteractionHandlingConfig = InteractionHandlingConfig(
@@ -119,6 +169,7 @@ class AvailableEndpoints:
119
169
  ),
120
170
  ) -> None:
121
171
  """Create an `AvailableEndpoints` object."""
172
+ self.config_file_path = config_file_path
122
173
  self.model = model
123
174
  self.action = action
124
175
  self.nlu = nlu
@@ -127,20 +178,7 @@ class AvailableEndpoints:
127
178
  self.lock_store = lock_store
128
179
  self.event_broker = event_broker
129
180
  self.vector_store = vector_store
181
+ self.mcp_servers = mcp_servers
130
182
  self.model_groups = model_groups
131
183
  self.privacy = privacy
132
184
  self.interaction_handling = interaction_handling
133
-
134
- @classmethod
135
- def get_instance(
136
- cls, endpoint_file: Optional[str] = DEFAULT_ENDPOINTS_PATH
137
- ) -> AvailableEndpoints:
138
- """Get the singleton instance of AvailableEndpoints."""
139
- # Ensure that the instance is initialized only once.
140
- if cls._instance is None:
141
- cls._instance = cls.read_endpoints(endpoint_file)
142
- return cls._instance
143
-
144
- @classmethod
145
- def reset_instance(cls) -> None:
146
- cls._instance = None