rasa-pro 3.14.0.dev20250922__py3-none-any.whl → 3.14.0rc1__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 (290) 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/guardrails/{lakera.py → clients.py} +55 -5
  30. rasa/builder/guardrails/constants.py +3 -0
  31. rasa/builder/guardrails/models.py +45 -10
  32. rasa/builder/guardrails/policy_checker.py +324 -0
  33. rasa/builder/guardrails/utils.py +42 -276
  34. rasa/builder/llm_service.py +32 -5
  35. rasa/builder/models.py +1 -0
  36. rasa/builder/project_generator.py +6 -1
  37. rasa/builder/service.py +16 -13
  38. rasa/builder/training_service.py +18 -24
  39. rasa/builder/validation_service.py +1 -1
  40. rasa/cli/arguments/default_arguments.py +12 -0
  41. rasa/cli/arguments/run.py +2 -0
  42. rasa/cli/arguments/train.py +2 -0
  43. rasa/cli/data.py +10 -8
  44. rasa/cli/dialogue_understanding_test.py +10 -7
  45. rasa/cli/e2e_test.py +9 -6
  46. rasa/cli/evaluate.py +4 -2
  47. rasa/cli/export.py +5 -2
  48. rasa/cli/inspect.py +8 -4
  49. rasa/cli/interactive.py +5 -4
  50. rasa/cli/llm_fine_tuning.py +11 -6
  51. rasa/cli/project_templates/tutorial/credentials.yml +10 -0
  52. rasa/cli/run.py +12 -10
  53. rasa/cli/scaffold.py +4 -4
  54. rasa/cli/shell.py +9 -5
  55. rasa/cli/studio/studio.py +1 -1
  56. rasa/cli/test.py +34 -14
  57. rasa/cli/train.py +41 -28
  58. rasa/cli/utils.py +1 -393
  59. rasa/cli/validation/__init__.py +0 -0
  60. rasa/cli/validation/bot_config.py +223 -0
  61. rasa/cli/validation/config_path_validation.py +257 -0
  62. rasa/cli/x.py +8 -4
  63. rasa/constants.py +7 -1
  64. rasa/core/actions/action.py +51 -10
  65. rasa/core/actions/grpc_custom_action_executor.py +1 -1
  66. rasa/core/agent.py +19 -2
  67. rasa/core/available_agents.py +229 -0
  68. rasa/core/channels/__init__.py +82 -35
  69. rasa/core/channels/development_inspector.py +3 -3
  70. rasa/core/channels/inspector/README.md +25 -13
  71. rasa/core/channels/inspector/dist/assets/{arc-35222594.js → arc-6177260a.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-a0efbfd3.js → blockDiagram-38ab4fdb-b054f038.js} +1 -1
  73. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-0584c0f2.js → c4Diagram-3d4e48cf-f25427d5.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/channel-bf9cbb34.js +1 -0
  75. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-39f40dbe.js → classDiagram-70f12bd4-c7a2af53.js} +1 -1
  76. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-1ad755f3.js → classDiagram-v2-f2320105-58db65c0.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/clone-8f9083bb.js +1 -0
  78. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-b0f4f0fe.js → createText-2e5e7dd3-088372e2.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-9039bff9.js → edges-e0da2a9e-58676240.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-65c9b127.js → erDiagram-9861fffd-0c14d7c6.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-4f08b38e.js → flowDb-956e92f1-ea63f85c.js} +1 -1
  82. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-e95c362a.js → flowDiagram-66a62f08-a2af48cd.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-9ecd5b59.js +1 -0
  84. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-703c3015.js → flowchart-elk-definition-4a651766-6937abe7.js} +1 -1
  85. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-699328ea.js → ganttDiagram-c361ad54-7473f357.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-04cf4b05.js → gitGraphDiagram-72cf32ee-d0c9405e.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{graph-ee94449e.js → graph-0a6f8466.js} +1 -1
  88. rasa/core/channels/inspector/dist/assets/{index-3862675e-940162b4.js → index-3862675e-7610671a.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/index-74e01d94.js +1354 -0
  90. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-c79c2866.js → infoDiagram-f8f76790-be397dc7.js} +1 -1
  91. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-84489d30.js → journeyDiagram-49397b02-4cefbf62.js} +1 -1
  92. rasa/core/channels/inspector/dist/assets/{layout-a9aa9858.js → layout-e7fbc2bf.js} +1 -1
  93. rasa/core/channels/inspector/dist/assets/{line-eb73cf26.js → line-a8aa457c.js} +1 -1
  94. rasa/core/channels/inspector/dist/assets/{linear-b3399f9a.js → linear-3351e0d2.js} +1 -1
  95. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-b095bf1a.js → mindmap-definition-fc14e90a-b8cbf605.js} +1 -1
  96. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-07644b66.js → pieDiagram-8a3498a8-f327f774.js} +1 -1
  97. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-573a3f9c.js → quadrantDiagram-120e2f19-2854c591.js} +1 -1
  98. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-d457e1e1.js → requirementDiagram-deff3bca-964985d5.js} +1 -1
  99. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-9d26e1a2.js → sankeyDiagram-04a897e0-edeb4f33.js} +1 -1
  100. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3a9cde10.js → sequenceDiagram-704730f1-fcf70125.js} +1 -1
  101. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-4f3e8cec.js → stateDiagram-587899a1-0e770395.js} +1 -1
  102. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-e617e5bf.js → stateDiagram-v2-d93cdb3a-af8dcd22.js} +1 -1
  103. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-eab30d2f.js → styles-6aaf32cf-36a9e70d.js} +1 -1
  104. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-09994be2.js → styles-9a916d00-884a8b5b.js} +1 -1
  105. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-b7110364.js → styles-c10674c1-dc097813.js} +1 -1
  106. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-3ebc92ad.js → svgDrawCommon-08f97a94-5a2c7eed.js} +1 -1
  107. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-7d13d2f2.js → timeline-definition-85554ec2-e89c4f6e.js} +1 -1
  108. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-488385e1.js → xychartDiagram-e933f94c-afb6fe56.js} +1 -1
  109. rasa/core/channels/inspector/dist/index.html +1 -1
  110. rasa/core/channels/inspector/package.json +18 -18
  111. rasa/core/channels/inspector/src/App.tsx +29 -4
  112. rasa/core/channels/inspector/src/components/DialogueAgentStack.tsx +108 -0
  113. rasa/core/channels/inspector/src/components/{DialogueStack.tsx → DialogueHistoryStack.tsx} +4 -2
  114. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +7 -4
  115. rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -0
  116. rasa/core/channels/inspector/src/helpers/formatters.ts +24 -3
  117. rasa/core/channels/inspector/src/helpers/utils.test.ts +127 -0
  118. rasa/core/channels/inspector/src/helpers/utils.ts +66 -1
  119. rasa/core/channels/inspector/src/theme/base/styles.ts +19 -1
  120. rasa/core/channels/inspector/src/types.ts +21 -0
  121. rasa/core/channels/inspector/yarn.lock +336 -189
  122. rasa/core/channels/studio_chat.py +6 -6
  123. rasa/core/channels/telegram.py +4 -9
  124. rasa/core/channels/voice_stream/genesys.py +1 -1
  125. rasa/core/channels/voice_stream/tts/deepgram.py +140 -0
  126. rasa/core/channels/voice_stream/twilio_media_streams.py +5 -1
  127. rasa/core/channels/voice_stream/voice_channel.py +3 -0
  128. rasa/core/config/__init__.py +0 -0
  129. rasa/core/{available_endpoints.py → config/available_endpoints.py} +51 -16
  130. rasa/core/config/configuration.py +260 -0
  131. rasa/core/config/credentials.py +19 -0
  132. rasa/core/config/message_procesing_config.py +34 -0
  133. rasa/core/constants.py +4 -0
  134. rasa/core/policies/enterprise_search_policy.py +5 -3
  135. rasa/core/policies/flow_policy.py +4 -4
  136. rasa/core/policies/flows/agent_executor.py +632 -0
  137. rasa/core/policies/flows/flow_executor.py +136 -75
  138. rasa/core/policies/flows/mcp_tool_executor.py +298 -0
  139. rasa/core/policies/intentless_policy.py +1 -1
  140. rasa/core/policies/ted_policy.py +20 -12
  141. rasa/core/policies/unexpected_intent_policy.py +6 -0
  142. rasa/core/processor.py +68 -44
  143. rasa/core/run.py +37 -8
  144. rasa/core/test.py +4 -0
  145. rasa/core/tracker_stores/tracker_store.py +3 -7
  146. rasa/core/train.py +1 -1
  147. rasa/core/training/interactive.py +20 -18
  148. rasa/core/training/story_conflict.py +5 -5
  149. rasa/core/utils.py +22 -23
  150. rasa/dialogue_understanding/commands/__init__.py +8 -0
  151. rasa/dialogue_understanding/commands/cancel_flow_command.py +19 -5
  152. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +21 -2
  153. rasa/dialogue_understanding/commands/clarify_command.py +20 -2
  154. rasa/dialogue_understanding/commands/continue_agent_command.py +91 -0
  155. rasa/dialogue_understanding/commands/knowledge_answer_command.py +21 -2
  156. rasa/dialogue_understanding/commands/restart_agent_command.py +162 -0
  157. rasa/dialogue_understanding/commands/start_flow_command.py +68 -7
  158. rasa/dialogue_understanding/commands/utils.py +124 -2
  159. rasa/dialogue_understanding/generator/command_parser.py +4 -0
  160. rasa/dialogue_understanding/generator/llm_based_command_generator.py +50 -12
  161. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
  162. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +1 -1
  163. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +66 -0
  164. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +66 -0
  165. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +89 -0
  166. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +88 -0
  167. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +42 -7
  168. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +40 -3
  169. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +20 -3
  170. rasa/dialogue_understanding/patterns/cancel.py +27 -6
  171. rasa/dialogue_understanding/patterns/clarify.py +3 -14
  172. rasa/dialogue_understanding/patterns/continue_interrupted.py +239 -6
  173. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +46 -8
  174. rasa/dialogue_understanding/processor/command_processor.py +136 -15
  175. rasa/dialogue_understanding/stack/dialogue_stack.py +98 -2
  176. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +57 -0
  177. rasa/dialogue_understanding/stack/utils.py +57 -3
  178. rasa/dialogue_understanding/utils.py +24 -4
  179. rasa/dialogue_understanding_test/du_test_runner.py +8 -3
  180. rasa/e2e_test/e2e_test_runner.py +13 -3
  181. rasa/engine/caching.py +2 -2
  182. rasa/engine/constants.py +1 -1
  183. rasa/engine/recipes/default_components.py +138 -49
  184. rasa/engine/recipes/default_recipe.py +108 -11
  185. rasa/engine/runner/dask.py +8 -5
  186. rasa/engine/validation.py +19 -6
  187. rasa/graph_components/validators/default_recipe_validator.py +86 -28
  188. rasa/hooks.py +5 -5
  189. rasa/llm_fine_tuning/utils.py +2 -2
  190. rasa/model_training.py +60 -47
  191. rasa/nlu/classifiers/diet_classifier.py +198 -98
  192. rasa/nlu/classifiers/logistic_regression_classifier.py +1 -4
  193. rasa/nlu/classifiers/mitie_intent_classifier.py +3 -0
  194. rasa/nlu/classifiers/sklearn_intent_classifier.py +1 -3
  195. rasa/nlu/extractors/crf_entity_extractor.py +9 -10
  196. rasa/nlu/extractors/mitie_entity_extractor.py +3 -0
  197. rasa/nlu/extractors/spacy_entity_extractor.py +3 -0
  198. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +4 -0
  199. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +5 -0
  200. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +2 -0
  201. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +3 -0
  202. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +4 -2
  203. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -0
  204. rasa/nlu/selectors/response_selector.py +10 -2
  205. rasa/nlu/tokenizers/jieba_tokenizer.py +3 -4
  206. rasa/nlu/tokenizers/mitie_tokenizer.py +3 -2
  207. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -2
  208. rasa/nlu/utils/mitie_utils.py +3 -0
  209. rasa/nlu/utils/spacy_utils.py +3 -2
  210. rasa/plugin.py +8 -8
  211. rasa/privacy/privacy_manager.py +12 -3
  212. rasa/server.py +15 -3
  213. rasa/shared/agents/__init__.py +0 -0
  214. rasa/shared/agents/auth/__init__.py +0 -0
  215. rasa/shared/agents/auth/agent_auth_factory.py +105 -0
  216. rasa/shared/agents/auth/agent_auth_manager.py +92 -0
  217. rasa/shared/agents/auth/auth_strategy/__init__.py +19 -0
  218. rasa/shared/agents/auth/auth_strategy/agent_auth_strategy.py +52 -0
  219. rasa/shared/agents/auth/auth_strategy/api_key_auth_strategy.py +42 -0
  220. rasa/shared/agents/auth/auth_strategy/bearer_token_auth_strategy.py +28 -0
  221. rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +167 -0
  222. rasa/shared/agents/auth/constants.py +12 -0
  223. rasa/shared/agents/auth/types.py +12 -0
  224. rasa/shared/agents/utils.py +35 -0
  225. rasa/shared/constants.py +8 -0
  226. rasa/shared/core/constants.py +16 -1
  227. rasa/shared/core/domain.py +0 -7
  228. rasa/shared/core/events.py +327 -0
  229. rasa/shared/core/flows/constants.py +5 -0
  230. rasa/shared/core/flows/flows_list.py +21 -5
  231. rasa/shared/core/flows/flows_yaml_schema.json +119 -184
  232. rasa/shared/core/flows/steps/call.py +49 -5
  233. rasa/shared/core/flows/steps/collect.py +98 -13
  234. rasa/shared/core/flows/validation.py +372 -8
  235. rasa/shared/core/flows/yaml_flows_io.py +3 -2
  236. rasa/shared/core/slots.py +2 -2
  237. rasa/shared/core/trackers.py +5 -2
  238. rasa/shared/exceptions.py +16 -0
  239. rasa/shared/importers/rasa.py +1 -1
  240. rasa/shared/importers/utils.py +9 -3
  241. rasa/shared/providers/llm/_base_litellm_client.py +41 -9
  242. rasa/shared/providers/llm/litellm_router_llm_client.py +8 -4
  243. rasa/shared/providers/llm/llm_client.py +7 -3
  244. rasa/shared/providers/llm/llm_response.py +66 -0
  245. rasa/shared/providers/llm/self_hosted_llm_client.py +8 -4
  246. rasa/shared/utils/common.py +24 -0
  247. rasa/shared/utils/health_check/health_check.py +7 -3
  248. rasa/shared/utils/llm.py +39 -16
  249. rasa/shared/utils/mcp/__init__.py +0 -0
  250. rasa/shared/utils/mcp/server_connection.py +247 -0
  251. rasa/shared/utils/mcp/utils.py +20 -0
  252. rasa/shared/utils/schemas/events.py +42 -0
  253. rasa/shared/utils/yaml.py +3 -1
  254. rasa/studio/pull/pull.py +3 -2
  255. rasa/studio/train.py +8 -7
  256. rasa/studio/upload.py +3 -6
  257. rasa/telemetry.py +69 -5
  258. rasa/tracing/config.py +45 -12
  259. rasa/tracing/constants.py +14 -0
  260. rasa/tracing/instrumentation/attribute_extractors.py +142 -9
  261. rasa/tracing/instrumentation/instrumentation.py +626 -21
  262. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +4 -4
  263. rasa/tracing/instrumentation/metrics.py +32 -0
  264. rasa/tracing/metric_instrument_provider.py +68 -0
  265. rasa/utils/common.py +92 -1
  266. rasa/utils/endpoints.py +11 -2
  267. rasa/utils/log_utils.py +96 -5
  268. rasa/utils/ml_utils.py +1 -1
  269. rasa/utils/tensorflow/__init__.py +7 -0
  270. rasa/utils/tensorflow/callback.py +136 -101
  271. rasa/utils/tensorflow/crf.py +1 -1
  272. rasa/utils/tensorflow/data_generator.py +21 -8
  273. rasa/utils/tensorflow/layers.py +21 -11
  274. rasa/utils/tensorflow/metrics.py +7 -3
  275. rasa/utils/tensorflow/models.py +56 -8
  276. rasa/utils/tensorflow/rasa_layers.py +8 -6
  277. rasa/utils/tensorflow/transformer.py +2 -3
  278. rasa/utils/train_utils.py +54 -24
  279. rasa/validator.py +5 -5
  280. rasa/version.py +1 -1
  281. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/METADATA +46 -41
  282. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/RECORD +285 -226
  283. rasa/builder/scrape_rasa_docs.py +0 -97
  284. rasa/core/channels/inspector/dist/assets/channel-8e08bed9.js +0 -1
  285. rasa/core/channels/inspector/dist/assets/clone-78c82dea.js +0 -1
  286. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b08f601.js +0 -1
  287. rasa/core/channels/inspector/dist/assets/index-c941dcb3.js +0 -1336
  288. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/NOTICE +0 -0
  289. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/WHEEL +0 -0
  290. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,327 @@
