rasa-pro 3.14.0rc4__py3-none-any.whl → 3.14.2__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 (79) hide show
  1. rasa/agents/agent_manager.py +7 -5
  2. rasa/agents/protocol/a2a/a2a_agent.py +13 -11
  3. rasa/agents/protocol/mcp/mcp_base_agent.py +49 -11
  4. rasa/agents/validation.py +4 -2
  5. rasa/builder/copilot/copilot_templated_message_provider.py +1 -1
  6. rasa/builder/validation_service.py +4 -0
  7. rasa/cli/arguments/data.py +9 -0
  8. rasa/cli/data.py +72 -6
  9. rasa/cli/interactive.py +3 -0
  10. rasa/cli/llm_fine_tuning.py +1 -0
  11. rasa/cli/project_templates/defaults.py +1 -0
  12. rasa/cli/validation/bot_config.py +2 -0
  13. rasa/constants.py +2 -1
  14. rasa/core/actions/action_clean_stack.py +32 -0
  15. rasa/core/actions/action_exceptions.py +1 -1
  16. rasa/core/actions/constants.py +4 -0
  17. rasa/core/actions/custom_action_executor.py +70 -12
  18. rasa/core/actions/grpc_custom_action_executor.py +41 -2
  19. rasa/core/actions/http_custom_action_executor.py +49 -25
  20. rasa/core/agent.py +4 -1
  21. rasa/core/available_agents.py +1 -1
  22. rasa/core/channels/voice_stream/browser_audio.py +3 -3
  23. rasa/core/channels/voice_stream/voice_channel.py +27 -17
  24. rasa/core/config/credentials.py +3 -3
  25. rasa/core/exceptions.py +1 -1
  26. rasa/core/featurizers/tracker_featurizers.py +3 -2
  27. rasa/core/persistor.py +7 -7
  28. rasa/core/policies/flows/agent_executor.py +84 -4
  29. rasa/core/policies/flows/flow_exceptions.py +5 -2
  30. rasa/core/policies/flows/flow_executor.py +52 -31
  31. rasa/core/policies/flows/mcp_tool_executor.py +7 -1
  32. rasa/core/policies/rule_policy.py +1 -1
  33. rasa/core/run.py +21 -5
  34. rasa/dialogue_understanding/commands/cancel_flow_command.py +1 -1
  35. rasa/dialogue_understanding/generator/llm_based_command_generator.py +6 -3
  36. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +15 -7
  37. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +15 -8
  38. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +1 -1
  39. rasa/dialogue_understanding/processor/command_processor.py +13 -7
  40. rasa/e2e_test/e2e_config.py +4 -3
  41. rasa/engine/recipes/default_components.py +16 -6
  42. rasa/graph_components/validators/default_recipe_validator.py +10 -4
  43. rasa/model_manager/runner_service.py +1 -1
  44. rasa/nlu/classifiers/diet_classifier.py +2 -0
  45. rasa/privacy/privacy_config.py +1 -1
  46. rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +4 -7
  47. rasa/shared/core/flows/flow.py +8 -2
  48. rasa/shared/core/slots.py +55 -24
  49. rasa/shared/core/training_data/story_reader/story_reader.py +1 -1
  50. rasa/shared/exceptions.py +23 -2
  51. rasa/shared/providers/_configs/azure_openai_client_config.py +4 -5
  52. rasa/shared/providers/_configs/default_litellm_client_config.py +4 -4
  53. rasa/shared/providers/_configs/litellm_router_client_config.py +3 -2
  54. rasa/shared/providers/_configs/openai_client_config.py +5 -7
  55. rasa/shared/providers/_configs/rasa_llm_client_config.py +4 -4
  56. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +4 -4
  57. rasa/shared/providers/llm/_base_litellm_client.py +42 -14
  58. rasa/shared/providers/llm/litellm_router_llm_client.py +40 -17
  59. rasa/shared/providers/llm/self_hosted_llm_client.py +34 -32
  60. rasa/shared/utils/common.py +9 -1
  61. rasa/shared/utils/configs.py +5 -8
  62. rasa/shared/utils/llm.py +21 -4
  63. rasa/shared/utils/mcp/server_connection.py +7 -4
  64. rasa/studio/download.py +3 -0
  65. rasa/studio/prompts.py +1 -0
  66. rasa/studio/upload.py +4 -0
  67. rasa/utils/common.py +9 -0
  68. rasa/utils/endpoints.py +6 -0
  69. rasa/utils/installation_utils.py +111 -0
  70. rasa/utils/log_utils.py +20 -1
  71. rasa/utils/tensorflow/callback.py +2 -0
  72. rasa/utils/tensorflow/models.py +3 -0
  73. rasa/utils/train_utils.py +2 -0
  74. rasa/version.py +1 -1
  75. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.2.dist-info}/METADATA +3 -3
  76. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.2.dist-info}/RECORD +79 -78
  77. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.2.dist-info}/NOTICE +0 -0
  78. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.2.dist-info}/WHEEL +0 -0
  79. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.2.dist-info}/entry_points.txt +0 -0
