rasa-pro 3.13.7__py3-none-any.whl → 3.14.0.dev1__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 (178) hide show
  1. rasa/agents/__init__.py +0 -0
  2. rasa/agents/agent_factory.py +122 -0
  3. rasa/agents/agent_manager.py +162 -0
  4. rasa/agents/constants.py +31 -0
  5. rasa/agents/core/__init__.py +0 -0
  6. rasa/agents/core/agent_protocol.py +108 -0
  7. rasa/agents/core/types.py +70 -0
  8. rasa/agents/exceptions.py +8 -0
  9. rasa/agents/protocol/__init__.py +5 -0
  10. rasa/agents/protocol/a2a/__init__.py +0 -0
  11. rasa/agents/protocol/a2a/a2a_agent.py +51 -0
  12. rasa/agents/protocol/mcp/__init__.py +0 -0
  13. rasa/agents/protocol/mcp/mcp_base_agent.py +697 -0
  14. rasa/agents/protocol/mcp/mcp_open_agent.py +275 -0
  15. rasa/agents/protocol/mcp/mcp_task_agent.py +447 -0
  16. rasa/agents/schemas/__init__.py +6 -0
  17. rasa/agents/schemas/agent_input.py +24 -0
  18. rasa/agents/schemas/agent_output.py +26 -0
  19. rasa/agents/schemas/agent_tool_result.py +51 -0
  20. rasa/agents/schemas/agent_tool_schema.py +112 -0
  21. rasa/agents/templates/__init__.py +0 -0
  22. rasa/agents/templates/mcp_open_agent_prompt_template.jinja2 +15 -0
  23. rasa/agents/templates/mcp_task_agent_prompt_template.jinja2 +13 -0
  24. rasa/agents/utils.py +72 -0
  25. rasa/api.py +5 -0
  26. rasa/cli/arguments/default_arguments.py +12 -0
  27. rasa/cli/arguments/run.py +2 -0
  28. rasa/cli/dialogue_understanding_test.py +4 -0
  29. rasa/cli/e2e_test.py +4 -0
  30. rasa/cli/inspect.py +3 -0
  31. rasa/cli/llm_fine_tuning.py +5 -0
  32. rasa/cli/run.py +4 -0
  33. rasa/cli/shell.py +3 -0
  34. rasa/cli/train.py +2 -2
  35. rasa/constants.py +6 -0
  36. rasa/core/actions/action.py +69 -39
  37. rasa/core/actions/action_run_slot_rejections.py +1 -1
  38. rasa/core/agent.py +16 -0
  39. rasa/core/available_agents.py +196 -0
  40. rasa/core/available_endpoints.py +30 -0
  41. rasa/core/channels/development_inspector.py +47 -14
  42. rasa/core/channels/inspector/dist/assets/{arc-0b11fe30.js → arc-2e78c586.js} +1 -1
  43. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-9eef30a7.js → blockDiagram-38ab4fdb-806b712e.js} +1 -1
  44. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-03e94f28.js → c4Diagram-3d4e48cf-0745efa9.js} +1 -1
  45. rasa/core/channels/inspector/dist/assets/channel-c436ca7c.js +1 -0
  46. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-95c09eba.js → classDiagram-70f12bd4-7bd1082b.js} +1 -1
  47. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-38e8446c.js → classDiagram-v2-f2320105-d937ba49.js} +1 -1
  48. rasa/core/channels/inspector/dist/assets/clone-50dd656b.js +1 -0
  49. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-57dc3038.js → createText-2e5e7dd3-a2a564ca.js} +1 -1
  50. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-4bac0545.js → edges-e0da2a9e-b5256940.js} +1 -1
  51. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-81795c90.js → erDiagram-9861fffd-e6883ad2.js} +1 -1
  52. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-89489ae6.js → flowDb-956e92f1-e576fc02.js} +1 -1
  53. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-cd152627.js → flowDiagram-66a62f08-2e298d01.js} +1 -1
  54. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b2aeaf8.js +1 -0
  55. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-3da369bc.js → flowchart-elk-definition-4a651766-dd7b150a.js} +1 -1
  56. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-85ec16f8.js → ganttDiagram-c361ad54-5b79575c.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-495bc140.js → gitGraphDiagram-72cf32ee-3016f40a.js} +1 -1
  58. rasa/core/channels/inspector/dist/assets/{graph-1ec4d266.js → graph-3e19170f.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/index-1bd9135e.js +1353 -0
  60. rasa/core/channels/inspector/dist/assets/{index-3862675e-0a0e97c9.js → index-3862675e-eb9c86de.js} +1 -1
  61. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-4d54bcde.js → infoDiagram-f8f76790-b4280e4d.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-dc097114.js → journeyDiagram-49397b02-556091f8.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{layout-1a08981e.js → layout-08436411.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{line-95f7f1d3.js → line-683c4f3b.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{linear-97e69543.js → linear-cee6d791.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-8c71ff03.js → mindmap-definition-fc14e90a-a0bf0b1a.js} +1 -1
  67. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-f14c71c7.js → pieDiagram-8a3498a8-3730d5c4.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-f1d3c9ff.js → quadrantDiagram-120e2f19-12a20fed.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-bfa2412f.js → requirementDiagram-deff3bca-b9732102.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-53f2c97b.js → sankeyDiagram-04a897e0-a2e72776.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-319d7c0e.js → sequenceDiagram-704730f1-8b7a76bb.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-76a09418.js → stateDiagram-587899a1-e65853ac.js} +1 -1
  73. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-a67f15d4.js → stateDiagram-v2-d93cdb3a-6f58a44b.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-0654e7c3.js → styles-6aaf32cf-df25b934.js} +1 -1
  75. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1394bb9d.js → styles-9a916d00-88357141.js} +1 -1
  76. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-e4c5bdae.js → styles-c10674c1-d600174d.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-50957104.js → svgDrawCommon-08f97a94-4adc3e0b.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-b0885a6a.js → timeline-definition-85554ec2-42816fa1.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-79e6541a.js → xychartDiagram-e933f94c-621eb66a.js} +1 -1
  80. rasa/core/channels/inspector/dist/index.html +2 -2
  81. rasa/core/channels/inspector/index.html +1 -1
  82. rasa/core/channels/inspector/src/App.tsx +53 -7
  83. rasa/core/channels/inspector/src/components/Chat.tsx +3 -2
  84. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +1 -1
  85. rasa/core/channels/inspector/src/components/DialogueStack.tsx +7 -5
  86. rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +268 -0
  87. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -2
  88. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +8 -3
  89. rasa/core/channels/inspector/src/helpers/formatters.ts +24 -3
  90. rasa/core/channels/inspector/src/theme/base/styles.ts +19 -1
  91. rasa/core/channels/inspector/src/types.ts +12 -0
  92. rasa/core/channels/studio_chat.py +125 -34
  93. rasa/core/channels/voice_ready/twilio_voice.py +1 -1
  94. rasa/core/channels/voice_stream/audiocodes.py +9 -6
  95. rasa/core/channels/voice_stream/browser_audio.py +39 -4
  96. rasa/core/channels/voice_stream/call_state.py +13 -2
  97. rasa/core/channels/voice_stream/genesys.py +16 -13
  98. rasa/core/channels/voice_stream/jambonz.py +13 -11
  99. rasa/core/channels/voice_stream/twilio_media_streams.py +14 -13
  100. rasa/core/channels/voice_stream/util.py +11 -1
  101. rasa/core/channels/voice_stream/voice_channel.py +101 -29
  102. rasa/core/constants.py +4 -0
  103. rasa/core/nlg/contextual_response_rephraser.py +11 -7
  104. rasa/core/nlg/generator.py +21 -5
  105. rasa/core/nlg/response.py +43 -6
  106. rasa/core/nlg/translate.py +8 -0
  107. rasa/core/policies/enterprise_search_policy.py +4 -2
  108. rasa/core/policies/flow_policy.py +2 -2
  109. rasa/core/policies/flows/flow_executor.py +374 -35
  110. rasa/core/policies/flows/mcp_tool_executor.py +240 -0
  111. rasa/core/processor.py +6 -1
  112. rasa/core/run.py +8 -1
  113. rasa/core/utils.py +21 -1
  114. rasa/dialogue_understanding/commands/__init__.py +8 -0
  115. rasa/dialogue_understanding/commands/cancel_flow_command.py +97 -4
  116. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +11 -0
  117. rasa/dialogue_understanding/commands/continue_agent_command.py +91 -0
  118. rasa/dialogue_understanding/commands/knowledge_answer_command.py +11 -0
  119. rasa/dialogue_understanding/commands/restart_agent_command.py +146 -0
  120. rasa/dialogue_understanding/commands/start_flow_command.py +129 -8
  121. rasa/dialogue_understanding/commands/utils.py +6 -2
  122. rasa/dialogue_understanding/generator/command_parser.py +4 -0
  123. rasa/dialogue_understanding/generator/llm_based_command_generator.py +50 -12
  124. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +61 -0
  125. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +61 -0
  126. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +81 -0
  127. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +81 -0
  128. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +7 -6
  129. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +7 -6
  130. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +41 -2
  131. rasa/dialogue_understanding/patterns/continue_interrupted.py +163 -1
  132. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +51 -7
  133. rasa/dialogue_understanding/stack/dialogue_stack.py +123 -2
  134. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +57 -0
  135. rasa/dialogue_understanding/stack/utils.py +3 -2
  136. rasa/dialogue_understanding_test/du_test_runner.py +7 -2
  137. rasa/dialogue_understanding_test/du_test_schema.yml +3 -3
  138. rasa/e2e_test/e2e_test_runner.py +5 -0
  139. rasa/e2e_test/e2e_test_schema.yml +3 -3
  140. rasa/model_manager/model_api.py +1 -1
  141. rasa/model_manager/socket_bridge.py +8 -2
  142. rasa/server.py +10 -0
  143. rasa/shared/agents/__init__.py +0 -0
  144. rasa/shared/agents/utils.py +35 -0
  145. rasa/shared/constants.py +5 -0
  146. rasa/shared/core/constants.py +12 -1
  147. rasa/shared/core/domain.py +5 -5
  148. rasa/shared/core/events.py +319 -0
  149. rasa/shared/core/flows/flows_list.py +2 -2
  150. rasa/shared/core/flows/flows_yaml_schema.json +101 -186
  151. rasa/shared/core/flows/steps/call.py +51 -5
  152. rasa/shared/core/flows/validation.py +45 -7
  153. rasa/shared/core/flows/yaml_flows_io.py +3 -3
  154. rasa/shared/providers/llm/_base_litellm_client.py +39 -7
  155. rasa/shared/providers/llm/litellm_router_llm_client.py +8 -4
  156. rasa/shared/providers/llm/llm_client.py +7 -3
  157. rasa/shared/providers/llm/llm_response.py +49 -0
  158. rasa/shared/providers/llm/self_hosted_llm_client.py +8 -4
  159. rasa/shared/utils/common.py +2 -1
  160. rasa/shared/utils/llm.py +28 -5
  161. rasa/shared/utils/mcp/__init__.py +0 -0
  162. rasa/shared/utils/mcp/server_connection.py +157 -0
  163. rasa/shared/utils/schemas/events.py +42 -0
  164. rasa/studio/upload.py +4 -7
  165. rasa/tracing/instrumentation/instrumentation.py +4 -2
  166. rasa/utils/common.py +53 -0
  167. rasa/utils/licensing.py +21 -10
  168. rasa/utils/plotting.py +1 -1
  169. rasa/version.py +1 -1
  170. {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev1.dist-info}/METADATA +16 -15
  171. {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev1.dist-info}/RECORD +174 -137
  172. rasa/core/channels/inspector/dist/assets/channel-51d02e9e.js +0 -1
  173. rasa/core/channels/inspector/dist/assets/clone-cc738fa6.js +0 -1
  174. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-0c716443.js +0 -1
  175. rasa/core/channels/inspector/dist/assets/index-c804b295.js +0 -1335
  176. {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev1.dist-info}/NOTICE +0 -0
  177. {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev1.dist-info}/WHEEL +0 -0
  178. {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,13 @@
1
+ You are a helpful assistant that should assist the user in the best possible way.
2
+
3
+ ### Task
4
+ {{ description }}
5
+
6
+ ### Instructions
7
+ * Always make sure to output responses to the user in a clear, helpful format.
8
+ * Always avoid asking multiple questions at once. Ask questions sequentially one at a time and wait for the user's response before proceeding to next question.
9
+ * Always avoid making assumptions about what values to pass into tools. Ask for clarification if a user's request is ambiguous.
10
+ * Strictly avoid making up information or ability to take some action which is not available in `tool` provided.
11
+
12
+ ### Conversation history
13
+ {{ conversation_history }}
rasa/agents/utils.py ADDED
@@ -0,0 +1,72 @@
1
+ from typing import List, Optional
2
+
3
+ from rasa.agents.agent_manager import AgentManager
4
+ from rasa.agents.exceptions import AgentNotFoundException
5
+ from rasa.core.available_agents import (
6
+ AgentConfig,
7
+ AgentMCPServerConfig,
8
+ AvailableAgents,
9
+ )
10
+ from rasa.core.available_endpoints import AvailableEndpoints
11
+ from rasa.shared.agents.utils import get_protocol_type
12
+ from rasa.shared.core.domain import Domain
13
+ from rasa.shared.core.flows import FlowsList
14
+ from rasa.shared.core.flows.steps import CallFlowStep
15
+
16
+
17
+ def resolve_agent_config(
18
+ agent_config: AgentConfig,
19
+ available_endpoints: AvailableEndpoints,
20
+ ) -> Optional[AgentConfig]:
21
+ if agent_config is None:
22
+ return None
23
+
24
+ connections = agent_config.connections
25
+ mcp_connections: List[AgentMCPServerConfig] = (
26
+ connections.mcp_servers
27
+ if connections and connections.mcp_servers is not None
28
+ else []
29
+ )
30
+
31
+ for mcp_server in mcp_connections:
32
+ for mcp_server_endpoint in available_endpoints.mcp_servers or []:
33
+ if mcp_server_endpoint.name == mcp_server.name:
34
+ mcp_server.url = mcp_server_endpoint.url
35
+ mcp_server.type = mcp_server_endpoint.type
36
+
37
+ return agent_config
38
+
39
+
40
+ async def initialize_agents(
41
+ flows: FlowsList,
42
+ domain: Domain,
43
+ sub_agents: AvailableAgents,
44
+ ) -> None:
45
+ """Iterate over flows and create/connect the referenced agents."""
46
+ agent_manager: AgentManager = AgentManager()
47
+ endpoints = AvailableEndpoints.get_instance()
48
+
49
+ for flow in flows.underlying_flows:
50
+ for step in flow.steps:
51
+ if isinstance(step, CallFlowStep):
52
+ if flows.flow_by_id(step.call) is not None:
53
+ continue
54
+
55
+ if step.is_calling_mcp_tool():
56
+ # The call step is calling an MCP tool, so we don't need to
57
+ # initialize any agent.
58
+ continue
59
+
60
+ if not step.is_calling_agent():
61
+ raise AgentNotFoundException(step.call)
62
+
63
+ agent_name = step.call
64
+ agent_config = sub_agents.get_agent_config(agent_name)
65
+ resolved_agent_config = resolve_agent_config(agent_config, endpoints)
66
+ protocol_type = get_protocol_type(step, agent_config)
67
+
68
+ await agent_manager.connect_agent(
69
+ agent_name,
70
+ protocol_type,
71
+ resolved_agent_config,
72
+ )
rasa/api.py CHANGED
@@ -20,6 +20,7 @@ if TYPE_CHECKING:
20
20
  def run(
21
21
  model: Text,
22
22
  endpoints: Text,
23
+ sub_agents: Text,
23
24
  connector: Optional[Text] = None,
24
25
  credentials: Optional[Text] = None,
25
26
  **kwargs: Dict[Text, Any],
@@ -29,6 +30,7 @@ def run(
29
30
  Args:
30
31
  model: Path to model archive.
31
32
  endpoints: Path to endpoints file.
33
+ sub_agents: Path to sub-agents directory.
32
34
  connector: Connector which should be use (overwrites `credentials`
33
35
  field).
34
36
  credentials: Path to channel credentials file.
@@ -38,11 +40,13 @@ def run(
38
40
  """
39
41
  import rasa.core.run
40
42
  import rasa.shared.utils.common
43
+ from rasa.core.available_agents import AvailableAgents
41
44
  from rasa.core.available_endpoints import AvailableEndpoints
42
45
  from rasa.shared.constants import DOCS_BASE_URL
43
46
  from rasa.shared.utils.cli import print_warning
44
47
 
45
48
  _endpoints = AvailableEndpoints.get_instance(endpoints)
49
+ _sub_agents = AvailableAgents.get_instance(sub_agents)
46
50
 
47
51
  if not connector and not credentials:
48
52
  connector = "rest"
@@ -61,6 +65,7 @@ def run(
61
65
  channel=connector,
62
66
  credentials=credentials,
63
67
  endpoints=_endpoints,
68
+ sub_agents=_sub_agents,
64
69
  **kwargs,
65
70
  )
66
71
 
@@ -3,6 +3,7 @@ import logging
3
3
  from enum import Enum
4
4
  from typing import List, Optional, Text, Union
5
5
 
6
+ from rasa.core.constants import DEFAULT_SUB_AGENTS
6
7
  from rasa.core.persistor import RemoteStorageType, StorageType, parse_remote_storage
7
8
  from rasa.shared.constants import (
8
9
  DEFAULT_CONFIG_PATH,
@@ -217,3 +218,14 @@ def add_skip_validation_flag(
217
218
  action="append",
218
219
  help="Skip YAML validation for selected parts of the training data.",
219
220
  )
221
+
222
+
223
+ def add_sub_agents_param(
224
+ parser: Union[argparse.ArgumentParser, argparse._ActionsContainer],
225
+ ) -> None:
226
+ parser.add_argument(
227
+ "--sub-agents",
228
+ type=str,
229
+ default=DEFAULT_SUB_AGENTS,
230
+ help="Directory that specifies sub-agents to use (default: %(default)s).",
231
+ )
rasa/cli/arguments/run.py CHANGED
@@ -7,6 +7,7 @@ from rasa.cli.arguments.default_arguments import (
7
7
  add_model_param,
8
8
  add_remote_storage_param,
9
9
  add_skip_validation_flag,
10
+ add_sub_agents_param,
10
11
  )
11
12
  from rasa.core import constants
12
13
  from rasa.env import (
@@ -24,6 +25,7 @@ def set_run_arguments(parser: argparse.ArgumentParser) -> None:
24
25
  add_server_arguments(parser)
25
26
  add_inspect_argument(parser)
26
27
  add_skip_validation_flag(parser)
28
+ add_sub_agents_param(parser)
27
29
 
28
30
 
29
31
  def set_run_action_arguments(parser: argparse.ArgumentParser) -> None:
@@ -14,6 +14,7 @@ from rasa.cli.arguments.default_arguments import (
14
14
  add_endpoint_param,
15
15
  add_model_param,
16
16
  add_remote_storage_param,
17
+ add_sub_agents_param,
17
18
  )
18
19
  from rasa.core.agent import Agent
19
20
  from rasa.core.available_endpoints import AvailableEndpoints
@@ -174,6 +175,8 @@ def add_du_test_arguments(parser: argparse.ArgumentParser) -> None:
174
175
  ),
175
176
  )
176
177
 
178
+ add_sub_agents_param(du_arguments)
179
+
177
180
 
178
181
  def ensure_calm_only_bot(agent: Agent) -> None:
179
182
  if agent.domain is None or agent.processor is None:
@@ -218,6 +221,7 @@ def execute_dialogue_understanding_tests(args: argparse.Namespace) -> None:
218
221
  model_path=args.model,
219
222
  model_server=endpoints.model,
220
223
  remote_storage=args.remote_storage,
224
+ sub_agents_path=args.sub_agents,
221
225
  )
222
226
  except AgentNotReady as error:
223
227
  structlogger.error(
rasa/cli/e2e_test.py CHANGED
@@ -17,6 +17,7 @@ from rasa.cli.arguments.default_arguments import (
17
17
  add_endpoint_param,
18
18
  add_model_param,
19
19
  add_remote_storage_param,
20
+ add_sub_agents_param,
20
21
  )
21
22
  from rasa.core.available_endpoints import AvailableEndpoints
22
23
  from rasa.core.exceptions import AgentNotReady
@@ -147,6 +148,8 @@ def add_e2e_test_arguments(parser: argparse.ArgumentParser) -> None:
147
148
  help="Directory where to save coverage report to.",
148
149
  )
149
150
 
151
+ add_sub_agents_param(parser)
152
+
150
153
 
151
154
  def execute_e2e_tests(args: argparse.Namespace) -> None:
152
155
  """Run the end-to-end tests.
@@ -192,6 +195,7 @@ def execute_e2e_tests(args: argparse.Namespace) -> None:
192
195
  model_server=endpoints.model,
193
196
  endpoints=endpoints,
194
197
  test_case_path=Path(test_case_path),
198
+ sub_agents_path=args.sub_agents,
195
199
  )
196
200
  except AgentNotReady as error:
197
201
  structlogger.error(
rasa/cli/inspect.py CHANGED
@@ -8,6 +8,7 @@ from sanic import Sanic
8
8
  from rasa import telemetry
9
9
  from rasa.cli import SubParsersAction
10
10
  from rasa.cli.arguments import shell as arguments
11
+ from rasa.cli.arguments.default_arguments import add_sub_agents_param
11
12
  from rasa.core import constants
12
13
  from rasa.core.available_endpoints import AvailableEndpoints
13
14
  from rasa.engine.storage.local_model_storage import LocalModelStorage
@@ -44,6 +45,8 @@ def add_subparser(
44
45
  "--voice", help="Enable voice", action="store_true", default=False
45
46
  )
46
47
 
48
+ add_sub_agents_param(inspect_parser)
49
+
47
50
  # it'd be confusing to expose those arguments to the user,
48
51
  # so we remove them
49
52
  remove_argument_from_parser(inspect_parser, "--credentials")
@@ -14,6 +14,7 @@ from rasa.cli.arguments.default_arguments import (
14
14
  add_endpoint_param,
15
15
  add_model_param,
16
16
  add_remote_storage_param,
17
+ add_sub_agents_param,
17
18
  )
18
19
  from rasa.cli.e2e_test import (
19
20
  RASA_PRO_BETA_FINE_TUNING_RECIPE_ENV_VAR_NAME,
@@ -137,6 +138,8 @@ def add_data_preparation_arguments(parser: argparse.ArgumentParser) -> None:
137
138
  default=DEFAULT_INPUT_E2E_TEST_PATH,
138
139
  )
139
140
 
141
+ add_sub_agents_param(parser)
142
+
140
143
  add_remote_storage_param(parser)
141
144
 
142
145
  rephrasing_arguments = parser.add_argument_group("Rephrasing Module")
@@ -376,6 +379,7 @@ def write_params(
376
379
  "rephrase_config": rephrase_config,
377
380
  "model": args.model,
378
381
  "endpoints": args.endpoints,
382
+ "sub-agents": args.sub_agents,
379
383
  "remote-storage": args.remote_storage,
380
384
  "train_frac": args.train_frac,
381
385
  "output_format": args.output_format,
@@ -420,6 +424,7 @@ def set_up_e2e_test_runner(args: argparse.Namespace) -> E2ETestRunner:
420
424
  model_path=args.model,
421
425
  model_server=endpoints.model,
422
426
  endpoints=endpoints,
427
+ sub_agents_path=args.sub_agents,
423
428
  )
424
429
  except AgentNotReady as error:
425
430
  structlogger.error(
rasa/cli/run.py CHANGED
@@ -109,6 +109,7 @@ def run(args: argparse.Namespace) -> None:
109
109
  # configured
110
110
 
111
111
  import rasa.model
112
+ from rasa.core.available_agents import AvailableAgents
112
113
  from rasa.core.available_endpoints import AvailableEndpoints
113
114
 
114
115
  # start server if remote storage is configured
@@ -123,6 +124,9 @@ def run(args: argparse.Namespace) -> None:
123
124
  rasa_run(**vars(args))
124
125
  return
125
126
 
127
+ # load sub-agents
128
+ AvailableAgents.get_instance(args.sub_agents)
129
+
126
130
  # start server if local model found
127
131
  args.model = _validate_model_path(args.model, "model", DEFAULT_MODELS_PATH)
128
132
  local_model_set = True
rasa/cli/shell.py CHANGED
@@ -6,6 +6,7 @@ from typing import List
6
6
  from rasa import telemetry
7
7
  from rasa.cli import SubParsersAction
8
8
  from rasa.cli.arguments import shell as arguments
9
+ from rasa.cli.arguments.default_arguments import add_sub_agents_param
9
10
  from rasa.core.available_endpoints import AvailableEndpoints
10
11
  from rasa.engine.storage.local_model_storage import LocalModelStorage
11
12
  from rasa.exceptions import ModelNotFound
@@ -45,6 +46,8 @@ def add_subparser(
45
46
  help="Set the conversation ID.",
46
47
  )
47
48
 
49
+ add_sub_agents_param(shell_parser)
50
+
48
51
  run_subparsers = shell_parser.add_subparsers()
49
52
 
50
53
  shell_nlu_subparser = run_subparsers.add_parser(
rasa/cli/train.py CHANGED
@@ -15,7 +15,7 @@ from rasa.core.nlg.contextual_response_rephraser import ContextualResponseRephra
15
15
  from rasa.core.nlg.generator import NaturalLanguageGenerator
16
16
  from rasa.core.train import do_compare_training
17
17
  from rasa.engine.validation import validate_api_type_config_key_usage
18
- from rasa.exceptions import ValidationError
18
+ from rasa.exceptions import DetailedRasaException
19
19
  from rasa.shared.constants import (
20
20
  CONFIG_MANDATORY_KEYS,
21
21
  CONFIG_MANDATORY_KEYS_CORE,
@@ -82,7 +82,7 @@ def _check_nlg_endpoint_validity(endpoint: Union[Path, str]) -> None:
82
82
  ContextualResponseRephraser.__name__,
83
83
  )
84
84
  NaturalLanguageGenerator.create(endpoints.nlg)
85
- except ValidationError as e:
85
+ except DetailedRasaException as e:
86
86
  structlogger.error(
87
87
  e.code,
88
88
  event_info=e.info,
rasa/constants.py CHANGED
@@ -22,8 +22,14 @@ MINIMUM_COMPATIBLE_VERSION = "3.11.0rc1"
22
22
 
23
23
  GLOBAL_USER_CONFIG_PATH = os.path.expanduser("~/.config/rasa/global.yml")
24
24
 
25
+ # Logging level for external libraries (default: ERROR to reduce noise)
25
26
  DEFAULT_LOG_LEVEL_LIBRARIES = "ERROR"
26
27
  ENV_LOG_LEVEL_LIBRARIES = "LOG_LEVEL_LIBRARIES"
28
+
29
+ # MCP (Model Context Protocol) logging configuration
30
+ ENV_LOG_LEVEL_MCP = "LOG_LEVEL_MCP"
31
+ ENV_MCP_LOGGING_ENABLED = "MCP_LOGGING_ENABLED"
32
+
27
33
  ENV_LOG_LEVEL_MATPLOTLIB = "LOG_LEVEL_MATPLOTLIB"
28
34
  ENV_LOG_LEVEL_RABBITMQ = "LOG_LEVEL_RABBITMQ"
29
35
  ENV_LOG_LEVEL_KAFKA = "LOG_LEVEL_KAFKA"
@@ -23,11 +23,9 @@ from rasa.core.constants import (
23
23
  KEY_IS_COEXISTENCE_ASSISTANT,
24
24
  UTTER_SOURCE_METADATA_KEY,
25
25
  )
26
- from rasa.core.nlg.translate import get_translated_buttons, get_translated_text
27
26
  from rasa.core.policies.policy import PolicyPrediction
28
27
  from rasa.core.utils import add_bot_utterance_metadata
29
28
  from rasa.e2e_test.constants import KEY_STUB_CUSTOM_ACTIONS
30
- from rasa.engine.language import Language
31
29
  from rasa.nlu.constants import (
32
30
  RESPONSE_SELECTOR_DEFAULT_INTENT,
33
31
  RESPONSE_SELECTOR_PREDICTION_KEY,
@@ -49,6 +47,7 @@ from rasa.shared.constants import (
49
47
  UTTER_PREFIX,
50
48
  )
51
49
  from rasa.shared.core.constants import (
50
+ ACTION_AGENT_REQUEST_USER_INPUT_NAME,
52
51
  ACTION_BACK_NAME,
53
52
  ACTION_DEACTIVATE_LOOP_NAME,
54
53
  ACTION_DEFAULT_ASK_AFFIRMATION_NAME,
@@ -58,6 +57,8 @@ from rasa.shared.core.constants import (
58
57
  ACTION_LISTEN_NAME,
59
58
  ACTION_METADATA_EXECUTION_ERROR_MESSAGE,
60
59
  ACTION_METADATA_EXECUTION_SUCCESS,
60
+ ACTION_METADATA_MESSAGE_KEY,
61
+ ACTION_METADATA_TEXT_KEY,
61
62
  ACTION_RESET_ROUTING,
62
63
  ACTION_RESTART_NAME,
63
64
  ACTION_REVERT_FALLBACK_EVENTS_NAME,
@@ -84,7 +85,6 @@ from rasa.shared.core.events import (
84
85
  UserUttered,
85
86
  )
86
87
  from rasa.shared.core.flows import FlowsList
87
- from rasa.shared.core.flows.constants import KEY_TRANSLATION
88
88
  from rasa.shared.core.slot_mappings import (
89
89
  SlotFillingManager,
90
90
  extract_slot_value,
@@ -116,6 +116,12 @@ def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["A
116
116
  from rasa.core.actions.two_stage_fallback import TwoStageFallbackAction
117
117
  from rasa.dialogue_understanding.patterns.cancel import ActionCancelFlow
118
118
  from rasa.dialogue_understanding.patterns.clarify import ActionClarifyFlows
119
+ from rasa.dialogue_understanding.patterns.continue_interrupted import (
120
+ ActionAskInterruptedFlowToContinue,
121
+ ActionCancelInterruptedFlow,
122
+ ActionContinueInterruptedFlow,
123
+ ActionSetInterruptedFlows,
124
+ )
119
125
  from rasa.dialogue_understanding.patterns.correction import ActionCorrectFlowSlot
120
126
 
121
127
  return [
@@ -130,6 +136,7 @@ def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["A
130
136
  TwoStageFallbackAction(action_endpoint),
131
137
  ActionUnlikelyIntent(),
132
138
  ActionSendText(),
139
+ ActionAgentRequestUserInfo(),
133
140
  ActionBack(),
134
141
  ActionExtractSlots(action_endpoint),
135
142
  ActionCancelFlow(),
@@ -142,6 +149,10 @@ def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["A
142
149
  ActionResetRouting(),
143
150
  ActionHangup(),
144
151
  ActionRepeatBotMessages(),
152
+ ActionContinueInterruptedFlow(),
153
+ ActionSetInterruptedFlows(),
154
+ ActionCancelInterruptedFlow(),
155
+ ActionAskInterruptedFlowToContinue(),
145
156
  ]
146
157
 
147
158
 
@@ -251,36 +262,25 @@ def action_for_name_or_text(
251
262
  return RemoteAction(action_name_or_text, action_endpoint)
252
263
 
253
264
 
254
- def create_bot_utterance(
255
- message: Dict[Text, Any], language: Optional[Language] = None
256
- ) -> BotUttered:
257
- """Create BotUttered event from message with translation support."""
258
- message_copy = copy.deepcopy(message)
259
-
260
- text = get_translated_text(
261
- text=message_copy.pop(TEXT, None),
262
- translation=message_copy.pop(KEY_TRANSLATION, {}),
263
- language=language,
264
- )
265
-
266
- buttons = get_translated_buttons(
267
- buttons=message_copy.pop(BUTTONS, None), language=language
265
+ def create_bot_utterance(message: Dict[Text, Any]) -> BotUttered:
266
+ """Create BotUttered event from message."""
267
+ bot_message = BotUttered(
268
+ text=message.pop(TEXT, None),
269
+ data={
270
+ ELEMENTS: message.pop(ELEMENTS, None),
271
+ QUICK_REPLIES: message.pop(QUICK_REPLIES, None),
272
+ BUTTONS: message.pop(BUTTONS, None),
273
+ # for legacy / compatibility reasons we need to set the image
274
+ # to be the attachment if there is no other attachment (the
275
+ # `.get` is intentional - no `pop` as we still need the image`
276
+ # property to set it in the following line)
277
+ ATTACHMENT: message.pop(ATTACHMENT, None) or message.get(IMAGE, None),
278
+ IMAGE: message.pop(IMAGE, None),
279
+ CUSTOM: message.pop(CUSTOM, None),
280
+ },
281
+ metadata=message,
268
282
  )
269
-
270
- data = {
271
- ELEMENTS: message_copy.pop(ELEMENTS, None),
272
- QUICK_REPLIES: message_copy.pop(QUICK_REPLIES, None),
273
- BUTTONS: buttons,
274
- # for legacy / compatibility reasons we need to set the image
275
- # to be the attachment if there is no other attachment (the
276
- # `.get` is intentional - no `pop` as we still need the image`
277
- # property to set it in the following line)
278
- ATTACHMENT: message_copy.pop(ATTACHMENT, None) or message_copy.get(IMAGE, None),
279
- IMAGE: message_copy.pop(IMAGE, None),
280
- CUSTOM: message_copy.pop(CUSTOM, None),
281
- }
282
-
283
- return BotUttered(text=text, data=data, metadata=message_copy)
283
+ return bot_message
284
284
 
285
285
 
286
286
  class Action:
@@ -393,7 +393,7 @@ class ActionBotResponse(Action):
393
393
  message = add_bot_utterance_metadata(
394
394
  message, self.utter_action, nlg, domain, tracker
395
395
  )
396
- return [create_bot_utterance(message, tracker.current_language)]
396
+ return [create_bot_utterance(message)]
397
397
 
398
398
  def name(self) -> Text:
399
399
  """Returns action name."""
@@ -427,7 +427,7 @@ class ActionEndToEndResponse(Action):
427
427
  ) -> List[Event]:
428
428
  """Runs action (see parent class for full docstring)."""
429
429
  message = {"text": self.action_text}
430
- return [create_bot_utterance(message, tracker.current_language)]
430
+ return [create_bot_utterance(message)]
431
431
 
432
432
  def event_for_successful_execution(
433
433
  self,
@@ -893,7 +893,10 @@ class RemoteAction(Action):
893
893
  generated_response = response.pop("response", None)
894
894
  if generated_response is not None:
895
895
  draft = await nlg.generate(
896
- generated_response, tracker, output_channel.name(), **response
896
+ generated_response,
897
+ tracker,
898
+ output_channel.name(),
899
+ **response,
897
900
  )
898
901
  if not draft:
899
902
  continue
@@ -1068,6 +1071,7 @@ def _revert_rephrasing_events() -> List[Event]:
1068
1071
  ]
1069
1072
 
1070
1073
 
1074
+ # TODO: this should be removed, e.g. it uses a hardcoded message and no translation
1071
1075
  class ActionDefaultAskAffirmation(Action):
1072
1076
  """Default implementation which asks the user to affirm his intent.
1073
1077
 
@@ -1119,7 +1123,7 @@ class ActionDefaultAskAffirmation(Action):
1119
1123
  "utter_action": self.name(),
1120
1124
  }
1121
1125
 
1122
- return [create_bot_utterance(message, tracker.current_language)]
1126
+ return [create_bot_utterance(message)]
1123
1127
 
1124
1128
 
1125
1129
  class ActionDefaultAskRephrase(ActionBotResponse):
@@ -1149,16 +1153,42 @@ class ActionSendText(Action):
1149
1153
  metadata: Optional[Dict[Text, Any]] = None,
1150
1154
  ) -> List[Event]:
1151
1155
  """Runs action. Please see parent class for the full docstring."""
1152
- fallback = {"text": ""}
1156
+ fallback = {ACTION_METADATA_TEXT_KEY: ""}
1153
1157
  metadata_copy = copy.deepcopy(metadata) if metadata else {}
1154
- message = metadata_copy.get("message", fallback)
1158
+ message = metadata_copy.get(ACTION_METADATA_MESSAGE_KEY, fallback)
1155
1159
 
1156
1160
  should_send_text = metadata_copy.get("should_send_text", True)
1157
1161
  if should_send_text:
1158
- return [create_bot_utterance(message, tracker.current_language)]
1162
+ return [create_bot_utterance(message)]
1159
1163
  return []
1160
1164
 
1161
1165
 
1166
+ class ActionAgentRequestUserInfo(Action):
1167
+ """Sends a text message to the output channel that requests some user information.
1168
+
1169
+ The difference to `ActionSendText` is that this action will pause the main advancing
1170
+ flow loop until the user responds to the request
1171
+ (`should_predict_another_action` will return False for this action).
1172
+ """
1173
+
1174
+ def name(self) -> Text:
1175
+ return ACTION_AGENT_REQUEST_USER_INPUT_NAME
1176
+
1177
+ async def run(
1178
+ self,
1179
+ output_channel: "OutputChannel",
1180
+ nlg: "NaturalLanguageGenerator",
1181
+ tracker: "DialogueStateTracker",
1182
+ domain: "Domain",
1183
+ metadata: Optional[Dict[Text, Any]] = None,
1184
+ ) -> List[Event]:
1185
+ """Runs action. Please see parent class for the full docstring."""
1186
+ fallback = {ACTION_METADATA_TEXT_KEY: ""}
1187
+ metadata_copy = copy.deepcopy(metadata) if metadata else {}
1188
+ message = metadata_copy.get(ACTION_METADATA_MESSAGE_KEY, fallback)
1189
+ return [create_bot_utterance(message)]
1190
+
1191
+
1162
1192
  class ActionExtractSlots(Action):
1163
1193
  """Default action that runs after each user turn.
1164
1194
 
@@ -216,6 +216,6 @@ class ActionRunSlotRejections(Action):
216
216
  message = add_bot_utterance_metadata(
217
217
  message, utterance, nlg, domain, tracker
218
218
  )
219
- events.append(create_bot_utterance(message, tracker.current_language))
219
+ events.append(create_bot_utterance(message))
220
220
 
221
221
  return events
rasa/core/agent.py CHANGED
@@ -12,7 +12,9 @@ import aiohttp
12
12
  from aiohttp import ClientError
13
13
 
14
14
  import rasa.shared.utils.io
15
+ from rasa.agents.utils import initialize_agents
15
16
  from rasa.core import jobs
17
+ from rasa.core.available_agents import AvailableAgents
16
18
  from rasa.core.available_endpoints import AvailableEndpoints
17
19
  from rasa.core.channels.channel import OutputChannel, UserMessage
18
20
  from rasa.core.constants import DEFAULT_REQUEST_TIMEOUT
@@ -202,6 +204,7 @@ async def load_agent(
202
204
  model_server: Optional[EndpointConfig] = None,
203
205
  remote_storage: Optional[StorageType] = None,
204
206
  endpoints: Optional[AvailableEndpoints] = None,
207
+ sub_agents: Optional[AvailableAgents] = None,
205
208
  loop: Optional[AbstractEventLoop] = None,
206
209
  ) -> Agent:
207
210
  """Loads agent from server, remote storage or disk.
@@ -211,6 +214,7 @@ async def load_agent(
211
214
  model_server: Configuration for a potential server which serves the model.
212
215
  remote_storage: Remote storage to use for loading the model.
213
216
  endpoints: Endpoint configuration.
217
+ sub_agents: Sub-agents configuration.
214
218
  loop: Optional async loop to pass to broker creation.
215
219
 
216
220
  Returns:
@@ -281,6 +285,16 @@ async def load_agent(
281
285
  "No valid configuration given to load agent. "
282
286
  "Agent loaded with no model!"
283
287
  )
288
+
289
+ if agent.processor:
290
+ flows = await agent.processor.get_flows()
291
+ domain = agent.processor.domain
292
+ # CLI commands that accept --sub-agents
293
+ # all route through this entry point.
294
+ # With all required data available,
295
+ # this is the best spot to initialize the subagents.
296
+ await initialize_agents(flows, domain, sub_agents)
297
+
284
298
  return agent
285
299
 
286
300
  except Exception as e:
@@ -322,6 +336,7 @@ class Agent:
322
336
  remote_storage: Optional[StorageType] = None,
323
337
  http_interpreter: Optional[RasaNLUHttpInterpreter] = None,
324
338
  endpoints: Optional[AvailableEndpoints] = None,
339
+ sub_agents: Optional[AvailableAgents] = None,
325
340
  privacy_manager: Optional[BackgroundPrivacyManager] = None,
326
341
  ):
327
342
  """Initializes an `Agent`."""
@@ -334,6 +349,7 @@ class Agent:
334
349
  self.action_endpoint = action_endpoint
335
350
  self.http_interpreter = http_interpreter
336
351
  self.endpoints = endpoints
352
+ self.sub_agents = sub_agents
337
353
 
338
354
  self._set_fingerprint(fingerprint)
339
355
  self.model_server = model_server