1
+ import importlib
2
+ import json
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ import structlog
6
+
7
+ from rasa.agents.constants import (
8
+ KEY_CONTENT,
9
+ KEY_ROLE,
10
+ KEY_TOOL_CALL_ID,
11
+ TOOL_ADDITIONAL_PROPERTIES_KEY,
12
+ TOOL_DESCRIPTION_KEY,
13
+ TOOL_NAME_KEY,
14
+ TOOL_PARAMETERS_KEY,
15
+ TOOL_PROPERTIES_KEY,
16
+ TOOL_REQUIRED_KEY,
17
+ TOOL_STRICT_KEY,
18
+ TOOL_TYPE_FUNCTION_KEY,
19
+ TOOL_TYPE_KEY,
20
+ )
21
+ from rasa.agents.core.types import AgentStatus, ProtocolType
22
+ from rasa.agents.protocol.mcp.mcp_base_agent import MCPBaseAgent
23
+ from rasa.agents.schemas import (
24
+ AgentInput,
25
+ AgentOutput,
26
+ AgentToolResult,
27
+ AgentToolSchema,
28
+ )
29
+ from rasa.core.available_agents import AgentMCPServerConfig, ProtocolConfig
30
+ from rasa.shared.agents.utils import make_agent_identifier
31
+ from rasa.shared.constants import (
32
+ ROLE_TOOL,
33
+ )
34
+ from rasa.shared.exceptions import (
35
+ LLMToolResponseDecodeError,
36
+ ProviderClientAPIException,
37
+ )
38
+ from rasa.shared.providers.llm.llm_response import LLMResponse, LLMToolCall
39
+
40
+ DEFAULT_OPEN_AGENT_PROMPT_TEMPLATE = importlib.resources.read_text(
41
+ "rasa.agents.templates", "mcp_open_agent_prompt_template.jinja2"
42
+ )
43
+
44
+ KEY_TASK_COMPLETED = "task_completed"
45
+
46
+ TASK_COMPLETED_TOOL = {
47
+ TOOL_TYPE_KEY: TOOL_TYPE_FUNCTION_KEY,
48
+ TOOL_TYPE_FUNCTION_KEY: {
49
+ TOOL_NAME_KEY: KEY_TASK_COMPLETED,
50
+ TOOL_DESCRIPTION_KEY: "Signal that the MCP agent has FULLY completed its "
51
+ "primary task. Once you have presented your findings, follow-up with "
52
+ "a message summarizing the completed task in a comprehensive and well-written "
53
+ "manner. Avoid repeating information already provided in the conversation.",
54
+ TOOL_PARAMETERS_KEY: {
55
+ TOOL_TYPE_KEY: "object",
56
+ TOOL_PROPERTIES_KEY: {
57
+ "message": {
58
+ TOOL_TYPE_KEY: "string",
59
+ TOOL_DESCRIPTION_KEY: "A message describing the completed task.",
60
+ }
61
+ },
62
+ TOOL_REQUIRED_KEY: ["message"],
63
+ TOOL_ADDITIONAL_PROPERTIES_KEY: False,
64
+ },
65
+ TOOL_STRICT_KEY: True,
66
+ },
67
+ }
68
+
69
+ structlogger = structlog.get_logger()
70
+
71
+
72
+ class MCPOpenAgent(MCPBaseAgent):
73
+ """MCP protocol implementation."""
74
+
75
+ def __init__(
76
+ self,
77
+ name: str,
78
+ description: str,
79
+ protocol_type: ProtocolConfig,
80
+ server_configs: List[AgentMCPServerConfig],
81
+ llm_config: Optional[Dict[str, Any]] = None,
82
+ prompt_template: Optional[str] = None,
83
+ timeout: Optional[int] = None,
84
+ max_retries: Optional[int] = None,
85
+ ):
86
+ super().__init__(
87
+ name,
88
+ description,
89
+ protocol_type,
90
+ server_configs,
91
+ llm_config,
92
+ prompt_template,
93
+ timeout,
94
+ max_retries,
95
+ )
96
+
97
+ @property
98
+ def protocol_type(self) -> ProtocolType:
99
+ return ProtocolType.MCP_OPEN
100
+
101
+ @staticmethod
102
+ def get_default_prompt_template() -> str:
103
+ return DEFAULT_OPEN_AGENT_PROMPT_TEMPLATE
104
+
105
+ @staticmethod
106
+ def get_task_completed_tool() -> Dict[str, Any]:
107
+ """Get the task completed tool for MCP. Override to customize/disable."""
108
+ return TASK_COMPLETED_TOOL
109
+
110
+ @classmethod
111
+ def get_agent_specific_built_in_tools(
112
+ cls, agent_input: AgentInput
113
+ ) -> List[AgentToolSchema]:
114
+ """Get agentic specific built-in tools."""
115
+ return [AgentToolSchema.from_litellm_json_format(cls.get_task_completed_tool())]
116
+
117
+ def _run_task_completed_tool(
118
+ self,
119
+ tool_call: LLMToolCall,
120
+ agent_input: AgentInput,
121
+ tool_results: Dict[str, AgentToolResult],
122
+ ) -> AgentOutput:
123
+ """Run the task completed tool."""
124
+ # Create the agent tool result for the task completed tool.
125
+
126
+ tool_result = AgentToolResult(
127
+ tool_name=tool_call.tool_name,
128
+ result=tool_call.tool_args.get("message", "Task completed"),
129
+ )
130
+ tool_results[tool_call.id] = tool_result
131
+
132
+ # Create the agent output for the task completed tool.
133
+ return AgentOutput(
134
+ id=agent_input.id,
135
+ status=AgentStatus.COMPLETED,
136
+ response_message=tool_result.result,
137
+ structured_results=self._get_structured_results_for_agent_output(
138
+ agent_input, tool_results
139
+ ),
140
+ )
141
+
142
+ async def send_message(self, agent_input: AgentInput) -> AgentOutput:
143
+ """Send a message to the LLM and return the response."""
144
+ messages = self.build_messages_for_llm_request(agent_input)
145
+ tool_results: Dict[str, AgentToolResult] = {}
146
+ # Convert available tools to OpenAI JSON format
147
+ tools_in_openai_format = [
148
+ tool.to_litellm_json_format()
149
+ for tool in self.get_available_tools(agent_input)
150
+ ]
151
+
152
+ for iteration in range(self.MAX_ITERATIONS):
153
+ try:
154
+ structlogger.debug(
155
+ "mcp_task_agent.send_message.iteration",
156
+ event_info=(
157
+ f"Starting iteration {iteration + 1} for agent {self._name}"
158
+ ),
159
+ agent_id=str(make_agent_identifier(self._name, self.protocol_type)),
160
+ highlight=True,
161
+ )
162
+ # Make the LLM call using the llm_client
163
+ structlogger.debug(
164
+ "mcp_open_agent.send_message.sending_message_to_llm",
165
+ messages=messages,
166
+ event_info=f"Sending message to LLM (iteration {iteration + 1})",
167
+ agent_name=self._name,
168
+ agent_id=str(make_agent_identifier(self._name, self.protocol_type)),
169
+ )
170
+ llm_response = LLMResponse.ensure_llm_response(
171
+ await self.llm_client.acompletion(
172
+ messages, tools=tools_in_openai_format
173
+ )
174
+ )
175
+
176
+ # If no response from LLM, return an error output.
177
+ if llm_response is None or not (
178
+ llm_response.choices or llm_response.tool_calls
179
+ ):
180
+ event_info = "No response from LLM."
181
+ structlogger.warning(
182
+ "mcp_open_agent.send_message.no_llm_response",
183
+ event_info=event_info,
184
+ agent_name=self._name,
185
+ agent_id=str(
186
+ make_agent_identifier(self._name, self.protocol_type)
187
+ ),
188
+ )
189
+ return AgentOutput(
190
+ id=agent_input.id,
191
+ status=AgentStatus.RECOVERABLE_ERROR,
192
+ error_message=event_info,
193
+ structured_results=(
194
+ self._get_structured_results_for_agent_output(
195
+ agent_input, tool_results
196
+ )
197
+ ),
198
+ )
199
+
200
+ # If no tool calls, return the response directly with input required.
201
+ if not llm_response.tool_calls and len(llm_response.choices) == 1:
202
+ return AgentOutput(
203
+ id=agent_input.id,
204
+ status=AgentStatus.INPUT_REQUIRED,
205
+ response_message=llm_response.choices[0],
206
+ structured_results=(
207
+ self._get_structured_results_for_agent_output(
208
+ agent_input, tool_results
209
+ )
210
+ ),
211
+ )
212
+
213
+ # If there are tool calls, process them.
214
+ if llm_response.tool_calls:
215
+ # Add the assistant message with tool calls to the messages.
216
+ messages.append(
217
+ self._get_assistant_message_with_tool_calls(llm_response)
218
+ )
219
+ for tool_call in llm_response.tool_calls:
220
+ structlogger.debug(
221
+ "mcp_open_agent.send_message.tool_call",
222
+ event_info=f"Processing tool call {tool_call.tool_name}",
223
+ tool_name=tool_call.tool_name,
224
+ tool_args=json.dumps(tool_call.tool_args),
225
+ agent_name=self._name,
226
+ agent_id=str(
227
+ make_agent_identifier(self._name, self.protocol_type)
228
+ ),
229
+ json_formatting=["tool_args"],
230
+ )
231
+
232
+ # Agent signals task completion.
233
+ if tool_call.tool_name == KEY_TASK_COMPLETED:
234
+ return self._run_task_completed_tool(
235
+ tool_call, agent_input, tool_results
236
+ )
237
+
238
+ else:
239
+ # Execute the tool call.
240
+ tool_output = await self._execute_tool_call(
241
+ tool_call.tool_name,
242
+ tool_call.tool_args,
243
+ )
244
+
245
+ structlogger.debug(
246
+ "mcp_open_agent.send_message.tool_output",
247
+ event_info=(
248
+ f"Tool output for tool call {tool_call.tool_name}"
249
+ ),
250
+ tool_output=tool_output.model_dump(),
251
+ json_formatting=["tool_output"],
252
+ agent_name=self._name,
253
+ agent_id=str(
254
+ make_agent_identifier(
255
+ self._name, self.protocol_type
256
+ )
257
+ ),
258
+ )
259
+
260
+ # If the tool call failed, generate an agent error output.
261
+ if tool_output.is_error or tool_output.result is None:
262
+ return self._generate_agent_error_output(
263
+ tool_output, agent_input, tool_call
264
+ )
265
+
266
+ # Store the tool output in the tool_results.
267
+ tool_results[tool_call.id] = tool_output
268
+
269
+ # Add the tool call message to the messages.
270
+ messages.append(
271
+ {
272
+ KEY_ROLE: ROLE_TOOL,
273
+ KEY_TOOL_CALL_ID: tool_call.id,
274
+ KEY_CONTENT: tool_output.result,
275
+ }
276
+ )
277
+
278
+ except Exception as e:
279
+ if isinstance(e, ProviderClientAPIException) and isinstance(
280
+ e.original_exception, LLMToolResponseDecodeError
281
+ ):
282
+ structlogger.debug(
283
+ "mcp_open_agent.send_message.malformed_tool_response_error",
284
+ event_info=(
285
+ "Malformed tool response received from LLM "
286
+ "(JSON decode error). Retrying the LLM call."
287
+ ),
288
+ user_message=agent_input.user_message,
289
+ agent_name=self._name,
290
+ agent_id=str(
291
+ make_agent_identifier(self._name, self.protocol_type)
292
+ ),
293
+ original_exception=str(e.original_exception),
294
+ )
295
+ # Continue to make another LLM call by breaking out of the current
296
+ # iteration and letting the loop continue with a fresh LLM request
297
+ messages.append(
298
+ self._get_system_message_for_malformed_tool_response()
299
+ )
300
+ continue
301
+ structlogger.error(
302
+ "mcp_open_agent.send_message.error_in_agent_loop",
303
+ event_info=f"Failed to send message: {e}",
304
+ user_message=agent_input.user_message,
305
+ agent_name=self._name,
306
+ agent_id=str(make_agent_identifier(self._name, self.protocol_type)),
307
+ )
308
+ return AgentOutput(
309
+ id=agent_input.id,
310
+ status=AgentStatus.FATAL_ERROR,
311
+ response_message=f"I encountered an error: {e!s}",
312
+ structured_results=self._get_structured_results_for_agent_output(
313
+ agent_input, tool_results
314
+ ),
315
+ error_message=str(e),
316
+ )
317
+ return AgentOutput(
318
+ id=agent_input.id,
319
+ status=AgentStatus.COMPLETED,
320
+ response_message=(
321
+ "I've completed my research but couldn't provide a final answer within"
322
+ "the allowed steps."
323
+ ),
324
+ structured_results=self._get_structured_results_for_agent_output(
325
+ agent_input, tool_results
326
+ ),
327
+ )