rasa-pro 3.14.0rc4__py3-none-any.whl → 3.14.1__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 (44) 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 +1 -1
  14. rasa/core/actions/action_exceptions.py +1 -1
  15. rasa/core/agent.py +4 -1
  16. rasa/core/available_agents.py +1 -1
  17. rasa/core/exceptions.py +1 -1
  18. rasa/core/featurizers/tracker_featurizers.py +3 -2
  19. rasa/core/persistor.py +7 -7
  20. rasa/core/policies/flows/agent_executor.py +84 -4
  21. rasa/core/policies/flows/flow_exceptions.py +5 -2
  22. rasa/core/policies/flows/flow_executor.py +3 -2
  23. rasa/core/policies/flows/mcp_tool_executor.py +7 -1
  24. rasa/core/policies/rule_policy.py +1 -1
  25. rasa/dialogue_understanding/commands/cancel_flow_command.py +1 -1
  26. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +1 -1
  27. rasa/model_manager/runner_service.py +1 -1
  28. rasa/privacy/privacy_config.py +1 -1
  29. rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +4 -7
  30. rasa/shared/core/training_data/story_reader/story_reader.py +1 -1
  31. rasa/shared/exceptions.py +23 -2
  32. rasa/shared/providers/llm/litellm_router_llm_client.py +2 -2
  33. rasa/shared/utils/llm.py +21 -4
  34. rasa/shared/utils/mcp/server_connection.py +7 -4
  35. rasa/studio/download.py +3 -0
  36. rasa/studio/prompts.py +1 -0
  37. rasa/studio/upload.py +4 -0
  38. rasa/utils/log_utils.py +20 -1
  39. rasa/version.py +1 -1
  40. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/METADATA +2 -2
  41. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/RECORD +44 -44
  42. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/NOTICE +0 -0
  43. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/WHEEL +0 -0
  44. {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- from typing import Any, Dict, List, Optional, cast
4
+ from typing import Any, Dict, List, Optional, Tuple, cast
5
5
 
6
6
  import structlog
7
7
 
@@ -24,6 +24,7 @@ from rasa.core.policies.flows.flow_step_result import (
24
24
  PauseFlowReturnPrediction,
25
25
  )
26
26
  from rasa.core.utils import get_slot_names_from_exit_conditions
27
+ from rasa.dialogue_understanding.patterns.cancel import CancelPatternFlowStackFrame
27
28
  from rasa.dialogue_understanding.patterns.internal_error import (
28
29
  InternalErrorPatternFlowStackFrame,
29
30
  )
@@ -31,6 +32,7 @@ from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
31
32
  from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
32
33
  AgentStackFrame,
33
34
  AgentState,
35
+ BaseFlowStackFrame,
34
36
  )
35
37
  from rasa.shared.agents.utils import get_protocol_type
