rasa-pro 3.12.0.dev10__py3-none-any.whl → 3.12.0.dev12__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/core/actions/action.py +3 -17
- rasa/core/actions/forms.py +2 -4
- rasa/core/channels/voice_ready/audiocodes.py +23 -42
- rasa/core/channels/voice_stream/tts/azure.py +1 -2
- rasa/core/migrate.py +2 -2
- rasa/core/policies/flows/flow_executor.py +1 -33
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -2
- rasa/dialogue_understanding/commands/cancel_flow_command.py +4 -62
- rasa/dialogue_understanding/commands/change_flow_command.py +2 -2
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -2
- rasa/dialogue_understanding/commands/clarify_command.py +2 -2
- rasa/dialogue_understanding/commands/correct_slots_command.py +2 -11
- rasa/dialogue_understanding/commands/human_handoff_command.py +2 -2
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -2
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -2
- rasa/dialogue_understanding/commands/set_slot_command.py +15 -7
- rasa/dialogue_understanding/commands/skip_question_command.py +2 -2
- rasa/dialogue_understanding/commands/start_flow_command.py +2 -43
- rasa/dialogue_understanding/commands/utils.py +1 -1
- rasa/dialogue_understanding/constants.py +0 -1
- rasa/dialogue_understanding/generator/command_generator.py +76 -10
- rasa/dialogue_understanding/generator/command_parser.py +1 -1
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +2 -126
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +2 -10
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -4
- rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +79 -53
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +19 -11
- rasa/dialogue_understanding/patterns/correction.py +1 -13
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +2 -62
- rasa/dialogue_understanding/processor/command_processor.py +28 -117
- rasa/dialogue_understanding/utils.py +0 -31
- rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +2 -2
- rasa/shared/core/constants.py +1 -22
- rasa/shared/core/domain.py +4 -6
- rasa/shared/core/events.py +2 -13
- rasa/shared/core/flows/flow.py +0 -17
- rasa/shared/core/flows/flows_yaml_schema.json +0 -38
- rasa/shared/core/flows/steps/collect.py +1 -18
- rasa/shared/core/flows/utils.py +1 -16
- rasa/shared/core/slot_mappings.py +6 -6
- rasa/shared/core/slots.py +0 -19
- rasa/shared/core/trackers.py +1 -3
- rasa/shared/nlu/constants.py +0 -1
- rasa/shared/utils/llm.py +1 -1
- rasa/shared/utils/schemas/domain.yml +1 -0
- rasa/validator.py +22 -172
- rasa/version.py +1 -1
- {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev12.dist-info}/METADATA +1 -1
- {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev12.dist-info}/RECORD +52 -55
- rasa/core/actions/action_handle_digressions.py +0 -142
- rasa/dialogue_understanding/commands/handle_digressions_command.py +0 -150
- rasa/dialogue_understanding/patterns/handle_digressions.py +0 -81
- {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev12.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev12.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev12.dist-info}/entry_points.txt +0 -0
rasa/core/actions/action.py
CHANGED
|
@@ -72,11 +72,10 @@ from rasa.shared.core.constants import (
|
|
|
72
72
|
ACTION_UNLIKELY_INTENT_NAME,
|
|
73
73
|
ACTION_VALIDATE_SLOT_MAPPINGS,
|
|
74
74
|
DEFAULT_SLOT_NAMES,
|
|
75
|
-
KEY_MAPPING_TYPE,
|
|
76
75
|
KNOWLEDGE_BASE_SLOT_NAMES,
|
|
76
|
+
MAPPING_TYPE,
|
|
77
77
|
REQUESTED_SLOT,
|
|
78
78
|
USER_INTENT_OUT_OF_SCOPE,
|
|
79
|
-
SetSlotExtractor,
|
|
80
79
|
SlotMappingType,
|
|
81
80
|
)
|
|
82
81
|
from rasa.shared.core.domain import Domain
|
|
@@ -119,10 +118,6 @@ logger = logging.getLogger(__name__)
|
|
|
119
118
|
def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["Action"]:
|
|
120
119
|
"""List default actions."""
|
|
121
120
|
from rasa.core.actions.action_clean_stack import ActionCleanStack
|
|
122
|
-
from rasa.core.actions.action_handle_digressions import (
|
|
123
|
-
ActionBlockDigressions,
|
|
124
|
-
ActionContinueDigression,
|
|
125
|
-
)
|
|
126
121
|
from rasa.core.actions.action_hangup import ActionHangup
|
|
127
122
|
from rasa.core.actions.action_repeat_bot_messages import ActionRepeatBotMessages
|
|
128
123
|
from rasa.core.actions.action_run_slot_rejections import ActionRunSlotRejections
|
|
@@ -157,8 +152,6 @@ def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["A
|
|
|
157
152
|
ActionResetRouting(),
|
|
158
153
|
ActionHangup(),
|
|
159
154
|
ActionRepeatBotMessages(),
|
|
160
|
-
ActionBlockDigressions(),
|
|
161
|
-
ActionContinueDigression(),
|
|
162
155
|
]
|
|
163
156
|
|
|
164
157
|
|
|
@@ -947,14 +940,7 @@ class RemoteAction(Action):
|
|
|
947
940
|
)
|
|
948
941
|
|
|
949
942
|
events = rasa.shared.core.events.deserialise_events(events_json)
|
|
950
|
-
|
|
951
|
-
processed_events = []
|
|
952
|
-
for event in events:
|
|
953
|
-
if isinstance(event, SlotSet) and event.filled_by is None:
|
|
954
|
-
event.filled_by = SetSlotExtractor.CUSTOM.value
|
|
955
|
-
processed_events.append(event)
|
|
956
|
-
|
|
957
|
-
return cast(List[Event], bot_messages) + processed_events
|
|
943
|
+
return cast(List[Event], bot_messages) + events
|
|
958
944
|
|
|
959
945
|
def name(self) -> Text:
|
|
960
946
|
return self._name
|
|
@@ -1331,7 +1317,7 @@ class ActionExtractSlots(Action):
|
|
|
1331
1317
|
slot_events.append(SlotSet(slot.name, slot_value))
|
|
1332
1318
|
|
|
1333
1319
|
for mapping in slot.mappings:
|
|
1334
|
-
mapping_type = SlotMappingType(mapping.get(
|
|
1320
|
+
mapping_type = SlotMappingType(mapping.get(MAPPING_TYPE))
|
|
1335
1321
|
should_fill_custom_slot = mapping_type == SlotMappingType.CUSTOM
|
|
1336
1322
|
|
|
1337
1323
|
if should_fill_custom_slot:
|
rasa/core/actions/forms.py
CHANGED
|
@@ -16,7 +16,7 @@ from rasa.shared.constants import UTTER_PREFIX
|
|
|
16
16
|
from rasa.shared.core.constants import (
|
|
17
17
|
ACTION_EXTRACT_SLOTS,
|
|
18
18
|
ACTION_LISTEN_NAME,
|
|
19
|
-
|
|
19
|
+
MAPPING_TYPE,
|
|
20
20
|
REQUESTED_SLOT,
|
|
21
21
|
SLOT_MAPPINGS,
|
|
22
22
|
SlotMappingType,
|
|
@@ -158,9 +158,7 @@ class FormAction(LoopAction):
|
|
|
158
158
|
domain_slots = domain.as_dict().get(KEY_SLOTS, {})
|
|
159
159
|
for slot in domain.required_slots_for_form(self.name()):
|
|
160
160
|
for slot_mapping in domain_slots.get(slot, {}).get(SLOT_MAPPINGS, []):
|
|
161
|
-
if slot_mapping.get(
|
|
162
|
-
SlotMappingType.FROM_ENTITY
|
|
163
|
-
):
|
|
161
|
+
if slot_mapping.get(MAPPING_TYPE) == str(SlotMappingType.FROM_ENTITY):
|
|
164
162
|
mapping_as_string = json.dumps(slot_mapping, sort_keys=True)
|
|
165
163
|
if mapping_as_string in unique_entity_slot_mappings:
|
|
166
164
|
unique_entity_slot_mappings.remove(mapping_as_string)
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import asyncio
|
|
2
1
|
import copy
|
|
3
2
|
import json
|
|
4
3
|
import uuid
|
|
5
|
-
from collections import defaultdict
|
|
6
4
|
from dataclasses import asdict
|
|
7
5
|
from datetime import datetime, timedelta, timezone
|
|
8
|
-
from typing import Any, Awaitable, Callable, Dict, List, Optional,
|
|
6
|
+
from typing import Any, Awaitable, Callable, Dict, List, Optional, Text, Union
|
|
9
7
|
|
|
10
8
|
import structlog
|
|
11
9
|
from jsonschema import ValidationError, validate
|
|
@@ -225,16 +223,6 @@ class AudiocodesInput(InputChannel):
|
|
|
225
223
|
self.scheduler_job = None
|
|
226
224
|
self.keep_alive = keep_alive
|
|
227
225
|
self.keep_alive_expiration_factor = keep_alive_expiration_factor
|
|
228
|
-
self.background_tasks: Dict[Text, Set[asyncio.Task]] = defaultdict(set)
|
|
229
|
-
|
|
230
|
-
def _create_task(self, conversation_id: Text, coro: Awaitable[Any]) -> asyncio.Task:
|
|
231
|
-
"""Create and track an asyncio task for a conversation."""
|
|
232
|
-
task: asyncio.Task = asyncio.create_task(coro)
|
|
233
|
-
self.background_tasks[conversation_id].add(task)
|
|
234
|
-
task.add_done_callback(
|
|
235
|
-
lambda t: self.background_tasks[conversation_id].discard(t)
|
|
236
|
-
)
|
|
237
|
-
return task
|
|
238
226
|
|
|
239
227
|
async def _set_scheduler_job(self) -> None:
|
|
240
228
|
if self.scheduler_job:
|
|
@@ -263,20 +251,11 @@ class AudiocodesInput(InputChannel):
|
|
|
263
251
|
)
|
|
264
252
|
now = datetime.now(timezone.utc)
|
|
265
253
|
delta = timedelta(seconds=self.keep_alive * self.keep_alive_expiration_factor)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if not conv.is_active_conversation(now, delta)
|
|
272
|
-
]
|
|
273
|
-
|
|
274
|
-
# cancel tasks and remove conversations
|
|
275
|
-
for conv_id in inactive:
|
|
276
|
-
for task in self.background_tasks[conv_id]:
|
|
277
|
-
task.cancel()
|
|
278
|
-
self.background_tasks.pop(conv_id, None)
|
|
279
|
-
self.conversations.pop(conv_id, None)
|
|
254
|
+
self.conversations = {
|
|
255
|
+
k: v
|
|
256
|
+
for k, v in self.conversations.items()
|
|
257
|
+
if v.is_active_conversation(now, delta)
|
|
258
|
+
}
|
|
280
259
|
|
|
281
260
|
def handle_start_conversation(self, body: Dict[Text, Any]) -> Dict[Text, Any]:
|
|
282
261
|
conversation_id = body["conversation"]
|
|
@@ -368,29 +347,31 @@ class AudiocodesInput(InputChannel):
|
|
|
368
347
|
structlogger.debug("audiocodes.on_activities", conversation=conversation_id)
|
|
369
348
|
conversation = self._get_conversation(request.token, conversation_id)
|
|
370
349
|
if conversation is None:
|
|
371
|
-
structlogger.warning(
|
|
372
|
-
"audiocodes.on_activities.no_conversation", request=request.json
|
|
373
|
-
)
|
|
374
350
|
return response.json({})
|
|
375
351
|
elif conversation.ws:
|
|
376
352
|
ac_output: Union[WebsocketOutput, AudiocodesOutput] = WebsocketOutput(
|
|
377
353
|
conversation.ws, conversation_id
|
|
378
354
|
)
|
|
379
|
-
|
|
355
|
+
await conversation.handle_activities(
|
|
356
|
+
request.json,
|
|
357
|
+
output_channel=ac_output,
|
|
358
|
+
on_new_message=on_new_message,
|
|
359
|
+
)
|
|
360
|
+
return response.json({})
|
|
380
361
|
else:
|
|
381
362
|
# handle non websocket case where messages get returned in json
|
|
382
363
|
ac_output = AudiocodesOutput()
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
364
|
+
await conversation.handle_activities(
|
|
365
|
+
request.json,
|
|
366
|
+
output_channel=ac_output,
|
|
367
|
+
on_new_message=on_new_message,
|
|
368
|
+
)
|
|
369
|
+
return response.json(
|
|
370
|
+
{
|
|
371
|
+
"conversation": conversation_id,
|
|
372
|
+
"activities": ac_output.messages,
|
|
373
|
+
}
|
|
374
|
+
)
|
|
394
375
|
|
|
395
376
|
@ac_webhook.route(
|
|
396
377
|
"/conversation/<conversation_id>/disconnect", methods=["POST"]
|
|
@@ -81,8 +81,7 @@ class AzureTTS(TTSEngine[AzureTTSConfig]):
|
|
|
81
81
|
@staticmethod
|
|
82
82
|
def create_request_body(text: str, conf: AzureTTSConfig) -> str:
|
|
83
83
|
return f"""
|
|
84
|
-
<speak version='1.0' xml:lang='{conf.language}'
|
|
85
|
-
xmlns='http://www.w3.org/2001/10/synthesis'>
|
|
84
|
+
<speak version='1.0' xml:lang='{conf.language}'>
|
|
86
85
|
<voice xml:lang='{conf.language}' name='{conf.voice}'>
|
|
87
86
|
{text}
|
|
88
87
|
</voice>
|
rasa/core/migrate.py
CHANGED
|
@@ -14,7 +14,7 @@ from rasa.shared.constants import (
|
|
|
14
14
|
)
|
|
15
15
|
from rasa.shared.core.constants import (
|
|
16
16
|
ACTIVE_LOOP,
|
|
17
|
-
|
|
17
|
+
MAPPING_TYPE,
|
|
18
18
|
REQUESTED_SLOT,
|
|
19
19
|
SLOT_MAPPINGS,
|
|
20
20
|
SlotMappingType,
|
|
@@ -43,7 +43,7 @@ def _create_back_up(domain_file: Path, backup_location: Path) -> Dict[Text, Any]
|
|
|
43
43
|
def _get_updated_mapping_condition(
|
|
44
44
|
condition: Dict[Text, Text], mapping: Dict[Text, Any], slot_name: Text
|
|
45
45
|
) -> Dict[Text, Text]:
|
|
46
|
-
if mapping.get(
|
|
46
|
+
if mapping.get(MAPPING_TYPE) not in [
|
|
47
47
|
str(SlotMappingType.FROM_ENTITY),
|
|
48
48
|
str(SlotMappingType.FROM_TRIGGER_INTENT),
|
|
49
49
|
]:
|
|
@@ -23,7 +23,6 @@ from rasa.core.policies.flows.flow_step_result import (
|
|
|
23
23
|
)
|
|
24
24
|
from rasa.dialogue_understanding.commands import CancelFlowCommand
|
|
25
25
|
from rasa.dialogue_understanding.patterns.cancel import CancelPatternFlowStackFrame
|
|
26
|
-
from rasa.dialogue_understanding.patterns.clarify import ClarifyPatternFlowStackFrame
|
|
27
26
|
from rasa.dialogue_understanding.patterns.collect_information import (
|
|
28
27
|
CollectInformationPatternFlowStackFrame,
|
|
29
28
|
)
|
|
@@ -51,7 +50,6 @@ from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
|
51
50
|
)
|
|
52
51
|
from rasa.dialogue_understanding.stack.utils import (
|
|
53
52
|
top_user_flow_frame,
|
|
54
|
-
user_flows_on_the_stack,
|
|
55
53
|
)
|
|
56
54
|
from rasa.shared.constants import RASA_PATTERN_HUMAN_HANDOFF
|
|
57
55
|
from rasa.shared.core.constants import ACTION_LISTEN_NAME, SlotMappingType
|
|
@@ -274,28 +272,6 @@ def trigger_pattern_continue_interrupted(
|
|
|
274
272
|
return events
|
|
275
273
|
|
|
276
274
|
|
|
277
|
-
def trigger_pattern_clarification(
|
|
278
|
-
current_frame: DialogueStackFrame, stack: DialogueStack, flows: FlowsList
|
|
279
|
-
) -> None:
|
|
280
|
-
"""Trigger the pattern to clarify which topic to continue if needed."""
|
|
281
|
-
if not isinstance(current_frame, UserFlowStackFrame):
|
|
282
|
-
return None
|
|
283
|
-
|
|
284
|
-
if current_frame.frame_type == FlowStackFrameType.CALL:
|
|
285
|
-
# we want to return to the flow that called the current flow
|
|
286
|
-
return None
|
|
287
|
-
|
|
288
|
-
pending_flows = [
|
|
289
|
-
flows.flow_by_id(frame.flow_id)
|
|
290
|
-
for frame in stack.frames
|
|
291
|
-
if isinstance(frame, UserFlowStackFrame)
|
|
292
|
-
and frame.flow_id != current_frame.flow_id
|
|
293
|
-
]
|
|
294
|
-
|
|
295
|
-
flow_names = [flow.readable_name() for flow in pending_flows if flow is not None]
|
|
296
|
-
stack.push(ClarifyPatternFlowStackFrame(names=flow_names))
|
|
297
|
-
|
|
298
|
-
|
|
299
275
|
def trigger_pattern_completed(
|
|
300
276
|
current_frame: DialogueStackFrame, stack: DialogueStack, flows: FlowsList
|
|
301
277
|
) -> None:
|
|
@@ -693,15 +669,7 @@ def _run_end_step(
|
|
|
693
669
|
structlogger.debug("flow.step.run.flow_end")
|
|
694
670
|
current_frame = stack.pop()
|
|
695
671
|
trigger_pattern_completed(current_frame, stack, flows)
|
|
696
|
-
resumed_events =
|
|
697
|
-
if len(user_flows_on_the_stack(stack)) > 1:
|
|
698
|
-
# if there are more user flows on the stack,
|
|
699
|
-
# we need to trigger the pattern clarify
|
|
700
|
-
trigger_pattern_clarification(current_frame, stack, flows)
|
|
701
|
-
else:
|
|
702
|
-
resumed_events = trigger_pattern_continue_interrupted(
|
|
703
|
-
current_frame, stack, flows
|
|
704
|
-
)
|
|
672
|
+
resumed_events = trigger_pattern_continue_interrupted(current_frame, stack, flows)
|
|
705
673
|
reset_events: List[Event] = reset_scoped_slots(current_frame, flow, tracker)
|
|
706
674
|
return ContinueFlowWithNextStep(
|
|
707
675
|
events=initial_events + reset_events + resumed_events, has_flow_ended=True
|
|
@@ -74,7 +74,7 @@ class CannotHandleCommand(Command):
|
|
|
74
74
|
|
|
75
75
|
def to_dsl(self) -> str:
|
|
76
76
|
"""Converts the command to a DSL string."""
|
|
77
|
-
return "
|
|
77
|
+
return "cannot handle"
|
|
78
78
|
|
|
79
79
|
@classmethod
|
|
80
80
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> CannotHandleCommand:
|
|
@@ -86,4 +86,4 @@ class CannotHandleCommand(Command):
|
|
|
86
86
|
|
|
87
87
|
@staticmethod
|
|
88
88
|
def regex_pattern() -> str:
|
|
89
|
-
return r"
|
|
89
|
+
return r"^cannot handle$"
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import copy
|
|
4
3
|
import re
|
|
5
4
|
from dataclasses import dataclass
|
|
6
5
|
from typing import Any, Dict, List
|
|
@@ -9,11 +8,8 @@ import structlog
|
|
|
9
8
|
|
|
10
9
|
from rasa.dialogue_understanding.commands.command import Command
|
|
11
10
|
from rasa.dialogue_understanding.patterns.cancel import CancelPatternFlowStackFrame
|
|
12
|
-
from rasa.dialogue_understanding.patterns.clarify import ClarifyPatternFlowStackFrame
|
|
13
11
|
from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
|
|
14
|
-
from rasa.dialogue_understanding.stack.frames import
|
|
15
|
-
UserFlowStackFrame,
|
|
16
|
-
)
|
|
12
|
+
from rasa.dialogue_understanding.stack.frames import UserFlowStackFrame
|
|
17
13
|
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import FlowStackFrameType
|
|
18
14
|
from rasa.dialogue_understanding.stack.utils import top_user_flow_frame
|
|
19
15
|
from rasa.shared.core.events import Event, FlowCancelled
|
|
@@ -93,8 +89,7 @@ class CancelFlowCommand(Command):
|
|
|
93
89
|
original_stack = original_tracker.stack
|
|
94
90
|
|
|
95
91
|
applied_events: List[Event] = []
|
|
96
|
-
|
|
97
|
-
initial_top_frame = stack.top()
|
|
92
|
+
|
|
98
93
|
user_frame = top_user_flow_frame(original_stack)
|
|
99
94
|
current_flow = user_frame.flow(all_flows) if user_frame else None
|
|
100
95
|
|
|
@@ -119,21 +114,6 @@ class CancelFlowCommand(Command):
|
|
|
119
114
|
if user_frame:
|
|
120
115
|
applied_events.append(FlowCancelled(user_frame.flow_id, user_frame.step_id))
|
|
121
116
|
|
|
122
|
-
if initial_top_frame and isinstance(
|
|
123
|
-
initial_top_frame, ClarifyPatternFlowStackFrame
|
|
124
|
-
):
|
|
125
|
-
structlogger.debug(
|
|
126
|
-
"command_executor.cancel_flow.cancel_clarification_options",
|
|
127
|
-
clarification_options=initial_top_frame.clarification_options,
|
|
128
|
-
)
|
|
129
|
-
applied_events += cancel_all_pending_clarification_options(
|
|
130
|
-
initial_top_frame,
|
|
131
|
-
original_stack,
|
|
132
|
-
canceled_frames,
|
|
133
|
-
all_flows,
|
|
134
|
-
stack,
|
|
135
|
-
)
|
|
136
|
-
|
|
137
117
|
return applied_events + tracker.create_stack_updated_events(stack)
|
|
138
118
|
|
|
139
119
|
def __hash__(self) -> int:
|
|
@@ -144,7 +124,7 @@ class CancelFlowCommand(Command):
|
|
|
144
124
|
|
|
145
125
|
def to_dsl(self) -> str:
|
|
146
126
|
"""Converts the command to a DSL string."""
|
|
147
|
-
return "
|
|
127
|
+
return "cancel flow"
|
|
148
128
|
|
|
149
129
|
@classmethod
|
|
150
130
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> CancelFlowCommand:
|
|
@@ -153,42 +133,4 @@ class CancelFlowCommand(Command):
|
|
|
153
133
|
|
|
154
134
|
@staticmethod
|
|
155
135
|
def regex_pattern() -> str:
|
|
156
|
-
return r"
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def cancel_all_pending_clarification_options(
|
|
160
|
-
initial_top_frame: ClarifyPatternFlowStackFrame,
|
|
161
|
-
original_stack: DialogueStack,
|
|
162
|
-
canceled_frames: List[str],
|
|
163
|
-
all_flows: FlowsList,
|
|
164
|
-
stack: DialogueStack,
|
|
165
|
-
) -> List[FlowCancelled]:
|
|
166
|
-
"""Cancel all pending clarification options.
|
|
167
|
-
|
|
168
|
-
This is a special case when the assistant asks the user to clarify
|
|
169
|
-
which pending digression flow to start after the completion of an active flow.
|
|
170
|
-
If the user chooses to cancel all options, this function takes care of
|
|
171
|
-
updating the stack by removing all pending flow stack frames
|
|
172
|
-
listed as clarification options.
|
|
173
|
-
"""
|
|
174
|
-
clarification_names = set(initial_top_frame.names)
|
|
175
|
-
to_be_canceled_frames = []
|
|
176
|
-
applied_events = []
|
|
177
|
-
for frame in reversed(original_stack.frames):
|
|
178
|
-
if frame.frame_id in canceled_frames:
|
|
179
|
-
continue
|
|
180
|
-
|
|
181
|
-
to_be_canceled_frames.append(frame.frame_id)
|
|
182
|
-
if isinstance(frame, UserFlowStackFrame):
|
|
183
|
-
readable_flow_name = frame.flow(all_flows).readable_name()
|
|
184
|
-
if readable_flow_name in clarification_names:
|
|
185
|
-
stack.push(
|
|
186
|
-
CancelPatternFlowStackFrame(
|
|
187
|
-
canceled_name=readable_flow_name,
|
|
188
|
-
canceled_frames=copy.deepcopy(to_be_canceled_frames),
|
|
189
|
-
)
|
|
190
|
-
)
|
|
191
|
-
applied_events.append(FlowCancelled(frame.flow_id, frame.step_id))
|
|
192
|
-
to_be_canceled_frames.clear()
|
|
193
|
-
|
|
194
|
-
return applied_events
|
|
136
|
+
return r"^cancel flow$"
|
|
@@ -48,7 +48,7 @@ class ChangeFlowCommand(Command):
|
|
|
48
48
|
|
|
49
49
|
def to_dsl(self) -> str:
|
|
50
50
|
"""Converts the command to a DSL string."""
|
|
51
|
-
return "
|
|
51
|
+
return "change"
|
|
52
52
|
|
|
53
53
|
@staticmethod
|
|
54
54
|
def from_dsl(match: re.Match, **kwargs: Any) -> ChangeFlowCommand:
|
|
@@ -57,4 +57,4 @@ class ChangeFlowCommand(Command):
|
|
|
57
57
|
|
|
58
58
|
@staticmethod
|
|
59
59
|
def regex_pattern() -> str:
|
|
60
|
-
return r"
|
|
60
|
+
return r"^change"
|
|
@@ -59,7 +59,7 @@ class ChitChatAnswerCommand(FreeFormAnswerCommand):
|
|
|
59
59
|
|
|
60
60
|
def to_dsl(self) -> str:
|
|
61
61
|
"""Converts the command to a DSL string."""
|
|
62
|
-
return "
|
|
62
|
+
return "offtopic reply"
|
|
63
63
|
|
|
64
64
|
@classmethod
|
|
65
65
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> ChitChatAnswerCommand:
|
|
@@ -68,4 +68,4 @@ class ChitChatAnswerCommand(FreeFormAnswerCommand):
|
|
|
68
68
|
|
|
69
69
|
@staticmethod
|
|
70
70
|
def regex_pattern() -> str:
|
|
71
|
-
return r"
|
|
71
|
+
return r"^offtopic reply$"
|
|
@@ -89,7 +89,7 @@ class ClarifyCommand(Command):
|
|
|
89
89
|
|
|
90
90
|
def to_dsl(self) -> str:
|
|
91
91
|
"""Converts the command to a DSL string."""
|
|
92
|
-
return f"
|
|
92
|
+
return f"disambiguate flows {' '.join(self.options)}"
|
|
93
93
|
|
|
94
94
|
@classmethod
|
|
95
95
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> Optional[ClarifyCommand]:
|
|
@@ -99,4 +99,4 @@ class ClarifyCommand(Command):
|
|
|
99
99
|
|
|
100
100
|
@staticmethod
|
|
101
101
|
def regex_pattern() -> str:
|
|
102
|
-
return r"
|
|
102
|
+
return r"^disambiguate flows([\"\'a-zA-Z0-9_, ]*)$"
|
|
@@ -31,7 +31,6 @@ class CorrectedSlot:
|
|
|
31
31
|
|
|
32
32
|
name: str
|
|
33
33
|
value: Any
|
|
34
|
-
filled_by: Optional[str] = None
|
|
35
34
|
|
|
36
35
|
|
|
37
36
|
@dataclass
|
|
@@ -55,9 +54,7 @@ class CorrectSlotsCommand(Command):
|
|
|
55
54
|
try:
|
|
56
55
|
return CorrectSlotsCommand(
|
|
57
56
|
corrected_slots=[
|
|
58
|
-
CorrectedSlot(
|
|
59
|
-
s["name"], value=s["value"], filled_by=s.get("filled_by", None)
|
|
60
|
-
)
|
|
57
|
+
CorrectedSlot(s["name"], value=s["value"])
|
|
61
58
|
for s in data["corrected_slots"]
|
|
62
59
|
]
|
|
63
60
|
)
|
|
@@ -138,10 +135,7 @@ class CorrectSlotsCommand(Command):
|
|
|
138
135
|
proposed_slots = {}
|
|
139
136
|
for corrected_slot in self.corrected_slots:
|
|
140
137
|
if tracker.get_slot(corrected_slot.name) != corrected_slot.value:
|
|
141
|
-
proposed_slots[corrected_slot.name] =
|
|
142
|
-
"value": corrected_slot.value,
|
|
143
|
-
"filled_by": corrected_slot.filled_by,
|
|
144
|
-
}
|
|
138
|
+
proposed_slots[corrected_slot.name] = corrected_slot.value
|
|
145
139
|
else:
|
|
146
140
|
structlogger.debug(
|
|
147
141
|
"command_executor.skip_correction.slot_already_set", command=self
|
|
@@ -246,9 +240,6 @@ class CorrectSlotsCommand(Command):
|
|
|
246
240
|
corrected_slots=proposed_slots,
|
|
247
241
|
reset_flow_id=earliest_collect.flow_id if earliest_collect else None,
|
|
248
242
|
reset_step_id=earliest_collect.step.id if earliest_collect else None,
|
|
249
|
-
new_slot_values=[
|
|
250
|
-
value.get("value") for slot, value in proposed_slots.items()
|
|
251
|
-
],
|
|
252
243
|
)
|
|
253
244
|
|
|
254
245
|
def run_command_on_tracker(
|
|
@@ -66,7 +66,7 @@ class HumanHandoffCommand(Command):
|
|
|
66
66
|
|
|
67
67
|
def to_dsl(self) -> str:
|
|
68
68
|
"""Converts the command to a DSL string."""
|
|
69
|
-
return "
|
|
69
|
+
return "hand over"
|
|
70
70
|
|
|
71
71
|
@classmethod
|
|
72
72
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> HumanHandoffCommand:
|
|
@@ -75,4 +75,4 @@ class HumanHandoffCommand(Command):
|
|
|
75
75
|
|
|
76
76
|
@staticmethod
|
|
77
77
|
def regex_pattern() -> str:
|
|
78
|
-
return r"
|
|
78
|
+
return r"^hand over$"
|
|
@@ -59,7 +59,7 @@ class KnowledgeAnswerCommand(FreeFormAnswerCommand):
|
|
|
59
59
|
|
|
60
60
|
def to_dsl(self) -> str:
|
|
61
61
|
"""Converts the command to a DSL string."""
|
|
62
|
-
return "
|
|
62
|
+
return "provide info"
|
|
63
63
|
|
|
64
64
|
@classmethod
|
|
65
65
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> KnowledgeAnswerCommand:
|
|
@@ -68,4 +68,4 @@ class KnowledgeAnswerCommand(FreeFormAnswerCommand):
|
|
|
68
68
|
|
|
69
69
|
@staticmethod
|
|
70
70
|
def regex_pattern() -> str:
|
|
71
|
-
return r"
|
|
71
|
+
return r"^provide info$"
|
|
@@ -60,7 +60,7 @@ class RepeatBotMessagesCommand(Command):
|
|
|
60
60
|
|
|
61
61
|
def to_dsl(self) -> str:
|
|
62
62
|
"""Converts the command to a DSL string."""
|
|
63
|
-
return "
|
|
63
|
+
return "repeat message"
|
|
64
64
|
|
|
65
65
|
@classmethod
|
|
66
66
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> RepeatBotMessagesCommand:
|
|
@@ -69,4 +69,4 @@ class RepeatBotMessagesCommand(Command):
|
|
|
69
69
|
|
|
70
70
|
@staticmethod
|
|
71
71
|
def regex_pattern() -> str:
|
|
72
|
-
return r"
|
|
72
|
+
return r"^repeat message$"
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
+
from enum import Enum
|
|
5
6
|
from typing import Any, Dict, List
|
|
6
7
|
|
|
7
8
|
import structlog
|
|
@@ -18,7 +19,6 @@ from rasa.dialogue_understanding.stack.utils import (
|
|
|
18
19
|
get_collect_steps_excluding_ask_before_filling_for_active_flow,
|
|
19
20
|
)
|
|
20
21
|
from rasa.shared.constants import ROUTE_TO_CALM_SLOT
|
|
21
|
-
from rasa.shared.core.constants import SetSlotExtractor
|
|
22
22
|
from rasa.shared.core.events import Event, SlotSet
|
|
23
23
|
from rasa.shared.core.flows import FlowsList
|
|
24
24
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -27,6 +27,17 @@ from rasa.shared.nlu.constants import SET_SLOT_COMMAND
|
|
|
27
27
|
structlogger = structlog.get_logger()
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
class SetSlotExtractor(Enum):
|
|
31
|
+
"""The extractors that can set a slot."""
|
|
32
|
+
|
|
33
|
+
LLM = "LLM"
|
|
34
|
+
COMMAND_PAYLOAD_READER = "CommandPayloadReader"
|
|
35
|
+
NLU = "NLU"
|
|
36
|
+
|
|
37
|
+
def __str__(self) -> str:
|
|
38
|
+
return self.value
|
|
39
|
+
|
|
40
|
+
|
|
30
41
|
def get_flows_predicted_to_start_from_tracker(
|
|
31
42
|
tracker: DialogueStateTracker,
|
|
32
43
|
) -> List[str]:
|
|
@@ -126,7 +137,6 @@ class SetSlotCommand(Command):
|
|
|
126
137
|
in {
|
|
127
138
|
SetSlotExtractor.LLM.value,
|
|
128
139
|
SetSlotExtractor.COMMAND_PAYLOAD_READER.value,
|
|
129
|
-
SetSlotExtractor.NLU.value,
|
|
130
140
|
}
|
|
131
141
|
):
|
|
132
142
|
# Get the other predicted flows from the most recent message on the tracker.
|
|
@@ -144,9 +154,7 @@ class SetSlotCommand(Command):
|
|
|
144
154
|
return []
|
|
145
155
|
|
|
146
156
|
structlogger.debug("command_executor.set_slot", command=self)
|
|
147
|
-
return [
|
|
148
|
-
SlotSet(self.name, slot.coerce_value(self.value), filled_by=self.extractor)
|
|
149
|
-
]
|
|
157
|
+
return [SlotSet(self.name, slot.coerce_value(self.value))]
|
|
150
158
|
|
|
151
159
|
def __hash__(self) -> int:
|
|
152
160
|
return hash(self.value) + hash(self.name)
|
|
@@ -162,7 +170,7 @@ class SetSlotCommand(Command):
|
|
|
162
170
|
|
|
163
171
|
def to_dsl(self) -> str:
|
|
164
172
|
"""Converts the command to a DSL string."""
|
|
165
|
-
return f"
|
|
173
|
+
return f"set slot {self.name} {self.value}"
|
|
166
174
|
|
|
167
175
|
@classmethod
|
|
168
176
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> SetSlotCommand:
|
|
@@ -173,4 +181,4 @@ class SetSlotCommand(Command):
|
|
|
173
181
|
|
|
174
182
|
@staticmethod
|
|
175
183
|
def regex_pattern() -> str:
|
|
176
|
-
return r"""
|
|
184
|
+
return r"""^set slot ['"]?([a-zA-Z_][a-zA-Z0-9_-]*)['"]? ['"]?(.+?)['"]?$"""
|
|
@@ -75,7 +75,7 @@ class SkipQuestionCommand(Command):
|
|
|
75
75
|
|
|
76
76
|
def to_dsl(self) -> str:
|
|
77
77
|
"""Converts the command to a DSL string."""
|
|
78
|
-
return "
|
|
78
|
+
return "skip"
|
|
79
79
|
|
|
80
80
|
@classmethod
|
|
81
81
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> SkipQuestionCommand:
|
|
@@ -84,4 +84,4 @@ class SkipQuestionCommand(Command):
|
|
|
84
84
|
|
|
85
85
|
@staticmethod
|
|
86
86
|
def regex_pattern() -> str:
|
|
87
|
-
return r"
|
|
87
|
+
return r"^skip$"
|