rasa-pro 3.14.0.dev6__py3-none-any.whl → 3.14.0.dev7__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/exceptions.py +31 -1
- rasa/agents/protocol/a2a/a2a_agent.py +1 -1
- rasa/agents/protocol/mcp/mcp_base_agent.py +7 -6
- rasa/agents/protocol/mcp/mcp_task_agent.py +1 -1
- rasa/agents/utils.py +5 -0
- rasa/agents/validation.py +484 -0
- rasa/api.py +9 -6
- rasa/cli/arguments/train.py +2 -0
- rasa/cli/interactive.py +2 -0
- rasa/cli/train.py +2 -0
- rasa/cli/utils.py +85 -1
- rasa/core/actions/action.py +2 -6
- rasa/core/available_agents.py +47 -26
- rasa/core/channels/inspector/dist/assets/{arc-63212852.js → arc-cce7e0a8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-eecf6b13.js → blockDiagram-38ab4fdb-e2a49be7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-8f798a9a.js → c4Diagram-3d4e48cf-3def7895.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-858c2c20.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-df71a04c.js → classDiagram-70f12bd4-e66fe4df.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-9b275968.js → classDiagram-v2-f2320105-eb874aaa.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-4b80996c.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-1c669cad.js → createText-2e5e7dd3-cf934643.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-b1553799.js → edges-e0da2a9e-8fdf9155.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-112388d6.js → erDiagram-9861fffd-6106fb96.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-fdebec47.js → flowDb-956e92f1-4c2bb040.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-6280ede1.js → flowDiagram-66a62f08-f0ff96af.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-16f09b7a.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-e1dc03e5.js → flowchart-elk-definition-4a651766-a21707ec.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-83f68c51.js → ganttDiagram-c361ad54-c165acb1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-22f8666f.js → gitGraphDiagram-72cf32ee-b0564cf1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-ca9e6217.js → graph-e557e67a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-c5ceb692.js → index-3862675e-1ce60e9e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3e293924.js → index-996fe816.js} +173 -173
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-faa9999b.js → infoDiagram-f8f76790-893569e2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-c4dda8d9.js → journeyDiagram-49397b02-c29c864f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-d4307784.js → layout-649a5eae.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-0567aaa7.js → line-0e5685ed.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-c11b95cf.js → linear-eaa320bd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-0c7d3ca9.js → mindmap-definition-fc14e90a-f35df9e6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-34b433fa.js → pieDiagram-8a3498a8-78339e96.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-4cab816e.js → quadrantDiagram-120e2f19-9b5f2f14.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-8c22fa9e.js → requirementDiagram-deff3bca-d05ddb3a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-70ce9e8e.js → sankeyDiagram-04a897e0-d9be5dfd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-fbcd7fc9.js → sequenceDiagram-704730f1-0f1c4348.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-45f05ea6.js → stateDiagram-587899a1-9ddf63b3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-beab1ea6.js → stateDiagram-v2-d93cdb3a-bc2b81ed.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-2f29dbd5.js → styles-6aaf32cf-0a287936.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-951eac83.js → styles-9a916d00-e3941990.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-897fbfdd.js → styles-c10674c1-ce4eca24.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-d667fac1.js → svgDrawCommon-08f97a94-d822b1a8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-e3205144.js → timeline-definition-85554ec2-e144c7a7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-4abeb0e2.js → xychartDiagram-e933f94c-ab7f4e14.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +28 -4
- rasa/core/channels/inspector/src/components/DialogueAgentStack.tsx +108 -0
- rasa/core/channels/inspector/src/components/{DialogueStack.tsx → DialogueHistoryStack.tsx} +7 -8
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -0
- rasa/core/channels/inspector/src/helpers/utils.test.ts +127 -0
- rasa/core/channels/inspector/src/helpers/utils.ts +66 -1
- rasa/core/channels/inspector/src/types.ts +17 -0
- rasa/core/policies/flows/flow_executor.py +52 -31
- rasa/dialogue_understanding/commands/cancel_flow_command.py +2 -81
- rasa/dialogue_understanding/commands/start_flow_command.py +18 -113
- rasa/dialogue_understanding/commands/utils.py +118 -0
- rasa/dialogue_understanding/patterns/clarify.py +3 -14
- rasa/dialogue_understanding/patterns/continue_interrupted.py +185 -114
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +17 -23
- rasa/dialogue_understanding/stack/utils.py +43 -4
- rasa/dialogue_understanding/utils.py +24 -4
- rasa/model_training.py +8 -6
- rasa/shared/constants.py +3 -0
- rasa/shared/core/constants.py +5 -6
- rasa/shared/utils/health_check/health_check.py +7 -3
- rasa/shared/utils/mcp/server_connection.py +26 -6
- rasa/version.py +1 -1
- {rasa_pro-3.14.0.dev6.dist-info → rasa_pro-3.14.0.dev7.dist-info}/METADATA +1 -1
- {rasa_pro-3.14.0.dev6.dist-info → rasa_pro-3.14.0.dev7.dist-info}/RECORD +79 -76
- rasa/core/channels/inspector/dist/assets/channel-0cd70adf.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-a0f9c4ed.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-de9cc4aa.js +0 -1
- {rasa_pro-3.14.0.dev6.dist-info → rasa_pro-3.14.0.dev7.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0.dev6.dist-info → rasa_pro-3.14.0.dev7.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.0.dev6.dist-info → rasa_pro-3.14.0.dev7.dist-info}/entry_points.txt +0 -0
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import Any, Dict, List
|
|
5
|
+
from typing import Any, Dict, List
|
|
6
6
|
|
|
7
7
|
import structlog
|
|
8
8
|
|
|
@@ -16,7 +16,6 @@ from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
|
16
16
|
)
|
|
17
17
|
from rasa.dialogue_understanding.patterns.cancel import CancelPatternFlowStackFrame
|
|
18
18
|
from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
|
|
19
|
-
from rasa.dialogue_understanding.stack.frames import DialogueStackFrame
|
|
20
19
|
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
21
20
|
FlowStackFrameType,
|
|
22
21
|
UserFlowStackFrame,
|
|
@@ -74,8 +73,7 @@ class CancelFlowCommand(Command):
|
|
|
74
73
|
# we should never get here as we should always find the user flow
|
|
75
74
|
# that was canceled.
|
|
76
75
|
raise ValueError(
|
|
77
|
-
f"Could not find a user flow frame to cancel. "
|
|
78
|
-
f"Current stack: {stack}."
|
|
76
|
+
f"Could not find a user flow frame to cancel. Current stack: {stack}."
|
|
79
77
|
)
|
|
80
78
|
|
|
81
79
|
def run_command_on_tracker(
|
|
@@ -175,80 +173,3 @@ class CancelFlowCommand(Command):
|
|
|
175
173
|
CommandSyntaxManager.get_syntax_version(),
|
|
176
174
|
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
177
175
|
)
|
|
178
|
-
|
|
179
|
-
def cancel_flow(
|
|
180
|
-
self,
|
|
181
|
-
tracker: DialogueStateTracker,
|
|
182
|
-
stack: DialogueStack,
|
|
183
|
-
flow_id: str,
|
|
184
|
-
) -> List[Event]:
|
|
185
|
-
"""Cancels a flow by flow id."""
|
|
186
|
-
applied_events: List[Event] = []
|
|
187
|
-
|
|
188
|
-
frames_to_cancel, user_frame_to_cancel = self._collect_frames_to_cancel(
|
|
189
|
-
stack, flow_id
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
# if the flow is not on the stack, do nothing
|
|
193
|
-
if user_frame_to_cancel is None:
|
|
194
|
-
structlogger.error(
|
|
195
|
-
"cancel_flow_command.cancel_flow.no_user_frame_to_cancel",
|
|
196
|
-
command=self,
|
|
197
|
-
)
|
|
198
|
-
return []
|
|
199
|
-
|
|
200
|
-
frames_ids_to_cancel = [frame.frame_id for frame in frames_to_cancel]
|
|
201
|
-
|
|
202
|
-
stack.push(
|
|
203
|
-
CancelPatternFlowStackFrame(
|
|
204
|
-
canceled_name=flow_id,
|
|
205
|
-
canceled_frames=frames_ids_to_cancel,
|
|
206
|
-
)
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
# create flow cancelled event
|
|
210
|
-
applied_events.extend(
|
|
211
|
-
[
|
|
212
|
-
FlowCancelled(
|
|
213
|
-
user_frame_to_cancel.flow_id, user_frame_to_cancel.step_id
|
|
214
|
-
),
|
|
215
|
-
]
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
update_stack_events = tracker.create_stack_updated_events(stack)
|
|
219
|
-
|
|
220
|
-
return applied_events + update_stack_events
|
|
221
|
-
|
|
222
|
-
def _collect_frames_to_cancel(
|
|
223
|
-
self, stack: DialogueStack, target_flow_id: str
|
|
224
|
-
) -> Tuple[List[DialogueStackFrame], Optional[UserFlowStackFrame]]:
|
|
225
|
-
"""Collect frames that need to be cancelled.
|
|
226
|
-
|
|
227
|
-
Args:
|
|
228
|
-
stack: The stack to collect frames from.
|
|
229
|
-
target_flow_id: The ID of the flow to cancel.
|
|
230
|
-
|
|
231
|
-
Returns:
|
|
232
|
-
A tuple containing (frames_to_cancel, frame_to_cancel).
|
|
233
|
-
"""
|
|
234
|
-
frames_to_cancel: List[DialogueStackFrame] = []
|
|
235
|
-
frame_found = False
|
|
236
|
-
frame_to_cancel = None
|
|
237
|
-
|
|
238
|
-
for frame in stack.frames:
|
|
239
|
-
if isinstance(frame, UserFlowStackFrame) and (
|
|
240
|
-
frame.frame_type == FlowStackFrameType.REGULAR
|
|
241
|
-
or frame.frame_type == FlowStackFrameType.INTERRUPT
|
|
242
|
-
):
|
|
243
|
-
if frame.flow_id == target_flow_id:
|
|
244
|
-
frames_to_cancel.append(frame)
|
|
245
|
-
frame_to_cancel = frame
|
|
246
|
-
frame_found = True
|
|
247
|
-
continue
|
|
248
|
-
elif frame_found:
|
|
249
|
-
break
|
|
250
|
-
|
|
251
|
-
if frame_found:
|
|
252
|
-
frames_to_cancel.append(frame)
|
|
253
|
-
|
|
254
|
-
return list(frames_to_cancel), frame_to_cancel
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import Any, Dict, List, Optional
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
6
|
|
|
7
7
|
import structlog
|
|
8
8
|
|
|
@@ -11,17 +11,15 @@ from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
|
11
11
|
CommandSyntaxManager,
|
|
12
12
|
CommandSyntaxVersion,
|
|
13
13
|
)
|
|
14
|
-
from rasa.dialogue_understanding.
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
from rasa.dialogue_understanding.commands.utils import (
|
|
15
|
+
remove_pattern_continue_interrupted_frames,
|
|
16
|
+
resume_flow,
|
|
17
17
|
)
|
|
18
18
|
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
19
|
-
AgentStackFrame,
|
|
20
19
|
AgentState,
|
|
21
20
|
FlowStackFrameType,
|
|
22
21
|
UserFlowStackFrame,
|
|
23
22
|
)
|
|
24
|
-
from rasa.dialogue_understanding.stack.frames.pattern_frame import PatternFlowStackFrame
|
|
25
23
|
from rasa.dialogue_understanding.stack.utils import (
|
|
26
24
|
is_continue_interrupted_flow_active,
|
|
27
25
|
top_user_flow_frame,
|
|
@@ -29,10 +27,8 @@ from rasa.dialogue_understanding.stack.utils import (
|
|
|
29
27
|
)
|
|
30
28
|
from rasa.shared.core.events import (
|
|
31
29
|
AgentInterrupted,
|
|
32
|
-
AgentResumed,
|
|
33
30
|
Event,
|
|
34
31
|
FlowInterrupted,
|
|
35
|
-
FlowResumed,
|
|
36
32
|
)
|
|
37
33
|
from rasa.shared.core.flows import FlowsList
|
|
38
34
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -108,7 +104,7 @@ class StartFlowCommand(Command):
|
|
|
108
104
|
# predicted a start flow command for the flow which is on top of the stack,
|
|
109
105
|
# we just need to remove the pattern_continue_interrupted frame(s) from the
|
|
110
106
|
# stack
|
|
111
|
-
stack =
|
|
107
|
+
stack = remove_pattern_continue_interrupted_frames(stack)
|
|
112
108
|
return applied_events + tracker.create_stack_updated_events(stack)
|
|
113
109
|
|
|
114
110
|
# if the flow is already on the stack, resume it
|
|
@@ -118,11 +114,22 @@ class StartFlowCommand(Command):
|
|
|
118
114
|
):
|
|
119
115
|
# if pattern_continue_interrupted is active, we need to remove it
|
|
120
116
|
# from the stack before resuming the flow
|
|
121
|
-
stack =
|
|
122
|
-
|
|
117
|
+
stack = remove_pattern_continue_interrupted_frames(stack)
|
|
118
|
+
applied_events.extend(resume_flow(self.flow, tracker, stack))
|
|
119
|
+
# the current active flow is interrupted
|
|
120
|
+
applied_events.append(
|
|
121
|
+
FlowInterrupted(
|
|
122
|
+
original_user_frame.flow_id, original_user_frame.step_id
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
return applied_events
|
|
123
126
|
|
|
124
127
|
frame_type = FlowStackFrameType.REGULAR
|
|
125
128
|
|
|
129
|
+
# remove the pattern_continue_interrupted frames from the stack
|
|
130
|
+
# if it is currently active but the user digressed from the pattern
|
|
131
|
+
stack = remove_pattern_continue_interrupted_frames(stack)
|
|
132
|
+
|
|
126
133
|
if original_top_flow:
|
|
127
134
|
# if the original top flow is not the same as the flow to start,
|
|
128
135
|
# interrupt the current active flow
|
|
@@ -198,105 +205,3 @@ class StartFlowCommand(Command):
|
|
|
198
205
|
CommandSyntaxManager.get_syntax_version(),
|
|
199
206
|
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
200
207
|
)
|
|
201
|
-
|
|
202
|
-
def resume_flow(
|
|
203
|
-
self,
|
|
204
|
-
tracker: DialogueStateTracker,
|
|
205
|
-
stack: DialogueStack,
|
|
206
|
-
original_user_frame: UserFlowStackFrame,
|
|
207
|
-
) -> List[Event]:
|
|
208
|
-
"""Resumes a flow by reordering frames."""
|
|
209
|
-
applied_events: List[Event] = []
|
|
210
|
-
|
|
211
|
-
# Resume existing flow by reordering frames
|
|
212
|
-
frames_to_resume, user_frame_to_resume = self._collect_frames_to_resume(
|
|
213
|
-
stack, self.flow
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
# if the flow is not on the stack, do nothing
|
|
217
|
-
# this should not happen, but just in case
|
|
218
|
-
if user_frame_to_resume is None:
|
|
219
|
-
structlogger.error(
|
|
220
|
-
"start_flow_command.resume_flow.no_user_frame_to_resume",
|
|
221
|
-
command=self,
|
|
222
|
-
)
|
|
223
|
-
return []
|
|
224
|
-
|
|
225
|
-
# move the frames to the top of the stack, e.g. reorder the frames
|
|
226
|
-
# on the stack
|
|
227
|
-
stack.move_frames_to_top(frames_to_resume)
|
|
228
|
-
agent_stack_frame = next(
|
|
229
|
-
(frame for frame in frames_to_resume if isinstance(frame, AgentStackFrame)),
|
|
230
|
-
None,
|
|
231
|
-
)
|
|
232
|
-
if agent_stack_frame:
|
|
233
|
-
agent_id = agent_stack_frame.agent_id
|
|
234
|
-
applied_events.append(AgentResumed(agent_id, agent_stack_frame.flow_id))
|
|
235
|
-
|
|
236
|
-
# Create flow interruption and resumption events
|
|
237
|
-
applied_events.extend(
|
|
238
|
-
[
|
|
239
|
-
# the current active flow is interrupted
|
|
240
|
-
FlowInterrupted(
|
|
241
|
-
original_user_frame.flow_id, original_user_frame.step_id
|
|
242
|
-
),
|
|
243
|
-
# the flow, which was on the stack, is resumed
|
|
244
|
-
FlowResumed(user_frame_to_resume.flow_id, user_frame_to_resume.step_id),
|
|
245
|
-
]
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
return applied_events + tracker.create_stack_updated_events(stack)
|
|
249
|
-
|
|
250
|
-
def _collect_frames_to_resume(
|
|
251
|
-
self, stack: DialogueStack, target_flow_id: str
|
|
252
|
-
) -> Tuple[List[DialogueStackFrame], Optional[UserFlowStackFrame]]:
|
|
253
|
-
"""Collect frames that need to be resumed for the target flow.
|
|
254
|
-
|
|
255
|
-
Args:
|
|
256
|
-
stack: The stack to collect frames from.
|
|
257
|
-
target_flow_id: The ID of the flow to resume.
|
|
258
|
-
|
|
259
|
-
Returns:
|
|
260
|
-
A tuple containing (frames_to_resume, frame_to_resume).
|
|
261
|
-
"""
|
|
262
|
-
frames_to_resume: List[DialogueStackFrame] = []
|
|
263
|
-
frame_found = False
|
|
264
|
-
frame_to_resume = None
|
|
265
|
-
|
|
266
|
-
for frame in stack.frames:
|
|
267
|
-
if isinstance(frame, UserFlowStackFrame) and (
|
|
268
|
-
frame.frame_type == FlowStackFrameType.REGULAR
|
|
269
|
-
or frame.frame_type == FlowStackFrameType.INTERRUPT
|
|
270
|
-
):
|
|
271
|
-
if frame.flow_id == target_flow_id:
|
|
272
|
-
frames_to_resume.append(frame)
|
|
273
|
-
frame_to_resume = frame
|
|
274
|
-
frame_found = True
|
|
275
|
-
continue
|
|
276
|
-
elif frame_found:
|
|
277
|
-
break
|
|
278
|
-
|
|
279
|
-
if frame_found:
|
|
280
|
-
frames_to_resume.append(frame)
|
|
281
|
-
|
|
282
|
-
return list(frames_to_resume), frame_to_resume
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
def _remove_pattern_continue_interrupted_frames(stack: DialogueStack) -> DialogueStack:
|
|
286
|
-
"""Remove pattern_continue_interrupted frames from the stack."""
|
|
287
|
-
if not is_continue_interrupted_flow_active(stack):
|
|
288
|
-
return stack
|
|
289
|
-
|
|
290
|
-
# remove pattern_continue_interrupted from the stack
|
|
291
|
-
top_frame = stack.top()
|
|
292
|
-
while isinstance(top_frame, PatternFlowStackFrame):
|
|
293
|
-
# If the top frame is a pattern frame, we need to remove it
|
|
294
|
-
# before continuing with the active user flow frame.
|
|
295
|
-
# This prevents the pattern frame
|
|
296
|
-
# from being left on the stack when the flow is started
|
|
297
|
-
# which would prevent pattern_completed to be triggered
|
|
298
|
-
# once the user flow is completed.
|
|
299
|
-
stack.pop()
|
|
300
|
-
top_frame = stack.top()
|
|
301
|
-
|
|
302
|
-
return stack
|
|
@@ -5,9 +5,21 @@ import structlog
|
|
|
5
5
|
from rasa.dialogue_understanding.patterns.validate_slot import (
|
|
6
6
|
ValidateSlotPatternFlowStackFrame,
|
|
7
7
|
)
|
|
8
|
+
from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
|
|
9
|
+
from rasa.dialogue_understanding.stack.frames.dialogue_stack_frame import (
|
|
10
|
+
DialogueStackFrame,
|
|
11
|
+
)
|
|
12
|
+
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
13
|
+
AgentStackFrame,
|
|
14
|
+
FlowStackFrameType,
|
|
15
|
+
UserFlowStackFrame,
|
|
16
|
+
)
|
|
17
|
+
from rasa.dialogue_understanding.stack.frames.pattern_frame import PatternFlowStackFrame
|
|
8
18
|
from rasa.shared.constants import ACTION_ASK_PREFIX, UTTER_ASK_PREFIX
|
|
9
19
|
from rasa.shared.core.events import (
|
|
20
|
+
AgentResumed,
|
|
10
21
|
Event,
|
|
22
|
+
FlowResumed,
|
|
11
23
|
SlotSet,
|
|
12
24
|
)
|
|
13
25
|
from rasa.shared.core.flows import FlowsList
|
|
@@ -154,3 +166,109 @@ def find_default_flows_collecting_slot(
|
|
|
154
166
|
for step in flow.get_collect_steps()
|
|
155
167
|
)
|
|
156
168
|
]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def resume_flow(
|
|
172
|
+
flow_to_resume: str,
|
|
173
|
+
tracker: DialogueStateTracker,
|
|
174
|
+
stack: DialogueStack,
|
|
175
|
+
) -> List[Event]:
|
|
176
|
+
"""Resumes a flow by reordering frames."""
|
|
177
|
+
applied_events: List[Event] = []
|
|
178
|
+
|
|
179
|
+
# Resume existing flow by reordering frames
|
|
180
|
+
frames_to_resume, user_frame_to_resume = collect_frames_to_resume(
|
|
181
|
+
stack, flow_to_resume
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# if the flow is not on the stack, do nothing
|
|
185
|
+
# this should not happen, but just in case
|
|
186
|
+
if user_frame_to_resume is None:
|
|
187
|
+
structlogger.error(
|
|
188
|
+
"resume_flow.no_user_frame_to_resume",
|
|
189
|
+
flow_to_resume=flow_to_resume,
|
|
190
|
+
)
|
|
191
|
+
return []
|
|
192
|
+
|
|
193
|
+
# move the frames to the top of the stack, e.g. reorder the frames
|
|
194
|
+
# on the stack
|
|
195
|
+
stack.move_frames_to_top(frames_to_resume)
|
|
196
|
+
|
|
197
|
+
# create agent resumed events if the agent frame is now on top of the stack
|
|
198
|
+
agent_stack_frame = next(
|
|
199
|
+
(frame for frame in frames_to_resume if isinstance(frame, AgentStackFrame)),
|
|
200
|
+
None,
|
|
201
|
+
)
|
|
202
|
+
if agent_stack_frame:
|
|
203
|
+
agent_id = agent_stack_frame.agent_id
|
|
204
|
+
applied_events.append(AgentResumed(agent_id, agent_stack_frame.flow_id))
|
|
205
|
+
|
|
206
|
+
# Create flow interruption and resumption events
|
|
207
|
+
applied_events.extend(
|
|
208
|
+
[
|
|
209
|
+
# the flow, which was on the stack, is resumed
|
|
210
|
+
FlowResumed(user_frame_to_resume.flow_id, user_frame_to_resume.step_id),
|
|
211
|
+
]
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
return applied_events + tracker.create_stack_updated_events(stack)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def collect_frames_to_resume(
|
|
218
|
+
stack: DialogueStack,
|
|
219
|
+
target_flow_id: str, # pyright: ignore[reportUndefinedVariable]
|
|
220
|
+
) -> Tuple[List[DialogueStackFrame], Optional[UserFlowStackFrame]]:
|
|
221
|
+
"""Collect frames that need to be resumed for the target flow.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
stack: The stack to collect frames from.
|
|
225
|
+
target_flow_id: The ID of the flow to resume.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
A tuple containing (frames_to_resume, frame_to_resume).
|
|
229
|
+
"""
|
|
230
|
+
frames_to_resume: List[DialogueStackFrame] = []
|
|
231
|
+
frame_found = False
|
|
232
|
+
frame_to_resume = None
|
|
233
|
+
|
|
234
|
+
for frame in stack.frames:
|
|
235
|
+
if isinstance(frame, UserFlowStackFrame) and (
|
|
236
|
+
frame.frame_type == FlowStackFrameType.REGULAR
|
|
237
|
+
or frame.frame_type == FlowStackFrameType.INTERRUPT
|
|
238
|
+
):
|
|
239
|
+
if frame.flow_id == target_flow_id:
|
|
240
|
+
frames_to_resume.append(frame)
|
|
241
|
+
frame_to_resume = frame
|
|
242
|
+
frame_found = True
|
|
243
|
+
continue
|
|
244
|
+
elif frame_found:
|
|
245
|
+
break
|
|
246
|
+
|
|
247
|
+
if frame_found:
|
|
248
|
+
frames_to_resume.append(frame)
|
|
249
|
+
|
|
250
|
+
return list(frames_to_resume), frame_to_resume
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def remove_pattern_continue_interrupted_frames(stack: DialogueStack) -> DialogueStack:
|
|
254
|
+
"""Remove pattern_continue_interrupted frames from the stack."""
|
|
255
|
+
from rasa.dialogue_understanding.stack.utils import (
|
|
256
|
+
is_continue_interrupted_flow_active,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
if not is_continue_interrupted_flow_active(stack):
|
|
260
|
+
return stack
|
|
261
|
+
|
|
262
|
+
# remove pattern_continue_interrupted from the stack
|
|
263
|
+
top_frame = stack.top()
|
|
264
|
+
while isinstance(top_frame, PatternFlowStackFrame):
|
|
265
|
+
# If the top frame is a pattern frame, we need to remove it
|
|
266
|
+
# before continuing with the active user flow frame.
|
|
267
|
+
# This prevents the pattern frame
|
|
268
|
+
# from being left on the stack when the flow is started
|
|
269
|
+
# which would prevent pattern_completed to be triggered
|
|
270
|
+
# once the user flow is completed.
|
|
271
|
+
stack.pop()
|
|
272
|
+
top_frame = stack.top()
|
|
273
|
+
|
|
274
|
+
return stack
|
|
@@ -61,19 +61,6 @@ class ActionClarifyFlows(action.Action):
|
|
|
61
61
|
"""Return the flow name."""
|
|
62
62
|
return ACTION_CLARIFY_FLOWS
|
|
63
63
|
|
|
64
|
-
@staticmethod
|
|
65
|
-
def assemble_options_string(names: List[str]) -> str:
|
|
66
|
-
"""Concatenate options to a human-readable string."""
|
|
67
|
-
clarification_message = ""
|
|
68
|
-
for i, name in enumerate(names):
|
|
69
|
-
if i == 0:
|
|
70
|
-
clarification_message += name
|
|
71
|
-
elif i == len(names) - 1:
|
|
72
|
-
clarification_message += f" or {name}"
|
|
73
|
-
else:
|
|
74
|
-
clarification_message += f", {name}"
|
|
75
|
-
return clarification_message
|
|
76
|
-
|
|
77
64
|
async def run(
|
|
78
65
|
self,
|
|
79
66
|
output_channel: "OutputChannel",
|
|
@@ -83,6 +70,8 @@ class ActionClarifyFlows(action.Action):
|
|
|
83
70
|
metadata: Optional[Dict[str, Any]] = None,
|
|
84
71
|
) -> List[Event]:
|
|
85
72
|
"""Correct the slots."""
|
|
73
|
+
from rasa.dialogue_understanding.utils import assemble_options_string
|
|
74
|
+
|
|
86
75
|
stack = tracker.stack
|
|
87
76
|
if not (top := stack.top()):
|
|
88
77
|
structlogger.warning("action.clarify_flows.no_active_flow")
|
|
@@ -92,7 +81,7 @@ class ActionClarifyFlows(action.Action):
|
|
|
92
81
|
structlogger.warning("action.clarify_flows.no_clarification_frame")
|
|
93
82
|
return []
|
|
94
83
|
|
|
95
|
-
options_string =
|
|
84
|
+
options_string = assemble_options_string(top.names, conjunction="or")
|
|
96
85
|
top.clarification_options = options_string
|
|
97
86
|
# since we modified the stack frame, we need to update the stack
|
|
98
87
|
return tracker.create_stack_updated_events(stack)
|