@@ -15,7 +15,7 @@ structlogger = structlog.get_logger()
15
15
 
16
16
 
17
17
  class AgentManager(metaclass=Singleton):
18
- """High-level agent management with protocol abstraction"""
18
+ """High-level agent management with protocol abstraction."""
19
19
 
20
20
  agents: ClassVar[Dict[AgentIdentifier, AgentProtocol]] = {}
21
21
 
@@ -66,9 +66,11 @@ class AgentManager(metaclass=Singleton):
66
66
  async def connect_agent(
67
67
  self, agent_name: str, protocol_type: ProtocolType, config: AgentConfig
68
68
  ) -> None:
69
- """Connect to agent using specified protocol, load the default resources
70
- and persist the agent to the manager in a ready-to-use state so that
71
- it can be used immediately to send messages to the agent.
69
+ """Connect to agent using specified protocol.
70
+
71
+ Also, load the default resources and persist the agent to the manager
72
+ in a ready-to-use state so that it can be used immediately
73
+ to send messages to the agent.
72
74
 
73
75
  Args:
74
76
  agent_name: The name of the agent.
@@ -109,7 +111,7 @@ class AgentManager(metaclass=Singleton):
109
111
  agent_id=str(agent_identifier),
110
112
  event_info=event_info,
111
113
  )
112
- raise AgentInitializationException(e) from e
114
+ raise AgentInitializationException(e, suppress_stack_trace=True) from e
113
115
 
114
116
  async def run_agent(
115
117
  self, agent_name: str, protocol_type: ProtocolType, context: AgentInput
@@ -65,7 +65,7 @@ structlogger = structlog.get_logger()
65
65
 
66
66
 
67
67
  class A2AAgent(AgentProtocol):
68
- """A2A client implementation"""
68
+ """A2A client implementation."""
69
69
 
70
70
  __SUPPORTED_OUTPUT_MODES: ClassVar[list[str]] = [
71
71
  "text",
@@ -169,7 +169,8 @@ class A2AAgent(AgentProtocol):
169
169
  error=str(exception),
170
170
  )
171
171
  raise AgentInitializationException(
172
- f"Failed to initialize A2A client for agent '{self._name}': {exception}"
172
+ f"Failed to initialize A2A client "
173
+ f"for agent '{self._name}': {exception}",
173
174
  ) from exception
174
175
 
175
176
  await self._perform_health_check()
@@ -180,7 +181,7 @@ class A2AAgent(AgentProtocol):
180
181
  )
181
182
 
182
183
  async def disconnect(self) -> None:
183
- """We don't need to explicitly disconnect the A2A client"""
184
+ """We don't need to explicitly disconnect the A2A client."""
184
185
  return
185
186
 
186
187
  # ============================================================================
@@ -297,7 +298,7 @@ class A2AAgent(AgentProtocol):
297
298
  def _handle_send_message_response(
298
299
  self, agent_input: AgentInput, response: ClientEvent | Message
299
300
  ) -> Optional[AgentOutput]:
300
- """Handle possible response types from the A2A client:
301
+ """Handle possible response types from the A2A client.
301
302
 
302
303
  In case of streaming, the response can be either exactly *one* Message,
