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.
- rasa/agents/agent_manager.py +7 -5
- rasa/agents/protocol/a2a/a2a_agent.py +13 -11
- rasa/agents/protocol/mcp/mcp_base_agent.py +49 -11
- rasa/agents/validation.py +4 -2
- rasa/builder/copilot/copilot_templated_message_provider.py +1 -1
- rasa/builder/validation_service.py +4 -0
- rasa/cli/arguments/data.py +9 -0
- rasa/cli/data.py +72 -6
- rasa/cli/interactive.py +3 -0
- rasa/cli/llm_fine_tuning.py +1 -0
- rasa/cli/project_templates/defaults.py +1 -0
- rasa/cli/validation/bot_config.py +2 -0
- rasa/constants.py +1 -1
- rasa/core/actions/action_exceptions.py +1 -1
- rasa/core/agent.py +4 -1
- rasa/core/available_agents.py +1 -1
- rasa/core/exceptions.py +1 -1
- rasa/core/featurizers/tracker_featurizers.py +3 -2
- rasa/core/persistor.py +7 -7
- rasa/core/policies/flows/agent_executor.py +84 -4
- rasa/core/policies/flows/flow_exceptions.py +5 -2
- rasa/core/policies/flows/flow_executor.py +3 -2
- rasa/core/policies/flows/mcp_tool_executor.py +7 -1
- rasa/core/policies/rule_policy.py +1 -1
- rasa/dialogue_understanding/commands/cancel_flow_command.py +1 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +1 -1
- rasa/model_manager/runner_service.py +1 -1
- rasa/privacy/privacy_config.py +1 -1
- rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +4 -7
- rasa/shared/core/training_data/story_reader/story_reader.py +1 -1
- rasa/shared/exceptions.py +23 -2
- rasa/shared/providers/llm/litellm_router_llm_client.py +2 -2
- rasa/shared/utils/llm.py +21 -4
- rasa/shared/utils/mcp/server_connection.py +7 -4
- rasa/studio/download.py +3 -0
- rasa/studio/prompts.py +1 -0
- rasa/studio/upload.py +4 -0
- rasa/utils/log_utils.py +20 -1
- rasa/version.py +1 -1
- {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/METADATA +2 -2
- {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/RECORD +44 -44
- {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0rc4.dist-info → rasa_pro-3.14.1.dist-info}/WHEEL +0 -0
- {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(
|
|
185
|
+
return _handle_agent_fatal_error(
|
|
186
|
+
output, final_events, stack, step, flows, tracker
|
|
187
|
+
)
|
|
181
188
|
else:
|
|
182
|
-
return _handle_agent_unknown_status(
|
|
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
|
-
|
|
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(
|
|
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:
|
|
@@ -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
|
|
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(
|
rasa/privacy/privacy_config.py
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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]
|
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
|
-
"""
|
|
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.
|
|
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.
|
|
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],
|
|
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=
|
|
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
|
|
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(
|
|
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}
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: rasa-pro
|
|
3
|
-
Version: 3.14.
|
|
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.
|
|
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)
|