36
38
  from rasa.shared.core.constants import (
@@ -46,9 +48,11 @@ from rasa.shared.core.events import (
46
48
  AgentResumed,
47
49
  AgentStarted,
48
50
  Event,
51
+ FlowCancelled,
49
52
  SlotSet,
50
53
  deserialise_events,
51
54
  )
55
+ from rasa.shared.core.flows.flows_list import FlowsList
52
56
  from rasa.shared.core.flows.steps import (
53
57
  CallFlowStep,
54
58
  )
@@ -85,6 +89,7 @@ async def run_agent(
85
89
  step: CallFlowStep,
86
90
  tracker: DialogueStateTracker,
87
91
  slots: List[Slot],
92
+ flows: FlowsList,
88
93
  ) -> FlowStepResult:
89
94
  """Run an agent call step."""
90
95
  structlogger.debug(
@@ -177,9 +182,13 @@ async def run_agent(
177
182
  elif output.status == AgentStatus.COMPLETED:
178
183
  return _handle_agent_completed(output, final_events, stack, step)
179
184
  elif output.status == AgentStatus.FATAL_ERROR:
180
- return _handle_agent_fatal_error(output, final_events, stack, step)
185
+ return _handle_agent_fatal_error(
186
+ output, final_events, stack, step, flows, tracker
187
+ )
181
188
  else:
182
- return _handle_agent_unknown_status(output, final_events, stack, step)
189
+ return _handle_agent_unknown_status(
190
+ output, final_events, stack, step, flows, tracker
191
+ )
183
192
 
184
193
 
185
194
  async def _call_agent_with_retry(
@@ -299,6 +308,8 @@ def _handle_agent_unknown_status(
299
308
  final_events: List[Event],
300
309
  stack: DialogueStack,
301
310
  step: CallFlowStep,
311
+ flows: FlowsList,
312
+ tracker: DialogueStateTracker,
302
313
  ) -> FlowStepResult:
303
314
  """Handle unknown agent status.
304
315
 
@@ -307,6 +318,8 @@ def _handle_agent_unknown_status(
307
318
  final_events: List of events to be added to the final result
308
319
  stack: The dialogue stack
309
320
  step: The flow step that called the agent
321
+ flows: All flows
322
+ tracker: The dialogue state tracker
310
323
 
311
324
  Returns:
312
325
  FlowStepResult indicating to continue with internal error pattern
@@ -320,8 +333,21 @@ def _handle_agent_unknown_status(
320
333
  flow_id=step.flow_id,
321
334
  status=output.status,
322
335
  )
336
+ # remove the agent stack frame
323
337
  remove_agent_stack_frame(stack, step.call)
324
338
  final_events.append(AgentCancelled(agent_id=step.call, flow_id=step.flow_id))
339
+
340
+ # cancel the current active flow:
341
+ # push the cancel pattern stack frame and add the flow cancelled event
342
+ cancel_pattern_stack_frame, flow_cancelled_event = _cancel_flow(
343
+ stack, flows, tracker, step
344
+ )
345
+ if cancel_pattern_stack_frame:
346
+ stack.push(cancel_pattern_stack_frame)
347
+ if flow_cancelled_event:
348
+ final_events.append(flow_cancelled_event)
349
+
350
+ # trigger the internal error pattern
325
351
  stack.push(InternalErrorPatternFlowStackFrame())
326
352
  return ContinueFlowWithNextStep(events=final_events)
327
353
 
@@ -418,6 +444,8 @@ def _handle_agent_fatal_error(
418
444
  final_events: List[Event],
419
445
  stack: DialogueStack,
420
446
  step: CallFlowStep,
447
+ flows: FlowsList,
448
+ tracker: DialogueStateTracker,
421
449
  ) -> FlowStepResult:
422
450
  """Handle fatal error from agent execution.
423
451
 
@@ -426,13 +454,15 @@ def _handle_agent_fatal_error(
426
454
  final_events: List of events to be added to the final result
427
455
  stack: The dialogue stack
428
456
  step: The flow step that called the agent
457
+ flows: All flows
458
+ tracker: The dialogue state tracker
429
459
 
430
460
  Returns:
431
461
  FlowStepResult indicating to continue with internal error pattern
432
462
  """
433
463
  output.metadata = output.metadata or {}
434
464
  _update_agent_events(final_events, output.metadata)
435
- # the agent failed, trigger pattern_internal_error
465
+ # the agent failed, cancel the current flow and trigger pattern_internal_error
436
466
  structlogger.error(
437
467
  "flow.step.run_agent.fatal_error",
438
468
  agent_name=step.call,
@@ -440,16 +470,66 @@ def _handle_agent_fatal_error(
440
470
  flow_id=step.flow_id,
441
471
  error_message=output.error_message,
442
472
  )
473
+ # remove the agent stack frame
443
474
  remove_agent_stack_frame(stack, step.call)
444
475
  final_events.append(
445
476
  AgentCancelled(
446
477
  agent_id=step.call, flow_id=step.flow_id, reason=output.error_message
447
478
  )
448
479
  )
480
+
481
+ # cancel the current active flow:
482
+ # push the cancel pattern stack frame and add the flow cancelled event
483
+ cancel_pattern_stack_frame, flow_cancelled_event = _cancel_flow(
484
+ stack, flows, tracker, step
485
+ )
486
+ if cancel_pattern_stack_frame:
487
+ stack.push(cancel_pattern_stack_frame)
488
+ if flow_cancelled_event:
489
+ final_events.append(flow_cancelled_event)
490
+
491
+ # push the internal error pattern stack frame
449
492
  stack.push(InternalErrorPatternFlowStackFrame())
450
493
  return ContinueFlowWithNextStep(events=final_events)
451
494
 
452
495
 
496
+ def _cancel_flow(
497
+ stack: DialogueStack,
498
+ flows: FlowsList,
499
+ tracker: DialogueStateTracker,
500
+ step: CallFlowStep,
501
+ ) -> Tuple[Optional[CancelPatternFlowStackFrame], Optional[FlowCancelled]]:
502
+ """Cancel the current active flow.
503
+
504
+ Creates a cancel pattern stack frame and a flow cancelled event.
505
+ """
506
+ from rasa.dialogue_understanding.commands import CancelFlowCommand
507
+
508
+ cancel_pattern_stack_frame = None
509
+ flow_cancelled_event = None
510
+
511
+ top_frame = stack.top()
512
+
513
+ if isinstance(top_frame, BaseFlowStackFrame):
514
+ flow = flows.flow_by_id(step.flow_id)
515
+ flow_name = (
516
+ flow.readable_name(language=tracker.current_language)
517
+ if flow
518
+ else step.flow_id
519
+ )
520
+
521
+ canceled_frames = CancelFlowCommand.select_canceled_frames(stack)
522
+
523
+ cancel_pattern_stack_frame = CancelPatternFlowStackFrame(
524
+ canceled_name=flow_name,
525
+ canceled_frames=canceled_frames,
526
+ )
527
+
528
+ flow_cancelled_event = FlowCancelled(step.flow_id, step.id)
529
+
530
+ return cancel_pattern_stack_frame, flow_cancelled_event
531
+
532
+
453
533
  ################################################################################
454
534
  # Create predictions
455
535
  ################################################################################
@@ -5,14 +5,17 @@ from rasa.shared.exceptions import RasaException
5
5
  class FlowException(RasaException):
6
6
  """Exception that is raised when there is a problem with a flow."""
7
7
 
8
- pass
8
+ def __init__(self, message: str = "Flow error occurred") -> None:
9
+ """Initialize FlowException with a message."""
10
+ super().__init__(message)
9
11
 
10
12
 
11
13
  class FlowCircuitBreakerTrippedException(FlowException):
12
14
  """Exception that is raised when the flow circuit breaker tripped.
13
15
 
14
16
  The circuit breaker gets tripped when a flow seems to be stuck in
15
- executing steps and does not make any progress."""
17
+ executing steps and does not make any progress.
18
+ """
16
19
 
17
20
  def __init__(
18
21
  self, dialogue_stack: DialogueStack, number_of_steps_taken: int
@@ -650,7 +650,7 @@ async def run_step(
650
650
  return _run_link_step(initial_events, stack, step)
651
651
 
652
652
  elif isinstance(step, CallFlowStep):
653
- return await _run_call_step(initial_events, stack, step, tracker, slots)
653
+ return await _run_call_step(initial_events, stack, step, tracker, slots, flows)
654
654
 
655
655
  elif isinstance(step, SetSlotsFlowStep):
656
656
  return _run_set_slot_step(initial_events, step)
@@ -723,12 +723,13 @@ async def _run_call_step(
723
723
  step: CallFlowStep,
724
724
  tracker: DialogueStateTracker,
725
725
  slots: List[Slot],
726
+ flows: FlowsList,
726
727
  ) -> FlowStepResult:
727
728
  structlogger.debug("flow.step.run.call")
728
729
  if step.is_calling_mcp_tool():
729
730
  return await call_mcp_tool(initial_events, stack, step, tracker)
730
731
  elif step.is_calling_agent():
731
- return await run_agent(initial_events, stack, step, tracker, slots)
732
+ return await run_agent(initial_events, stack, step, tracker, slots, flows)
732
733
  else:
733
734
  stack.push(
734
735
  UserFlowStackFrame(
@@ -1,4 +1,5 @@
1
1
  import json
2
+ from datetime import timedelta
2
3
  from typing import Any, Dict, List, Optional
3
4
 
4
5
  import structlog
@@ -24,6 +25,7 @@ structlogger = structlog.get_logger()
24
25
 
25
26
  CONFIG_VALUE = "value"
26
27
  CONFIG_SLOT = "slot"
28
+ TOOL_CALL_DEFATULT_TIMEOUT = 10 # seconds
27
29
 
28
30
 
29
31
  async def call_mcp_tool(
@@ -102,7 +104,11 @@ async def _execute_mcp_tool_call(
102
104
 
103
105
  # Call the tool with parameters
104
106
  mcp_server = await mcp_server_connection.ensure_active_session()
105
- result = await mcp_server.call_tool(step.call, arguments)
107
+ result = await mcp_server.call_tool(
108
+ step.call,
109
+ arguments,
110
+ read_timeout_seconds=timedelta(seconds=TOOL_CALL_DEFATULT_TIMEOUT),
111
+ )
106
112
 
107
113
  # Handle tool execution result
108
114
  if result is None or result.isError:
@@ -84,7 +84,7 @@ class InvalidRule(RasaException):
84
84
  """Exception that can be raised when rules are not valid."""
85
85
 
86
86
  def __init__(self, message: Text) -> None:
87
- super().__init__()
87
+ super().__init__(message)
88
88
  self.message = message
89
89
 
90
90
  def __str__(self) -> Text:
@@ -56,7 +56,7 @@ class CancelFlowCommand(Command):
56
56
  Returns:
57
57
  The frames that were canceled.
58
58
  """
59
- canceled_frames = []
59
+ canceled_frames: List[str] = []
60
60
  # we need to go through the original stack dump in reverse order
61
61
  # to find the frames that were canceled. we cancel everything from
62
62
  # the top of the stack until we hit the user flow that was canceled.
@@ -233,7 +233,7 @@ flows:
233
233
  collect: interrupted_flow_to_continue
234
234
  description: "Fill this slot with the name of the flow the user wants to continue. If the user does not want to continue any of the interrupted flows, fill this slot with 'none'."
235
235
  next:
236
- - if: slots.interrupted_flow_to_continue != "none"
236
+ - if: slots.interrupted_flow_to_continue is not "none"
237
237
  then:
238
238
  - action: action_continue_interrupted_flow
239
239
  next: END
@@ -195,7 +195,7 @@ def fetch_remote_model_to_dir(
195
195
  try:
196
196
  return persistor.retrieve(model_name=model_name, target_path=target_path)
197
197
  except FileNotFoundError as e:
198
- raise ModelNotFound() from e
198
+ raise ModelNotFound("Model not found") from e
199
199
 
200
200
 
201
201
  def fetch_size_of_remote_model(
@@ -211,7 +211,7 @@ def get_cron_trigger(cron_expression: str) -> CronTrigger:
211
211
  "privacy_config.invalid_cron_expression",
212
212
  cron=cron_expression,
213
213
  )
214
- raise RasaException from exc
214
+ raise RasaException("Invalid cron expression") from exc
215
215
 
216
216
  return cron
217
217
 
@@ -139,20 +139,17 @@ class OAuth2AuthStrategy(AgentAuthStrategy):
139
139
  resp.raise_for_status()
140
140
  token_data = resp.json()
141
141
  except httpx.HTTPStatusError as e:
142
- raise ValueError(
143
- f"OAuth2 token request failed with status {e.response.status_code}: "
144
- f"{e.response.text}"
145
- ) from e
142
+ raise e
146
143
  except httpx.RequestError as e:
147
- raise ValueError(f"OAuth2 token request failed: {e}") from e
144
+ raise ValueError(f"OAuth2 token request failed - {e}") from e
148
145
  except Exception as e:
149
146
  raise ValueError(
150
- f"Unexpected error during OAuth2 token request: {e}"
147
+ f"Unexpected error during OAuth2 token request - {e}"
151
148
  ) from e
152
149
 
153
150
  # Validate token data
154
151
  if KEY_ACCESS_TOKEN not in token_data:
155
- raise ValueError(f"No {KEY_ACCESS_TOKEN} in OAuth2 response")
152
+ raise ValueError(f"No `{KEY_ACCESS_TOKEN}` in OAuth2 response")
156
153
 
157
154
  # Set access token and expires at
158
155
  self._access_token = token_data[KEY_ACCESS_TOKEN]
@@ -126,4 +126,4 @@ class StoryParseError(RasaCoreException, ValueError):
126
126
 
127
127
  def __init__(self, message: Text) -> None:
128
128
  self.message = message
129
- super(StoryParseError, self).__init__()
129
+ super(StoryParseError, self).__init__(message)
rasa/shared/exceptions.py CHANGED
@@ -16,6 +16,17 @@ class RasaException(Exception):
16
16
  to the users, but will be ignored in telemetry.
17
17
  """
18
18
 
19
+ def __init__(self, message: str, suppress_stack_trace: bool = False, **kwargs: Any):
20
+ """Initialize the exception.
21
+
22
+ Args:
23
+ message: The error message.
24
+ suppress_stack_trace: If True, the stack trace will be suppressed in logs.
25
+ **kwargs: Additional keyword arguments (e.g., cause for exception chaining).
26
+ """
27
+ Exception.__init__(self, message)
28
+ self.suppress_stack_trace = suppress_stack_trace
29
+
19
30
 
20
31
  class RasaCoreException(RasaException):
21
32
  """Basic exception for errors raised by Rasa Core."""
@@ -113,6 +124,17 @@ class SchemaValidationError(RasaException, jsonschema.ValidationError):
113
124
  class InvalidEntityFormatException(RasaException, json.JSONDecodeError):
114
125
  """Raised if the format of an entity is invalid."""
115
126
 
127
+ def __init__(self, msg: str, doc: str = "", pos: int = 0):
128
+ """Initialize the exception.
129
+
130
+ Args:
131
+ msg: The error message.
132
+ doc: The document that caused the error.
133
+ pos: The position in the document where the error occurred.
134
+ """
135
+ RasaException.__init__(self, msg)
136
+ json.JSONDecodeError.__init__(self, msg, doc, pos)
137
+
116
138
  @classmethod
117
139
  def create_from(
118
140
  cls, other: json.JSONDecodeError, msg: Text
@@ -130,8 +152,7 @@ class ConnectionException(RasaException):
130
152
 
131
153
 
132
154
  class ProviderClientAPIException(RasaException):
133
- """Raised for errors that occur during API interactions
134
- with LLM / embedding providers.
155
+ """For errors during API interactions with LLM / embedding providers.
135
156
 
136
157
  Attributes:
137
158
  original_exception (Exception): The original exception that was
@@ -151,7 +151,7 @@ class LiteLLMRouterLLMClient(_BaseLiteLLMRouterClient, _BaseLiteLLMClient):
151
151
  if not self._use_chat_completions_endpoint:
152
152
  return self._text_completion(messages)
153
153
  try:
154
- formatted_messages = self._format_messages(messages)
154
+ formatted_messages = self._get_formatted_messages(messages)
155
155
  response = self.router_client.completion(
156
156
  messages=formatted_messages, **{**self._completion_fn_args, **kwargs}
157
157
  )
@@ -189,7 +189,7 @@ class LiteLLMRouterLLMClient(_BaseLiteLLMRouterClient, _BaseLiteLLMClient):
189
189
  if not self._use_chat_completions_endpoint:
190
190
  return await self._atext_completion(messages)
191
191
  try:
192
- formatted_messages = self._format_messages(messages)
192
+ formatted_messages = self._get_formatted_messages(messages)
193
193
  response = await self.router_client.acompletion(
194
194
  messages=formatted_messages, **{**self._completion_fn_args, **kwargs}
195
195
  )
rasa/shared/utils/llm.py CHANGED
@@ -1074,7 +1074,7 @@ def _get_llm_command_generator_config(
1074
1074
 
1075
1075
 
1076
1076
  def _get_compact_llm_command_generator_prompt(
1077
- config: Dict[Text, Any], endpoints: Dict[Text, Any]
1077
+ config: Dict[Text, Any], model_groups: Dict[Text, Any]
1078
1078
  ) -> Text:
1079
1079
  """Get the command generator prompt based on the config."""
1080
1080
  from rasa.dialogue_understanding.generator.single_step.compact_llm_command_generator import ( # noqa: E501
@@ -1084,7 +1084,7 @@ def _get_compact_llm_command_generator_prompt(
1084
1084
  model_config = _get_llm_command_generator_config(config)
1085
1085
  llm_config = resolve_model_client_config(
1086
1086
  model_config=model_config,
1087
- model_groups=endpoints.get(MODEL_GROUPS_CONFIG_KEY),
1087
+ model_groups=model_groups,
1088
1088
  )
1089
1089
  return get_default_prompt_template_based_on_model(
1090
1090
  llm_config=llm_config or {},
@@ -1119,7 +1119,7 @@ def get_system_default_prompts(
1119
1119
 
1120
1120
  Args:
1121
1121
  config: The config.yml file data.
1122
- endpoints: The endpoints.yml file data.
1122
+ endpoints: The endpoints configuration dictionary.
1123
1123
 
1124
1124
  Returns:
1125
1125
  SystemPrompts: A Pydantic model containing all default prompts.
@@ -1128,8 +1128,25 @@ def get_system_default_prompts(
1128
1128
  DEFAULT_RESPONSE_VARIATION_PROMPT_TEMPLATE,
1129
1129
  )
1130
1130
 
1131
+ # The Model Manager / Model API service receives the endpoints configuration
1132
+ # as raw YAML text rather than as a file path. However, both
1133
+ # Configuration.initialise_endpoints() and AvailableEndpoints.read_endpoints()
1134
+ # currently only accept a Path input and do not support loading from in-memory
1135
+ # YAML content.
1136
+
1137
+ # Since these classes only support file-based initialization today, we need
1138
+ # to bootstrap the Configuration with an empty AvailableEndpoints instance for now.
1139
+
1140
+ # IMPORTANT: This configuration must be properly initialized with valid endpoints
1141
+ # and available agents once Studio introduces full support for Agent configurations
1142
+ # (A2A and MCP).
1143
+ Configuration.initialise_empty()
1144
+
1145
+ model_groups = endpoints.get(MODEL_GROUPS_CONFIG_KEY)
1131
1146
  return SystemPrompts(
1132
- command_generator=_get_compact_llm_command_generator_prompt(config, endpoints),
1147
+ command_generator=_get_compact_llm_command_generator_prompt(
1148
+ config, model_groups
1149
+ ),
1133
1150
  enterprise_search=_get_enterprise_search_prompt(config),
1134
1151
  contextual_response_rephraser=DEFAULT_RESPONSE_VARIATION_PROMPT_TEMPLATE,
1135
1152
  )
@@ -121,7 +121,8 @@ class MCPServerConnection:
121
121
  except Exception as eg:
122
122
  for exc in getattr(eg, "exceptions", [eg]):
123
123
  event_info = (
124
- f"Failed to connect to MCP server `{self.server_name}`: {exc!s}"
124
+ f"Failed to connect to MCP server `{self.server_name}`. \nOriginal "
125
+ f"error: {exc!s}"
125
126
  )
126
127
  if isinstance(exc, HTTPStatusError):
127
128
  status_code = exc.response.status_code
@@ -135,9 +136,11 @@ class MCPServerConnection:
135
136
  )
136
137
  await self._cleanup()
137
138
  if status_code in [400, 401, 403]:
138
- raise AuthenticationError(eg) from eg
139
+ raise AuthenticationError(str(exc)) from eg
140
+ elif status_code == 404:
141
+ raise Exception(str(exc)) from eg
139
142
  else:
140
- raise ConnectionError(eg) from eg
143
+ raise ConnectionError(str(exc)) from eg
141
144
  else:
142
145
  structlogger.error(
143
146
  "mcp_server_connection.connect.other_exception",
@@ -147,7 +150,7 @@ class MCPServerConnection:
147
150
  error=str(exc),
148
151
  )
149
152
  await self._cleanup()
150
- raise ConnectionError(eg) from eg
153
+ raise ConnectionError(str(exc)) from eg
151
154
 
152
155
  except asyncio.CancelledError as e:
153
156
  event_info = f"Connection to MCP server `{self.server_name}` was cancelled."
rasa/studio/download.py CHANGED
@@ -10,6 +10,7 @@ from ruamel.yaml.scalarstring import LiteralScalarString
10
10
 
11
11
  import rasa.cli.utils
12
12
  import rasa.shared.utils.cli
13
+ from rasa.core.config.configuration import Configuration
13
14
  from rasa.shared.constants import (
14
15
  DEFAULT_CONFIG_PATH,
15
16
  DEFAULT_DATA_PATH,
@@ -116,6 +117,8 @@ def _handle_endpoints(handler: StudioDataHandler, root: Path) -> None:
116
117
  endpoints_path = root / DEFAULT_ENDPOINTS_PATH
117
118
  endpoints_path.write_text(endpoints_data, encoding="utf-8")
118
119
 
120
+ Configuration.initialise_endpoints(endpoints_path=endpoints_path)
121
+
119
122
 
120
123
  def _handle_domain(handler: StudioDataHandler, root: Path) -> None:
121
124
  """Persist the assistant’s domain file.
rasa/studio/prompts.py CHANGED
@@ -43,6 +43,7 @@ def handle_prompts(prompts: Dict[Text, Text], root: Path) -> None:
43
43
  config: Dict = read_yaml(config_path)
44
44
  endpoints: Dict = read_yaml(endpoints_path)
45
45
 
46
+ # System default prompts are dependent on the endpoints
46
47
  system_prompts = get_system_default_prompts(config, endpoints)
47
48
 
48
49
  _handle_contextual_response_rephraser(
rasa/studio/upload.py CHANGED
@@ -154,6 +154,10 @@ def handle_upload(args: argparse.Namespace) -> None:
154
154
  "Authentication is invalid or expired. Please run `rasa studio login`."
155
155
  )
156
156
 
157
+ from rasa.core.config.configuration import Configuration
158
+
159
+ Configuration.initialise_empty()
160
+
157
161
  structlogger.info("rasa.studio.upload.loading_data", event_info="Loading data...")
158
162
 
159
163
  args.domain = get_validated_path(args.domain, "domain", DEFAULT_DOMAIN_PATHS)
rasa/utils/log_utils.py CHANGED
@@ -23,6 +23,25 @@ ANSI_CYAN_BOLD = "\033[1;36m"
23
23
  ANSI_RESET = "\033[0m"
24
24
 
25
25
 
26
+ def conditional_set_exc_info(
27
+ logger: WrappedLogger, name: str, event_dict: EventDict
28
+ ) -> EventDict:
29
+ """Set exception info only if exception does not have suppress_stack_trace flag."""
30
+ exc_info = event_dict.get("exc_info")
31
+ if exc_info is not None:
32
+ is_debug_mode = logger.isEnabledFor(logging.DEBUG)
33
+
34
+ if (
35
+ hasattr(exc_info, "suppress_stack_trace")
36
+ and exc_info.suppress_stack_trace
37
+ and not is_debug_mode
38
+ ):
39
+ event_dict.pop("exc_info", None)
40
+ else:
41
+ return structlog.dev.set_exc_info(logger, name, event_dict)
42
+ return event_dict
43
+
44
+
26
45
  class HumanConsoleRenderer(ConsoleRenderer):
27
46
  """Console renderer that outputs human-readable logs."""
28
47
 
@@ -158,7 +177,7 @@ def configure_structlog(
158
177
  structlog.processors.StackInfoRenderer(),
159
178
  # If some value is in bytes, decode it to a unicode str.
160
179
  structlog.processors.UnicodeDecoder(),
161
- structlog.dev.set_exc_info,
180
+ conditional_set_exc_info,
162
181
  # add structlog sentry integration. only log fatal log entries
163
182
  # as events as we are tracking exceptions anyways
164
183
  SentryProcessor(event_level=logging.FATAL),
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.0rc4"
3
+ __version__ = "3.14.1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rasa-pro
3
- Version: 3.14.0rc4
3
+ Version: 3.14.1
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
@@ -108,7 +108,7 @@ Requires-Dist: pyyaml (>=6.0.2,<6.1.0)
108
108
  Requires-Dist: qdrant-client (>=1.9.1,<1.10.0)
109
109
  Requires-Dist: questionary (>=2.1.1,<2.2.0)
110
110
  Requires-Dist: randomname (>=0.2.1,<0.3.0)
111
- Requires-Dist: rasa-sdk (==3.14.0rc1)
111
+ Requires-Dist: rasa-sdk (==3.14.0)
112
112
  Requires-Dist: redis (>=4.6.0,<6.0)
113
113
  Requires-Dist: regex (>=2024.7.24,<2024.8.0)
114
114
  Requires-Dist: requests (>=2.32.5,<2.33.0)