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
|
@@ -8,6 +8,13 @@ from typing import Any, Callable, Dict, List, Optional
|
|
|
8
8
|
import jsonpatch
|
|
9
9
|
import structlog
|
|
10
10
|
|
|
11
|
+
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
12
|
+
AgentStackFrame,
|
|
13
|
+
AgentState,
|
|
14
|
+
FlowStackFrameType,
|
|
15
|
+
UserFlowStackFrame,
|
|
16
|
+
)
|
|
17
|
+
|
|
11
18
|
if typing.TYPE_CHECKING:
|
|
12
19
|
from rasa.dialogue_understanding.stack.frames import DialogueStackFrame
|
|
13
20
|
|
|
@@ -91,6 +98,42 @@ class DialogueStack:
|
|
|
91
98
|
"""
|
|
92
99
|
return self.frames.pop()
|
|
93
100
|
|
|
101
|
+
def move_frames_to_top(self, frames_to_move: List["DialogueStackFrame"]) -> None:
|
|
102
|
+
"""Moves specified frames to top of stack while preserving their relative order.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
frames_to_move: The frames to move to the top of the stack.
|
|
106
|
+
"""
|
|
107
|
+
# Get frames that are not being moved
|
|
108
|
+
frames_to_keep = [frame for frame in self.frames if frame not in frames_to_move]
|
|
109
|
+
|
|
110
|
+
# Reorder: keep frames first, then moved frames
|
|
111
|
+
self.frames = frames_to_keep + frames_to_move
|
|
112
|
+
|
|
113
|
+
# set all frames to interrupt except for LINK and CALL
|
|
114
|
+
for frame in self.frames:
|
|
115
|
+
if (
|
|
116
|
+
isinstance(frame, UserFlowStackFrame)
|
|
117
|
+
and frame.frame_type == FlowStackFrameType.LINK
|
|
118
|
+
):
|
|
119
|
+
continue
|
|
120
|
+
if (
|
|
121
|
+
isinstance(frame, UserFlowStackFrame)
|
|
122
|
+
and frame.frame_type == FlowStackFrameType.CALL
|
|
123
|
+
):
|
|
124
|
+
continue
|
|
125
|
+
if (
|
|
126
|
+
isinstance(frame, UserFlowStackFrame)
|
|
127
|
+
and frame.frame_type == FlowStackFrameType.REGULAR
|
|
128
|
+
):
|
|
129
|
+
frame.frame_type = FlowStackFrameType.INTERRUPT
|
|
130
|
+
|
|
131
|
+
# set the first frame to regular
|
|
132
|
+
for frame in self.frames:
|
|
133
|
+
if isinstance(frame, UserFlowStackFrame):
|
|
134
|
+
frame.frame_type = FlowStackFrameType.REGULAR
|
|
135
|
+
return
|
|
136
|
+
|
|
94
137
|
def current_context(self) -> Dict[str, Any]:
|
|
95
138
|
"""Returns the context of the topmost frame.
|
|
96
139
|
|
|
@@ -109,7 +152,7 @@ class DialogueStack:
|
|
|
109
152
|
"""Returns the topmost frame from the stack.
|
|
110
153
|
|
|
111
154
|
Args:
|
|
112
|
-
|
|
155
|
+
ignore: The ID of the flow to ignore. Picks the top most
|
|
113
156
|
frame that has a different flow ID.
|
|
114
157
|
|
|
115
158
|
Returns:
|
|
@@ -136,7 +179,8 @@ class DialogueStack:
|
|
|
136
179
|
patch_dump: The patch to apply to the stack.
|
|
137
180
|
|
|
138
181
|
Returns:
|
|
139
|
-
|
|
182
|
+
The updated stack.
|
|
183
|
+
"""
|
|
140
184
|
patch = jsonpatch.JsonPatch.from_string(patch_dump)
|
|
141
185
|
dialogue_stack_dump = patch.apply(self.as_dict())
|
|
142
186
|
return DialogueStack.from_dict(dialogue_stack_dump)
|
|
@@ -177,3 +221,80 @@ class DialogueStack:
|
|
|
177
221
|
if patch:
|
|
178
222
|
return patch.to_string()
|
|
179
223
|
return None
|
|
224
|
+
|
|
225
|
+
def _find_agent_frame_by_predicate(
|
|
226
|
+
self, predicate: Callable[[AgentStackFrame], bool]
|
|
227
|
+
) -> List[AgentStackFrame]:
|
|
228
|
+
stack_frames: List[AgentStackFrame] = []
|
|
229
|
+
for stack_frame in reversed(self.frames):
|
|
230
|
+
if isinstance(stack_frame, AgentStackFrame) and predicate(stack_frame):
|
|
231
|
+
stack_frames.append(stack_frame)
|
|
232
|
+
return stack_frames
|
|
233
|
+
|
|
234
|
+
def find_active_agent_frame(self) -> Optional[AgentStackFrame]:
|
|
235
|
+
stack_frames = self._find_agent_frame_by_predicate(
|
|
236
|
+
lambda frame: frame.state == AgentState.WAITING_FOR_INPUT
|
|
237
|
+
)
|
|
238
|
+
if stack_frames:
|
|
239
|
+
return stack_frames[0]
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
def find_agent_stack_frame_by_agent(
|
|
243
|
+
self, agent_id: str
|
|
244
|
+
) -> Optional[AgentStackFrame]:
|
|
245
|
+
"""Get the agent stack frame for a specific agent ID.
|
|
246
|
+
|
|
247
|
+
May also include the agent stack frame in the INTERRUPTED state.
|
|
248
|
+
"""
|
|
249
|
+
stack_frames = self._find_agent_frame_by_predicate(
|
|
250
|
+
lambda frame: frame.agent_id == agent_id
|
|
251
|
+
)
|
|
252
|
+
if stack_frames:
|
|
253
|
+
return stack_frames[0]
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
def find_active_agent_stack_frame_for_flow(
|
|
257
|
+
self, flow_id: str
|
|
258
|
+
) -> Optional[AgentStackFrame]:
|
|
259
|
+
"""Get the agent stack frame of a specific flow."""
|
|
260
|
+
stack_frames = self._find_agent_frame_by_predicate(
|
|
261
|
+
lambda frame: frame.flow_id == flow_id
|
|
262
|
+
)
|
|
263
|
+
for stack_frame in stack_frames:
|
|
264
|
+
if stack_frame.state == AgentState.WAITING_FOR_INPUT:
|
|
265
|
+
return stack_frame
|
|
266
|
+
return None
|
|
267
|
+
|
|
268
|
+
def get_active_agent_id(self) -> Optional[typing.Text]:
|
|
269
|
+
agent_frame = self.find_active_agent_frame()
|
|
270
|
+
if agent_frame:
|
|
271
|
+
return agent_frame.agent_id
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
def agent_is_active(self) -> bool:
|
|
275
|
+
return self.find_active_agent_frame() is not None
|
|
276
|
+
|
|
277
|
+
def get_all_user_flow_frames(
|
|
278
|
+
self, ignore_call_and_link_frames: bool = True
|
|
279
|
+
) -> List[UserFlowStackFrame]:
|
|
280
|
+
"""Get all user flow frames from the dialogue stack.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
ignore_call_and_link_frames: Whether to ignore user frames of type `call`
|
|
284
|
+
and `link`. By default, these frames are ignored.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
A list of all user flow frames in the dialogue stack.
|
|
288
|
+
"""
|
|
289
|
+
return [
|
|
290
|
+
frame
|
|
291
|
+
for frame in self.frames
|
|
292
|
+
if isinstance(frame, UserFlowStackFrame)
|
|
293
|
+
and (
|
|
294
|
+
not ignore_call_and_link_frames
|
|
295
|
+
or (
|
|
296
|
+
frame.frame_type != FlowStackFrameType.CALL
|
|
297
|
+
and frame.frame_type != FlowStackFrameType.LINK
|
|
298
|
+
)
|
|
299
|
+
)
|
|
300
|
+
]
|
|
@@ -94,6 +94,18 @@ class InvalidFlowStepIdException(Exception):
|
|
|
94
94
|
super().__init__(f"Invalid flow step ID '{step_id}' for flow '{flow_id}'.")
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
class InvalidAgentState(RasaException):
|
|
98
|
+
"""Raised if the agent state is invalid."""
|
|
99
|
+
|
|
100
|
+
def __init__(self, invalid_state: str) -> None:
|
|
101
|
+
"""Creates a `InvalidAgentState`.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
invalid_state: The invalid agent state.
|
|
105
|
+
"""
|
|
106
|
+
super().__init__(f"Invalid agent state '{invalid_state}'.")
|
|
107
|
+
|
|
108
|
+
|
|
97
109
|
@dataclass
|
|
98
110
|
class BaseFlowStackFrame(DialogueStackFrame):
|
|
99
111
|
flow_id: str = "" # needed to avoid "default arg before non-default" error
|
|
@@ -171,3 +183,48 @@ class UserFlowStackFrame(BaseFlowStackFrame):
|
|
|
171
183
|
step_id=data["step_id"],
|
|
172
184
|
frame_type=FlowStackFrameType.from_str(data.get("frame_type")),
|
|
173
185
|
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class AgentState(str, Enum):
|
|
189
|
+
INTERRUPTED = "interrupted"
|
|
190
|
+
WAITING_FOR_INPUT = "waiting_for_input"
|
|
191
|
+
|
|
192
|
+
@staticmethod
|
|
193
|
+
def from_str(state: Optional[str]) -> AgentState:
|
|
194
|
+
if state == AgentState.WAITING_FOR_INPUT.value:
|
|
195
|
+
return AgentState.WAITING_FOR_INPUT
|
|
196
|
+
elif state == AgentState.INTERRUPTED.value:
|
|
197
|
+
return AgentState.INTERRUPTED
|
|
198
|
+
else:
|
|
199
|
+
raise InvalidAgentState(state)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@dataclass
|
|
203
|
+
class AgentStackFrame(BaseFlowStackFrame):
|
|
204
|
+
agent_id: str = ""
|
|
205
|
+
state: AgentState = AgentState.WAITING_FOR_INPUT
|
|
206
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
207
|
+
|
|
208
|
+
@classmethod
|
|
209
|
+
def type(cls) -> str:
|
|
210
|
+
"""Returns the type of the frame."""
|
|
211
|
+
return "agent"
|
|
212
|
+
|
|
213
|
+
@staticmethod
|
|
214
|
+
def from_dict(data: Dict[str, Any]) -> AgentStackFrame:
|
|
215
|
+
"""Creates a `AgentStackFrame` from a dictionary.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
data: The dictionary to create the `AgentStackFrame` from.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
The created `AgentStackFrame`.
|
|
222
|
+
"""
|
|
223
|
+
return AgentStackFrame(
|
|
224
|
+
frame_id=data["frame_id"],
|
|
225
|
+
flow_id=data["flow_id"],
|
|
226
|
+
step_id=data["step_id"],
|
|
227
|
+
agent_id=data["agent_id"],
|
|
228
|
+
state=AgentState.from_str(data["state"]),
|
|
229
|
+
metadata=data.get("metadata"),
|
|
230
|
+
)
|
|
@@ -198,8 +198,9 @@ def end_top_user_flow(stack: DialogueStack) -> DialogueStack:
|
|
|
198
198
|
def get_collect_steps_excluding_ask_before_filling_for_active_flow(
|
|
199
199
|
dialogue_stack: DialogueStack, all_flows: FlowsList
|
|
200
200
|
) -> Set[str]:
|
|
201
|
-
"""Get all collect steps that are part of the current flow
|
|
202
|
-
|
|
201
|
+
"""Get all collect steps that are part of the current flow.
|
|
202
|
+
|
|
203
|
+
Collect steps that have to be asked before filling are not considered.
|
|
203
204
|
|
|
204
205
|
Args:
|
|
205
206
|
dialogue_stack: The dialogue stack.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import time
|
|
3
|
-
from
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict, List, Optional, Union
|
|
4
5
|
|
|
5
6
|
import structlog
|
|
6
7
|
from tqdm import tqdm
|
|
7
8
|
|
|
9
|
+
from rasa.core.available_agents import AvailableAgents
|
|
8
10
|
from rasa.core.available_endpoints import AvailableEndpoints
|
|
9
11
|
from rasa.core.channels import CollectingOutputChannel, UserMessage
|
|
10
12
|
from rasa.core.exceptions import AgentNotReady
|
|
@@ -52,10 +54,11 @@ class DialogueUnderstandingTestRunner:
|
|
|
52
54
|
|
|
53
55
|
def __init__(
|
|
54
56
|
self,
|
|
55
|
-
model_path: Optional[
|
|
57
|
+
model_path: Optional[str] = None,
|
|
56
58
|
model_server: Optional[EndpointConfig] = None,
|
|
57
59
|
remote_storage: Optional[StorageType] = None,
|
|
58
60
|
endpoints: Optional[AvailableEndpoints] = None,
|
|
61
|
+
sub_agents_path: Optional[Union[Path, str]] = None,
|
|
59
62
|
) -> None:
|
|
60
63
|
"""Initializes the Dialogue Understanding test suite runner.
|
|
61
64
|
|
|
@@ -68,6 +71,7 @@ class DialogueUnderstandingTestRunner:
|
|
|
68
71
|
import rasa.core.agent
|
|
69
72
|
|
|
70
73
|
self._check_action_server(endpoints)
|
|
74
|
+
sub_agents = AvailableAgents.get_instance(sub_agents_path)
|
|
71
75
|
|
|
72
76
|
self.agent = asyncio.run(
|
|
73
77
|
rasa.core.agent.load_agent(
|
|
@@ -75,6 +79,7 @@ class DialogueUnderstandingTestRunner:
|
|
|
75
79
|
model_server=model_server,
|
|
76
80
|
remote_storage=remote_storage,
|
|
77
81
|
endpoints=endpoints,
|
|
82
|
+
sub_agents=sub_agents,
|
|
78
83
|
)
|
|
79
84
|
)
|
|
80
85
|
if not self.agent.is_ready():
|
|
@@ -5,12 +5,12 @@ mapping:
|
|
|
5
5
|
sequence:
|
|
6
6
|
- type: map
|
|
7
7
|
mapping:
|
|
8
|
-
regex;(^[a-zA-Z_]+[a-zA-Z0-9_]*$):
|
|
8
|
+
regex;(^[a-zA-Z_]+[a-zA-Z0-9_\-]*$):
|
|
9
9
|
type: "seq"
|
|
10
10
|
sequence:
|
|
11
11
|
- type: map
|
|
12
12
|
mapping:
|
|
13
|
-
regex;(^[a-zA-Z_]+[a-zA-Z0-9_]*$):
|
|
13
|
+
regex;(^[a-zA-Z_]+[a-zA-Z0-9_\-]*$):
|
|
14
14
|
type: any
|
|
15
15
|
|
|
16
16
|
metadata:
|
|
@@ -129,7 +129,7 @@ mapping:
|
|
|
129
129
|
type: "seq"
|
|
130
130
|
sequence:
|
|
131
131
|
- type: "str"
|
|
132
|
-
pattern: ^[a-zA-Z_]+[a-zA-Z0-9_]*$
|
|
132
|
+
pattern: ^[a-zA-Z_]+[a-zA-Z0-9_\-]*$
|
|
133
133
|
metadata:
|
|
134
134
|
type: "str"
|
|
135
135
|
pattern: ^[a-zA-Z_]+[a-zA-Z0-9_]*$
|
rasa/e2e_test/e2e_test_runner.py
CHANGED
|
@@ -13,6 +13,7 @@ import structlog
|
|
|
13
13
|
from tqdm import tqdm
|
|
14
14
|
|
|
15
15
|
import rasa.shared.utils.io
|
|
16
|
+
from rasa.core.available_agents import AvailableAgents
|
|
16
17
|
from rasa.core.available_endpoints import AvailableEndpoints
|
|
17
18
|
from rasa.core.channels import CollectingOutputChannel, UserMessage
|
|
18
19
|
from rasa.core.constants import ACTIVE_FLOW_METADATA_KEY, STEP_ID_METADATA_KEY
|
|
@@ -65,6 +66,7 @@ class E2ETestRunner:
|
|
|
65
66
|
model_server: Optional[EndpointConfig] = None,
|
|
66
67
|
remote_storage: Optional[StorageType] = None,
|
|
67
68
|
endpoints: Optional[AvailableEndpoints] = None,
|
|
69
|
+
sub_agents_path: Optional[Text] = None,
|
|
68
70
|
**kwargs: Any,
|
|
69
71
|
) -> None:
|
|
70
72
|
"""Initializes the E2E test suite runner.
|
|
@@ -94,12 +96,15 @@ class E2ETestRunner:
|
|
|
94
96
|
if endpoints and not are_custom_actions_stubbed:
|
|
95
97
|
self._action_server_is_reachable(endpoints)
|
|
96
98
|
|
|
99
|
+
sub_agents = AvailableAgents.get_instance(sub_agents_path)
|
|
100
|
+
|
|
97
101
|
self.agent = asyncio.run(
|
|
98
102
|
rasa.core.agent.load_agent(
|
|
99
103
|
model_path=model_path,
|
|
100
104
|
model_server=model_server,
|
|
101
105
|
remote_storage=remote_storage,
|
|
102
106
|
endpoints=endpoints,
|
|
107
|
+
sub_agents=sub_agents,
|
|
103
108
|
)
|
|
104
109
|
)
|
|
105
110
|
|
|
@@ -5,12 +5,12 @@ mapping:
|
|
|
5
5
|
sequence:
|
|
6
6
|
- type: map
|
|
7
7
|
mapping:
|
|
8
|
-
regex;(^[a-zA-Z_]+[a-zA-Z0-9_]*$):
|
|
8
|
+
regex;(^[a-zA-Z_]+[a-zA-Z0-9_\-]*$):
|
|
9
9
|
type: "seq"
|
|
10
10
|
sequence:
|
|
11
11
|
- type: map
|
|
12
12
|
mapping:
|
|
13
|
-
regex;(^[a-zA-Z_]+[a-zA-Z0-9_]*$):
|
|
13
|
+
regex;(^[a-zA-Z_]+[a-zA-Z0-9_\-]*$):
|
|
14
14
|
type: any
|
|
15
15
|
|
|
16
16
|
metadata:
|
|
@@ -129,7 +129,7 @@ mapping:
|
|
|
129
129
|
type: "seq"
|
|
130
130
|
sequence:
|
|
131
131
|
- type: "str"
|
|
132
|
-
pattern: ^[a-zA-Z_]+[a-zA-Z0-9_]*$
|
|
132
|
+
pattern: ^[a-zA-Z_]+[a-zA-Z0-9_\-]*$
|
|
133
133
|
metadata:
|
|
134
134
|
type: "str"
|
|
135
135
|
pattern: ^[a-zA-Z_]+[a-zA-Z0-9_]*$
|
rasa/model_manager/model_api.py
CHANGED
|
@@ -571,7 +571,7 @@ def external_blueprint() -> Blueprint:
|
|
|
571
571
|
"""Create a blueprint for the model manager API."""
|
|
572
572
|
from rasa.core.channels.socketio import SocketBlueprint
|
|
573
573
|
|
|
574
|
-
sio = AsyncServer(async_mode="sanic", cors_allowed_origins=
|
|
574
|
+
sio = AsyncServer(async_mode="sanic", cors_allowed_origins="*")
|
|
575
575
|
bp = SocketBlueprint(sio, "", "model_api_external")
|
|
576
576
|
|
|
577
577
|
create_bridge_server(sio, running_bots)
|
|
@@ -2,8 +2,7 @@ import json
|
|
|
2
2
|
from typing import Any, Dict, Optional
|
|
3
3
|
|
|
4
4
|
import structlog
|
|
5
|
-
from socketio import AsyncServer
|
|
6
|
-
from socketio.asyncio_client import AsyncClient
|
|
5
|
+
from socketio import AsyncClient, AsyncServer # type: ignore[attr-defined]
|
|
7
6
|
from socketio.exceptions import ConnectionRefusedError
|
|
8
7
|
|
|
9
8
|
from rasa.model_manager.runner_service import BotSession
|
|
@@ -131,6 +130,13 @@ async def create_bridge_client(
|
|
|
131
130
|
structlogger.debug("model_runner.bot_message", deployment_id=deployment_id)
|
|
132
131
|
await sio.emit("bot_message", data, room=sid)
|
|
133
132
|
|
|
133
|
+
@client.event # type: ignore[misc]
|
|
134
|
+
async def error(data: Dict[str, Any]) -> None:
|
|
135
|
+
structlogger.debug(
|
|
136
|
+
"model_runner.bot_error", deployment_id=deployment_id, data=data
|
|
137
|
+
)
|
|
138
|
+
await sio.emit("error", data, room=sid)
|
|
139
|
+
|
|
134
140
|
@client.event # type: ignore[misc]
|
|
135
141
|
async def tracker(data: Dict[str, Any]) -> None:
|
|
136
142
|
await sio.emit("tracker", json.loads(data), room=sid)
|
rasa/server.py
CHANGED
|
@@ -44,6 +44,7 @@ import rasa.utils.endpoints
|
|
|
44
44
|
import rasa.utils.io
|
|
45
45
|
from rasa.constants import MINIMUM_COMPATIBLE_VERSION
|
|
46
46
|
from rasa.core.agent import Agent
|
|
47
|
+
from rasa.core.available_agents import AvailableAgents
|
|
47
48
|
from rasa.core.available_endpoints import AvailableEndpoints
|
|
48
49
|
from rasa.core.channels.channel import (
|
|
49
50
|
CollectingOutputChannel,
|
|
@@ -693,6 +694,7 @@ def create_app(
|
|
|
693
694
|
jwt_private_key: Optional[Text] = None,
|
|
694
695
|
jwt_method: Text = "HS256",
|
|
695
696
|
endpoints: Optional[AvailableEndpoints] = None,
|
|
697
|
+
sub_agents: Optional[AvailableAgents] = None,
|
|
696
698
|
is_inspector_enabled: bool = False,
|
|
697
699
|
) -> Sanic:
|
|
698
700
|
"""Class representing a Rasa HTTP server."""
|
|
@@ -728,6 +730,7 @@ def create_app(
|
|
|
728
730
|
user_id="username",
|
|
729
731
|
)
|
|
730
732
|
|
|
733
|
+
app.ctx.sub_agents = sub_agents
|
|
731
734
|
app.ctx.agent = agent
|
|
732
735
|
# Initialize shared object of type unsigned int for tracking
|
|
733
736
|
# the number of active training processes
|
|
@@ -1463,6 +1466,13 @@ def create_app(
|
|
|
1463
1466
|
flows = await processor.get_flows()
|
|
1464
1467
|
return response.json(flows.as_json_list())
|
|
1465
1468
|
|
|
1469
|
+
@app.get("/sub-agents")
|
|
1470
|
+
@requires_auth(app, auth_token)
|
|
1471
|
+
async def get_sub_agents(request: Request) -> HTTPResponse:
|
|
1472
|
+
"""Get all the sub-agents currently stored by the agent."""
|
|
1473
|
+
sub_agents = app.ctx.sub_agents
|
|
1474
|
+
return response.json(sub_agents.as_json_list())
|
|
1475
|
+
|
|
1466
1476
|
@app.get("/domain")
|
|
1467
1477
|
@requires_auth(app, auth_token)
|
|
1468
1478
|
@ensure_loaded_agent(app)
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from rasa.agents.core.types import AgentIdentifier, ProtocolType
|
|
4
|
+
from rasa.core.available_agents import AgentConfig, ProtocolConfig
|
|
5
|
+
from rasa.shared.core.flows.steps import CallFlowStep
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def make_agent_identifier(
|
|
9
|
+
agent_name: str, protocol_type: ProtocolType
|
|
10
|
+
) -> AgentIdentifier:
|
|
11
|
+
"""Make an agent identifier."""
|
|
12
|
+
return AgentIdentifier(agent_name, protocol_type)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_protocol_type(
|
|
16
|
+
step: CallFlowStep, agent_config: Optional[AgentConfig]
|
|
17
|
+
) -> ProtocolType:
|
|
18
|
+
"""Get the protocol type for an agent.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
step: The step that is calling the agent.
|
|
22
|
+
agent_config: The agent configuration.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
The protocol type for the agent.
|
|
26
|
+
"""
|
|
27
|
+
if step.exit_if:
|
|
28
|
+
protocol_type = ProtocolType.MCP_TASK
|
|
29
|
+
else:
|
|
30
|
+
protocol_type = (
|
|
31
|
+
ProtocolType.A2A
|
|
32
|
+
if agent_config and agent_config.agent.protocol == ProtocolConfig.A2A
|
|
33
|
+
else ProtocolType.MCP_OPEN
|
|
34
|
+
)
|
|
35
|
+
return protocol_type
|
rasa/shared/constants.py
CHANGED
|
@@ -345,6 +345,8 @@ PAYLOAD = "payload"
|
|
|
345
345
|
# Used for LLM command generation
|
|
346
346
|
ROLE_USER = "user"
|
|
347
347
|
ROLE_SYSTEM = "system"
|
|
348
|
+
ROLE_ASSISTANT = "assistant"
|
|
349
|
+
ROLE_TOOL = "tool"
|
|
348
350
|
|
|
349
351
|
# Used for key values in ValidateSlotPatternFlowStackFrame
|
|
350
352
|
REFILL_UTTER = "refill_utter"
|
|
@@ -359,3 +361,6 @@ FAQ_INPUT_DATA_QUESTION_LINE_PREFIX = "Q:"
|
|
|
359
361
|
FAQ_INPUT_DATA_ANSWER_LINE_PREFIX = "A:"
|
|
360
362
|
FAQ_DOCUMENT_ENTRY_SEPARATOR = "\n\n"
|
|
361
363
|
FAQ_DOCUMENT_LINE_SEPARATOR = "\n"
|
|
364
|
+
|
|
365
|
+
# Constants for the MCP server
|
|
366
|
+
KEY_TOOL_CALLS = "tool_calls"
|
rasa/shared/core/constants.py
CHANGED
|
@@ -30,6 +30,7 @@ LOOP_NAME = "name"
|
|
|
30
30
|
ACTION_LISTEN_NAME = "action_listen"
|
|
31
31
|
ACTION_RESTART_NAME = "action_restart"
|
|
32
32
|
ACTION_SEND_TEXT_NAME = "action_send_text"
|
|
33
|
+
ACTION_AGENT_REQUEST_USER_INPUT_NAME = "action_agent_request_user_input"
|
|
33
34
|
ACTION_SESSION_START_NAME = "action_session_start"
|
|
34
35
|
ACTION_DEFAULT_FALLBACK_NAME = "action_default_fallback"
|
|
35
36
|
ACTION_DEACTIVATE_LOOP_NAME = "action_deactivate_loop"
|
|
@@ -52,10 +53,16 @@ ACTION_TRIGGER_CHITCHAT = "action_trigger_chitchat"
|
|
|
52
53
|
ACTION_RESET_ROUTING = "action_reset_routing"
|
|
53
54
|
ACTION_HANGUP = "action_hangup"
|
|
54
55
|
ACTION_REPEAT_BOT_MESSAGES = "action_repeat_bot_messages"
|
|
56
|
+
ACTION_CONTINUE_INTERRUPTED_FLOW = "action_continue_interrupted_flow"
|
|
57
|
+
ACTION_SET_INTERRUPTED_FLOWS = "action_set_interrupted_flows"
|
|
58
|
+
ACTION_CANCEL_INTERRUPTED_FLOW = "action_cancel_interrupted_flow"
|
|
59
|
+
ACTION_ASK_INTERRUPTED_FLOW_TO_CONTINUE = "action_ask_interrupted_flow_to_continue"
|
|
55
60
|
|
|
56
61
|
ACTION_METADATA_EXECUTION_SUCCESS = "execution_success"
|
|
57
62
|
ACTION_METADATA_EXECUTION_ERROR_MESSAGE = "execution_error_message"
|
|
58
63
|
|
|
64
|
+
ACTION_METADATA_MESSAGE_KEY = "message"
|
|
65
|
+
ACTION_METADATA_TEXT_KEY = "text"
|
|
59
66
|
|
|
60
67
|
DEFAULT_ACTION_NAMES = [
|
|
61
68
|
ACTION_LISTEN_NAME,
|
|
@@ -70,6 +77,7 @@ DEFAULT_ACTION_NAMES = [
|
|
|
70
77
|
ACTION_UNLIKELY_INTENT_NAME,
|
|
71
78
|
ACTION_BACK_NAME,
|
|
72
79
|
ACTION_SEND_TEXT_NAME,
|
|
80
|
+
ACTION_AGENT_REQUEST_USER_INPUT_NAME,
|
|
73
81
|
RULE_SNIPPET_ACTION_NAME,
|
|
74
82
|
ACTION_EXTRACT_SLOTS,
|
|
75
83
|
ACTION_CANCEL_FLOW,
|
|
@@ -82,6 +90,10 @@ DEFAULT_ACTION_NAMES = [
|
|
|
82
90
|
ACTION_RESET_ROUTING,
|
|
83
91
|
ACTION_HANGUP,
|
|
84
92
|
ACTION_REPEAT_BOT_MESSAGES,
|
|
93
|
+
ACTION_CONTINUE_INTERRUPTED_FLOW,
|
|
94
|
+
ACTION_SET_INTERRUPTED_FLOWS,
|
|
95
|
+
ACTION_CANCEL_INTERRUPTED_FLOW,
|
|
96
|
+
ACTION_ASK_INTERRUPTED_FLOW_TO_CONTINUE,
|
|
85
97
|
]
|
|
86
98
|
|
|
87
99
|
ACTION_SHOULD_SEND_DOMAIN = "send_domain"
|
|
@@ -136,7 +148,6 @@ DEFAULT_SLOT_NAMES = {
|
|
|
136
148
|
FLOW_HASHES_SLOT,
|
|
137
149
|
}
|
|
138
150
|
|
|
139
|
-
|
|
140
151
|
SLOT_MAPPINGS = "mappings"
|
|
141
152
|
MAPPING_CONDITIONS = "conditions"
|
|
142
153
|
KEY_MAPPING_TYPE = "type"
|
rasa/shared/core/domain.py
CHANGED
|
@@ -508,8 +508,8 @@ class Domain:
|
|
|
508
508
|
return combined
|
|
509
509
|
|
|
510
510
|
def partial_merge(self, other: Domain) -> Domain:
|
|
511
|
-
"""
|
|
512
|
-
|
|
511
|
+
"""Returns a new Domain with intersection-based merging.
|
|
512
|
+
|
|
513
513
|
- For each domain section only overwrite items that already exist in self.
|
|
514
514
|
- Brand-new items in `other` are ignored.
|
|
515
515
|
|
|
@@ -543,9 +543,9 @@ class Domain:
|
|
|
543
543
|
return Domain.from_dict(updated_self)
|
|
544
544
|
|
|
545
545
|
def difference(self, other: Domain) -> Domain:
|
|
546
|
-
"""
|
|
547
|
-
|
|
548
|
-
using
|
|
546
|
+
"""Returns a new Domain containing items in `self` that are NOT in `other`.
|
|
547
|
+
|
|
548
|
+
Simple using equality checks for dict/list items.
|
|
549
549
|
|
|
550
550
|
Args:
|
|
551
551
|
other: The domain to compare with.
|