rasa-pro 3.14.0.dev2__py3-none-any.whl → 3.14.0.dev3__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.

@@ -77,6 +77,8 @@ class AgentManager(metaclass=Singleton):
77
77
  Raises:
78
78
  ConnectionError: If the agent connection fails.
79
79
  """
80
+ # Add the agent to the manager
81
+ agent_identifier = make_agent_identifier(agent_name, protocol_type)
80
82
  try:
81
83
  # Create the agent client
82
84
  client = AgentFactory.create_client(protocol_type, config)
@@ -84,8 +86,6 @@ class AgentManager(metaclass=Singleton):
84
86
  # Connect the agent client
85
87
  await client.connect()
86
88
 
87
- # Add the agent to the manager
88
- agent_identifier = make_agent_identifier(agent_name, protocol_type)
89
89
  self._add_agent(agent_identifier, client)
90
90
  structlogger.info(
91
91
  "agent_manager.connect_agent.success",
rasa/agents/constants.py CHANGED
@@ -5,6 +5,7 @@ TOOL_DESCRIPTION_KEY = "description"
5
5
  TOOL_PARAMETERS_KEY = "parameters"
6
6
  TOOL_STRICT_KEY = "strict"
7
7
  TOOL_TYPE_FUNCTION_KEY = "function"
8
+ TOOL_EXECUTOR_KEY = "tool_executor"
8
9
 
9
10
  # MCP Tool related constants (secondary)
10
11
  TOOL_ADDITIONAL_PROPERTIES_KEY = "additionalProperties"
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  from abc import abstractmethod
3
+ from inspect import isawaitable
3
4
  from typing import Any, Dict, List, Optional, Tuple
4
5
 
5
6
  import structlog
@@ -25,6 +26,7 @@ from rasa.agents.schemas import (
25
26
  AgentOutput,
26
27
  AgentToolResult,
27
28
  AgentToolSchema,
29
+ CustomToolSchema,
28
30
  )
29
31
  from rasa.core.available_agents import AgentConfig, AgentMCPServerConfig, ProtocolConfig
30
32
  from rasa.shared.agents.utils import make_agent_identifier
@@ -112,6 +114,12 @@ class MCPBaseAgent(AgentProtocol):
112
114
  # Stores the MCP tools for the agent.
113
115
  self._mcp_tools: List[AgentToolSchema] = []
114
116
 
117
+ # Stores the custom tools for the agent.
118
+ self._custom_tools: List[CustomToolSchema] = [
119
+ CustomToolSchema.from_dict(tool)
120
+ for tool in self.get_custom_tool_definitions()
121
+ ]
122
+
115
123
  # Maps the tool names to the MCP servers that provide them.
116
124
  # key: tool name, value: server name.
117
125
  self._tool_to_server_mapper: Dict[str, str] = {}
@@ -164,28 +172,29 @@ class MCPBaseAgent(AgentProtocol):
164
172
  @classmethod
165
173
  def get_agent_specific_built_in_tools(
166
174
  cls, agent_input: AgentInput
167
- ) -> List[Dict[str, Any]]:
175
+ ) -> List[AgentToolSchema]:
168
176
  """Get agentic specific built-in tools."""
169
177
  return []
170
178
 
171
- @staticmethod
172
- def get_additional_tools(agent_input: AgentInput) -> List[Dict[str, Any]]:
173
- """Get additional tools for MCP. Override to add specific tools.
174
- This method can be overridden to provide additional tools that the agent
179
+ def get_custom_tool_definitions(self) -> List[Dict[str, Any]]:
180
+ """Add custom tool definitions and their executors for MCP agents.
181
+
182
+ This method can be overridden to provide custom tools that the agent
175
183
  can use during its operation. The tools should be defined in the OpenAI
176
184
  JSON format, which includes the tool name, description, and parameters.
177
185
 
178
186
  Refer: https://platform.openai.com/docs/guides/function-calling?api-mode=responses
179
187
 
180
- Args:
181
- agent_input: The agent input.
188
+ Note:
189
+ The tool executor method should be a coroutine function that returns an
190
+ AgentToolResult object.
182
191
 
183
192
  Returns:
184
- A list of additional tools.
193
+ A list of custom tool definitions along with their tool executor method.
185
194
 
186
195
  Example:
187
196
  ```python
188
- def get_additional_tools(self) -> List[Dict[str, Any]]:
197
+ def get_custom_tool_definitions(self) -> List[Dict[str, Any]]:
189
198
  return [
190
199
  {
191
200
  "type": "function",
@@ -207,6 +216,7 @@ class MCPBaseAgent(AgentProtocol):
207
216
  "required": ["location"],
208
217
  },
209
218
  },
219
+ "tool_executor": self.get_current_weather,
210
220
  }
211
221
  ]
212
222
  ```
@@ -334,23 +344,17 @@ class MCPBaseAgent(AgentProtocol):
334
344
  session = await connection.ensure_active_session()
335
345
  return await session.list_tools()
336
346
 
337
- @classmethod
338
- def get_built_in_tools(cls, agent_input: AgentInput) -> List[AgentToolSchema]:
339
- """Get built-in tools that are always available for MCP agents."""
340
- built_in_tools = []
341
- if agent_specific_built_in_tools := cls.get_agent_specific_built_in_tools(
342
- agent_input
343
- ):
344
- built_in_tools.extend(agent_specific_built_in_tools)
345
- if additional_tools := cls.get_additional_tools(agent_input):
346
- built_in_tools.extend(additional_tools)
347
- return [
348
- AgentToolSchema.from_openai_json_format(tool) for tool in built_in_tools
349
- ]
347
+ def get_custom_tools(self) -> List[AgentToolSchema]:
348
+ """Get the custom tools for the agent."""
349
+ return [tool.tool_definition for tool in self._custom_tools]
350
350
 
351
351
  def get_available_tools(self, agent_input: AgentInput) -> List[AgentToolSchema]:
352
352
  """Get the available tools for the agent."""
353
- return self._mcp_tools + self.get_built_in_tools(agent_input)
353
+ return (
354
+ self._mcp_tools
355
+ + self.get_agent_specific_built_in_tools(agent_input)
356
+ + self.get_custom_tools()
357
+ )
354
358
 
355
359
  async def _get_filtered_tools_from_server(
356
360
  self,
@@ -567,33 +571,6 @@ class MCPBaseAgent(AgentProtocol):
567
571
  ),
568
572
  )
569
573
 
570
- async def execute_additional_tool(
571
- self, tool_name: str, arguments: Dict[str, Any]
572
- ) -> Optional[AgentToolResult]:
573
- """Execute additional tool. Override to add logic for specific tool.
574
-
575
- Args:
576
- tool_name: The name of the tool to execute.
577
- arguments: The arguments to pass to the tool.
578
-
579
- Returns:
580
- The result of the tool execution as an AgentOutput object.
581
-
582
- Example:
583
- ```python
584
- async def execute_additional_tool(
585
- self, tool_name: str, arguments: Dict[str, Any]
586
- ) -> Optional[AgentToolResult]:
587
- if tool_name == "get_location":
588
- return get_location_tool(arguments)
589
- elif tool_name == "get_current_weather":
590
- return get_current_weather_tool(arguments)
591
- return None
592
-
593
- ```
594
- """
595
- return None
596
-
597
574
  async def _execute_tool_call(
598
575
  self, tool_name: str, arguments: Dict[str, Any]
599
576
  ) -> AgentToolResult:
@@ -610,10 +587,10 @@ class MCPBaseAgent(AgentProtocol):
610
587
  The result of the tool execution as an AgentToolResult object.
611
588
  """
612
589
  try:
613
- if additional_tool_result := await self.execute_additional_tool(
614
- tool_name, arguments
615
- ):
616
- return additional_tool_result
590
+ for custom_tool in self._custom_tools:
591
+ if custom_tool.tool_name == tool_name:
592
+ result = custom_tool.tool_executor(arguments)
593
+ return await result if isawaitable(result) else result
617
594
  except Exception as e:
618
595
  return AgentToolResult(
619
596
  tool_name=tool_name,
@@ -24,6 +24,7 @@ from rasa.agents.schemas import (
24
24
  AgentInput,
25
25
  AgentOutput,
26
26
  AgentToolResult,
27
+ AgentToolSchema,
27
28
  )
28
29
  from rasa.core.available_agents import AgentMCPServerConfig, ProtocolConfig
29
30
  from rasa.shared.agents.utils import make_agent_identifier
@@ -105,9 +106,9 @@ class MCPOpenAgent(MCPBaseAgent):
105
106
  @classmethod
106
107
  def get_agent_specific_built_in_tools(
107
108
  cls, agent_input: AgentInput
108
- ) -> List[Dict[str, Any]]:
109
+ ) -> List[AgentToolSchema]:
109
110
  """Get agentic specific built-in tools."""
110
- return [cls.get_task_completed_tool()]
111
+ return [AgentToolSchema.from_openai_json_format(cls.get_task_completed_tool())]
111
112
 
112
113
  def _run_task_completed_tool(
113
114
  self,
@@ -18,7 +18,9 @@ from rasa.agents.schemas import (
18
18
  AgentInput,
19
19
  AgentOutput,
20
20
  AgentToolResult,
21
+ AgentToolSchema,
21
22
  )
23
+ from rasa.agents.schemas.agent_input import AgentInputSlot
22
24
  from rasa.core.available_agents import AgentMCPServerConfig, ProtocolConfig
23
25
  from rasa.shared.agents.utils import make_agent_identifier
24
26
  from rasa.shared.constants import (
@@ -70,11 +72,18 @@ class MCPTaskAgent(MCPBaseAgent):
70
72
  @classmethod
71
73
  def get_agent_specific_built_in_tools(
72
74
  cls, agent_input: AgentInput
73
- ) -> List[Dict[str, Any]]:
75
+ ) -> List[AgentToolSchema]:
74
76
  """Get agentic specific built-in tools."""
77
+ slot_names = cls._get_slot_names_from_exit_conditions(agent_input)
78
+ slot_definitions = [
79
+ slot for slot in agent_input.slots if slot.name in slot_names
80
+ ]
81
+
75
82
  return [
76
- cls.get_slot_specific_set_slot_tool(slot_name)
77
- for slot_name in cls._get_slot_names_from_exit_conditions(agent_input)
83
+ AgentToolSchema.from_openai_json_format(
84
+ cls.get_slot_specific_set_slot_tool(slot)
85
+ )
86
+ for slot in slot_definitions
78
87
  ]
79
88
 
80
89
  @classmethod
@@ -89,11 +98,11 @@ class MCPTaskAgent(MCPBaseAgent):
89
98
  for name in re.findall(r"\bslots\.(\w+)", condition)
90
99
  }
91
100
 
101
+ slot_names = agent_input.slot_names
102
+
92
103
  # Keep only slots that actually exist in agent_input.slots
93
104
  valid_slot_names = [
94
- slot_name
95
- for slot_name in extracted_slot_names
96
- if slot_name in agent_input.slots
105
+ slot_name for slot_name in extracted_slot_names if slot_name in slot_names
97
106
  ]
98
107
 