303
304
  or a *series* of tuples of (Task, Optional[TaskUpdateEvent]).
@@ -410,8 +411,8 @@ class A2AAgent(AgentProtocol):
410
411
  agent_input: AgentInput,
411
412
  task: Task,
412
413
  ) -> Optional[AgentOutput]:
413
- """If the task status is terminal (i.e., completed, failed, etc.),
414
- return an AgentOutput.
414
+ """If task status is terminal (e.g. completed, failed) return AgentOutput.
415
+
415
416
  If the task is still in progress (i.e., submitted, working), return None,
416
417
  so that the streaming or pooling agent can continue to wait for updates.
417
418
  """
@@ -655,6 +656,7 @@ class A2AAgent(AgentProtocol):
655
656
  @staticmethod
656
657
  def _generate_completed_response_message(task: Task) -> str:
657
658
  """Generate a response message for a completed task.
659
+
658
660
  In case of completed tasks, the final message might be in
659
661
  the task status message or in the artifacts (or both).
660
662
  """
@@ -728,19 +730,19 @@ class A2AAgent(AgentProtocol):
728
730
 
729
731
  except FileNotFoundError as e:
730
732
  raise AgentInitializationException(
731
- f"Agent card file not found: {agent_card_path}"
733
+ f"Agent card file not found: {agent_card_path}",
732
734
  ) from e
733
735
  except (IOError, PermissionError) as e:
734
736
  raise AgentInitializationException(
735
- f"Error reading agent card file {agent_card_path}: {e}"
737
+ f"Error reading agent card file {agent_card_path}: {e}",
736
738
  ) from e
737
739
  except json.JSONDecodeError as e:
738
740
  raise AgentInitializationException(
739
- f"Invalid JSON in agent card file {agent_card_path}: {e}"
741
+ f"Invalid JSON in agent card file {agent_card_path}: {e}",
740
742
  ) from e
741
743
  except ValidationError as e:
742
744
  raise AgentInitializationException(
743
- f"Failed to load agent card from {agent_card_path}: {e}"
745
+ f"Failed to load agent card from {agent_card_path}: {e}",
744
746
  ) from e
745
747
 
746
748
  @staticmethod
@@ -798,7 +800,7 @@ class A2AAgent(AgentProtocol):
798
800
 
799
801
  raise AgentInitializationException(
800
802
  f"Failed to resolve agent card from {agent_card_path} after "
801
- f"{max_retries} attempts."
803
+ f"{max_retries} attempts.",
802
804
  )
803
805
 
804
806
  # ============================================================================
@@ -1,9 +1,10 @@
1
1
  import json
2
2
  from abc import abstractmethod
3
- from datetime import datetime
3
+ from datetime import datetime, timedelta
4
4
  from inspect import isawaitable
5
5
  from typing import Any, Dict, List, Optional, Tuple
6
6
 
7
+ import anyio
7
8
  import structlog
8
9
  from jinja2 import Template
9
10
  from mcp import ListToolsResult
@@ -75,6 +76,8 @@ class MCPBaseAgent(AgentProtocol):
75
76
 
76
77
  MAX_ITERATIONS = 10
77
78
 
79
+ TOOL_CALL_DEFAULT_TIMEOUT = 10 # seconds
80
+
78
81
  # ============================================================================
79
82
  # Initialization & Setup
80
83
  # ============================================================================
@@ -288,14 +291,16 @@ class MCPBaseAgent(AgentProtocol):
288
291
  event_info="All connection attempts failed.",
289
292
  )
290
293
  raise AgentInitializationException(
291
- f"Failed to connect to MCP servers after {self._max_retries} "
292
- f"attempts. Agent `{self._name}` failed to initialize."
294
+ f"Agent `{self._name}` failed to initialize. Failed to connect "
295
+ f"to MCP servers after {self._max_retries} attempts. {ce!s}"
293
296
  ) from ce
294
297
  except (Exception, AuthenticationError) as e:
295
298
  if isinstance(e, AuthenticationError):
296
- event_info = "Authentication error during agent initialization."
299
+ event_info = (
300
+ f"Authentication error during agent initialization. {e!s}"
301
+ )
297
302
  else:
298
- event_info = "Unexpected error during agent initialization."
303
+ event_info = f"Unexpected error during agent initialization. {e!s}"
299
304
  structlogger.error(
300
305
  "mcp_agent.connect.unexpected_exception",
301
306
  event_info=event_info,
@@ -303,7 +308,7 @@ class MCPBaseAgent(AgentProtocol):
303
308
  agent_name=self._name,
304
309
  agent_id=str(make_agent_identifier(self._name, self.protocol_type)),
305
310
  )
306
- raise AgentInitializationException(e) from e
311
+ raise AgentInitializationException(event_info) from e
307
312
 
308
313
  async def connect_to_server(self, server_config: AgentMCPServerConfig) -> None:
309
314
  server_name = server_config.name
@@ -325,7 +330,7 @@ class MCPBaseAgent(AgentProtocol):
325
330
  except Exception as e:
326
331
  event_info = (
327
332
  f"Agent `{self._name}` failed to connect to MCP server - "
328
- f"`{server_name}` @ `{server_config.url}`: {e!s}"
333
+ f"`{server_name}` @ `{server_config.url}`"
329
334
  )
330
335
  structlogger.error(
331
336
  "mcp_agent.connect.failed_to_connect",
@@ -335,7 +340,9 @@ class MCPBaseAgent(AgentProtocol):
335
340
  agent_name=self._name,
336
341
  agent_id=str(make_agent_identifier(self._name, self.protocol_type)),
337
342
  )
338
- raise e
343
+
344
+ # Wrap exceptions with extra info and raise the same type of exception.
345
+ raise type(e)(f"{event_info} : {e!s}") from e
339
346
 
340
347
  async def connect_to_servers(self) -> None:
341
348
  """Connect to MCP servers."""
@@ -624,7 +631,11 @@ class MCPBaseAgent(AgentProtocol):
624
631
  connection = self._server_connections[server_id]
625
632
  try:
626
633
  session = await connection.ensure_active_session()
627
- result = await session.call_tool(tool_name, arguments)
634
+ result = await session.call_tool(
635
+ tool_name,
636
+ arguments,
637
+ read_timeout_seconds=timedelta(seconds=self.TOOL_CALL_DEFAULT_TIMEOUT),
638
+ )
628
639
  return AgentToolResult.from_mcp_tool_result(tool_name, result)
629
640
  except Exception as e:
630
641
  return AgentToolResult(
@@ -637,6 +648,21 @@ class MCPBaseAgent(AgentProtocol):
637
648
  ),
638
649
  )
639
650
 
651
+ async def _run_custom_tool(
652
+ self, custom_tool: CustomToolSchema, arguments: Dict[str, Any]
653
+ ) -> AgentToolResult:
654
+ """Run a custom tool and return the result.
655
+
656
+ Args:
657
+ custom_tool: The custom tool schema containing the tool executor.
658
+ arguments: The arguments to pass to the tool executor.
659
+
660
+ Returns:
661
+ The result of the tool execution as an AgentToolResult.
662
+ """
663
+ result = custom_tool.tool_executor(arguments)
664
+ return await result if isawaitable(result) else result
665
+
640
666
  async def _execute_tool_call(
641
667
  self, tool_name: str, arguments: Dict[str, Any]
642
668
  ) -> AgentToolResult:
@@ -655,8 +681,20 @@ class MCPBaseAgent(AgentProtocol):
655
681
  try:
656
682
  for custom_tool in self._custom_tools:
657
683
  if custom_tool.tool_name == tool_name:
658
- result = custom_tool.tool_executor(arguments)
659
- return await result if isawaitable(result) else result
684
+ try:
685
+ with anyio.fail_after(self.TOOL_CALL_DEFAULT_TIMEOUT):
686
+ return await self._run_custom_tool(custom_tool, arguments)
687
+
688
+ except TimeoutError:
689
+ return AgentToolResult(
690
+ tool_name=tool_name,
691
+ result=None,
692
+ is_error=True,
693
+ error_message=(
694
+ f"Built-in tool `{tool_name}` timed out after "
695
+ f"{self.TOOL_CALL_DEFAULT_TIMEOUT} seconds."
696
+ ),
697
+ )
660
698
  except Exception as e:
661
699
  return AgentToolResult(
662
700
  tool_name=tool_name,
rasa/agents/validation.py CHANGED
@@ -347,9 +347,11 @@ def _handle_pydantic_validation_error(
347
347
  def _validate_endpoint_references(agent_config: AgentConfig) -> None:
348
348
  """Validate that LLM and MCP server references in agent config are valid."""
349
349
  agent_name = agent_config.agent.name
350
-
351
- # Get available endpoints
352
350
  endpoints = Configuration.get_instance().endpoints
351
+ if not endpoints.config_file_path:
352
+ # If no endpoints were loaded (e.g., `data validate` without --endpoints), skip
353
+ # endpoint reference checks
354
+ return
353
355
 
354
356
  # Validate LLM configuration references
355
357
  if agent_config.configuration and agent_config.configuration.llm:
@@ -2,7 +2,7 @@ import importlib.resources
2
2
  from typing import Dict
3
3
 
4
4
  import structlog
5
- import yaml # type: ignore
5
+ import yaml # type: ignore[import-untyped]
6
6
 
7
7
  from rasa.builder.copilot.constants import (
8
8
  COPILOT_HANDLER_RESPONSES_FILE,
@@ -47,6 +47,10 @@ async def validate_project(importer: TrainingDataImporter) -> Optional[str]:
47
47
  with capture_validation_logs() as captured_logs:
48
48
  try:
49
49
  with _mock_sys_exit() as exit_tracker:
50
+ from rasa.core.config.configuration import Configuration
51
+
52
+ Configuration.initialise_empty()
53
+
50
54
  validate_files(
51
55
  fail_on_warnings=config.VALIDATION_FAIL_ON_WARNINGS,
52
56
  max_history=config.VALIDATION_MAX_HISTORY,
@@ -4,8 +4,10 @@ from typing import Text
4
4
  from rasa.cli.arguments.default_arguments import (
5
5
  add_data_param,
6
6
  add_domain_param,
7
+ add_endpoint_param,
7
8
  add_nlu_data_param,
8
9
  add_out_param,
10
+ add_sub_agents_param,
9
11
  )
10
12
  from rasa.shared.constants import DEFAULT_CONVERTED_DATA_PATH
11
13
 
@@ -91,6 +93,13 @@ def set_validator_arguments(parser: argparse.ArgumentParser) -> None:
91
93
  )
92
94
  add_domain_param(parser)
93
95
  add_data_param(parser)
96
+ add_sub_agents_param(parser)
97
+ # Endpoints are optional for `data validate` command
98
+ add_endpoint_param(
99
+ parser,
100
+ help_text="Configuration file for the connectors as a yml file.",
101
+ default=None,
102
+ )
94
103
 
95
104
 
96
105
  def set_migrate_arguments(parser: argparse.ArgumentParser) -> None:
rasa/cli/data.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import argparse
2
2
  import logging
3
3
  import pathlib
4
- from typing import List
4
+ from typing import List, Optional
5
5
 
6
6
  import rasa.cli.utils
7
7
  import rasa.shared.core.domain
@@ -17,6 +17,7 @@ from rasa.cli.arguments import data as arguments
17
17
  from rasa.cli.arguments import default_arguments
18
18
  from rasa.cli.validation.bot_config import validate_files
19
19
  from rasa.cli.validation.config_path_validation import get_validated_path
20
+ from rasa.core.config.configuration import Configuration
20
21
  from rasa.e2e_test.e2e_config import create_llm_e2e_test_converter_config
21
22
  from rasa.e2e_test.e2e_test_converter import E2ETestConverter
22
23
  from rasa.e2e_test.utils.e2e_yaml_utils import E2ETestYAMLWriter
@@ -139,8 +140,12 @@ def _add_data_validate_parsers(
139
140
  )
140
141
  _append_story_structure_arguments(validate_parser)
141
142
  validate_parser.set_defaults(
142
- func=lambda args: validate_files(
143
- args.fail_on_warnings, args.max_history, _build_training_data_importer(args)
143
+ func=lambda args: _validate_files_with_configuration(
144
+ args.fail_on_warnings,
145
+ args.max_history,
146
+ _build_training_data_importer(args),
147
+ sub_agents=args.sub_agents,
148
+ endpoints=args.endpoints,
144
149
  )
145
150
  )
146
151
  arguments.set_validator_arguments(validate_parser)
@@ -155,10 +160,12 @@ def _add_data_validate_parsers(
155
160
  _append_story_structure_arguments(story_structure_parser)
156
161
 
157
162
  story_structure_parser.set_defaults(
158
- func=lambda args: validate_files(
163
+ func=lambda args: _validate_files_with_configuration(
159
164
  args.fail_on_warnings,
160
165
  args.max_history,
161
166
  _build_training_data_importer(args),
167
+ sub_agents=args.sub_agents,
168
+ endpoints=args.endpoints,
162
169
  stories_only=True,
163
170
  )
164
171
  )
@@ -171,10 +178,12 @@ def _add_data_validate_parsers(
171
178
  help="Checks for inconsistencies in the flows files.",
172
179
  )
173
180
  flows_structure_parser.set_defaults(
174
- func=lambda args: validate_files(
181
+ func=lambda args: _validate_files_with_configuration(
175
182
  args.fail_on_warnings,
176
183
  args.max_history,
177
184
  _build_training_data_importer(args),
185
+ sub_agents=args.sub_agents,
186
+ endpoints=args.endpoints,
178
187
  flows_only=True,
179
188
  )
180
189
  )
@@ -187,10 +196,12 @@ def _add_data_validate_parsers(
187
196
  help="Checks for inconsistencies of the flow and response translation.",
188
197
  )
189
198
  translations_structure_parser.set_defaults(
190
- func=lambda args: validate_files(
199
+ func=lambda args: _validate_files_with_configuration(
191
200
  args.fail_on_warnings,
192
201
  args.max_history,
193
202
  _build_training_data_importer(args),
203
+ sub_agents=args.sub_agents,
204
+ endpoints=args.endpoints,
194
205
  translations_only=True,
195
206
  )
196
207
  )
@@ -376,3 +387,58 @@ def convert_data_to_e2e_tests(args: argparse.Namespace) -> None:
376
387
  rasa.shared.utils.cli.print_error_and_exit(
377
388
  f"Failed to convert the data into E2E tests. Error: {exc}"
378
389
  )
390
+
391
+
392
+ def _initialize_configuration_for_validation(
393
+ sub_agents: Optional[str] = None, endpoints: Optional[str] = None
394
+ ) -> None:
395
+ """Initialize Configuration before validation.
396
+
397
+ Args:
398
+ sub_agents: Path to sub-agents directory for validation.
399
+ endpoints: Path to the endpoints configuration file.
400
+ """
401
+ if endpoints:
402
+ Configuration.initialise_endpoints(endpoints_path=pathlib.Path(endpoints))
403
+ if sub_agents:
404
+ Configuration.initialise_sub_agents(pathlib.Path(sub_agents))
405
+ if not endpoints and not sub_agents:
406
+ Configuration.initialise_empty()
407
+
408
+
409
+ def _validate_files_with_configuration(
410
+ fail_on_warnings: bool,
411
+ max_history: int,
412
+ importer: TrainingDataImporter,
413
+ sub_agents: Optional[str] = None,
414
+ endpoints: Optional[str] = None,
415
+ stories_only: bool = False,
416
+ flows_only: bool = False,
417
+ translations_only: bool = False,
418
+ ) -> None:
419
+ """Wrapper for validate_files that ensures Configuration is initialized first.
420
+
421
+ Args:
422
+ fail_on_warnings: `True` if the process should exit with a non-zero status
423
+ max_history: The max history to use when validating the story structure.
424
+ importer: The `TrainingDataImporter` to use to load the training data.
425
+ sub_agents: Path to sub-agents directory for validation.
426
+ endpoints: Path to the endpoints configuration file.
427
+ stories_only: If `True`, only the story structure is validated.
428
+ flows_only: If `True`, only the flows are validated.
429
+ translations_only: If `True`, only the translations data is validated.
430
+ """
431
+ # Initialize Configuration before calling validate_files
432
+ _initialize_configuration_for_validation(sub_agents=sub_agents, endpoints=endpoints)
433
+
434
+ # Call the original validate_files function
435
+ validate_files(
436
+ fail_on_warnings=fail_on_warnings,
437
+ max_history=max_history,
438
+ importer=importer,
439
+ stories_only=stories_only,
440
+ flows_only=flows_only,
441
+ translations_only=translations_only,
442
+ sub_agents=sub_agents,
443
+ endpoints=endpoints,
444
+ )
rasa/cli/interactive.py CHANGED
@@ -12,6 +12,7 @@ from rasa import model
12
12
  from rasa.cli import SubParsersAction
13
13
  from rasa.cli.arguments import interactive as arguments
14
14
  from rasa.cli.validation.config_path_validation import get_validated_path
15
+ from rasa.core.config.configuration import Configuration
15
16
  from rasa.core.constants import DEFAULT_SUB_AGENTS
16
17
  from rasa.engine.storage.local_model_storage import LocalModelStorage
17
18
  from rasa.shared.constants import (
@@ -140,6 +141,8 @@ def perform_interactive_learning(
140
141
  args.endpoints, "endpoints", DEFAULT_ENDPOINTS_PATH, True
141
142
  )
142
143
 
144
+ Configuration.initialise_endpoints(endpoints_path=Path(args.endpoints))
145
+
143
146
  do_interactive_learning(args, file_importer)
144
147
 
145
148
 
@@ -414,6 +414,7 @@ def get_valid_endpoints(endpoints_file: str) -> AvailableEndpoints:
414
414
 
415
415
  def set_up_e2e_test_runner(args: argparse.Namespace) -> E2ETestRunner:
416
416
  endpoints = get_valid_endpoints(args.endpoints)
417
+ Configuration.initialise_sub_agents(args.sub_agents)
417
418
 
418
419
  if endpoints.model is None:
419
420
  args.model = validate_model_path(args.model, "model", DEFAULT_MODELS_PATH)
@@ -138,6 +138,7 @@ def get_rasa_defaults(config_yaml: Text, endpoints_yaml: Text) -> RasaDefaults:
138
138
  A RasaDefaults object containing the default values for the project.
139
139
  """
