rasa-pro 3.14.0.dev20250922__py3-none-any.whl → 3.14.0rc2__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 (304) 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 +211 -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 +879 -0
  13. rasa/agents/protocol/mcp/__init__.py +0 -0
  14. rasa/agents/protocol/mcp/mcp_base_agent.py +726 -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 +206 -0
  26. rasa/agents/validation.py +485 -0
  27. rasa/api.py +24 -9
  28. rasa/builder/config.py +6 -2
  29. rasa/builder/copilot/constants.py +4 -1
  30. rasa/builder/copilot/copilot.py +155 -79
  31. rasa/builder/copilot/models.py +304 -108
  32. rasa/builder/copilot/prompts/copilot_training_error_handler_prompt.jinja2 +53 -0
  33. rasa/builder/guardrails/{lakera.py → clients.py} +55 -5
  34. rasa/builder/guardrails/constants.py +3 -0
  35. rasa/builder/guardrails/models.py +45 -10
  36. rasa/builder/guardrails/policy_checker.py +324 -0
  37. rasa/builder/guardrails/utils.py +42 -276
  38. rasa/builder/jobs.py +182 -12
  39. rasa/builder/llm_service.py +32 -5
  40. rasa/builder/models.py +13 -3
  41. rasa/builder/project_generator.py +6 -1
  42. rasa/builder/service.py +31 -15
  43. rasa/builder/training_service.py +18 -24
  44. rasa/builder/validation_service.py +1 -1
  45. rasa/cli/arguments/default_arguments.py +12 -0
  46. rasa/cli/arguments/run.py +2 -0
  47. rasa/cli/arguments/train.py +2 -0
  48. rasa/cli/data.py +10 -8
  49. rasa/cli/dialogue_understanding_test.py +10 -7
  50. rasa/cli/e2e_test.py +9 -6
  51. rasa/cli/evaluate.py +4 -2
  52. rasa/cli/export.py +5 -2
  53. rasa/cli/inspect.py +8 -4
  54. rasa/cli/interactive.py +5 -4
  55. rasa/cli/llm_fine_tuning.py +11 -6
  56. rasa/cli/project_templates/finance/domain/general/help.yml +0 -0
  57. rasa/cli/project_templates/tutorial/credentials.yml +10 -0
  58. rasa/cli/run.py +12 -10
  59. rasa/cli/scaffold.py +4 -4
  60. rasa/cli/shell.py +9 -5
  61. rasa/cli/studio/studio.py +1 -1
  62. rasa/cli/test.py +34 -14
  63. rasa/cli/train.py +41 -28
  64. rasa/cli/utils.py +1 -393
  65. rasa/cli/validation/__init__.py +0 -0
  66. rasa/cli/validation/bot_config.py +223 -0
  67. rasa/cli/validation/config_path_validation.py +257 -0
  68. rasa/cli/x.py +8 -4
  69. rasa/constants.py +7 -1
  70. rasa/core/actions/action.py +51 -10
  71. rasa/core/actions/grpc_custom_action_executor.py +1 -1
  72. rasa/core/agent.py +19 -2
  73. rasa/core/available_agents.py +229 -0
  74. rasa/core/brokers/kafka.py +5 -1
  75. rasa/core/channels/__init__.py +82 -35
  76. rasa/core/channels/development_inspector.py +3 -3
  77. rasa/core/channels/inspector/README.md +25 -13
  78. rasa/core/channels/inspector/dist/assets/{arc-35222594.js → arc-6177260a.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-a0efbfd3.js → blockDiagram-38ab4fdb-b054f038.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-0584c0f2.js → c4Diagram-3d4e48cf-f25427d5.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/channel-bf9cbb34.js +1 -0
  82. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-39f40dbe.js → classDiagram-70f12bd4-c7a2af53.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-1ad755f3.js → classDiagram-v2-f2320105-58db65c0.js} +1 -1
  84. rasa/core/channels/inspector/dist/assets/clone-8f9083bb.js +1 -0
  85. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-b0f4f0fe.js → createText-2e5e7dd3-088372e2.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-9039bff9.js → edges-e0da2a9e-58676240.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-65c9b127.js → erDiagram-9861fffd-0c14d7c6.js} +1 -1
  88. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-4f08b38e.js → flowDb-956e92f1-ea63f85c.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-e95c362a.js → flowDiagram-66a62f08-a2af48cd.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-9ecd5b59.js +1 -0
  91. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-703c3015.js → flowchart-elk-definition-4a651766-6937abe7.js} +1 -1
  92. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-699328ea.js → ganttDiagram-c361ad54-7473f357.js} +1 -1
  93. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-04cf4b05.js → gitGraphDiagram-72cf32ee-d0c9405e.js} +1 -1
  94. rasa/core/channels/inspector/dist/assets/{graph-ee94449e.js → graph-0a6f8466.js} +1 -1
  95. rasa/core/channels/inspector/dist/assets/{index-3862675e-940162b4.js → index-3862675e-7610671a.js} +1 -1
  96. rasa/core/channels/inspector/dist/assets/index-74e01d94.js +1354 -0
  97. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-c79c2866.js → infoDiagram-f8f76790-be397dc7.js} +1 -1
  98. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-84489d30.js → journeyDiagram-49397b02-4cefbf62.js} +1 -1
  99. rasa/core/channels/inspector/dist/assets/{layout-a9aa9858.js → layout-e7fbc2bf.js} +1 -1
  100. rasa/core/channels/inspector/dist/assets/{line-eb73cf26.js → line-a8aa457c.js} +1 -1
  101. rasa/core/channels/inspector/dist/assets/{linear-b3399f9a.js → linear-3351e0d2.js} +1 -1
  102. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-b095bf1a.js → mindmap-definition-fc14e90a-b8cbf605.js} +1 -1
  103. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-07644b66.js → pieDiagram-8a3498a8-f327f774.js} +1 -1
  104. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-573a3f9c.js → quadrantDiagram-120e2f19-2854c591.js} +1 -1
  105. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-d457e1e1.js → requirementDiagram-deff3bca-964985d5.js} +1 -1
  106. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-9d26e1a2.js → sankeyDiagram-04a897e0-edeb4f33.js} +1 -1
  107. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3a9cde10.js → sequenceDiagram-704730f1-fcf70125.js} +1 -1
  108. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-4f3e8cec.js → stateDiagram-587899a1-0e770395.js} +1 -1
  109. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-e617e5bf.js → stateDiagram-v2-d93cdb3a-af8dcd22.js} +1 -1
  110. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-eab30d2f.js → styles-6aaf32cf-36a9e70d.js} +1 -1
  111. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-09994be2.js → styles-9a916d00-884a8b5b.js} +1 -1
  112. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-b7110364.js → styles-c10674c1-dc097813.js} +1 -1
  113. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-3ebc92ad.js → svgDrawCommon-08f97a94-5a2c7eed.js} +1 -1
  114. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-7d13d2f2.js → timeline-definition-85554ec2-e89c4f6e.js} +1 -1
  115. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-488385e1.js → xychartDiagram-e933f94c-afb6fe56.js} +1 -1
  116. rasa/core/channels/inspector/dist/index.html +1 -1
  117. rasa/core/channels/inspector/package.json +18 -18
  118. rasa/core/channels/inspector/src/App.tsx +29 -4
  119. rasa/core/channels/inspector/src/components/DialogueAgentStack.tsx +108 -0
  120. rasa/core/channels/inspector/src/components/{DialogueStack.tsx → DialogueHistoryStack.tsx} +4 -2
  121. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +7 -4
  122. rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -0
  123. rasa/core/channels/inspector/src/helpers/formatters.ts +24 -3
  124. rasa/core/channels/inspector/src/helpers/utils.test.ts +127 -0
  125. rasa/core/channels/inspector/src/helpers/utils.ts +66 -1
  126. rasa/core/channels/inspector/src/theme/base/styles.ts +19 -1
  127. rasa/core/channels/inspector/src/types.ts +21 -0
  128. rasa/core/channels/inspector/yarn.lock +336 -189
  129. rasa/core/channels/studio_chat.py +6 -6
  130. rasa/core/channels/telegram.py +4 -9
  131. rasa/core/channels/voice_stream/genesys.py +1 -1
  132. rasa/core/channels/voice_stream/tts/deepgram.py +140 -0
  133. rasa/core/channels/voice_stream/twilio_media_streams.py +5 -1
  134. rasa/core/channels/voice_stream/voice_channel.py +3 -0
  135. rasa/core/concurrent_lock_store.py +38 -21
  136. rasa/core/config/__init__.py +0 -0
  137. rasa/core/{available_endpoints.py → config/available_endpoints.py} +51 -16
  138. rasa/core/config/configuration.py +260 -0
  139. rasa/core/config/credentials.py +19 -0
  140. rasa/core/config/message_procesing_config.py +34 -0
  141. rasa/core/constants.py +10 -0
  142. rasa/core/iam_credentials_providers/aws_iam_credentials_providers.py +69 -4
  143. rasa/core/iam_credentials_providers/credentials_provider_protocol.py +2 -1
  144. rasa/core/lock_store.py +4 -0
  145. rasa/core/policies/enterprise_search_policy.py +5 -3
  146. rasa/core/policies/flow_policy.py +4 -4
  147. rasa/core/policies/flows/agent_executor.py +632 -0
  148. rasa/core/policies/flows/flow_executor.py +136 -75
  149. rasa/core/policies/flows/mcp_tool_executor.py +298 -0
  150. rasa/core/policies/intentless_policy.py +1 -1
  151. rasa/core/policies/ted_policy.py +20 -12
  152. rasa/core/policies/unexpected_intent_policy.py +6 -0
  153. rasa/core/processor.py +68 -44
  154. rasa/core/redis_connection_factory.py +7 -2
  155. rasa/core/run.py +37 -8
  156. rasa/core/test.py +4 -0
  157. rasa/core/tracker_stores/redis_tracker_store.py +4 -0
  158. rasa/core/tracker_stores/sql_tracker_store.py +3 -1
  159. rasa/core/tracker_stores/tracker_store.py +3 -7
  160. rasa/core/train.py +1 -1
  161. rasa/core/training/interactive.py +20 -18
  162. rasa/core/training/story_conflict.py +5 -5
  163. rasa/core/utils.py +22 -23
  164. rasa/dialogue_understanding/commands/__init__.py +8 -0
  165. rasa/dialogue_understanding/commands/cancel_flow_command.py +19 -5
  166. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +21 -2
  167. rasa/dialogue_understanding/commands/clarify_command.py +20 -2
  168. rasa/dialogue_understanding/commands/continue_agent_command.py +91 -0
  169. rasa/dialogue_understanding/commands/knowledge_answer_command.py +21 -2
  170. rasa/dialogue_understanding/commands/restart_agent_command.py +162 -0
  171. rasa/dialogue_understanding/commands/start_flow_command.py +68 -7
  172. rasa/dialogue_understanding/commands/utils.py +124 -2
  173. rasa/dialogue_understanding/generator/command_parser.py +4 -0
  174. rasa/dialogue_understanding/generator/llm_based_command_generator.py +50 -12
  175. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
  176. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +1 -1
  177. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +66 -0
  178. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +66 -0
  179. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +89 -0
  180. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +88 -0
  181. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +42 -7
  182. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +40 -3
  183. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +20 -3
  184. rasa/dialogue_understanding/patterns/cancel.py +27 -6
  185. rasa/dialogue_understanding/patterns/clarify.py +3 -14
  186. rasa/dialogue_understanding/patterns/continue_interrupted.py +239 -6
  187. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +46 -8
  188. rasa/dialogue_understanding/processor/command_processor.py +136 -15
  189. rasa/dialogue_understanding/stack/dialogue_stack.py +98 -2
  190. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +57 -0
  191. rasa/dialogue_understanding/stack/utils.py +57 -3
  192. rasa/dialogue_understanding/utils.py +24 -4
  193. rasa/dialogue_understanding_test/du_test_runner.py +8 -3
  194. rasa/e2e_test/e2e_test_runner.py +13 -3
  195. rasa/engine/caching.py +2 -2
  196. rasa/engine/constants.py +1 -1
  197. rasa/engine/recipes/default_components.py +138 -49
  198. rasa/engine/recipes/default_recipe.py +108 -11
  199. rasa/engine/runner/dask.py +8 -5
  200. rasa/engine/validation.py +19 -6
  201. rasa/graph_components/validators/default_recipe_validator.py +86 -28
  202. rasa/hooks.py +5 -5
  203. rasa/llm_fine_tuning/utils.py +2 -2
  204. rasa/model_training.py +60 -47
  205. rasa/nlu/classifiers/diet_classifier.py +198 -98
  206. rasa/nlu/classifiers/logistic_regression_classifier.py +1 -4
  207. rasa/nlu/classifiers/mitie_intent_classifier.py +3 -0
  208. rasa/nlu/classifiers/sklearn_intent_classifier.py +1 -3
  209. rasa/nlu/extractors/crf_entity_extractor.py +9 -10
  210. rasa/nlu/extractors/mitie_entity_extractor.py +3 -0
  211. rasa/nlu/extractors/spacy_entity_extractor.py +3 -0
  212. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +4 -0
  213. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +5 -0
  214. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +2 -0
  215. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +3 -0
  216. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +4 -2
  217. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -0
  218. rasa/nlu/selectors/response_selector.py +10 -2
  219. rasa/nlu/tokenizers/jieba_tokenizer.py +3 -4
  220. rasa/nlu/tokenizers/mitie_tokenizer.py +3 -2
  221. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -2
  222. rasa/nlu/utils/mitie_utils.py +3 -0
  223. rasa/nlu/utils/spacy_utils.py +3 -2
  224. rasa/plugin.py +8 -8
  225. rasa/privacy/privacy_manager.py +12 -3
  226. rasa/server.py +15 -3
  227. rasa/shared/agents/__init__.py +0 -0
  228. rasa/shared/agents/auth/__init__.py +0 -0
  229. rasa/shared/agents/auth/agent_auth_factory.py +105 -0
  230. rasa/shared/agents/auth/agent_auth_manager.py +92 -0
  231. rasa/shared/agents/auth/auth_strategy/__init__.py +19 -0
  232. rasa/shared/agents/auth/auth_strategy/agent_auth_strategy.py +52 -0
  233. rasa/shared/agents/auth/auth_strategy/api_key_auth_strategy.py +42 -0
  234. rasa/shared/agents/auth/auth_strategy/bearer_token_auth_strategy.py +28 -0
  235. rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +167 -0
  236. rasa/shared/agents/auth/constants.py +12 -0
  237. rasa/shared/agents/auth/types.py +12 -0
  238. rasa/shared/agents/utils.py +35 -0
  239. rasa/shared/constants.py +8 -0
  240. rasa/shared/core/constants.py +16 -1
  241. rasa/shared/core/domain.py +0 -7
  242. rasa/shared/core/events.py +327 -0
  243. rasa/shared/core/flows/constants.py +5 -0
  244. rasa/shared/core/flows/flows_list.py +21 -5
  245. rasa/shared/core/flows/flows_yaml_schema.json +119 -184
  246. rasa/shared/core/flows/steps/call.py +49 -5
  247. rasa/shared/core/flows/steps/collect.py +98 -13
  248. rasa/shared/core/flows/validation.py +372 -8
  249. rasa/shared/core/flows/yaml_flows_io.py +3 -2
  250. rasa/shared/core/slots.py +2 -2
  251. rasa/shared/core/trackers.py +5 -2
  252. rasa/shared/exceptions.py +16 -0
  253. rasa/shared/importers/rasa.py +1 -1
  254. rasa/shared/importers/utils.py +9 -3
  255. rasa/shared/providers/llm/_base_litellm_client.py +41 -9
  256. rasa/shared/providers/llm/litellm_router_llm_client.py +8 -4
  257. rasa/shared/providers/llm/llm_client.py +7 -3
  258. rasa/shared/providers/llm/llm_response.py +66 -0
  259. rasa/shared/providers/llm/self_hosted_llm_client.py +8 -4
  260. rasa/shared/utils/common.py +24 -0
  261. rasa/shared/utils/health_check/health_check.py +7 -3
  262. rasa/shared/utils/llm.py +39 -16
  263. rasa/shared/utils/mcp/__init__.py +0 -0
  264. rasa/shared/utils/mcp/server_connection.py +247 -0
  265. rasa/shared/utils/mcp/utils.py +20 -0
  266. rasa/shared/utils/schemas/events.py +42 -0
  267. rasa/shared/utils/yaml.py +3 -1
  268. rasa/studio/pull/pull.py +3 -2
  269. rasa/studio/train.py +8 -7
  270. rasa/studio/upload.py +3 -6
  271. rasa/telemetry.py +69 -5
  272. rasa/tracing/config.py +45 -12
  273. rasa/tracing/constants.py +14 -0
  274. rasa/tracing/instrumentation/attribute_extractors.py +142 -9
  275. rasa/tracing/instrumentation/instrumentation.py +626 -21
  276. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +4 -4
  277. rasa/tracing/instrumentation/metrics.py +32 -0
  278. rasa/tracing/metric_instrument_provider.py +68 -0
  279. rasa/utils/common.py +92 -1
  280. rasa/utils/endpoints.py +11 -2
  281. rasa/utils/log_utils.py +96 -5
  282. rasa/utils/ml_utils.py +1 -1
  283. rasa/utils/tensorflow/__init__.py +7 -0
  284. rasa/utils/tensorflow/callback.py +136 -101
  285. rasa/utils/tensorflow/crf.py +1 -1
  286. rasa/utils/tensorflow/data_generator.py +21 -8
  287. rasa/utils/tensorflow/layers.py +21 -11
  288. rasa/utils/tensorflow/metrics.py +7 -3
  289. rasa/utils/tensorflow/models.py +56 -8
  290. rasa/utils/tensorflow/rasa_layers.py +8 -6
  291. rasa/utils/tensorflow/transformer.py +2 -3
  292. rasa/utils/train_utils.py +54 -24
  293. rasa/validator.py +5 -5
  294. rasa/version.py +1 -1
  295. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc2.dist-info}/METADATA +47 -41
  296. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc2.dist-info}/RECORD +299 -238
  297. rasa/builder/scrape_rasa_docs.py +0 -97
  298. rasa/core/channels/inspector/dist/assets/channel-8e08bed9.js +0 -1
  299. rasa/core/channels/inspector/dist/assets/clone-78c82dea.js +0 -1
  300. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b08f601.js +0 -1
  301. rasa/core/channels/inspector/dist/assets/index-c941dcb3.js +0 -1336
  302. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc2.dist-info}/NOTICE +0 -0
  303. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc2.dist-info}/WHEEL +0 -0
  304. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc2.dist-info}/entry_points.txt +0 -0
