rasa-pro 3.13.7__py3-none-any.whl → 3.14.0.dev2__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/__init__.py +0 -0
- rasa/agents/agent_factory.py +122 -0
- rasa/agents/agent_manager.py +162 -0
- rasa/agents/constants.py +31 -0
- rasa/agents/core/__init__.py +0 -0
- rasa/agents/core/agent_protocol.py +108 -0
- rasa/agents/core/types.py +70 -0
- rasa/agents/exceptions.py +8 -0
- rasa/agents/protocol/__init__.py +5 -0
- rasa/agents/protocol/a2a/__init__.py +0 -0
- rasa/agents/protocol/a2a/a2a_agent.py +51 -0
- rasa/agents/protocol/mcp/__init__.py +0 -0
- rasa/agents/protocol/mcp/mcp_base_agent.py +697 -0
- rasa/agents/protocol/mcp/mcp_open_agent.py +275 -0
- rasa/agents/protocol/mcp/mcp_task_agent.py +447 -0
- rasa/agents/schemas/__init__.py +6 -0
- rasa/agents/schemas/agent_input.py +24 -0
- rasa/agents/schemas/agent_output.py +26 -0
- rasa/agents/schemas/agent_tool_result.py +51 -0
- rasa/agents/schemas/agent_tool_schema.py +112 -0
- rasa/agents/templates/__init__.py +0 -0
- rasa/agents/templates/mcp_open_agent_prompt_template.jinja2 +15 -0
- rasa/agents/templates/mcp_task_agent_prompt_template.jinja2 +13 -0
- rasa/agents/utils.py +72 -0
- rasa/api.py +5 -0
- rasa/cli/arguments/default_arguments.py +12 -0
- rasa/cli/arguments/run.py +2 -0
- rasa/cli/dialogue_understanding_test.py +4 -0
- rasa/cli/e2e_test.py +4 -0
- rasa/cli/inspect.py +3 -0
- rasa/cli/llm_fine_tuning.py +5 -0
- rasa/cli/run.py +4 -0
- rasa/cli/shell.py +3 -0
- rasa/cli/train.py +2 -2
- rasa/constants.py +6 -0
- rasa/core/actions/action.py +69 -39
- rasa/core/actions/action_run_slot_rejections.py +1 -1
- rasa/core/agent.py +16 -0
- rasa/core/available_agents.py +196 -0
- rasa/core/available_endpoints.py +30 -0
- rasa/core/channels/development_inspector.py +47 -14
- rasa/core/channels/inspector/dist/assets/{arc-0b11fe30.js → arc-2e78c586.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-9eef30a7.js → blockDiagram-38ab4fdb-806b712e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-03e94f28.js → c4Diagram-3d4e48cf-0745efa9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-c436ca7c.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-95c09eba.js → classDiagram-70f12bd4-7bd1082b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-38e8446c.js → classDiagram-v2-f2320105-d937ba49.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-50dd656b.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-57dc3038.js → createText-2e5e7dd3-a2a564ca.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-4bac0545.js → edges-e0da2a9e-b5256940.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-81795c90.js → erDiagram-9861fffd-e6883ad2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-89489ae6.js → flowDb-956e92f1-e576fc02.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-cd152627.js → flowDiagram-66a62f08-2e298d01.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b2aeaf8.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-3da369bc.js → flowchart-elk-definition-4a651766-dd7b150a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-85ec16f8.js → ganttDiagram-c361ad54-5b79575c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-495bc140.js → gitGraphDiagram-72cf32ee-3016f40a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-1ec4d266.js → graph-3e19170f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/index-1bd9135e.js +1353 -0
- rasa/core/channels/inspector/dist/assets/{index-3862675e-0a0e97c9.js → index-3862675e-eb9c86de.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-4d54bcde.js → infoDiagram-f8f76790-b4280e4d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-dc097114.js → journeyDiagram-49397b02-556091f8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-1a08981e.js → layout-08436411.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-95f7f1d3.js → line-683c4f3b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-97e69543.js → linear-cee6d791.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-8c71ff03.js → mindmap-definition-fc14e90a-a0bf0b1a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-f14c71c7.js → pieDiagram-8a3498a8-3730d5c4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-f1d3c9ff.js → quadrantDiagram-120e2f19-12a20fed.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-bfa2412f.js → requirementDiagram-deff3bca-b9732102.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-53f2c97b.js → sankeyDiagram-04a897e0-a2e72776.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-319d7c0e.js → sequenceDiagram-704730f1-8b7a76bb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-76a09418.js → stateDiagram-587899a1-e65853ac.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-a67f15d4.js → stateDiagram-v2-d93cdb3a-6f58a44b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-0654e7c3.js → styles-6aaf32cf-df25b934.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1394bb9d.js → styles-9a916d00-88357141.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-e4c5bdae.js → styles-c10674c1-d600174d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-50957104.js → svgDrawCommon-08f97a94-4adc3e0b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-b0885a6a.js → timeline-definition-85554ec2-42816fa1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-79e6541a.js → xychartDiagram-e933f94c-621eb66a.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +2 -2
- rasa/core/channels/inspector/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +53 -7
- rasa/core/channels/inspector/src/components/Chat.tsx +3 -2
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +1 -1
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +7 -5
- rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +268 -0
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -2
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +8 -3
- rasa/core/channels/inspector/src/helpers/formatters.ts +24 -3
- rasa/core/channels/inspector/src/theme/base/styles.ts +19 -1
- rasa/core/channels/inspector/src/types.ts +12 -0
- rasa/core/channels/studio_chat.py +125 -34
- rasa/core/channels/voice_ready/twilio_voice.py +1 -1
- rasa/core/channels/voice_stream/audiocodes.py +9 -6
- rasa/core/channels/voice_stream/browser_audio.py +39 -4
- rasa/core/channels/voice_stream/call_state.py +13 -2
- rasa/core/channels/voice_stream/genesys.py +16 -13
- rasa/core/channels/voice_stream/jambonz.py +13 -11
- rasa/core/channels/voice_stream/twilio_media_streams.py +14 -13
- rasa/core/channels/voice_stream/util.py +11 -1
- rasa/core/channels/voice_stream/voice_channel.py +101 -29
- rasa/core/constants.py +4 -0
- rasa/core/nlg/contextual_response_rephraser.py +11 -7
- rasa/core/nlg/generator.py +21 -5
- rasa/core/nlg/response.py +43 -6
- rasa/core/nlg/translate.py +8 -0
- rasa/core/policies/enterprise_search_policy.py +4 -2
- rasa/core/policies/flow_policy.py +2 -2
- rasa/core/policies/flows/flow_executor.py +374 -35
- rasa/core/policies/flows/mcp_tool_executor.py +240 -0
- rasa/core/processor.py +6 -1
- rasa/core/run.py +8 -1
- rasa/core/utils.py +21 -1
- rasa/dialogue_understanding/commands/__init__.py +8 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +97 -4
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +11 -0
- rasa/dialogue_understanding/commands/clarify_command.py +10 -0
- rasa/dialogue_understanding/commands/continue_agent_command.py +91 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +11 -0
- rasa/dialogue_understanding/commands/restart_agent_command.py +162 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +129 -8
- rasa/dialogue_understanding/commands/utils.py +6 -2
- rasa/dialogue_understanding/generator/command_parser.py +4 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +50 -12
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +61 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +61 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +81 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +81 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +7 -6
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +7 -6
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +41 -2
- rasa/dialogue_understanding/patterns/continue_interrupted.py +163 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +51 -7
- rasa/dialogue_understanding/stack/dialogue_stack.py +123 -2
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +57 -0
- rasa/dialogue_understanding/stack/utils.py +3 -2
- rasa/dialogue_understanding_test/du_test_runner.py +7 -2
- rasa/dialogue_understanding_test/du_test_schema.yml +3 -3
- rasa/e2e_test/e2e_test_runner.py +5 -0
- rasa/e2e_test/e2e_test_schema.yml +3 -3
- rasa/model_manager/model_api.py +1 -1
- rasa/model_manager/socket_bridge.py +8 -2
- rasa/server.py +10 -0
- rasa/shared/agents/__init__.py +0 -0
- rasa/shared/agents/utils.py +35 -0
- rasa/shared/constants.py +5 -0
- rasa/shared/core/constants.py +12 -1
- rasa/shared/core/domain.py +5 -5
- rasa/shared/core/events.py +319 -0
- rasa/shared/core/flows/flows_list.py +2 -2
- rasa/shared/core/flows/flows_yaml_schema.json +101 -186
- rasa/shared/core/flows/steps/call.py +51 -5
- rasa/shared/core/flows/validation.py +45 -7
- rasa/shared/core/flows/yaml_flows_io.py +3 -3
- rasa/shared/providers/llm/_base_litellm_client.py +39 -7
- rasa/shared/providers/llm/litellm_router_llm_client.py +8 -4
- rasa/shared/providers/llm/llm_client.py +7 -3
- rasa/shared/providers/llm/llm_response.py +49 -0
- rasa/shared/providers/llm/self_hosted_llm_client.py +8 -4
- rasa/shared/utils/common.py +2 -1
- rasa/shared/utils/llm.py +28 -5
- rasa/shared/utils/mcp/__init__.py +0 -0
- rasa/shared/utils/mcp/server_connection.py +157 -0
- rasa/shared/utils/schemas/events.py +42 -0
- rasa/studio/upload.py +4 -7
- rasa/tracing/instrumentation/instrumentation.py +4 -2
- rasa/utils/common.py +53 -0
- rasa/utils/licensing.py +21 -10
- rasa/utils/plotting.py +1 -1
- rasa/version.py +1 -1
- {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev2.dist-info}/METADATA +16 -15
- {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev2.dist-info}/RECORD +175 -138
- rasa/core/channels/inspector/dist/assets/channel-51d02e9e.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-cc738fa6.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-0c716443.js +0 -1
- rasa/core/channels/inspector/dist/assets/index-c804b295.js +0 -1335
- {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev2.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev2.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.7.dist-info → rasa_pro-3.14.0.dev2.dist-info}/entry_points.txt +0 -0
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import asyncio
|
|
4
|
+
from typing import Any, Dict, List, Optional, Text, cast
|
|
4
5
|
|
|
5
6
|
import structlog
|
|
6
7
|
from jinja2 import Template
|
|
7
8
|
from pypred import Predicate
|
|
8
|
-
from structlog.contextvars import
|
|
9
|
-
bound_contextvars,
|
|
10
|
-
)
|
|
9
|
+
from structlog.contextvars import bound_contextvars
|
|
11
10
|
|
|
11
|
+
from rasa.agents.agent_manager import AgentManager
|
|
12
|
+
from rasa.agents.constants import (
|
|
13
|
+
AGENT_METADATA_AGENT_RESPONSE_KEY,
|
|
14
|
+
AGENT_METADATA_EXIT_IF_KEY,
|
|
15
|
+
AGENT_METADATA_TOOL_RESULTS_KEY,
|
|
16
|
+
)
|
|
17
|
+
from rasa.agents.core.types import AgentStatus, ProtocolType
|
|
18
|
+
from rasa.agents.schemas import AgentInput, AgentOutput
|
|
19
|
+
from rasa.core.available_agents import AvailableAgents
|
|
12
20
|
from rasa.core.available_endpoints import AvailableEndpoints
|
|
13
21
|
from rasa.core.constants import ACTIVE_FLOW_METADATA_KEY, STEP_ID_METADATA_KEY
|
|
14
22
|
from rasa.core.policies.flows.flow_exceptions import (
|
|
@@ -22,7 +30,8 @@ from rasa.core.policies.flows.flow_step_result import (
|
|
|
22
30
|
FlowStepResult,
|
|
23
31
|
PauseFlowReturnPrediction,
|
|
24
32
|
)
|
|
25
|
-
from rasa.
|
|
33
|
+
from rasa.core.policies.flows.mcp_tool_executor import call_mcp_tool
|
|
34
|
+
from rasa.core.utils import get_slot_names_from_exit_conditions
|
|
26
35
|
from rasa.dialogue_understanding.patterns.cancel import CancelPatternFlowStackFrame
|
|
27
36
|
from rasa.dialogue_understanding.patterns.collect_information import (
|
|
28
37
|
FLOW_PATTERN_COLLECT_INFORMATION,
|
|
@@ -49,17 +58,27 @@ from rasa.dialogue_understanding.stack.frames import (
|
|
|
49
58
|
UserFlowStackFrame,
|
|
50
59
|
)
|
|
51
60
|
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
61
|
+
AgentStackFrame,
|
|
62
|
+
AgentState,
|
|
52
63
|
FlowStackFrameType,
|
|
53
64
|
)
|
|
54
|
-
from rasa.dialogue_understanding.stack.utils import
|
|
55
|
-
|
|
56
|
-
)
|
|
65
|
+
from rasa.dialogue_understanding.stack.utils import top_user_flow_frame
|
|
66
|
+
from rasa.shared.agents.utils import get_protocol_type
|
|
57
67
|
from rasa.shared.constants import RASA_PATTERN_HUMAN_HANDOFF
|
|
58
68
|
from rasa.shared.core.constants import (
|
|
69
|
+
ACTION_AGENT_REQUEST_USER_INPUT_NAME,
|
|
59
70
|
ACTION_LISTEN_NAME,
|
|
71
|
+
ACTION_METADATA_MESSAGE_KEY,
|
|
72
|
+
ACTION_METADATA_TEXT_KEY,
|
|
73
|
+
ACTION_SEND_TEXT_NAME,
|
|
74
|
+
FLOW_HASHES_SLOT,
|
|
60
75
|
SILENCE_TIMEOUT_SLOT,
|
|
61
76
|
)
|
|
62
77
|
from rasa.shared.core.events import (
|
|
78
|
+
AgentCancelled,
|
|
79
|
+
AgentCompleted,
|
|
80
|
+
AgentResumed,
|
|
81
|
+
AgentStarted,
|
|
63
82
|
Event,
|
|
64
83
|
FlowCompleted,
|
|
65
84
|
FlowResumed,
|
|
@@ -67,11 +86,7 @@ from rasa.shared.core.events import (
|
|
|
67
86
|
SlotSet,
|
|
68
87
|
)
|
|
69
88
|
from rasa.shared.core.flows import FlowsList
|
|
70
|
-
from rasa.shared.core.flows.flow import
|
|
71
|
-
END_STEP,
|
|
72
|
-
Flow,
|
|
73
|
-
FlowStep,
|
|
74
|
-
)
|
|
89
|
+
from rasa.shared.core.flows.flow import END_STEP, Flow, FlowStep
|
|
75
90
|
from rasa.shared.core.flows.flow_step_links import (
|
|
76
91
|
ElseFlowStepLink,
|
|
77
92
|
IfFlowStepLink,
|
|
@@ -89,14 +104,19 @@ from rasa.shared.core.flows.steps import (
|
|
|
89
104
|
)
|
|
90
105
|
from rasa.shared.core.flows.steps.constants import START_STEP
|
|
91
106
|
from rasa.shared.core.slots import Slot, SlotRejection
|
|
92
|
-
from rasa.shared.core.trackers import
|
|
93
|
-
|
|
94
|
-
)
|
|
107
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
108
|
+
from rasa.shared.utils.llm import tracker_as_readable_transcript
|
|
95
109
|
|
|
96
110
|
structlogger = structlog.get_logger()
|
|
97
111
|
|
|
98
112
|
MAX_NUMBER_OF_STEPS = 250
|
|
99
113
|
|
|
114
|
+
MAX_AGENT_RETRY_DELAY_SECONDS = 5
|
|
115
|
+
MAX_AGENT_RETRIES = 3
|
|
116
|
+
|
|
117
|
+
# Slots that should not be forwarded to sub-agents via AgentInput
|
|
118
|
+
SLOTS_EXCLUDED_FOR_AGENT = [FLOW_HASHES_SLOT]
|
|
119
|
+
|
|
100
120
|
|
|
101
121
|
def render_template_variables(text: str, context: Dict[Text, Any]) -> str:
|
|
102
122
|
"""Replace context variables in a text."""
|
|
@@ -148,6 +168,13 @@ def select_next_step_id(
|
|
|
148
168
|
tracker: DialogueStateTracker,
|
|
149
169
|
) -> Optional[Text]:
|
|
150
170
|
"""Selects the next step id based on the current step."""
|
|
171
|
+
# if the current step is a call step to an agent, and we already have an
|
|
172
|
+
# AgentStackFrame on top of the stack, we need to return the current
|
|
173
|
+
# step id again in order to loop back to the agent.
|
|
174
|
+
agent_stack_frame = tracker.stack.top()
|
|
175
|
+
if agent_stack_frame and isinstance(agent_stack_frame, AgentStackFrame):
|
|
176
|
+
return current.id
|
|
177
|
+
|
|
151
178
|
next_step = current.next
|
|
152
179
|
if len(next_step.links) == 1 and isinstance(next_step.links[0], StaticFlowStepLink):
|
|
153
180
|
return next_step.links[0].target
|
|
@@ -359,7 +386,7 @@ def reset_scoped_slots(
|
|
|
359
386
|
return events
|
|
360
387
|
|
|
361
388
|
|
|
362
|
-
def advance_flows(
|
|
389
|
+
async def advance_flows(
|
|
363
390
|
tracker: DialogueStateTracker, available_actions: List[str], flows: FlowsList
|
|
364
391
|
) -> FlowActionPrediction:
|
|
365
392
|
"""Advance the current flows until the next action.
|
|
@@ -377,10 +404,10 @@ def advance_flows(
|
|
|
377
404
|
# if there are no flows, there is nothing to do
|
|
378
405
|
return FlowActionPrediction(None, 0.0)
|
|
379
406
|
|
|
380
|
-
return advance_flows_until_next_action(tracker, available_actions, flows)
|
|
407
|
+
return await advance_flows_until_next_action(tracker, available_actions, flows)
|
|
381
408
|
|
|
382
409
|
|
|
383
|
-
def advance_flows_until_next_action(
|
|
410
|
+
async def advance_flows_until_next_action(
|
|
384
411
|
tracker: DialogueStateTracker,
|
|
385
412
|
available_actions: List[str],
|
|
386
413
|
flows: FlowsList,
|
|
@@ -441,7 +468,7 @@ def advance_flows_until_next_action(
|
|
|
441
468
|
|
|
442
469
|
with bound_contextvars(step_id=next_step.id):
|
|
443
470
|
step_stack = tracker.stack
|
|
444
|
-
step_result = run_step(
|
|
471
|
+
step_result = await run_step(
|
|
445
472
|
next_step,
|
|
446
473
|
current_flow,
|
|
447
474
|
step_stack,
|
|
@@ -477,10 +504,9 @@ def advance_flows_until_next_action(
|
|
|
477
504
|
# make sure we really return all events that got created during the
|
|
478
505
|
# step execution of all steps (not only the last one)
|
|
479
506
|
prediction.events = gathered_events
|
|
480
|
-
prediction.metadata = {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
507
|
+
prediction.metadata = prediction.metadata or {}
|
|
508
|
+
prediction.metadata[ACTIVE_FLOW_METADATA_KEY] = tracker.active_flow
|
|
509
|
+
prediction.metadata[STEP_ID_METADATA_KEY] = tracker.current_step_id
|
|
484
510
|
return prediction
|
|
485
511
|
else:
|
|
486
512
|
structlogger.warning("flow.step.execution.no_action")
|
|
@@ -522,6 +548,8 @@ def validate_collect_step(
|
|
|
522
548
|
|
|
523
549
|
def cancel_flow_and_push_internal_error(stack: DialogueStack, flow_name: str) -> None:
|
|
524
550
|
"""Cancel the top user flow and push the internal error pattern."""
|
|
551
|
+
from rasa.dialogue_understanding.commands import CancelFlowCommand
|
|
552
|
+
|
|
525
553
|
top_frame = stack.top()
|
|
526
554
|
|
|
527
555
|
if isinstance(top_frame, BaseFlowStackFrame):
|
|
@@ -550,7 +578,7 @@ def attach_stack_metadata_to_events(
|
|
|
550
578
|
event.metadata[ACTIVE_FLOW_METADATA_KEY] = flow_id
|
|
551
579
|
|
|
552
580
|
|
|
553
|
-
def run_step(
|
|
581
|
+
async def run_step(
|
|
554
582
|
step: FlowStep,
|
|
555
583
|
flow: Flow,
|
|
556
584
|
stack: DialogueStack,
|
|
@@ -615,7 +643,7 @@ def run_step(
|
|
|
615
643
|
return _run_link_step(initial_events, stack, step)
|
|
616
644
|
|
|
617
645
|
elif isinstance(step, CallFlowStep):
|
|
618
|
-
return _run_call_step(initial_events, stack, step)
|
|
646
|
+
return await _run_call_step(initial_events, stack, step, tracker)
|
|
619
647
|
|
|
620
648
|
elif isinstance(step, SetSlotsFlowStep):
|
|
621
649
|
return _run_set_slot_step(initial_events, step)
|
|
@@ -684,17 +712,25 @@ def _run_set_slot_step(
|
|
|
684
712
|
return ContinueFlowWithNextStep(events=initial_events + slot_events)
|
|
685
713
|
|
|
686
714
|
|
|
687
|
-
def _run_call_step(
|
|
688
|
-
initial_events: List[Event],
|
|
715
|
+
async def _run_call_step(
|
|
716
|
+
initial_events: List[Event],
|
|
717
|
+
stack: DialogueStack,
|
|
718
|
+
step: CallFlowStep,
|
|
719
|
+
tracker: DialogueStateTracker,
|
|
689
720
|
) -> FlowStepResult:
|
|
690
721
|
structlogger.debug("flow.step.run.call")
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
722
|
+
if step.is_calling_mcp_tool():
|
|
723
|
+
return await call_mcp_tool(initial_events, stack, step, tracker)
|
|
724
|
+
elif step.is_calling_agent():
|
|
725
|
+
return await run_agent(initial_events, stack, step, tracker)
|
|
726
|
+
else:
|
|
727
|
+
stack.push(
|
|
728
|
+
UserFlowStackFrame(
|
|
729
|
+
flow_id=step.call,
|
|
730
|
+
frame_type=FlowStackFrameType.CALL,
|
|
731
|
+
),
|
|
732
|
+
)
|
|
733
|
+
return ContinueFlowWithNextStep(events=initial_events)
|
|
698
734
|
|
|
699
735
|
|
|
700
736
|
def _run_link_step(
|
|
@@ -832,3 +868,306 @@ def _append_global_silence_timeout_event(
|
|
|
832
868
|
AvailableEndpoints.get_instance().interaction_handling.global_silence_timeout,
|
|
833
869
|
)
|
|
834
870
|
)
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
def _reset_slots_covered_by_exit_if(
|
|
874
|
+
exit_conditions: List[str], tracker: DialogueStateTracker
|
|
875
|
+
) -> None:
|
|
876
|
+
"""Reset the slots covered by the exit_if condition."""
|
|
877
|
+
reset_slot_names = get_slot_names_from_exit_conditions(exit_conditions)
|
|
878
|
+
for slot_name in reset_slot_names:
|
|
879
|
+
if tracker.slots.get(slot_name) is not None:
|
|
880
|
+
tracker.update(SlotSet(slot_name, None))
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
async def run_agent(
|
|
884
|
+
initial_events: List[Event],
|
|
885
|
+
stack: DialogueStack,
|
|
886
|
+
step: CallFlowStep,
|
|
887
|
+
tracker: DialogueStateTracker,
|
|
888
|
+
) -> FlowStepResult:
|
|
889
|
+
"""Run an agent call step."""
|
|
890
|
+
structlogger.debug(
|
|
891
|
+
"flow.step.run_agent", agent_id=step.call, step_id=step.id, flow_id=step.flow_id
|
|
892
|
+
)
|
|
893
|
+
|
|
894
|
+
final_events = initial_events
|
|
895
|
+
agent_stack_frame = tracker.stack.find_agent_stack_frame_by_agent(
|
|
896
|
+
agent_id=step.call
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
if (
|
|
900
|
+
agent_stack_frame
|
|
901
|
+
and agent_stack_frame == stack.top()
|
|
902
|
+
and agent_stack_frame.state == AgentState.INTERRUPTED
|
|
903
|
+
):
|
|
904
|
+
structlogger.debug(
|
|
905
|
+
"flow.step.run_agent.resume_interrupted_agent",
|
|
906
|
+
agent_id=step.call,
|
|
907
|
+
step_id=step.id,
|
|
908
|
+
flow_id=step.flow_id,
|
|
909
|
+
)
|
|
910
|
+
# The agent was previously interrupted when waiting for user input.
|
|
911
|
+
# Now we're back to the agent execution step and need to output the last message
|
|
912
|
+
# from the agent (user input request) again and wait for user input
|
|
913
|
+
cast(AgentStackFrame, stack.top()).state = AgentState.WAITING_FOR_INPUT
|
|
914
|
+
tracker.update_stack(stack)
|
|
915
|
+
utterance = (
|
|
916
|
+
agent_stack_frame.metadata.get(AGENT_METADATA_AGENT_RESPONSE_KEY, "")
|
|
917
|
+
if agent_stack_frame.metadata
|
|
918
|
+
else ""
|
|
919
|
+
)
|
|
920
|
+
final_events.append(AgentResumed(agent_id=step.call, flow_id=step.flow_id))
|
|
921
|
+
return PauseFlowReturnPrediction(
|
|
922
|
+
_create_agent_request_user_input_prediction(utterance, final_events)
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
agent_input_metadata = (
|
|
926
|
+
agent_stack_frame.metadata
|
|
927
|
+
if agent_stack_frame and agent_stack_frame.metadata
|
|
928
|
+
else {}
|
|
929
|
+
)
|
|
930
|
+
if step.exit_if:
|
|
931
|
+
# TODO: this is a temporary fix to reset the slots covered by the exit_if
|
|
932
|
+
if (
|
|
933
|
+
agent_stack_frame
|
|
934
|
+
and agent_stack_frame.frame_id == f"restart_agent_{step.call}"
|
|
935
|
+
):
|
|
936
|
+
# when restarting an agent, we need to reset the slots covered by the
|
|
937
|
+
# exit_if condition so that the agent can run again.
|
|
938
|
+
_reset_slots_covered_by_exit_if(step.exit_if, tracker)
|
|
939
|
+
agent_input_metadata[AGENT_METADATA_EXIT_IF_KEY] = step.exit_if
|
|
940
|
+
agent_input = AgentInput(
|
|
941
|
+
id=step.call,
|
|
942
|
+
user_message=tracker.latest_message.text or ""
|
|
943
|
+
if tracker.latest_message
|
|
944
|
+
else "",
|
|
945
|
+
slots=_filter_slots_for_agent(tracker.current_slot_values()),
|
|
946
|
+
conversation_history=tracker_as_readable_transcript(tracker),
|
|
947
|
+
events=tracker.current_state().get("events") or [],
|
|
948
|
+
metadata=agent_input_metadata,
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
final_events.append(AgentStarted(step.call, step.flow_id))
|
|
952
|
+
|
|
953
|
+
protocol_type = get_protocol_type(step, AvailableAgents.get_agent_config(step.call))
|
|
954
|
+
# send the input to the agent and wait for a response
|
|
955
|
+
structlogger.debug(
|
|
956
|
+
"flow.step.run_agent.agent_input",
|
|
957
|
+
agent_name=step.call,
|
|
958
|
+
step_id=step.id,
|
|
959
|
+
flow_id=step.flow_id,
|
|
960
|
+
agent_input=agent_input,
|
|
961
|
+
)
|
|
962
|
+
output: AgentOutput = await _call_agent_with_retry(
|
|
963
|
+
agent_name=step.call,
|
|
964
|
+
protocol_type=protocol_type,
|
|
965
|
+
agent_input=agent_input,
|
|
966
|
+
max_retries=MAX_AGENT_RETRIES,
|
|
967
|
+
)
|
|
968
|
+
structlogger.debug(
|
|
969
|
+
"flow.step.run_agent.agent_response",
|
|
970
|
+
agent_name=step.call,
|
|
971
|
+
step_id=step.id,
|
|
972
|
+
flow_id=step.flow_id,
|
|
973
|
+
agent_response=output,
|
|
974
|
+
)
|
|
975
|
+
|
|
976
|
+
# add the set slot events returned by the agent to the list of final events
|
|
977
|
+
if output.events:
|
|
978
|
+
final_events.extend(output.events)
|
|
979
|
+
|
|
980
|
+
if output.status == AgentStatus.INPUT_REQUIRED:
|
|
981
|
+
output.metadata = output.metadata or {}
|
|
982
|
+
output.metadata[AGENT_METADATA_AGENT_RESPONSE_KEY] = (
|
|
983
|
+
output.response_message or ""
|
|
984
|
+
)
|
|
985
|
+
output.metadata[AGENT_METADATA_TOOL_RESULTS_KEY] = output.tool_results or []
|
|
986
|
+
|
|
987
|
+
top_stack_frame = stack.top()
|
|
988
|
+
# update the agent stack frame if it is already on the stack
|
|
989
|
+
# otherwise push a new one
|
|
990
|
+
if isinstance(top_stack_frame, AgentStackFrame):
|
|
991
|
+
top_stack_frame.state = AgentState.WAITING_FOR_INPUT
|
|
992
|
+
top_stack_frame.metadata = output.metadata
|
|
993
|
+
top_stack_frame.step_id = step.id
|
|
994
|
+
top_stack_frame.agent_id = step.call
|
|
995
|
+
top_stack_frame.flow_id = step.flow_id
|
|
996
|
+
else:
|
|
997
|
+
stack.push(
|
|
998
|
+
AgentStackFrame(
|
|
999
|
+
flow_id=step.flow_id,
|
|
1000
|
+
agent_id=step.call,
|
|
1001
|
+
state=AgentState.WAITING_FOR_INPUT,
|
|
1002
|
+
step_id=step.id,
|
|
1003
|
+
metadata=output.metadata,
|
|
1004
|
+
)
|
|
1005
|
+
)
|
|
1006
|
+
|
|
1007
|
+
action_prediction = _create_agent_request_user_input_prediction(
|
|
1008
|
+
output.response_message, final_events
|
|
1009
|
+
)
|
|
1010
|
+
return PauseFlowReturnPrediction(action_prediction)
|
|
1011
|
+
elif output.status == AgentStatus.COMPLETED:
|
|
1012
|
+
structlogger.debug(
|
|
1013
|
+
"flow.step.run_agent.completed",
|
|
1014
|
+
agent_name=step.call,
|
|
1015
|
+
step_id=step.id,
|
|
1016
|
+
flow_id=step.flow_id,
|
|
1017
|
+
)
|
|
1018
|
+
remove_agent_stack_frame(stack, step.call)
|
|
1019
|
+
agent_completed_event = AgentCompleted(agent_id=step.call, flow_id=step.flow_id)
|
|
1020
|
+
final_events.append(agent_completed_event)
|
|
1021
|
+
if output.response_message:
|
|
1022
|
+
# for open-ended agents we want to utter the last agent message
|
|
1023
|
+
|
|
1024
|
+
return PauseFlowReturnPrediction(
|
|
1025
|
+
_create_send_text_prediction(output.response_message, final_events)
|
|
1026
|
+
)
|
|
1027
|
+
else:
|
|
1028
|
+
return ContinueFlowWithNextStep(events=final_events)
|
|
1029
|
+
elif output.status == AgentStatus.FATAL_ERROR:
|
|
1030
|
+
# the agent failed, trigger pattern_internal_error
|
|
1031
|
+
structlogger.error(
|
|
1032
|
+
"flow.step.run_agent.fatal_error",
|
|
1033
|
+
agent_name=step.call,
|
|
1034
|
+
step_id=step.id,
|
|
1035
|
+
flow_id=step.flow_id,
|
|
1036
|
+
error_message=output.error_message,
|
|
1037
|
+
)
|
|
1038
|
+
remove_agent_stack_frame(stack, step.call)
|
|
1039
|
+
final_events.append(
|
|
1040
|
+
AgentCancelled(
|
|
1041
|
+
agent_id=step.call, flow_id=step.flow_id, reason=output.error_message
|
|
1042
|
+
)
|
|
1043
|
+
)
|
|
1044
|
+
stack.push(InternalErrorPatternFlowStackFrame())
|
|
1045
|
+
return ContinueFlowWithNextStep(events=final_events)
|
|
1046
|
+
else:
|
|
1047
|
+
structlogger.error(
|
|
1048
|
+
"flow.step.run_agent.unknown_status",
|
|
1049
|
+
agent_name=step.call,
|
|
1050
|
+
step_id=step.id,
|
|
1051
|
+
flow_id=step.flow_id,
|
|
1052
|
+
status=output.status,
|
|
1053
|
+
)
|
|
1054
|
+
remove_agent_stack_frame(stack, step.call)
|
|
1055
|
+
final_events.append(AgentCancelled(agent_id=step.call, flow_id=step.flow_id))
|
|
1056
|
+
stack.push(InternalErrorPatternFlowStackFrame())
|
|
1057
|
+
return ContinueFlowWithNextStep(events=final_events)
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
def remove_agent_stack_frame(stack: DialogueStack, agent_id: str) -> None:
|
|
1061
|
+
"""Finishes the agentic loop by popping the agent stack frame from the
|
|
1062
|
+
provided `stack`. The `tracker.stack` is NOT modified.
|
|
1063
|
+
"""
|
|
1064
|
+
agent_stack_frame = stack.find_agent_stack_frame_by_agent(agent_id)
|
|
1065
|
+
if not agent_stack_frame:
|
|
1066
|
+
return
|
|
1067
|
+
|
|
1068
|
+
while removed_frame := stack.pop():
|
|
1069
|
+
structlogger.debug(
|
|
1070
|
+
"flow_executor.remove_agent_stack_frame",
|
|
1071
|
+
removed_frame=removed_frame,
|
|
1072
|
+
)
|
|
1073
|
+
if removed_frame == agent_stack_frame:
|
|
1074
|
+
break
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
def _create_action_prediction(
|
|
1078
|
+
action_name: str, message: Optional[str], events: Optional[List[Event]]
|
|
1079
|
+
) -> FlowActionPrediction:
|
|
1080
|
+
"""Create a prediction for an action with a text message."""
|
|
1081
|
+
action_metadata = {
|
|
1082
|
+
ACTION_METADATA_MESSAGE_KEY: {
|
|
1083
|
+
ACTION_METADATA_TEXT_KEY: message,
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return FlowActionPrediction(
|
|
1087
|
+
action_name,
|
|
1088
|
+
1.0,
|
|
1089
|
+
events=events if events else [],
|
|
1090
|
+
metadata=action_metadata,
|
|
1091
|
+
)
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
def _create_agent_request_user_input_prediction(
|
|
1095
|
+
message: Optional[str], events: Optional[List[Event]]
|
|
1096
|
+
) -> FlowActionPrediction:
|
|
1097
|
+
"""Create a prediction for requesting user input from the agent
|
|
1098
|
+
and waiting for it.
|
|
1099
|
+
"""
|
|
1100
|
+
return _create_action_prediction(
|
|
1101
|
+
ACTION_AGENT_REQUEST_USER_INPUT_NAME, message, events
|
|
1102
|
+
)
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
def _create_send_text_prediction(
|
|
1106
|
+
message: Optional[str], events: Optional[List[Event]]
|
|
1107
|
+
) -> FlowActionPrediction:
|
|
1108
|
+
"""Create a prediction for sending a text message to the user."""
|
|
1109
|
+
return _create_action_prediction(ACTION_SEND_TEXT_NAME, message, events)
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
async def _call_agent_with_retry(
|
|
1113
|
+
agent_name: str,
|
|
1114
|
+
protocol_type: ProtocolType,
|
|
1115
|
+
agent_input: AgentInput,
|
|
1116
|
+
max_retries: int,
|
|
1117
|
+
) -> AgentOutput:
|
|
1118
|
+
"""Call an agent with retries in case of recoverable errors."""
|
|
1119
|
+
for attempt in range(max_retries):
|
|
1120
|
+
if attempt > 0:
|
|
1121
|
+
structlogger.debug(
|
|
1122
|
+
"flow_executor.call_agent_with_retry.retrying",
|
|
1123
|
+
agent_name=agent_name,
|
|
1124
|
+
attempt=attempt + 1,
|
|
1125
|
+
num_retries=max_retries,
|
|
1126
|
+
)
|
|
1127
|
+
|
|
1128
|
+
agent_response: AgentOutput = await AgentManager().run_agent(
|
|
1129
|
+
agent_name=agent_name, protocol_type=protocol_type, context=agent_input
|
|
1130
|
+
)
|
|
1131
|
+
if agent_response.status != AgentStatus.RECOVERABLE_ERROR:
|
|
1132
|
+
return agent_response
|
|
1133
|
+
|
|
1134
|
+
structlogger.warning(
|
|
1135
|
+
"flow_executor.call_agent_with_retry.recoverable_error",
|
|
1136
|
+
agent_name=agent_name,
|
|
1137
|
+
attempt=attempt + 1,
|
|
1138
|
+
num_retries=max_retries,
|
|
1139
|
+
error_message=agent_response.error_message,
|
|
1140
|
+
)
|
|
1141
|
+
if attempt < max_retries - 1:
|
|
1142
|
+
# exponential backoff - wait longer with each retry
|
|
1143
|
+
# 1 second, 2 seconds, 4 seconds, etc.
|
|
1144
|
+
await asyncio.sleep(min(2**attempt, MAX_AGENT_RETRY_DELAY_SECONDS))
|
|
1145
|
+
|
|
1146
|
+
# we exhausted all retries, return fatal error
|
|
1147
|
+
structlogger.warning(
|
|
1148
|
+
"flow_executor.call_agent_with_retry.exhausted_retries",
|
|
1149
|
+
agent_name=agent_name,
|
|
1150
|
+
num_retries=max_retries,
|
|
1151
|
+
)
|
|
1152
|
+
return AgentOutput(
|
|
1153
|
+
id=agent_name,
|
|
1154
|
+
status=AgentStatus.FATAL_ERROR,
|
|
1155
|
+
error_message="Exhausted all retries for agent call.",
|
|
1156
|
+
)
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
def _filter_slots_for_agent(slots: Dict[str, Any]) -> Dict[str, Any]:
|
|
1160
|
+
"""Filter out slots that should not be forwarded to agents.
|
|
1161
|
+
|
|
1162
|
+
Args:
|
|
1163
|
+
slots: The full slot dictionary from the tracker.
|
|
1164
|
+
|
|
1165
|
+
Returns:
|
|
1166
|
+
A copy of the slot dictionary excluding slots listed in
|
|
1167
|
+
`SLOTS_EXCLUDED_FOR_AGENT`.
|
|
1168
|
+
"""
|
|
1169
|
+
return {
|
|
1170
|
+
key: value
|
|
1171
|
+
for key, value in slots.items()
|
|
1172
|
+
if key not in SLOTS_EXCLUDED_FOR_AGENT
|
|
1173
|
+
}
|