140
140
  config = read_yaml(config_yaml)
141
+ # Does not read from file, it converts the YAML content to a dictionary.
141
142
  endpoints = read_yaml(endpoints_yaml)
142
143
 
143
144
  prompts = get_system_default_prompts(config, endpoints)
@@ -149,6 +149,7 @@ def validate_files(
149
149
  flows_only: bool = False,
150
150
  translations_only: bool = False,
151
151
  sub_agents: Optional[str] = None,
152
+ endpoints: Optional[str] = None,
152
153
  ) -> None:
153
154
  """Validates either the story structure or the entire project.
154
155
 
@@ -160,6 +161,7 @@ def validate_files(
160
161
  flows_only: If `True`, only the flows are validated.
161
162
  translations_only: If `True`, only the translations data is validated.
162
163
  sub_agents: Path to sub-agents directory for validation.
164
+ endpoints: Path to the endpoints configuration file.
163
165
  """
164
166
  from rasa.validator import Validator
165
167
 
rasa/constants.py CHANGED
@@ -18,7 +18,7 @@ CONFIG_TELEMETRY_ID = "rasa_user_id"
18
18
  CONFIG_TELEMETRY_ENABLED = "enabled"
19
19
  CONFIG_TELEMETRY_DATE = "date"
20
20
 