@@ -37,7 +37,7 @@ def _instrument_select_response_examples(
37
37
 
38
38
  return wrapper
39
39
 
40
- policy_class.select_response_examples = tracing_select_response_examples_wrapper( # type: ignore[assignment]
40
+ policy_class.select_response_examples = tracing_select_response_examples_wrapper( # type: ignore[method-assign]
41
41
  policy_class.select_response_examples
42
42
  )
43
43
 
@@ -72,7 +72,7 @@ def _instrument_select_few_shot_conversations(
72
72
 
73
73
  return wrapper
74
74
 
75
- policy_class.select_few_shot_conversations = ( # type: ignore[assignment]
75
+ policy_class.select_few_shot_conversations = ( # type: ignore[method-assign]
76
76
  tracing_select_few_shot_conversations_wrapper(
77
77
  policy_class.select_few_shot_conversations
78
78
  )
@@ -104,7 +104,7 @@ def _instrument_extract_ai_responses(
104
104
 
105
105
  return wrapper
106
106
 
107
- policy_class.extract_ai_responses = tracing_extract_ai_responses_wrapper( # type: ignore[assignment]
107
+ policy_class.extract_ai_responses = tracing_extract_ai_responses_wrapper( # type: ignore[method-assign]
108
108
  policy_class.extract_ai_responses
109
109
  )
110
110
 
@@ -137,7 +137,7 @@ def _instrument_generate_answer(
137
137
 
138
138
  return wrapper
139
139
 
140
- policy_class.generate_answer = tracing_generate_answer_wrapper( # type: ignore[assignment]
140
+ policy_class.generate_answer = tracing_generate_answer_wrapper( # type: ignore[method-assign]
141
141
  policy_class.generate_answer
142
142
  )
143
143
 
@@ -2,6 +2,7 @@ from typing import Any, Dict
2
2
 
3
3
  import psutil
4
4
 
5
+ from rasa.agents.protocol.mcp.mcp_base_agent import MCPBaseAgent
5
6
  from rasa.core.nlg.contextual_response_rephraser import ContextualResponseRephraser
6
7
  from rasa.core.policies.enterprise_search_policy import EnterpriseSearchPolicy
7
8
  from rasa.core.policies.intentless_policy import IntentlessPolicy
@@ -27,6 +28,10 @@ from rasa.tracing.constants import (
27
28
  LLM_COMMAND_GENERATOR_LLM_RESPONSE_DURATION_METRIC_NAME,
28
29
  LLM_COMMAND_GENERATOR_MEMORY_USAGE_METRIC_NAME,
29
30
  LLM_COMMAND_GENERATOR_PROMPT_TOKEN_USAGE_METRIC_NAME,
31
+ MCP_AGENT_LLM_CPU_USAGE_METRIC_NAME,
32
+ MCP_AGENT_LLM_MEMORY_USAGE_METRIC_NAME,
33
+ MCP_AGENT_LLM_PROMPT_TOKEN_USAGE_METRIC_NAME,
34
+ MCP_AGENT_LLM_RESPONSE_DURATION_METRIC_NAME,
30
35
  MULTI_STEP_LLM_COMMAND_GENERATOR_CPU_USAGE_METRIC_NAME,
31
36
  MULTI_STEP_LLM_COMMAND_GENERATOR_LLM_RESPONSE_DURATION_METRIC_NAME,
32
37
  MULTI_STEP_LLM_COMMAND_GENERATOR_MEMORY_USAGE_METRIC_NAME,
@@ -385,6 +390,11 @@ def record_callable_duration_metrics(
385
390
  )
386
391
  attributes = {"url": kwargs.get("url")}
387
392
 
393
+ if isinstance(self, MCPBaseAgent):
394
+ metric_instrument = instrument_provider.get_instrument(
395
+ MCP_AGENT_LLM_RESPONSE_DURATION_METRIC_NAME
396
+ )
397
+
388
398
  if not metric_instrument:
389
399
  return None
390
400
 
@@ -416,3 +426,25 @@ def record_request_size_in_bytes(attributes: Dict[str, Any]) -> None:
416
426
 
417
427
  request_body_size = attributes.pop(REQUEST_BODY_SIZE_IN_BYTES_ATTRIBUTE_NAME, 0)
418
428
  metric_instrument.record(amount=request_body_size, attributes=attributes)
429
+
430
+
431
+ def record_mcp_agent_llm_metrics(attributes: Dict[str, Any]) -> None:
432
+ """Record MCP agent LLM metrics."""
433
+ instrument_provider = MetricInstrumentProvider()
434
+
435
+ if not instrument_provider.instruments:
436
+ return None
437
+
438
+ # Use MCP agent specific metric names
439
+ record_llm_based_component_cpu_usage(
440
+ instrument_provider, MCP_AGENT_LLM_CPU_USAGE_METRIC_NAME
441
+ )
442
+ record_llm_based_component_memory_usage(
443
+ instrument_provider, MCP_AGENT_LLM_MEMORY_USAGE_METRIC_NAME
444
+ )
445
+ record_llm_based_component_prompt_token(
446
+ instrument_provider,
447
+ attributes,
448
+ MCP_AGENT_LLM_PROMPT_TOKEN_USAGE_METRIC_NAME,
449
+ )
450
+ return None
@@ -4,6 +4,7 @@ from opentelemetry.metrics import get_meter_provider
4
4
  from opentelemetry.sdk.metrics import Meter
5
5
 
6
6
  from rasa.tracing.constants import (
7
+ AGENT_EXECUTION_DURATION_METRIC_NAME,
7
8
  COMPACT_LLM_COMMAND_GENERATOR_CPU_USAGE_METRIC_NAME,
8
9
  COMPACT_LLM_COMMAND_GENERATOR_LLM_RESPONSE_DURATION_METRIC_NAME,
9
10
  COMPACT_LLM_COMMAND_GENERATOR_MEMORY_USAGE_METRIC_NAME,
@@ -20,6 +21,11 @@ from rasa.tracing.constants import (
20
21
  LLM_COMMAND_GENERATOR_LLM_RESPONSE_DURATION_METRIC_NAME,
21
22
  LLM_COMMAND_GENERATOR_MEMORY_USAGE_METRIC_NAME,
22
23
  LLM_COMMAND_GENERATOR_PROMPT_TOKEN_USAGE_METRIC_NAME,
24
+ MCP_AGENT_LLM_CPU_USAGE_METRIC_NAME,
25
+ MCP_AGENT_LLM_MEMORY_USAGE_METRIC_NAME,
26
+ MCP_AGENT_LLM_PROMPT_TOKEN_USAGE_METRIC_NAME,
27
+ MCP_AGENT_LLM_RESPONSE_DURATION_METRIC_NAME,
28
+ MCP_TOOL_EXECUTION_DURATION_METRIC_NAME,
23
29
  MULTI_STEP_LLM_COMMAND_GENERATOR_CPU_USAGE_METRIC_NAME,
24
30
  MULTI_STEP_LLM_COMMAND_GENERATOR_LLM_RESPONSE_DURATION_METRIC_NAME,
25
31
  MULTI_STEP_LLM_COMMAND_GENERATOR_MEMORY_USAGE_METRIC_NAME,
@@ -59,6 +65,8 @@ class MetricInstrumentProvider(metaclass=Singleton):
59
65
  **self._create_multi_step_llm_command_generator_instruments(meter),
60
66
  **self._create_enterprise_search_policy_instruments(meter),
61
67
  **self._create_llm_response_duration_instruments(meter),
68
+ **self._create_mcp_and_a2a_agent_instruments(meter),
69
+ **self._create_mcp_agent_llm_instruments(meter),
62
70
  **self._create_client_request_instruments(meter),
63
71
  }
64
72
 
@@ -295,6 +303,28 @@ class MetricInstrumentProvider(metaclass=Singleton):
295
303
  CONTEXTUAL_RESPONSE_REPHRASER_LLM_RESPONSE_DURATION_METRIC_NAME: llm_response_duration_contextual_nlg, # noqa: E501
296
304
  }
297
305
 
306
+ @staticmethod
307
+ def _create_mcp_and_a2a_agent_instruments(
308
+ meter: Meter,
309
+ ) -> Dict[str, Any]:
310
+ """Create instruments for MCP tool execution and agent execution."""
311
+ mcp_tool_execution_duration = meter.create_histogram(
312
+ name=MCP_TOOL_EXECUTION_DURATION_METRIC_NAME,
313
+ description="The duration of MCP tool execution",
314
+ unit=DURATION_UNIT_NAME,
315
+ )
316
+
317
+ agent_execution_duration = meter.create_histogram(
318
+ name=AGENT_EXECUTION_DURATION_METRIC_NAME,
319
+ description="The duration of agent execution",
320
+ unit=DURATION_UNIT_NAME,
321
+ )
322
+
323
+ return {
324
+ MCP_TOOL_EXECUTION_DURATION_METRIC_NAME: mcp_tool_execution_duration,
325
+ AGENT_EXECUTION_DURATION_METRIC_NAME: agent_execution_duration,
326
+ }
327
+
298
328
  @staticmethod
299
329
  def _create_client_request_instruments(
300
330
  meter: Meter,
@@ -315,3 +345,41 @@ class MetricInstrumentProvider(metaclass=Singleton):
315
345
  RASA_CLIENT_REQUEST_DURATION_METRIC_NAME: client_request_duration,
316
346
  RASA_CLIENT_REQUEST_BODY_SIZE_METRIC_NAME: client_request_body_size,
317
347
  }
348
+
349
+ @staticmethod
350
+ def _create_mcp_agent_llm_instruments(meter: Meter) -> Dict[str, Any]:
351
+ """Create instruments for MCP agent LLM calls."""
352
+ mcp_agent_llm_cpu_usage = meter.create_histogram(
353
+ name=MCP_AGENT_LLM_CPU_USAGE_METRIC_NAME,
354
+ description="CPU usage during MCP agent LLM calls",
355
+ unit=LLM_BASED_COMMAND_GENERATOR_CPU_MEMORY_USAGE_UNIT_NAME,
356
+ )
357
+
358
+ mcp_agent_llm_memory_usage = meter.create_histogram(
359
+ name=MCP_AGENT_LLM_MEMORY_USAGE_METRIC_NAME,
360
+ description="Memory usage during MCP agent LLM calls",
361
+ unit=LLM_BASED_COMMAND_GENERATOR_CPU_MEMORY_USAGE_UNIT_NAME,
362
+ )
363
+
364
+ mcp_agent_llm_prompt_token_usage = meter.create_histogram(
365
+ name=MCP_AGENT_LLM_PROMPT_TOKEN_USAGE_METRIC_NAME,
366
+ description="Prompt token usage for MCP agent LLM calls",
367
+ unit="token",
368
+ )
369
+
370
+ mcp_agent_llm_response_duration = meter.create_histogram(
371
+ name=MCP_AGENT_LLM_RESPONSE_DURATION_METRIC_NAME,
372
+ description="Duration of MCP agent LLM calls",
373
+ unit=DURATION_UNIT_NAME,
374
+ )
375
+
376
+ return {
377
+ MCP_AGENT_LLM_CPU_USAGE_METRIC_NAME: mcp_agent_llm_cpu_usage,
378
+ MCP_AGENT_LLM_MEMORY_USAGE_METRIC_NAME: mcp_agent_llm_memory_usage,
379
+ MCP_AGENT_LLM_PROMPT_TOKEN_USAGE_METRIC_NAME: (
380
+ mcp_agent_llm_prompt_token_usage
381
+ ),
382
+ MCP_AGENT_LLM_RESPONSE_DURATION_METRIC_NAME: (
383
+ mcp_agent_llm_response_duration
384
+ ),
385
+ }
rasa/utils/common.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import copy
2
2
  import inspect
3
+ import json
3
4
  import logging
4
5
  import logging.config
5
6
  import logging.handlers
@@ -34,7 +35,9 @@ from rasa.constants import (
34
35
  ENV_LOG_LEVEL_KAFKA,
35
36
  ENV_LOG_LEVEL_LIBRARIES,
36
37
  ENV_LOG_LEVEL_MATPLOTLIB,
38
+ ENV_LOG_LEVEL_MCP,
37
39
  ENV_LOG_LEVEL_RABBITMQ,
40
+ ENV_MCP_LOGGING_ENABLED,
38
41
  )
39
42
  from rasa.shared.constants import DEFAULT_LOG_LEVEL, ENV_LOG_LEVEL, TCP_PROTOCOL
40
43
  from rasa.shared.exceptions import RasaException
@@ -49,7 +52,7 @@ EXPECTED_WARNINGS: List[Tuple[Type[Warning], str]] = [
49
52
  # TODO (issue #9932)
50
53
  # DM1 warnings
51
54
  (
52
- np.VisibleDeprecationWarning,
55
+ np.exceptions.VisibleDeprecationWarning,
53
56
  "Creating an ndarray from ragged nested sequences.*",
54
57
  ),
55
58
  # raised by magic_filter, google rpc
@@ -129,6 +132,18 @@ EXPECTED_WARNINGS: List[Tuple[Type[Warning], str]] = [
129
132
  FutureWarning,
130
133
  "'request_timeout' is deprecated and will be removed in 4.0.0. Use 'timeout'*",
131
134
  ),
135
+ (
136
+ FutureWarning,
137
+ "TEDPolicy is deprecated and will be removed in a future version.*",
138
+ ),
139
+ (
140
+ FutureWarning,
141
+ "DIETClassifier is deprecated and will be removed in a future version.*",
142
+ ),
143
+ (
144
+ FutureWarning,
145
+ "ResponseSelector is deprecated and will be removed in a future version.*",
146
+ ),
132
147
  ]
133
148
 
134
149
  PYTHON_LOGGING_SCHEMA_DOCS = (
@@ -281,6 +296,7 @@ def configure_library_logging() -> None:
281
296
  update_kafka_log_level(library_log_level)
282
297
  update_rabbitmq_log_level(library_log_level)
283
298
  update_websockets_log_level(library_log_level)
299
+ update_mcp_log_level()
284
300
 
285
301
 
286
302
  def update_apscheduler_log_level() -> None:
@@ -415,6 +431,56 @@ def update_websockets_log_level(library_log_level: Text) -> None:
415
431
  logging.getLogger("websockets").propagate = False
416
432
 
417
433
 
434
+ def update_mcp_log_level() -> None:
435
+ """Set the log level for MCP-related loggers.
436
+
437
+ This function configures logging levels for MCP (Model Context Protocol) related
438
+ loggers to reduce noise from HTTP and MCP client libraries.
439
+
440
+ Environment Variables:
441
+ LOG_LEVEL_MCP: Set the log level for MCP-related loggers.
442
+ Valid values: DEBUG, INFO, WARNING, ERROR, CRITICAL
443
+ Default: ERROR
444
+
445
+ MCP_LOGGING_ENABLED: Enable or disable MCP logging completely.
446
+ Valid values: true, false
447
+ Default: true
448
+
449
+ Examples:
450
+ # Show only ERROR and above for MCP logs
451
+ export LOG_LEVEL_MCP=ERROR
452
+
453
+ # Show DEBUG level MCP logs (very verbose)
454
+ export LOG_LEVEL_MCP=DEBUG
455
+
456
+ # Completely disable MCP logging
457
+ export MCP_LOGGING_ENABLED=false
458
+ """
459
+ # Check if MCP logging is completely disabled
460
+ mcp_logging_enabled = (
461
+ os.environ.get(ENV_MCP_LOGGING_ENABLED, "true").lower() == "true"
462
+ )
463
+
464
+ # Default to ERROR level for MCP logs to reduce noise
465
+ mcp_log_level: Union[int, str] = os.environ.get(ENV_LOG_LEVEL_MCP, "ERROR")
466
+ if not mcp_logging_enabled:
467
+ # Completely disable MCP logging
468
+ mcp_log_level = logging.CRITICAL + 1 # Higher than CRITICAL to disable all logs
469
+
470
+ # MCP client and HTTP-related loggers that are commonly noisy
471
+ mcp_loggers = [
472
+ "mcp.client.streamable_http",
473
+ "mcp.client",
474
+ "httpcore.connection",
475
+ "httpcore.http11",
476
+ "httpx",
477
+ ]
478
+
479
+ for logger_name in mcp_loggers:
480
+ logging.getLogger(logger_name).setLevel(mcp_log_level)
481
+ logging.getLogger(logger_name).propagate = False
482
+
483
+
418
484
  def sort_list_of_dicts_by_first_key(dicts: List[Dict]) -> List[Dict]:
419
485
  """Sorts a list of dictionaries by their first key."""
420
486
  return sorted(dicts, key=lambda d: next(iter(d.keys())))
@@ -646,3 +712,28 @@ def get_bool_env_variable(variable_name: str, default_variable_value: bool) -> b
646
712
  f"Available values are `{true_values + false_values}`"
647
713
  )
648
714
  return value.lower() in true_values
715
+
716
+
717
+ def try_parse_json(value: Any) -> Any:
718
+ """If value is a JSON string, parse it into a dict/list, else return as-is."""
719
+ if isinstance(value, str):
720
+ try:
721
+ return json.loads(value)
722
+ except json.JSONDecodeError:
723
+ return value
724
+ return value
725
+
726
+
727
+ def ensure_jsonified_iterable(value: Any) -> Any:
728
+ """Convert iterables to JSON strings, flatten nested JSON strings in dicts/lists."""
729
+ if isinstance(value, dict):
730
+ # Recursively process dict values
731
+ return {
732
+ key: ensure_jsonified_iterable(try_parse_json(val))
733
+ for key, val in value.items()
734
+ }
735
+ elif isinstance(value, list):
736
+ # Recursively process each item
737
+ return [ensure_jsonified_iterable(try_parse_json(val)) for val in value]
738
+ # Keep primitives as-is
739
+ return value
rasa/utils/endpoints.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import ssl
3
+ from pathlib import Path
3
4
  from types import ModuleType
4
5
  from typing import Any, Dict, List, Optional, Text, Union
5
6
 
@@ -16,7 +17,7 @@ structlogger = structlog.get_logger()
16
17
 
17
18
 
18
19
  def read_endpoint_config(
19
- filename: Text, endpoint_type: Text
20
+ filename: Union[str, Path], endpoint_type: Text
20
21
  ) -> Optional["EndpointConfig"]:
21
22
  """Read an endpoint configuration file from disk and extract one config."""
22
23
  if not filename:
@@ -25,6 +26,14 @@ def read_endpoint_config(
25
26
  try:
26
27
  content = read_config_file(filename)
27
28
 
29
+ structlogger.debug(
30
+ "endpoint.read.success",
31
+ filename=os.path.abspath(filename),
32
+ endpoint_type=endpoint_type,
33
+ event_info="Successfully read endpoint configuration file.",
34
+ content=content,
35
+ )
36
+
28
37
  if content.get(endpoint_type) is None:
29
38
  return None
30
39
 
@@ -42,7 +51,7 @@ def read_endpoint_config(
42
51
 
43
52
 
44
53
  def read_property_config_from_endpoints_file(
45
- filename: str, property_name: str
54
+ filename: Union[str, Path], property_name: str
46
55
  ) -> Optional[Union[Dict[str, Any], List]]:
47
56
  """Read a property from an endpoint configuration file."""
48
57
  if not filename:
rasa/utils/log_utils.py CHANGED
@@ -19,19 +19,110 @@ from rasa.shared.constants import (
19
19
  )
20
20
 
21
21
  FORCE_JSON_LOGGING = os.environ.get("FORCE_JSON_LOGGING")
22
+ ANSI_CYAN_BOLD = "\033[1;36m"
23
+ ANSI_RESET = "\033[0m"
22
24
 
23
25
 
24
26
  class HumanConsoleRenderer(ConsoleRenderer):
25
27
  """Console renderer that outputs human-readable logs."""
26
28
 
27
29
  def __call__(self, logger: WrappedLogger, name: str, event_dict: EventDict) -> str:
30
+ should_highlight = event_dict.get("highlight", False)
31
+ terminal_width = self._get_terminal_width()
32
+
33
+ # Use event_info as title for the log entry
28
34
  if "event_info" in event_dict:
29
35
  event_key = event_dict["event"]
30
36
  event_dict["event"] = event_dict["event_info"]
31
37
  event_dict["event_key"] = event_key
32
- del event_dict["event_info"]
33
-
34
- return super().__call__(logger, name, event_dict)
38
+ event_dict.pop("event_info", None)
39
+
40
+ # In case the log entry should be highlighted
41
+ # make sure to surround the log entry with ===
42
+ event_dict = self._highlight_log_entry(
43
+ event_dict, terminal_width, should_highlight
44
+ )
45
+
46
+ # Format JSON data for better readability
47
+ event_dict = self._format_json_data(event_dict)
48
+
49
+ # Render the log entry first
50
+ result = super().__call__(logger, name, event_dict)
51
+
52
+ # ensure that newlines are properly rendered
53
+ result = "\n".join(result.split("\\n"))
54
+
55
+ # Add closing === if we highlighted this entry
56
+ if should_highlight:
57
+ result += f"\n{'=' * terminal_width}"
58
+
59
+ return result
60
+
61
+ def _highlight_log_entry(
62
+ self, event_dict: EventDict, terminal_width: int, should_highlight: bool
63
+ ) -> EventDict:
64
+ if should_highlight:
65
+ # Only highlight if log level is DEBUG
66
+ # structlog passes log level as 'level' or 'levelname'
67
+ level = event_dict.get("level", event_dict.get("levelname", "")).upper()
68
+ if level == "DEBUG":
69
+ # Add opening === before the event info
70
+ if "event" in event_dict and isinstance(event_dict["event"], str):
71
+ event_info = event_dict["event"]
72
+ event_dict["event"] = (
73
+ f"\n{'=' * terminal_width}\n"
74
+ f"{ANSI_CYAN_BOLD}{event_info}{ANSI_RESET}\n"
75
+ )
76
+
77
+ event_dict.pop("highlight", None)
78
+
79
+ return event_dict
80
+
81
+ def _format_json_data(self, event_dict: EventDict) -> EventDict:
82
+ """Format JSON data in the event dict for better readability."""
83
+ # Get the list of fields to format from the event dict
84
+ fields_to_format = event_dict.get("json_formatting", [])
85
+
86
+ if not fields_to_format:
87
+ return event_dict
88
+
89
+ import json
90
+
91
+ # Format only the specified fields
92
+ for key in fields_to_format:
93
+ if key in event_dict:
94
+ value = event_dict[key]
95
+
96
+ try:
97
+ # Try to parse as JSON if it's a string
98
+ if isinstance(value, str):
99
+ parsed = json.loads(value)
100
+ # If it's a dict or list, format it nicely
101
+ if isinstance(parsed, (dict, list)):
102
+ formatted = json.dumps(parsed, indent=2, ensure_ascii=False)
103
+ event_dict[key] = formatted
104
+ elif isinstance(value, (dict, list)):
105
+ # Format JSON with indentation for better readability
106
+ formatted = json.dumps(value, indent=2, ensure_ascii=False)
107
+ event_dict[key] = formatted
108
+ except (TypeError, ValueError, json.JSONDecodeError):
109
+ # If it's not JSON serializable or if it's not valid JSON,
110
+ # leave it as is
111
+ pass
112
+
113
+ # Remove the json_formatting key from the output
114
+ event_dict.pop("json_formatting", None)
115
+
116
+ return event_dict
117
+
118
+ def _get_terminal_width(self) -> int:
119
+ """Get the width of the terminal."""
120
+ import shutil
121
+
122
+ try:
123
+ return shutil.get_terminal_size((80, 20)).columns
124
+ except Exception:
125
+ return 80
35
126
 
36
127
 
37
128
  def configure_structlog(
@@ -52,7 +143,7 @@ def configure_structlog(
52
143
  level=log_level,
53
144
  )
54
145
 
55
- shared_processors = [
146
+ shared_processors: List[structlog.typing.Processor] = [
56
147
  # Processors that have nothing to do with output,
57
148
  # e.g., add timestamps or log level names.
58
149
  # If log level is too low, abort pipeline and throw away log entry.
@@ -94,7 +185,7 @@ def configure_structlog(
94
185
  ]
95
186
 
96
187
  structlog.configure(
97
- processors=processors, # type: ignore
188
+ processors=processors,
98
189
  context_class=dict,
99
190
  # `logger_factory` is used to create wrapped loggers that are used for
100
191
  # OUTPUT. This one returns a `logging.Logger`. The final value (a JSON
rasa/utils/ml_utils.py CHANGED
@@ -119,7 +119,7 @@ def response_for_template(
119
119
  rsps = responses.get(template_name, [])
120
120
  usuable_responses = [r for r in rsps if r.get(KEY_RESPONSES_TEXT)]
121
121
  if usuable_responses:
122
- selected_response = np.random.choice(usuable_responses) # type: ignore
122
+ selected_response = np.random.choice(usuable_responses)
123
123
  return selected_response.get(KEY_RESPONSES_TEXT)
124
124
  else:
125
125
  structlogger.warning(
@@ -0,0 +1,7 @@
1
+ import importlib.util
2
+ import logging
3
+
4
+ logger = logging.getLogger(__name__)
5
+
6
+ # check if TensorFlow is available
7
+ TENSORFLOW_AVAILABLE = importlib.util.find_spec("tensorflow") is not None