99
108
  structlogger.debug(
@@ -105,15 +114,18 @@ class MCPTaskAgent(MCPBaseAgent):
105
114
  return valid_slot_names
106
115
 
107
116
  @classmethod
108
- def get_slot_specific_set_slot_tool(cls, slot_name: str) -> Dict[str, Any]:
117
+ def get_slot_specific_set_slot_tool(cls, slot: AgentInputSlot) -> Dict[str, Any]:
109
118
  """Get the set slot tool."""
119
+ tool_description = f"Set the slot '{slot.name}' to a specific value. "
120
+ tool_description += f"The slot type is {slot.type}."
121
+ if slot.type == "categorical":
122
+ tool_description += f" The allowed values are: {slot.allowed_values}."
123
+
110
124
  return {
111
125
  "type": "function",
112
126
  "function": {
113
- "name": f"set_slot_{slot_name}",
114
- # We need to add the description, slot type, and allowed values
115
- # (if present) to the description as well.
116
- "description": f"Set the slot {slot_name} to a specific value.",
127
+ "name": f"set_slot_{slot.name}",
128
+ "description": tool_description,
117
129
  "parameters": {
118
130
  "type": "object",
119
131
  "properties": {
@@ -234,12 +246,22 @@ class MCPTaskAgent(MCPBaseAgent):
234
246
  ),
235
247
  )
236
248
 
249
+ def render_prompt_template(self, context: AgentInput) -> str:
250
+ """Render the prompt template with the provided inputs."""
251
+ slot_names = self._get_slot_names_from_exit_conditions(context)
252
+
253
+ return Template(self.prompt_template).render(
254
+ **context.model_dump(exclude={"id", "timestamp", "events"}),
255
+ description=self._description,
256
+ slot_names=slot_names,
257
+ )
258
+
237
259
  async def send_message(self, agent_input: AgentInput) -> AgentOutput:
238
260
  """Send a message to the LLM and return the response."""
239
261
  messages = self.build_messages_for_llm_request(agent_input)
240
262
  tool_results: Dict[str, AgentToolResult] = {}
241
263
 
242
- _slots = agent_input.slots.copy()
264
+ _slot_values = {slot.name: slot.value for slot in agent_input.slots}
243
265
  _available_tools = self.get_available_tools(agent_input)
244
266
  _available_tools_names = [tool.name for tool in _available_tools]
245
267
 
@@ -337,10 +359,10 @@ class MCPTaskAgent(MCPBaseAgent):
337
359
  tool_call.tool_name
338
360
  ):
339
361
  if (
340
- slot_name in agent_input.slots
362
+ slot_name in _slot_values
341
363
  and "slot_value" in tool_call.tool_args
342
364
  ):
343
- _slots.update(
365
+ _slot_values.update(
344
366
  self._run_set_slot_tool(
345
367
  slot_name, tool_call.tool_args
346
368
  )
@@ -392,13 +414,13 @@ class MCPTaskAgent(MCPBaseAgent):
392
414
  )
393
415
 
394
416
  exit_met, internal_error = self._is_exit_conditions_met(
395
- agent_input, _slots
417
+ agent_input, _slot_values
396
418
  )
397
419
 
398
420
  # Agent signals task completion if exit conditions are met.
399
421
  if exit_met:
400
422
  return self._generate_agent_task_completed_output(
401
- agent_input, _slots, tool_results
423
+ agent_input, _slot_values, tool_results
402
424
  )
403
425
 
404
426
  # If an internal error occurred while checking the exit
@@ -1,6 +1,12 @@
1
1
  from rasa.agents.schemas.agent_input import AgentInput
2
2
  from rasa.agents.schemas.agent_output import AgentOutput
3
3
  from rasa.agents.schemas.agent_tool_result import AgentToolResult
4
- from rasa.agents.schemas.agent_tool_schema import AgentToolSchema
4
+ from rasa.agents.schemas.agent_tool_schema import AgentToolSchema, CustomToolSchema
5
5
 
6
- __all__ = ["AgentInput", "AgentOutput", "AgentToolSchema", "AgentToolResult"]
6
+ __all__ = [
7
+ "AgentInput",
8
+ "AgentOutput",
9
+ "AgentToolSchema",
10
+ "AgentToolResult",
11
+ "CustomToolSchema",
12
+ ]
@@ -5,12 +5,21 @@ from pydantic import BaseModel
5
5
  from rasa.shared.core.events import Event
6
6
 
7
7
 
8
+ class AgentInputSlot(BaseModel):
9
+ """A class that represents the schema of the input slot to the agent."""
10
+
11
+ name: str
12
+ value: Any
13
+ type: str
14
+ allowed_values: Optional[List[Any]] = None
15
+
16
+
8
17
  class AgentInput(BaseModel):
9
18
  """A class that represents the schema of the input to the agent."""
10
19
 
11
20
  id: str
12
21
  user_message: str
13
- slots: Dict[str, Any]
22
+ slots: List[AgentInputSlot]
14
23
  conversation_history: str
15
24
  events: List[Event]
16
25
  metadata: Dict[str, Any]
@@ -22,3 +31,8 @@ class AgentInput(BaseModel):
22
31
  """
23
32
 
24
33
  arbitrary_types_allowed = True
34
+
35
+ @property
36
+ def slot_names(self) -> List[str]:
37
+ """Get the names of the slots in the input."""
38
+ return [slot.name for slot in self.slots]
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, Optional
1
+ from typing import Any, Callable, Dict, Optional
2
2
 
3
3
  from mcp import Tool
4
4
  from pydantic import BaseModel
@@ -6,6 +6,7 @@ from pydantic import BaseModel
6
6
  from rasa.agents.constants import (
7
7
  TOOL_ADDITIONAL_PROPERTIES_KEY,
8
8
  TOOL_DESCRIPTION_KEY,
9
+ TOOL_EXECUTOR_KEY,
9
10
  TOOL_NAME_KEY,
10
11
  TOOL_PARAMETERS_KEY,
11
12
  TOOL_PROPERTIES_KEY,
@@ -110,3 +111,24 @@ class AgentToolSchema(BaseModel):
110
111
  TOOL_TYPE_KEY: TOOL_TYPE_FUNCTION_KEY,
111
112
  TOOL_TYPE_FUNCTION_KEY: self.model_dump(exclude={TOOL_TYPE_KEY}),
112
113
  }
114
+
115
+
116
+ class CustomToolSchema(BaseModel):
117
+ """A class that represents the schema of a custom agent tool."""
118
+
119
+ tool_name: str
120
+ tool_definition: AgentToolSchema
121
+ tool_executor: Callable
122
+
123
+ @classmethod
124
+ def from_dict(cls, config: Dict[str, Any]) -> "CustomToolSchema":
125
+ """Convert a custom tool config to CustomToolSchema."""
126
+ agent_tool_schema = AgentToolSchema.from_openai_json_format(config)
127
+ if TOOL_EXECUTOR_KEY not in config:
128
+ raise ValueError("Custom tool executor is required.")
129
+
130
+ return cls(
131
+ tool_name=agent_tool_schema.name,
132
+ tool_definition=agent_tool_schema,
133
+ tool_executor=config[TOOL_EXECUTOR_KEY],
134
+ )
@@ -1,8 +1,12 @@
1
1
  You are a helpful assistant that should assist the user in the best possible way.
2
2
 
3
- ### Task
3
+ ### Description of your capabilities
4
4
  {{ description }}
5
5
 
6
+ ### Task
7
+ * Use the tools available to gather the required information to set the following slots: {{ slot_names }}.
8
+ * In order to set the slot values, use the `set_slot_<slot_name>` tool.
9
+
6
10
  ### Instructions
7
11
  * Always make sure to output responses to the user in a clear, helpful format.
8
12
  * 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.
@@ -10,4 +14,4 @@ You are a helpful assistant that should assist the user in the best possible way
10
14
  * Strictly avoid making up information or ability to take some action which is not available in `tool` provided.
11
15
 
12
16
  ### Conversation history
13
- {{ conversation_history }}
17
+ {{ conversation_history }}
@@ -138,7 +138,7 @@ class FlowPolicy(Policy):
138
138
  # create executor and predict next action
139
139
  try:
140
140
  prediction = await flow_executor.advance_flows(
141
- tracker, domain.action_names_or_texts, flows
141
+ tracker, domain.action_names_or_texts, flows, domain.slots
142
142
  )
143
143
  return self._create_prediction_result(
144
144
  prediction.action_name,
@@ -165,7 +165,7 @@ class FlowPolicy(Policy):
165
165
  events = tracker.create_stack_updated_events(updated_stack)
166
166
  tracker.update_with_events(events)
167
167
  prediction = await flow_executor.advance_flows(
168
- tracker, domain.action_names_or_texts, flows
168
+ tracker, domain.action_names_or_texts, flows, domain.slots
169
169
  )
170
170
  collected_events = events + (prediction.events or [])
171
171
  return self._create_prediction_result(
@@ -16,6 +16,7 @@ from rasa.agents.constants import (
16
16
  )
17
17
  from rasa.agents.core.types import AgentStatus, ProtocolType
18
18
  from rasa.agents.schemas import AgentInput, AgentOutput
19
+ from rasa.agents.schemas.agent_input import AgentInputSlot
19
20
  from rasa.core.available_agents import AvailableAgents
20
21
  from rasa.core.available_endpoints import AvailableEndpoints
21
22
  from rasa.core.constants import ACTIVE_FLOW_METADATA_KEY, STEP_ID_METADATA_KEY
@@ -103,7 +104,7 @@ from rasa.shared.core.flows.steps import (
103
104
  SetSlotsFlowStep,
104
105
  )
105
106
  from rasa.shared.core.flows.steps.constants import START_STEP
106
- from rasa.shared.core.slots import Slot, SlotRejection
107
+ from rasa.shared.core.slots import CategoricalSlot, Slot, SlotRejection
107
108
  from rasa.shared.core.trackers import DialogueStateTracker
108
109
  from rasa.shared.utils.llm import tracker_as_readable_transcript
109
110
 
@@ -387,7 +388,10 @@ def reset_scoped_slots(
387
388
 
388
389
 
389
390
  async def advance_flows(
390
- tracker: DialogueStateTracker, available_actions: List[str], flows: FlowsList
391
+ tracker: DialogueStateTracker,
392
+ available_actions: List[str],
393
+ flows: FlowsList,
394
+ slots: List[Slot],
391
395
  ) -> FlowActionPrediction:
392
396
  """Advance the current flows until the next action.
393
397
 
@@ -395,6 +399,7 @@ async def advance_flows(
395
399
  tracker: The tracker to get the next action for.
396
400
  available_actions: The actions that are available in the domain.
397
401
  flows: All flows.
402
+ slots: The slots that are available in the domain.
398
403
 
399
404
  Returns:
400
405
  The predicted action and the events to run.
@@ -404,13 +409,16 @@ async def advance_flows(
404
409
  # if there are no flows, there is nothing to do
405
410
  return FlowActionPrediction(None, 0.0)
406
411
 
407
- return await advance_flows_until_next_action(tracker, available_actions, flows)
412
+ return await advance_flows_until_next_action(
413
+ tracker, available_actions, flows, slots
414
+ )
408
415
 
409
416
 
410
417
  async def advance_flows_until_next_action(
411
418
  tracker: DialogueStateTracker,
412
419
  available_actions: List[str],
413
420
  flows: FlowsList,
421
+ slots: List[Slot],
414
422
  ) -> FlowActionPrediction:
415
423
  """Advance the flow and select the next action to execute.
416
424
 
@@ -476,6 +484,7 @@ async def advance_flows_until_next_action(
476
484
  available_actions,
477
485
  flows,
478
486
  previous_step_id,
487
+ slots,
479
488
  )
480
489
  new_events = step_result.events
481
490
  if (
@@ -586,6 +595,7 @@ async def run_step(
586
595
  available_actions: List[str],
587
596
  flows: FlowsList,
588
597
  previous_step_id: str,
598
+ slots: List[Slot],
589
599
  ) -> FlowStepResult:
590
600
  """Run a single step of a flow.
591
601
 
@@ -604,6 +614,7 @@ async def run_step(
604
614
  available_actions: The actions that are available in the domain.
605
615
  flows: All flows.
606
616
  previous_step_id: The ID of the previous step.
617
+ slots: The slots that are available in the domain.
607
618
 
608
619
  Returns:
609
620
  A result of running the step describing where to transition to.
@@ -643,7 +654,7 @@ async def run_step(
643
654
  return _run_link_step(initial_events, stack, step)
644
655
 
645
656
  elif isinstance(step, CallFlowStep):
646
- return await _run_call_step(initial_events, stack, step, tracker)
657
+ return await _run_call_step(initial_events, stack, step, tracker, slots)
647
658
 
648
659
  elif isinstance(step, SetSlotsFlowStep):
649
660
  return _run_set_slot_step(initial_events, step)
@@ -717,12 +728,13 @@ async def _run_call_step(
717
728
  stack: DialogueStack,
718
729
  step: CallFlowStep,
719
730
  tracker: DialogueStateTracker,
731
+ slots: List[Slot],
720
732
  ) -> FlowStepResult:
721
733
  structlogger.debug("flow.step.run.call")
722
734
  if step.is_calling_mcp_tool():
723
735
  return await call_mcp_tool(initial_events, stack, step, tracker)
724
736
  elif step.is_calling_agent():
725
- return await run_agent(initial_events, stack, step, tracker)
737
+ return await run_agent(initial_events, stack, step, tracker, slots)
726
738
  else:
727
739
  stack.push(
728
740
  UserFlowStackFrame(
@@ -885,6 +897,7 @@ async def run_agent(
885
897
  stack: DialogueStack,
886
898
  step: CallFlowStep,
887
899
  tracker: DialogueStateTracker,
900
+ slots: List[Slot],
888
901
  ) -> FlowStepResult:
889
902
  """Run an agent call step."""
890
903
  structlogger.debug(
@@ -942,7 +955,7 @@ async def run_agent(
942
955
  user_message=tracker.latest_message.text or ""
943
956
  if tracker.latest_message
944
957
  else "",
945
- slots=_filter_slots_for_agent(tracker.current_slot_values()),
958
+ slots=_prepare_slots_for_agent(tracker.current_slot_values(), slots),
946
959
  conversation_history=tracker_as_readable_transcript(tracker),
947
960
  events=tracker.current_state().get("events") or [],
948
961
  metadata=agent_input_metadata,
@@ -1156,18 +1169,43 @@ async def _call_agent_with_retry(
1156
1169
  )
1157
1170
 
1158
1171
 
1159
- def _filter_slots_for_agent(slots: Dict[str, Any]) -> Dict[str, Any]:
1160
- """Filter out slots that should not be forwarded to agents.
1172
+ def _prepare_slots_for_agent(
1173
+ slot_values: Dict[str, Any], slot_definitions: List[Slot]
1174
+ ) -> List[AgentInputSlot]:
1175
+ """Prepare the slots for the agent.
1176
+
1177
+ Filter out slots that should not be forwarded to agents.
1178
+ Add the slot type and allowed values to the slot dictionary.
1161
1179
 
1162
1180
  Args:
1163
- slots: The full slot dictionary from the tracker.
1181
+ slot_values: The full slot dictionary from the tracker.
1182
+ slot_definitions: The slot definitions from the domain.
1164
1183
 
1165
1184
  Returns:
1166
- A copy of the slot dictionary excluding slots listed in
1167
- `SLOTS_EXCLUDED_FOR_AGENT`.
1185
+ A list of slots containing the name, current value, type, and allowed values.
1168
1186
  """
1169
- return {
1170
- key: value
1171
- for key, value in slots.items()
1172
- if key not in SLOTS_EXCLUDED_FOR_AGENT
1173
- }
1187
+
1188
+ def _get_slot_definition(slot_name: str) -> Optional[Slot]:
1189
+ for slot in slot_definitions:
1190
+ if slot.name == slot_name:
1191
+ return slot
1192
+ return None
1193
+
1194
+ filtered_slots: List[AgentInputSlot] = []
1195
+ for key, value in slot_values.items():
1196
+ if key in SLOTS_EXCLUDED_FOR_AGENT:
1197
+ continue
1198
+ slot_definition = _get_slot_definition(key)
1199
+ if slot_definition:
1200
+ filtered_slots.append(
1201
+ AgentInputSlot(
1202
+ name=key,
1203
+ value=value,
1204
+ type=slot_definition.type_name if slot_definition else "any",
1205
+ allowed_values=slot_definition.values
1206
+ if isinstance(slot_definition, CategoricalSlot)
1207
+ else None,
1208
+ )
1209
+ )
1210
+
1211
+ return filtered_slots
@@ -1,4 +1,6 @@
1
1
  import json
2
+ import operator
3
+ from functools import reduce
2
4
  from typing import Any, Dict, List, Optional
3
5
 
4
6
  import structlog
@@ -17,10 +19,12 @@ from rasa.shared.core.events import Event, SlotSet
17
19
  from rasa.shared.core.flows.steps import CallFlowStep
18
20
  from rasa.shared.core.trackers import DialogueStateTracker
19
21
  from rasa.shared.utils.mcp.server_connection import MCPServerConnection
22
+ from rasa.utils.common import ensure_jsonified_iterable
20
23
 
21
24
  structlogger = structlog.get_logger()
22
25
 
23
- SEPARATOR = "\n###\n"
26
+ CONFIG_RESULT_KEY = "result_key"
27
+ CONFIG_SLOT = "slot"
24
28
 
25
29
 
26
30
  async def call_mcp_tool(
@@ -101,7 +105,7 @@ async def _execute_mcp_tool_call(
101
105
  result = await mcp_server.call_tool(step.call, arguments)
102
106
 
103
107
  # Handle tool execution result
104
- if result.isError:
108
+ if result is None or result.isError:
105
109
  return _handle_mcp_tool_error(
106
110
  stack,
107
111
  initial_events,
@@ -121,12 +125,20 @@ async def _execute_mcp_tool_call(
121
125
  tool_name=step.call,
122
126
  mcp_server=step.mcp_server,
123
127
  result_content=result.content,
128
+ result_structured_content=result.structuredContent,
124
129
  )
125
130
 
126
131
  # Process successful result
127
- set_slot_event = _process_tool_result(result, step.mapping["output"])
128
- if set_slot_event:
129
- initial_events.append(set_slot_event)
132
+ if set_slot_event := _process_tool_result(result, step.mapping["output"]):
133
+ initial_events.extend(set_slot_event)
134
+ else:
135
+ return _handle_mcp_tool_error(
136
+ stack,
137
+ initial_events,
138
+ f"Failed to process tool result for '{step.call}'.",
139
+ tool_name=step.call,
140
+ mcp_server=step.mcp_server,
141
+ )
130
142
 
131
143
  return ContinueFlowWithNextStep(events=initial_events)
132
144
 
@@ -203,16 +215,41 @@ def _prepare_tool_arguments(
203
215
  return arguments
204
216
 
205
217
 
218
+ def _jsonify_slot_value(value: Any) -> str | int | float | bool | None:
219
+ """Prepare value for SlotSet: iterables -> JSON string, primitives -> as-is"""
220
+ if isinstance(value, (list, dict)) and len(value):
221
+ return json.dumps(ensure_jsonified_iterable(value))
222
+ return value
223
+
224
+
206
225
  def _process_tool_result(
207
226
  result: CallToolResult,
208
- output_mapping: str,
209
- ) -> Optional[SlotSet]:
227
+ output_mapping: List[Dict[str, str]],
228
+ ) -> Optional[List[SlotSet]]:
210
229
  """Create a SetSlot event for the tool result."""
211
230
  try:
212
- content_as_string = [
213
- json.dumps(content_part.model_dump()) for content_part in result.content
214
- ]
215
- return SlotSet(key=output_mapping, value=SEPARATOR.join(content_as_string))
231
+ _result_as_dict = {"result": result.model_dump()}
232
+ slots = []
233
+ for mapping in output_mapping:
234
+ try:
235
+ # Use reduce to navigate through nested keys in the result
236
+ slot_value = reduce(
237
+ operator.getitem,
238
+ mapping[CONFIG_RESULT_KEY].split("."),
239
+ _result_as_dict,
240
+ )
241
+ slots.append(
242
+ SlotSet(mapping[CONFIG_SLOT], _jsonify_slot_value(slot_value))
243
+ )
244
+ except (KeyError, TypeError):
245
+ structlogger.error(
246
+ "call_mcp_tool.result_key_not_found_in_tool_result",
247
+ slot=mapping[CONFIG_SLOT],
248
+ result_key=mapping[CONFIG_RESULT_KEY],
249
+ result=_result_as_dict,
250
+ )
251
+ return None
252
+ return slots
216
253
  except Exception as e:
217
254
  structlogger.error(
218
255
  "call_mcp_tool.result_processing_failed",
@@ -21,7 +21,9 @@ from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
21
21
  FlowStackFrameType,
22
22
  UserFlowStackFrame,
23
23
  )
24
+ from rasa.dialogue_understanding.stack.frames.pattern_frame import PatternFlowStackFrame
24
25
  from rasa.dialogue_understanding.stack.utils import (
26
+ is_continue_interrupted_flow_active,
25
27
  top_user_flow_frame,
26
28
  user_flows_on_the_stack,
27
29
  )
@@ -97,13 +99,26 @@ class StartFlowCommand(Command):
97
99
  # if the original top flow is the same as the flow to start, the flow is
98
100
  # already active, do nothing
99
101
  if original_top_flow is not None and original_top_flow.id == self.flow:
100
- return []
102
+ # in case continue_interrupted is not active, skip the already active start
103
+ # flow command
104
+ if not is_continue_interrupted_flow_active(stack):
105
+ return []
106
+
107
+ # if the continue interrupted flow is active, and the command generator
108
+ # predicted a start flow command for the flow which is on top of the stack,
109
+ # we just need to remove the pattern_continue_interrupted frame(s) from the
110
+ # stack
111
+ stack = _remove_pattern_continue_interrupted_frames(stack)
112
+ return applied_events + tracker.create_stack_updated_events(stack)
101
113
 
102
114
  # if the flow is already on the stack, resume it
103
115
  if (
104
116
  self.flow in user_flows_on_the_stack(stack)
105
117
  and original_user_frame is not None
106
118
  ):
119
+ # if pattern_continue_interrupted is active, we need to remove it
120
+ # from the stack before resuming the flow
121
+ stack = _remove_pattern_continue_interrupted_frames(stack)
107
122
  return self.resume_flow(tracker, stack, original_user_frame)
108
123
 
109
124
  frame_type = FlowStackFrameType.REGULAR
@@ -265,3 +280,23 @@ class StartFlowCommand(Command):
265
280
  frames_to_resume.append(frame)
266
281
 
267
282
  return list(frames_to_resume), frame_to_resume
283
+
284
+
285
+ def _remove_pattern_continue_interrupted_frames(stack: DialogueStack) -> DialogueStack:
286
+ """Remove pattern_continue_interrupted frames from the stack."""
287
+ if not is_continue_interrupted_flow_active(stack):
288
+ return stack
289
+
290
+ # remove pattern_continue_interrupted from the stack
291
+ top_frame = stack.top()
292
+ while isinstance(top_frame, PatternFlowStackFrame):
293
+ # If the top frame is a pattern frame, we need to remove it
294
+ # before continuing with the active user flow frame.
295
+ # This prevents the pattern frame
296
+ # from being left on the stack when the flow is started
297
+ # which would prevent pattern_completed to be triggered
298
+ # once the user flow is completed.
299
+ stack.pop()
300
+ top_frame = stack.top()
301
+
302
+ return stack
@@ -135,13 +135,13 @@ slots:
135
135
  type: bool
136
136
  initial_value: false
137
137
  confirmation_continue_interrupted_flow:
138
- type: bool
139
- initial_value: null
140
- mappings:
141
- - type: controlled
138
+ type: bool
139
+ mappings:
140
+ - type: from_llm
142
141
  interrupted_flow_to_continue:
143
142
  type: text
144
- initial_value: null
143
+ mappings:
144
+ - type: from_llm
145
145
 
146
146
  flows:
147
147
  pattern_cancel_flow:
@@ -37,6 +37,7 @@ from rasa.dialogue_understanding.stack.frames import (
37
37
  BaseFlowStackFrame,
38
38
  )
39
39
  from rasa.dialogue_understanding.stack.utils import (
40
+ is_continue_interrupted_flow_active,
40
41
  top_flow_frame,
41
42
  top_user_flow_frame,
42
43
  )
@@ -428,22 +429,9 @@ def clean_up_commands(
428
429
  )
429
430
 
430
431
  elif isinstance(command, StartFlowCommand):
431
- top_user_frame = top_user_flow_frame(
432
- tracker.stack, ignore_call_and_link_frames=False
432
+ clean_commands = clean_up_start_flow_command(
433
+ clean_commands, tracker, command
433
434
  )
434
- top_flow_id = top_user_frame.flow_id if top_user_frame else ""
435
-
436
- if top_flow_id == command.flow:
437
- # drop a start flow command if the starting flow is equal
438
- # to the currently active flow
439
- structlogger.debug(
440
- "command_processor.clean_up_commands."
441
- "skip_command_flow_already_active",
442
- command=command,
443
- )
444
- continue
445
-
446
- clean_commands.append(command)
447
435
 
448
436
  # handle chitchat command differently from other free-form answer commands
449
437
  elif isinstance(command, ChitChatAnswerCommand):
@@ -529,6 +517,34 @@ def ensure_max_number_of_command_type(
529
517
  return filtered
530
518
 
531
519
 
520
+ def clean_up_start_flow_command(
521
+ clean_commands: List[Command],
522
+ tracker: DialogueStateTracker,
523
+ command: StartFlowCommand,
524
+ ) -> List[Command]:
525
+ """Clean up a start flow command."""
526
+ continue_interrupted_flow_active = is_continue_interrupted_flow_active(
527
+ tracker.stack
528
+ )
529
+
530
+ top_user_frame = top_user_flow_frame(
531
+ tracker.stack, ignore_call_and_link_frames=False
532
+ )
533
+ top_flow_id = top_user_frame.flow_id if top_user_frame else ""
534
+
535
+ if top_flow_id == command.flow and not continue_interrupted_flow_active:
536
+ # drop a start flow command if the starting flow is equal
537
+ # to the currently active flow
538
+ structlogger.debug(
539
+ "command_processor.clean_up_commands." "skip_command_flow_already_active",
540
+ command=command,
541
+ )
542
+ return clean_commands
543
+
544
+ clean_commands.append(command)
545
+ return clean_commands
546
+
547
+
532
548
  def clean_up_clarify_command(
533
549
  commands_so_far: List[Command],
534
550
  all_commands: List[Command],
@@ -231,3 +231,17 @@ def get_collect_steps_excluding_ask_before_filling_for_active_flow(
231
231
  for step in active_flow.get_collect_steps()
232
232
  if not step.ask_before_filling
233
233
  )
234
+
235
+
236
+ def is_continue_interrupted_flow_active(stack: DialogueStack) -> bool:
237
+ """Check if the continue interrupted flow is active."""
238
+ from rasa.dialogue_understanding.patterns.continue_interrupted import (
239
+ ContinueInterruptedPatternFlowStackFrame,
240
+ )
241
+
242
+ for frame in reversed(stack.frames):
243
+ if isinstance(frame, ContinueInterruptedPatternFlowStackFrame):
244
+ return True
245
+ if isinstance(frame, UserFlowStackFrame):
246
+ return False
247
+ return False
@@ -233,7 +233,18 @@
233
233
  }
234
234
  }
235
235
  },
236
- "output": {"type": "string"}
236
+ "output": {
237
+ "type": "array",
238
+ "items": {
239
+ "type": "object",
240
+ "additionalProperties": false,
241
+ "required": ["slot", "result_key"],
242
+ "properties": {
243
+ "slot": {"type": "string"},
244
+ "result_key": {"type": "string"}
245
+ }
246
+ }
247
+ }
237
248
  }
238
249
  },
239
250
  "exit_if": {
@@ -18,11 +18,13 @@ class CallFlowStep(FlowStep):
18
18
  call: Text
19
19
  """The flow to be called or the ID of the agent to be called."""
20
20
  called_flow_reference: Optional["Flow"] = None
21
+
21
22
  # MCP Tool calling
22
23
  """The MCP server that hosts the tool to be called."""
23
24
  mcp_server: Optional[str] = None
24
25
  """The input and output mapping for the MCP tool."""
25
26
  mapping: Optional[Dict[str, Any]] = None
27
+
26
28
  # Call agent exit condition
27
29
  """A list of slot predicates that determine when to exit the agent loop."""
28
30
  exit_if: Optional[List[str]] = None
@@ -595,14 +595,15 @@ def validate_call_steps(flows: "FlowsList") -> None:
595
595
  if not isinstance(step, CallFlowStep):
596
596
  continue
597
597
 
598
+ _is_step_calling_agent = step.is_calling_agent()
598
599
  if (
599
- not step.is_calling_agent()
600
+ not _is_step_calling_agent
600
601
  and flows.flow_by_id(step.call) is None
601
602
  and not step.is_calling_mcp_tool()
602
603
  ):
603
604
  raise UnresolvedCallStepException(step.call, flow.id, step.id)
604
605
 
605
- if step.exit_if and not step.is_calling_agent():
606
+ if step.exit_if and not _is_step_calling_agent:
606
607
  # exit_if is only allowed for call steps that call an agent
607
608
  raise RasaException(
608
609
  f"Call step '{step.id}' in flow '{flow.id}' has an 'exit_if' "
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
@@ -699,3 +700,28 @@ def get_bool_env_variable(variable_name: str, default_variable_value: bool) -> b
699
700
  f"Available values are `{true_values + false_values}`"
700
701
  )
701
702
  return value.lower() in true_values
703
+
704
+
705
+ def try_parse_json(value: Any) -> Any:
706
+ """If value is a JSON string, parse it into a dict/list, else return as-is."""
707
+ if isinstance(value, str):
708
+ try:
709
+ return json.loads(value)
710
+ except json.JSONDecodeError:
711
+ return value
712
+ return value
713
+
714
+
715
+ def ensure_jsonified_iterable(value: Any) -> Any:
716
+ """Convert iterables to JSON strings, flatten nested JSON strings in dicts/lists."""
717
+ if isinstance(value, dict):
718
+ # Recursively process dict values
719
+ return {
720
+ key: ensure_jsonified_iterable(try_parse_json(val))
721
+ for key, val in value.items()
722
+ }
723
+ elif isinstance(value, list):
724
+ # Recursively process each item
725
+ return [ensure_jsonified_iterable(try_parse_json(val)) for val in value]
726
+ # Keep primitives as-is
727
+ return value
rasa/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # this file will automatically be changed,
2
2
  # do not add anything but the version number here!
3
- __version__ = "3.14.0.dev2"
3
+ __version__ = "3.14.0.dev3"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rasa-pro
3
- Version: 3.14.0.dev2
3
+ Version: 3.14.0.dev3
4
4
  Summary: State-of-the-art open-core Conversational AI framework for Enterprises that natively leverages generative AI for effortless assistant development.
5
5
  Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
6
6
  Author: Rasa Technologies GmbH
@@ -2,8 +2,8 @@ rasa/__init__.py,sha256=YXG8RzVxiSJ__v-AewtV453YoCbmzWlHsU_4S0O2XpE,206
2
2
  rasa/__main__.py,sha256=TVYPpDdKKnTxC9RRaPxAaoDosH8-UDMBPfd-UP7YBGg,6645
3
3
  rasa/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  rasa/agents/agent_factory.py,sha256=7v7mdMrTnG5KEg6gCmwPtlT637I6xight90h--syh_c,4675
5
- rasa/agents/agent_manager.py,sha256=1V39cDTHyJo_T2WLvW5nmDY2VjTe-Kp4FqnOfdJKZ8U,5965
6
- rasa/agents/constants.py,sha256=JKrVNMUSDul6vbuJa9JbzirXWE1kSBT32EYk7jLEYeQ,878
5
+ rasa/agents/agent_manager.py,sha256=NVrE3IEwKhlhA9YdbBsnSDBFbkBDbWrmAkIe06LAXiQ,5957
6
+ rasa/agents/constants.py,sha256=0Uc2ZWHChauubr3g84YCT6-E0lLrbtZ-oju3dUuTfzY,914
7
7
  rasa/agents/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  rasa/agents/core/agent_protocol.py,sha256=gqWignz64lnYWzv1GgYEdj5221nU_vNW49LhOMRZBpY,3397
9
9
  rasa/agents/core/types.py,sha256=5Ht6m5lgaNAtdmeCybBTA6MUoNeGPWaGgQgPsBCoYUw,2164
@@ -12,17 +12,17 @@ rasa/agents/protocol/__init__.py,sha256=rDR_QdaWuHvkHTKF1MmgzjIk7T8m__KJIK9wtjQn
12
12
  rasa/agents/protocol/a2a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  rasa/agents/protocol/a2a/a2a_agent.py,sha256=t1voRAwp5RSDK7r5lT7T0DITagkXXvaX4QXoXi087S0,1662
14
14
  rasa/agents/protocol/mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- rasa/agents/protocol/mcp/mcp_base_agent.py,sha256=684sIyL7_V4mTg_2t5lIJ7o7AwSQLYbHcf8SF6fdF3c,26704
16
- rasa/agents/protocol/mcp/mcp_open_agent.py,sha256=oYcCHM2KS4RuIlJHYSw4mn35MW0l2_FBz5dozO5kovE,10748
17
- rasa/agents/protocol/mcp/mcp_task_agent.py,sha256=9XW863Qu6WwHVxKx4z4lOXRv0LEGjG-1XeKHHzc3E-Q,18146
18
- rasa/agents/schemas/__init__.py,sha256=XW--Bw9bfCnSv_-NGyUQ0sHwLk4ta9tfh5d9FLHVNSk,323
19
- rasa/agents/schemas/agent_input.py,sha256=JF1ZcTJpy4_Dk9jOF4sTBScwfliL5pFLPabYB0NlOLA,602
15
+ rasa/agents/protocol/mcp/mcp_base_agent.py,sha256=rOSvuIaqp4MDPqRL9EEWsvxTQGtYl0dzLhQJhBmNjmI,25938
16
+ rasa/agents/protocol/mcp/mcp_open_agent.py,sha256=U-dRX2U_r-3Ep7iuk_fkrNqY822tGLucWfEW72zXtiY,10811
17
+ rasa/agents/protocol/mcp/mcp_task_agent.py,sha256=3xFnIOWQSG-zD9fPBXDBGU4v_qxnj95psjwAdcIqDtA,19022
18
+ rasa/agents/schemas/__init__.py,sha256=6iNKhFCh3UTFTfIeYJpRyMKvENucXpBZ7IiqNGOaM_Q,384
19
+ rasa/agents/schemas/agent_input.py,sha256=11LK0cMnuU29gwZD-zs0BOepnVfxxeWuY0Ax4nb6LPE,970
20
20
  rasa/agents/schemas/agent_output.py,sha256=Gc5W-d9ZGBY3JmTNVLiMCtw09my482HM-kWPSy34Evs,784
21
21
  rasa/agents/schemas/agent_tool_result.py,sha256=HkjFxn0f4_ubkAKLwxpC6kj0ciCf5FXSG7yaqTmsHKg,1689
22
- rasa/agents/schemas/agent_tool_schema.py,sha256=0CJWKJt2TtFJ6EG8s_sgRmMFMj0SeTz024juY-4OXCo,3847
22
+ rasa/agents/schemas/agent_tool_schema.py,sha256=V79xiei2Dkkuy_ivBKkoA7R3Z_bR7VbfvULguFP7JAk,4586
23
23
  rasa/agents/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  rasa/agents/templates/mcp_open_agent_prompt_template.jinja2,sha256=2sW5_oO1xqMdeLTd93ONLclN4CmNexu9py0nHg3gj5w,1139
25
- rasa/agents/templates/mcp_task_agent_prompt_template.jinja2,sha256=zpSwNBXnLwJAPQfiIGhRLzJe2TdgYsW5vyXj3Hp5FBs,660
25
+ rasa/agents/templates/mcp_task_agent_prompt_template.jinja2,sha256=EW5qB0Fx5SGcLvbn5776SJyaTRqXTqq61KF8kYjJrMI,878
26
26
  rasa/agents/utils.py,sha256=AsKTP4OXFgOWOeXxnnc9suWUWshkTopSiNZL7mpXj68,2471
27
27
  rasa/api.py,sha256=GLO3rTiGJ1HV9EZe3yEDD1ymtqP9t_JIeFwoOoP95I4,6542
28
28
  rasa/cli/__init__.py,sha256=eO5vp9rFCANtbTVU-pxN3iMBKw4p9WRcgzytt9MzinY,115
@@ -351,12 +351,12 @@ rasa/core/policies/enterprise_search_policy_config.py,sha256=rTIGBrfGfe_lvsYQW1c
351
351
  rasa/core/policies/enterprise_search_prompt_template.jinja2,sha256=dCS_seyBGxMQoMsOjjvPp0dd31OSzZCJSZeev1FJK5Q,1187
352
352
  rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2,sha256=va9rpP97dN3PKoJZOVfyuISt3cPBlb10Pqyz25RwO_Q,3294
353
353
  rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2,sha256=b_8ZzK1ar0SvLZRFS8d9tHWvYS7Xb8xPJiBKg-UcyAM,3743
354
- rasa/core/policies/flow_policy.py,sha256=5nmo2fXvQDvkikku21yEO4J4J5Mmflb_EowJOYyt8q4,7482
354
+ rasa/core/policies/flow_policy.py,sha256=Ulh3pjc1Yi4oJ4oLdmMgv9_SxcqO39m2AohhZaOEJgM,7510
355
355
  rasa/core/policies/flows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
356
356
  rasa/core/policies/flows/flow_exceptions.py,sha256=_FQuN-cerQDM1pivce9bz4zylh5UYkljvYS1gjDukHI,1527
357
- rasa/core/policies/flows/flow_executor.py,sha256=BLJc7P-4yPuPlq4aTLgyxklBApeacKcw639b4k1OxkE,41307
357
+ rasa/core/policies/flows/flow_executor.py,sha256=PxoF7dQe9kksbF5zOAPwUEXNphtN6qYCm1kScL3piB0,42631
358
358
  rasa/core/policies/flows/flow_step_result.py,sha256=agjPrD6lahGSe2ViO5peBeoMdI9ngVGRSgtytgxmJmg,1360
359
- rasa/core/policies/flows/mcp_tool_executor.py,sha256=EB84lv8AHFhYhW_Yi_59PporQuWVBg5QSk5IFQHVMz0,7884
359
+ rasa/core/policies/flows/mcp_tool_executor.py,sha256=EUyJ5puyYnClGMAeP2zebQ4dQYjH8DHFMJAVo-ZuRow,9384
360
360
  rasa/core/policies/intentless_policy.py,sha256=1A7FSkI4PQdN3t1p3GQhSImmO-m6UVCUzzEsjxz4nKc,38040
361
361
  rasa/core/policies/intentless_prompt_template.jinja2,sha256=KhIL3cruMmkxhrs5oVbqgSvK6ZiN_6TQ_jXrgtEB-ZY,677
362
362
  rasa/core/policies/memoization.py,sha256=CX2d3yP7FehSMW92Wi9NYLZei7tBzoT3T6yybu-Nb5s,19377
@@ -419,7 +419,7 @@ rasa/dialogue_understanding/commands/session_end_command.py,sha256=ZecUpYZDTX_68
419
419
  rasa/dialogue_understanding/commands/session_start_command.py,sha256=FA4yocMnFt5bn2dmXj48S4Pq_yTlEnOBxgK_mq-qAxg,1704
420
420
  rasa/dialogue_understanding/commands/set_slot_command.py,sha256=VWyv98yk65Jg-unKmytrbNeEsdNUfVkq7TrUzAMNQAs,7299
421
421
  rasa/dialogue_understanding/commands/skip_question_command.py,sha256=SlPeY0__XiRocUzBVW13kecxVNL5t7XtbOKvvVIWccQ,3387
422
- rasa/dialogue_understanding/commands/start_flow_command.py,sha256=GoJYits3xEMRK-TXJwBHIORvCuIznaW-Bb61OqsE7-s,9230
422
+ rasa/dialogue_understanding/commands/start_flow_command.py,sha256=pQlC9wRcjRurieUT44-cHAUo8Hgi3j1oICDLK4bG5KQ,10965
423
423
  rasa/dialogue_understanding/commands/user_silence_command.py,sha256=DQjRfZk09sV1o2emnLkmX7cZpsJwBHNeJGBDQVkejjY,1686
424
424
  rasa/dialogue_understanding/commands/utils.py,sha256=OpK_virArtaQaFbrV0v57MXB5SH_CIIQ2UQelNYjN9A,4814
425
425
  rasa/dialogue_understanding/constants.py,sha256=_kB0edGV23uvhujlF193N2jk6YG0R6LC599YDX5B5vo,129
@@ -464,7 +464,7 @@ rasa/dialogue_understanding/patterns/collect_information.py,sha256=8YWvhFTt8CJML
464
464
  rasa/dialogue_understanding/patterns/completed.py,sha256=7qkyUj2d__2R3mpwWVmQpfwCCbJruBrjRZbmbDr3Zbo,1278
465
465
  rasa/dialogue_understanding/patterns/continue_interrupted.py,sha256=FQRM0c9ly7LT_CpoY27dHumjhSUcrDkpY7vBo8d_ShU,7484
466
466
  rasa/dialogue_understanding/patterns/correction.py,sha256=7fQ02-JU1CGZiTjTi9YqmD1F4o-9Tv5WCAXnFgZlvtY,11380
467
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml,sha256=ql94NZvUE2Pzh4NfpMJ9SP57ONPGEJa8hWUSbVOCpIA,12904
467
+ rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml,sha256=dKve0DQxR2g-yMdOLtBI1RkiV1sqbY8BfQIcLBmMFM8,12883
468
468
  rasa/dialogue_understanding/patterns/domain_for_patterns.py,sha256=Zv_lCJn4nbkxeNYOPGsR0V8tmYAUsM_Ho_9to8hku-o,6493
469
469
  rasa/dialogue_understanding/patterns/human_handoff.py,sha256=1hkSdL6kui42rZc7zERZ9R7nLyvRHi_tHgNU7FyrhAQ,1132
470
470
  rasa/dialogue_understanding/patterns/internal_error.py,sha256=APCKVv16M6mSQ4upu4UwG0yIaaKTyr7uB2yV8ZtpMzo,1609
@@ -476,7 +476,7 @@ rasa/dialogue_understanding/patterns/skip_question.py,sha256=fJ1MC0WEEtS-BpnGJEf
476
476
  rasa/dialogue_understanding/patterns/user_silence.py,sha256=xP-QMnd-MsybH5z4g01hBv4OLOHcw6m3rc26LQfe2zo,1140
477
477
  rasa/dialogue_understanding/patterns/validate_slot.py,sha256=hqd5AEGT3M3HLNhMwuI9W9kZNCvgU6GyI-2xc2b4kz8,2085
478
478
  rasa/dialogue_understanding/processor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
479
- rasa/dialogue_understanding/processor/command_processor.py,sha256=X1sc0y1nPhmHiDRaREVCbIblsLIoAny7S1eQq6BNVmI,33507
479
+ rasa/dialogue_understanding/processor/command_processor.py,sha256=QgJGKM9rkY6FoBoXbYYcuyl21flEd_xuMkLoSxVSU6w,33927
480
480
  rasa/dialogue_understanding/processor/command_processor_component.py,sha256=rkErI_Uo7s3LsEojUSGSRbWGyGaX7GtGOYSJn0V-TI4,1650
481
481
  rasa/dialogue_understanding/stack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
482
482
  rasa/dialogue_understanding/stack/dialogue_stack.py,sha256=UmE5r1Jy0Yy-JIJHb4nQQhbQM-GDySnvZqFDXMCbk64,9528
@@ -486,7 +486,7 @@ rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py,sha256=SBTmCV4S
486
486
  rasa/dialogue_understanding/stack/frames/flow_stack_frame.py,sha256=h0qeWxPSEj0lWC2TMSjBHc_H4oYWrbOvX_24kAxY8Zk,7253
487
487
  rasa/dialogue_understanding/stack/frames/pattern_frame.py,sha256=EVrYWv5dCP7XTvNV-HqtOOrseP-IkF0jD2_JacAvIYw,235
488
488
  rasa/dialogue_understanding/stack/frames/search_frame.py,sha256=Eo6tSSbJpslKcs6DLu250NmtoKMe4bDHC8_ebx5sJ60,759
489
- rasa/dialogue_understanding/stack/utils.py,sha256=rA3P4XlAXPucm6qLhmaTxj72QDqJ8FPsBbjRsqZ_zrY,8287
489
+ rasa/dialogue_understanding/stack/utils.py,sha256=VFdxx5j9s8Y0ywPCYNFajugDgyeWvFDNgvWQ9ellZo0,8782
490
490
  rasa/dialogue_understanding/utils.py,sha256=p-KVd7VF21HFHwRMHp5zAnOcMs_BMkVnDgY17TLSUy8,7804
491
491
  rasa/dialogue_understanding_test/README.md,sha256=klUCq_FYd0MkIeyxlwYCfsB9EEsSmXUpTTDTxdR7EPc,17764
492
492
  rasa/dialogue_understanding_test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -690,11 +690,11 @@ rasa/shared/core/flows/flow_step.py,sha256=b1O2b5sJJP9lyPzcAStNJITYcPQWlyIlsu2qX
690
690
  rasa/shared/core/flows/flow_step_links.py,sha256=UNlE8xuhi-8R3CL2HPLEp0sAaKP_Obhv5yHSRNsiP8Q,11054
691
691
  rasa/shared/core/flows/flow_step_sequence.py,sha256=yFtG_1ihI7hUK8I1izawMWVPPct4uh1iW2U0BVeCzUk,2537
692
692
  rasa/shared/core/flows/flows_list.py,sha256=k3EsDTh6L7CSSeLmUInRbeU5lat29wofWs9FrYjerrw,9397
693
- rasa/shared/core/flows/flows_yaml_schema.json,sha256=Oiiq5OD3s6YsADfRPvajPhKIqRhOG3Fmrp7nt8OM61s,11112
693
+ rasa/shared/core/flows/flows_yaml_schema.json,sha256=CYqn3utfKxt2JbsuMmrLX6_m0NMyANidb2u2b8D-S1c,11631
694
694
  rasa/shared/core/flows/nlu_trigger.py,sha256=ujLXFo5WjIwtwRVEdxZkaE2fbd4KEmayeFPAd1mF26I,4352
695
695
  rasa/shared/core/flows/steps/__init__.py,sha256=jvJp02o9_Wx-rZeQ3SYiLVMpO6ulS1yKuiiKg0ld_nE,655
696
696
  rasa/shared/core/flows/steps/action.py,sha256=fRtNXLCK-r74tX3-rHyn_eKv7cRYRoNfEW2lCK0VdrQ,1920
697
- rasa/shared/core/flows/steps/call.py,sha256=Gvw1x90_y4a-GDAXXbOlKPXkT5V7hkhG3A8YaykursE,4189
697
+ rasa/shared/core/flows/steps/call.py,sha256=zl1NjBY1-YulIZeBcZFvtEXTNbpkPChhaM8QujcTXrs,4191
698
698
  rasa/shared/core/flows/steps/collect.py,sha256=XQSGnPeC_vS-qDvJInBc5uZ9-9p-AQZZXRAh7LMCfnE,5775
699
699
  rasa/shared/core/flows/steps/constants.py,sha256=DCxrEUGbJciBknHm-_t4tmcnH19IZKP-WYxqix9gm7M,132
700
700
  rasa/shared/core/flows/steps/continuation.py,sha256=5Rzayr80FsgS4bAajuRObVvVcLqPEh9nxGbT2te85xY,1498
@@ -705,7 +705,7 @@ rasa/shared/core/flows/steps/no_operation.py,sha256=ofcJmmqKHpjHDp23ZgAMVs60blwf
705
705
  rasa/shared/core/flows/steps/set_slots.py,sha256=NnPyHxY5gBiJ83qTbxRmgKh8BIMdi9U1TT71EfV35eE,1710
706
706
  rasa/shared/core/flows/steps/start.py,sha256=AJpKIm0S3GZYLEs3ybXW0Zrq03Pu9lvirNahiUy2I6k,1010
707
707
  rasa/shared/core/flows/utils.py,sha256=wqPWuEgYcbGMTs6wuckX400Sq1_Jz8yKYd2t91p3e8U,2270
708
- rasa/shared/core/flows/validation.py,sha256=42J7PJ73uKYSol-eaV5SB3JSngqLyUS6ZnZsxiFAq1s,29910
708
+ rasa/shared/core/flows/validation.py,sha256=fSCqZJTaJK_YcHIMAsYTwtxJX68Dy6M5ENoRWae5WI4,29969
709
709
  rasa/shared/core/flows/yaml_flows_io.py,sha256=mctlsJ8rX2Ci0_PDpl0Bb8cRJQOZtCt18a5nFxttyTU,18264
710
710
  rasa/shared/core/generator.py,sha256=UAuBPu5UjUhL9djVK-PvrWZcNhRACOEgnRsTleV7eeY,35686
711
711
  rasa/shared/core/policies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -850,7 +850,7 @@ rasa/tracing/metric_instrument_provider.py,sha256=FjdvAhKvJNKhvJPyFw1wWG6DWmlSyb
850
850
  rasa/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
851
851
  rasa/utils/beta.py,sha256=h2xwGagMh2SnpMuqhkEAEjL7C_CyU6b1te7sbtF-lm4,3240
852
852
  rasa/utils/cli.py,sha256=L-DT4nPdVBWfc2m1COHrziLitVWJxazSreb6JLbTho4,865
853
- rasa/utils/common.py,sha256=WU2R6R8OMAUsZYYDHXb5X1uPeqD0HbncvhqMDeesP74,23364
853
+ rasa/utils/common.py,sha256=BsA4V6AAoICNAXsnvzZJfpy41KURwetJk8YUT1ivdxk,24208
854
854
  rasa/utils/converter.py,sha256=H4LHpoAK7MXMmvNZG_uSn0gbccCJvHtsA2-6Zya4u6M,1656
855
855
  rasa/utils/endpoints.py,sha256=jX9xSI_3KJ-NpzymyfaO-Zj-ISaWbA4ql2Kx3NulBvE,10905
856
856
  rasa/utils/io.py,sha256=LIAdQQqUPA-V_mdpgeQzPDzA4rmsdZLyVKc8j_0Z70Y,7161
@@ -883,9 +883,9 @@ rasa/utils/train_utils.py,sha256=ClJx-6x3-h3Vt6mskacgkcCUJTMXjFPe3zAcy_DfmaU,212
883
883
  rasa/utils/url_tools.py,sha256=dZ1HGkVdWTJB7zYEdwoDIrEuyX9HE5WsxKKFVsXBLE0,1218
884
884
  rasa/utils/yaml.py,sha256=KjbZq5C94ZP7Jdsw8bYYF7HASI6K4-C_kdHfrnPLpSI,2000
885
885
  rasa/validator.py,sha256=fhRlHQvuBkiup0FnNYmwRmqQwC3QpdCJt0TuvW4jMaI,83125
886
- rasa/version.py,sha256=o7PAS756uUaUQnCkCsu5kbbkl1yiQqVXro0vyS2EXPQ,122
887
- rasa_pro-3.14.0.dev2.dist-info/METADATA,sha256=q9kbc8p59HGydwrjc0SIxyi-XEfz77lrjCV_bumqWt0,10615
888
- rasa_pro-3.14.0.dev2.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
889
- rasa_pro-3.14.0.dev2.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
890
- rasa_pro-3.14.0.dev2.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
891
- rasa_pro-3.14.0.dev2.dist-info/RECORD,,
886
+ rasa/version.py,sha256=-lUY2RKs3DkzuaGMLEs_Mu_Euh3syH3jLT7nS6OB_iU,122
887
+ rasa_pro-3.14.0.dev3.dist-info/METADATA,sha256=l9P5Y9t6Jj27y9_9_YccH10b8Lz5rAAWHPWRDnebGyQ,10615
888
+ rasa_pro-3.14.0.dev3.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
889
+ rasa_pro-3.14.0.dev3.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
890
+ rasa_pro-3.14.0.dev3.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
891
+ rasa_pro-3.14.0.dev3.dist-info/RECORD,,