21
- MINIMUM_COMPATIBLE_VERSION = "3.14.0.dev10"
21
+ MINIMUM_COMPATIBLE_VERSION = "3.14.0rc3"
22
22
 
23
23
  GLOBAL_USER_CONFIG_PATH = os.path.expanduser("~/.config/rasa/global.yml")
24
24
 
@@ -33,6 +33,7 @@ ENV_MCP_LOGGING_ENABLED = "MCP_LOGGING_ENABLED"
33
33
  ENV_LOG_LEVEL_MATPLOTLIB = "LOG_LEVEL_MATPLOTLIB"
34
34
  ENV_LOG_LEVEL_RABBITMQ = "LOG_LEVEL_RABBITMQ"
35
35
  ENV_LOG_LEVEL_KAFKA = "LOG_LEVEL_KAFKA"
36
+ ENV_LOG_LEVEL_PYMONGO = "LOG_LEVEL_PYMONGO"
36
37
 
37
38
  DEFAULT_SANIC_WORKERS = 1
38
39
  ENV_SANIC_WORKERS = "SANIC_WORKERS"
@@ -4,9 +4,11 @@ from typing import Any, Dict, List, Optional
4
4
 
5
5
  import structlog
6
6
 
7
+ import rasa.dialogue_understanding.stack.utils
7
8
  from rasa.core.actions.action import Action
8
9
  from rasa.core.channels import OutputChannel
9
10
  from rasa.core.nlg import NaturalLanguageGenerator
11
+ from rasa.dialogue_understanding.patterns.code_change import FLOW_PATTERN_CODE_CHANGE_ID
10
12
  from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
11
13
  from rasa.dialogue_understanding.stack.frames import (
12
14
  BaseFlowStackFrame,
@@ -41,6 +43,15 @@ class ActionCleanStack(Action):
41
43
  """Clean the stack."""
42
44
  structlogger.debug("action_clean_stack.run")
43
45
  new_frames = []
46
+ top_flow_frame = rasa.dialogue_understanding.stack.utils.top_flow_frame(
47
+ tracker.stack, ignore_call_frames=False
48
+ )
49
+ top_user_flow_frame = (
50
+ rasa.dialogue_understanding.stack.utils.top_user_flow_frame(
51
+ tracker.stack, ignore_call_and_link_frames=False
52
+ )
53
+ )
54
+
44
55
  # Set all frames to their end step, filter out any non-BaseFlowStackFrames
45
56
  for frame in tracker.stack.frames:
46
57
  if isinstance(frame, BaseFlowStackFrame):
@@ -56,4 +67,25 @@ class ActionCleanStack(Action):
56
67
  new_frames.append(frame)
57
68
  new_stack = DialogueStack.from_dict([frame.as_dict() for frame in new_frames])
58
69
 
70
+ # Check if the action is being called from within a user flow
71
+ if (
72
+ top_flow_frame
73
+ and top_flow_frame.flow_id != FLOW_PATTERN_CODE_CHANGE_ID
74
+ and top_user_flow_frame
75
+ and top_user_flow_frame.flow_id == top_flow_frame.flow_id
76
+ ):
77
+ # The action is being called from within a user flow on the stack.
78
+ # If there are other frames on the stack, we need to make sure
79
+ # the last executed frame is the end step of the current user flow so
80
+ # that we can trigger pattern_completed for this user flow.
81
+ new_stack.pop()
82
+ structlogger.debug(
83
+ "action_clean_stack.pushing_user_frame_at_the_bottom_of_stack",
84
+ flow_id=top_user_flow_frame.flow_id,
85
+ )
86
+ new_stack.push(
87
+ top_user_flow_frame,
88
+ index=0,
89
+ )
90
+
59
91
  return tracker.create_stack_updated_events(new_stack)
@@ -12,7 +12,7 @@ class ActionExecutionRejection(RasaException):
12
12
  self.message = message or "Custom action '{}' rejected to run".format(
13
13
  action_name
14
14
  )
15
- super(ActionExecutionRejection, self).__init__()
15
+ super(ActionExecutionRejection, self).__init__(self.message)
16
16
 
17
17
  def __str__(self) -> str:
18
18
  return self.message
@@ -3,3 +3,7 @@ SELECTIVE_DOMAIN = "enable_selective_domain"
3
3
 
4
4
  SSL_CLIENT_CERT_FIELD = "ssl_client_cert"
5
5
  SSL_CLIENT_KEY_FIELD = "ssl_client_key"
6
+
7
+ # Special marker key used by EndpointConfig to indicate 449 status
8
+ # without raising an exception
9
+ MISSING_DOMAIN_MARKER = "missing_domain"