rasa-pro 3.12.0.dev12__py3-none-any.whl → 3.12.0.dev13__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/cli/inspect.py +20 -1
- rasa/cli/shell.py +3 -3
- rasa/core/actions/action.py +20 -7
- rasa/core/actions/action_handle_digressions.py +142 -0
- rasa/core/actions/forms.py +10 -5
- rasa/core/channels/__init__.py +2 -0
- rasa/core/channels/voice_ready/audiocodes.py +42 -23
- rasa/core/channels/voice_stream/browser_audio.py +1 -0
- rasa/core/channels/voice_stream/call_state.py +7 -1
- rasa/core/channels/voice_stream/genesys.py +331 -0
- rasa/core/channels/voice_stream/tts/azure.py +2 -1
- rasa/core/channels/voice_stream/tts/cartesia.py +16 -3
- rasa/core/channels/voice_stream/twilio_media_streams.py +2 -1
- rasa/core/channels/voice_stream/voice_channel.py +2 -1
- rasa/core/migrate.py +2 -2
- rasa/core/policies/flows/flow_executor.py +36 -42
- rasa/core/run.py +4 -3
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -2
- rasa/dialogue_understanding/commands/cancel_flow_command.py +62 -4
- 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 +11 -2
- rasa/dialogue_understanding/commands/handle_digressions_command.py +150 -0
- 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 +7 -15
- rasa/dialogue_understanding/commands/skip_question_command.py +2 -2
- rasa/dialogue_understanding/commands/start_flow_command.py +43 -2
- rasa/dialogue_understanding/commands/utils.py +1 -1
- rasa/dialogue_understanding/constants.py +1 -0
- rasa/dialogue_understanding/generator/command_generator.py +110 -73
- rasa/dialogue_understanding/generator/command_parser.py +1 -1
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +161 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +10 -2
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +44 -3
- rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +53 -79
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -19
- rasa/dialogue_understanding/generator/utils.py +32 -1
- rasa/dialogue_understanding/patterns/correction.py +13 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +62 -2
- rasa/dialogue_understanding/patterns/handle_digressions.py +81 -0
- rasa/dialogue_understanding/processor/command_processor.py +115 -28
- rasa/dialogue_understanding/utils.py +31 -0
- rasa/dialogue_understanding_test/README.md +50 -0
- rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +3 -3
- rasa/model_manager/warm_rasa_process.py +0 -1
- rasa/model_training.py +24 -27
- rasa/shared/core/constants.py +28 -3
- rasa/shared/core/domain.py +13 -20
- rasa/shared/core/events.py +13 -2
- rasa/shared/core/flows/flow.py +17 -0
- rasa/shared/core/flows/flows_yaml_schema.json +38 -0
- rasa/shared/core/flows/steps/collect.py +18 -1
- rasa/shared/core/flows/utils.py +16 -1
- rasa/shared/core/slot_mappings.py +144 -108
- rasa/shared/core/slots.py +23 -2
- rasa/shared/core/trackers.py +3 -1
- rasa/shared/nlu/constants.py +1 -0
- rasa/shared/utils/llm.py +1 -1
- rasa/shared/utils/schemas/domain.yml +0 -1
- rasa/telemetry.py +43 -13
- rasa/utils/common.py +0 -1
- rasa/validator.py +189 -82
- rasa/version.py +1 -1
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0.dev13.dist-info}/METADATA +1 -1
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0.dev13.dist-info}/RECORD +71 -67
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0.dev13.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0.dev13.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0.dev13.dist-info}/entry_points.txt +0 -0
rasa/shared/core/domain.py
CHANGED
|
@@ -46,10 +46,8 @@ from rasa.shared.constants import (
|
|
|
46
46
|
)
|
|
47
47
|
from rasa.shared.core.constants import (
|
|
48
48
|
ACTION_SHOULD_SEND_DOMAIN,
|
|
49
|
-
|
|
49
|
+
KEY_MAPPING_TYPE,
|
|
50
50
|
KNOWLEDGE_BASE_SLOT_NAMES,
|
|
51
|
-
MAPPING_CONDITIONS,
|
|
52
|
-
MAPPING_TYPE,
|
|
53
51
|
SLOT_MAPPINGS,
|
|
54
52
|
SlotMappingType,
|
|
55
53
|
)
|
|
@@ -290,8 +288,6 @@ class Domain:
|
|
|
290
288
|
responses = data.get(KEY_RESPONSES, {})
|
|
291
289
|
|
|
292
290
|
domain_slots = data.get(KEY_SLOTS, {})
|
|
293
|
-
if domain_slots:
|
|
294
|
-
rasa.shared.core.slot_mappings.validate_slot_mappings(domain_slots)
|
|
295
291
|
slots = cls.collect_slots(domain_slots)
|
|
296
292
|
domain_actions = data.get(KEY_ACTIONS, [])
|
|
297
293
|
actions = cls._collect_action_names(domain_actions)
|
|
@@ -596,7 +592,7 @@ class Domain:
|
|
|
596
592
|
),
|
|
597
593
|
)
|
|
598
594
|
slot_dict[slot_name][SLOT_MAPPINGS] = [
|
|
599
|
-
{
|
|
595
|
+
{KEY_MAPPING_TYPE: SlotMappingType.FROM_LLM.value}
|
|
600
596
|
]
|
|
601
597
|
|
|
602
598
|
slot = slot_class(slot_name, **slot_dict[slot_name])
|
|
@@ -1569,21 +1565,18 @@ class Domain:
|
|
|
1569
1565
|
matching_entities = []
|
|
1570
1566
|
|
|
1571
1567
|
for mapping in slot.mappings:
|
|
1572
|
-
mapping_conditions = mapping.
|
|
1573
|
-
if mapping
|
|
1568
|
+
mapping_conditions = mapping.conditions
|
|
1569
|
+
if mapping.type != SlotMappingType.FROM_ENTITY or (
|
|
1574
1570
|
mapping_conditions
|
|
1575
|
-
and mapping_conditions[0].
|
|
1571
|
+
and mapping_conditions[0].active_loop is not None
|
|
1576
1572
|
):
|
|
1577
1573
|
continue
|
|
1578
1574
|
|
|
1579
1575
|
for entity in entities:
|
|
1580
1576
|
if (
|
|
1581
|
-
entity.get(ENTITY_ATTRIBUTE_TYPE)
|
|
1582
|
-
|
|
1583
|
-
and entity.get(
|
|
1584
|
-
== mapping.get(ENTITY_ATTRIBUTE_ROLE)
|
|
1585
|
-
and entity.get(ENTITY_ATTRIBUTE_GROUP)
|
|
1586
|
-
== mapping.get(ENTITY_ATTRIBUTE_GROUP)
|
|
1577
|
+
entity.get(ENTITY_ATTRIBUTE_TYPE) == mapping.entity
|
|
1578
|
+
and entity.get(ENTITY_ATTRIBUTE_ROLE) == mapping.role
|
|
1579
|
+
and entity.get(ENTITY_ATTRIBUTE_GROUP) == mapping.group
|
|
1587
1580
|
):
|
|
1588
1581
|
matching_entities.append(entity.get("value"))
|
|
1589
1582
|
|
|
@@ -2015,19 +2008,19 @@ class Domain:
|
|
|
2015
2008
|
is the total number of mappings which have conditions attached.
|
|
2016
2009
|
"""
|
|
2017
2010
|
total_mappings = 0
|
|
2018
|
-
|
|
2011
|
+
controlled_mappings = 0
|
|
2019
2012
|
conditional_mappings = 0
|
|
2020
2013
|
|
|
2021
2014
|
for slot in self.slots:
|
|
2022
2015
|
total_mappings += len(slot.mappings)
|
|
2023
2016
|
for mapping in slot.mappings:
|
|
2024
|
-
if mapping
|
|
2025
|
-
|
|
2017
|
+
if mapping.type == SlotMappingType.CONTROLLED:
|
|
2018
|
+
controlled_mappings += 1
|
|
2026
2019
|
|
|
2027
|
-
if
|
|
2020
|
+
if mapping.conditions:
|
|
2028
2021
|
conditional_mappings += 1
|
|
2029
2022
|
|
|
2030
|
-
return
|
|
2023
|
+
return total_mappings, controlled_mappings, conditional_mappings
|
|
2031
2024
|
|
|
2032
2025
|
def does_custom_action_explicitly_need_domain(self, action_name: Text) -> bool:
|
|
2033
2026
|
"""Assert if action has explicitly stated that it needs domain.
|
rasa/shared/core/events.py
CHANGED
|
@@ -1032,6 +1032,7 @@ class SlotSet(Event):
|
|
|
1032
1032
|
value: Optional[Any] = None,
|
|
1033
1033
|
timestamp: Optional[float] = None,
|
|
1034
1034
|
metadata: Optional[Dict[Text, Any]] = None,
|
|
1035
|
+
filled_by: Optional[str] = None,
|
|
1035
1036
|
) -> None:
|
|
1036
1037
|
"""Creates event to set slot.
|
|
1037
1038
|
|
|
@@ -1043,6 +1044,7 @@ class SlotSet(Event):
|
|
|
1043
1044
|
"""
|
|
1044
1045
|
self.key = key
|
|
1045
1046
|
self.value = value
|
|
1047
|
+
self._filled_by = filled_by
|
|
1046
1048
|
super().__init__(timestamp, metadata)
|
|
1047
1049
|
|
|
1048
1050
|
def __repr__(self) -> Text:
|
|
@@ -1060,6 +1062,14 @@ class SlotSet(Event):
|
|
|
1060
1062
|
|
|
1061
1063
|
return (self.key, self.value) == (other.key, other.value)
|
|
1062
1064
|
|
|
1065
|
+
@property
|
|
1066
|
+
def filled_by(self) -> Optional[str]:
|
|
1067
|
+
return self._filled_by
|
|
1068
|
+
|
|
1069
|
+
@filled_by.setter
|
|
1070
|
+
def filled_by(self, value: str) -> None:
|
|
1071
|
+
self._filled_by = value
|
|
1072
|
+
|
|
1063
1073
|
def as_story_string(self) -> Text:
|
|
1064
1074
|
"""Returns text representation of event."""
|
|
1065
1075
|
props = json.dumps({self.key: self.value}, ensure_ascii=False)
|
|
@@ -1081,7 +1091,7 @@ class SlotSet(Event):
|
|
|
1081
1091
|
def as_dict(self) -> Dict[Text, Any]:
|
|
1082
1092
|
"""Returns serialized event."""
|
|
1083
1093
|
d = super().as_dict()
|
|
1084
|
-
d.update({"name": self.key, "value": self.value})
|
|
1094
|
+
d.update({"name": self.key, "value": self.value, "filled_by": self.filled_by})
|
|
1085
1095
|
return d
|
|
1086
1096
|
|
|
1087
1097
|
@classmethod
|
|
@@ -1092,13 +1102,14 @@ class SlotSet(Event):
|
|
|
1092
1102
|
parameters.get("value"),
|
|
1093
1103
|
parameters.get("timestamp"),
|
|
1094
1104
|
parameters.get("metadata"),
|
|
1105
|
+
filled_by=parameters.get("filled_by"),
|
|
1095
1106
|
)
|
|
1096
1107
|
except KeyError as e:
|
|
1097
1108
|
raise ValueError(f"Failed to parse set slot event. {e}")
|
|
1098
1109
|
|
|
1099
1110
|
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1100
1111
|
"""Applies event to current conversation state."""
|
|
1101
|
-
tracker._set_slot(self.key, self.value)
|
|
1112
|
+
tracker._set_slot(self.key, self.value, self.filled_by)
|
|
1102
1113
|
|
|
1103
1114
|
|
|
1104
1115
|
class Restarted(AlwaysEqualEventMixin):
|
rasa/shared/core/flows/flow.py
CHANGED
|
@@ -11,6 +11,10 @@ from pypred import Predicate
|
|
|
11
11
|
|
|
12
12
|
import rasa.shared.utils.io
|
|
13
13
|
from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
|
|
14
|
+
from rasa.shared.core.constants import (
|
|
15
|
+
KEY_ASK_CONFIRM_DIGRESSIONS,
|
|
16
|
+
KEY_BLOCK_DIGRESSIONS,
|
|
17
|
+
)
|
|
14
18
|
from rasa.shared.core.flows.flow_path import FlowPath, FlowPathsList, PathNode
|
|
15
19
|
from rasa.shared.core.flows.flow_step import FlowStep
|
|
16
20
|
from rasa.shared.core.flows.flow_step_links import (
|
|
@@ -33,6 +37,7 @@ from rasa.shared.core.flows.steps.constants import (
|
|
|
33
37
|
START_STEP,
|
|
34
38
|
)
|
|
35
39
|
from rasa.shared.core.flows.steps.continuation import ContinueFlowStep
|
|
40
|
+
from rasa.shared.core.flows.utils import extract_digression_prop
|
|
36
41
|
from rasa.shared.core.slots import Slot
|
|
37
42
|
|
|
38
43
|
structlogger = structlog.get_logger()
|
|
@@ -62,6 +67,10 @@ class Flow:
|
|
|
62
67
|
"""The path to the file where the flow is stored."""
|
|
63
68
|
persisted_slots: List[str] = field(default_factory=list)
|
|
64
69
|
"""The list of slots that should be persisted after the flow ends."""
|
|
70
|
+
ask_confirm_digressions: List[str] = field(default_factory=list)
|
|
71
|
+
"""The flow ids for which the assistant should ask for confirmation."""
|
|
72
|
+
block_digressions: List[str] = field(default_factory=list)
|
|
73
|
+
"""The flow ids that the assistant should block from digressing to."""
|
|
65
74
|
|
|
66
75
|
@staticmethod
|
|
67
76
|
def from_json(
|
|
@@ -98,6 +107,10 @@ class Flow:
|
|
|
98
107
|
# data. When the model is trained, take the provided file_path.
|
|
99
108
|
file_path=data.get("file_path") if "file_path" in data else file_path,
|
|
100
109
|
persisted_slots=data.get("persisted_slots", []),
|
|
110
|
+
ask_confirm_digressions=extract_digression_prop(
|
|
111
|
+
KEY_ASK_CONFIRM_DIGRESSIONS, data
|
|
112
|
+
),
|
|
113
|
+
block_digressions=extract_digression_prop(KEY_BLOCK_DIGRESSIONS, data),
|
|
101
114
|
)
|
|
102
115
|
|
|
103
116
|
def get_full_name(self) -> str:
|
|
@@ -172,6 +185,10 @@ class Flow:
|
|
|
172
185
|
data["file_path"] = self.file_path
|
|
173
186
|
if self.persisted_slots:
|
|
174
187
|
data["persisted_slots"] = self.persisted_slots
|
|
188
|
+
if self.ask_confirm_digressions:
|
|
189
|
+
data[KEY_ASK_CONFIRM_DIGRESSIONS] = self.ask_confirm_digressions
|
|
190
|
+
if self.block_digressions:
|
|
191
|
+
data[KEY_BLOCK_DIGRESSIONS] = self.block_digressions
|
|
175
192
|
|
|
176
193
|
return data
|
|
177
194
|
|
|
@@ -217,6 +217,12 @@
|
|
|
217
217
|
"reset_after_flow_ends": {
|
|
218
218
|
"type": "boolean"
|
|
219
219
|
},
|
|
220
|
+
"ask_confirm_digressions": {
|
|
221
|
+
"$ref": "#/$defs/ask_confirm_digressions"
|
|
222
|
+
},
|
|
223
|
+
"block_digressions": {
|
|
224
|
+
"$ref": "#/$defs/block_digressions"
|
|
225
|
+
},
|
|
220
226
|
"utter": {
|
|
221
227
|
"type": "string"
|
|
222
228
|
},
|
|
@@ -247,6 +253,32 @@
|
|
|
247
253
|
}
|
|
248
254
|
}
|
|
249
255
|
},
|
|
256
|
+
"ask_confirm_digressions": {
|
|
257
|
+
"oneOf": [
|
|
258
|
+
{
|
|
259
|
+
"type": "boolean"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"type": "array",
|
|
263
|
+
"items": {
|
|
264
|
+
"type": "string"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
},
|
|
269
|
+
"block_digressions": {
|
|
270
|
+
"oneOf": [
|
|
271
|
+
{
|
|
272
|
+
"type": "boolean"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"type": "array",
|
|
276
|
+
"items": {
|
|
277
|
+
"type": "string"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
]
|
|
281
|
+
},
|
|
250
282
|
"flow": {
|
|
251
283
|
"required": [
|
|
252
284
|
"steps",
|
|
@@ -282,6 +314,12 @@
|
|
|
282
314
|
},
|
|
283
315
|
"persisted_slots": {
|
|
284
316
|
"$ref": "#/$defs/persisted_slots"
|
|
317
|
+
},
|
|
318
|
+
"ask_confirm_digressions": {
|
|
319
|
+
"$ref": "#/$defs/ask_confirm_digressions"
|
|
320
|
+
},
|
|
321
|
+
"block_digressions": {
|
|
322
|
+
"$ref": "#/$defs/block_digressions"
|
|
285
323
|
}
|
|
286
324
|
}
|
|
287
325
|
},
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from dataclasses import dataclass
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
4
|
from typing import Any, Dict, List, Set, Text
|
|
5
5
|
|
|
6
6
|
from rasa.shared.constants import ACTION_ASK_PREFIX, UTTER_ASK_PREFIX
|
|
7
|
+
from rasa.shared.core.constants import (
|
|
8
|
+
KEY_ASK_CONFIRM_DIGRESSIONS,
|
|
9
|
+
KEY_BLOCK_DIGRESSIONS,
|
|
10
|
+
)
|
|
7
11
|
from rasa.shared.core.flows.flow_step import FlowStep
|
|
12
|
+
from rasa.shared.core.flows.utils import extract_digression_prop
|
|
8
13
|
|
|
9
14
|
|
|
10
15
|
@dataclass
|
|
@@ -59,6 +64,10 @@ class CollectInformationFlowStep(FlowStep):
|
|
|
59
64
|
"""Whether to always ask the question even if the slot is already filled."""
|
|
60
65
|
reset_after_flow_ends: bool = True
|
|
61
66
|
"""Whether to reset the slot value at the end of the flow."""
|
|
67
|
+
ask_confirm_digressions: List[str] = field(default_factory=list)
|
|
68
|
+
"""The flow id digressions for which the assistant should ask for confirmation."""
|
|
69
|
+
block_digressions: List[str] = field(default_factory=list)
|
|
70
|
+
"""The flow id digressions that should be blocked during the flow step."""
|
|
62
71
|
|
|
63
72
|
@classmethod
|
|
64
73
|
def from_json(
|
|
@@ -86,6 +95,10 @@ class CollectInformationFlowStep(FlowStep):
|
|
|
86
95
|
SlotRejection.from_dict(rejection)
|
|
87
96
|
for rejection in data.get("rejections", [])
|
|
88
97
|
],
|
|
98
|
+
ask_confirm_digressions=extract_digression_prop(
|
|
99
|
+
KEY_ASK_CONFIRM_DIGRESSIONS, data
|
|
100
|
+
),
|
|
101
|
+
block_digressions=extract_digression_prop(KEY_BLOCK_DIGRESSIONS, data),
|
|
89
102
|
**base.__dict__,
|
|
90
103
|
)
|
|
91
104
|
|
|
@@ -101,6 +114,10 @@ class CollectInformationFlowStep(FlowStep):
|
|
|
101
114
|
data["ask_before_filling"] = self.ask_before_filling
|
|
102
115
|
data["reset_after_flow_ends"] = self.reset_after_flow_ends
|
|
103
116
|
data["rejections"] = [rejection.as_dict() for rejection in self.rejections]
|
|
117
|
+
data["ask_confirm_digressions"] = self.ask_confirm_digressions
|
|
118
|
+
data["block_digressions"] = (
|
|
119
|
+
self.block_digressions if self.block_digressions else False
|
|
120
|
+
)
|
|
104
121
|
|
|
105
122
|
return data
|
|
106
123
|
|
rasa/shared/core/flows/utils.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from typing import Set
|
|
1
|
+
from typing import Any, Dict, List, Set
|
|
2
2
|
|
|
3
3
|
from rasa.shared.utils.io import raise_deprecation_warning
|
|
4
4
|
|
|
5
5
|
RESET_PROPERTY_NAME = "reset_after_flow_ends"
|
|
6
6
|
PERSIST_PROPERTY_NAME = "persisted_slots"
|
|
7
|
+
ALL_LABEL = "ALL"
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def warn_deprecated_collect_step_config(flow_id: str, collect_step: str) -> None:
|
|
@@ -38,3 +39,17 @@ def get_invalid_slot_persistence_config_error_message(
|
|
|
38
39
|
f"are neither used in a collect step nor a set_slot step of the flow. "
|
|
39
40
|
f"Please remove such slots from the '{PERSIST_PROPERTY_NAME}' property."
|
|
40
41
|
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def extract_digression_prop(prop: str, data: Dict[str, Any]) -> List[str]:
|
|
45
|
+
"""Extracts the digression property from the data.
|
|
46
|
+
|
|
47
|
+
There can be two types of properties: ask_confirm_digressions and
|
|
48
|
+
block_digressions.
|
|
49
|
+
"""
|
|
50
|
+
digression_property = data.get(prop, [])
|
|
51
|
+
|
|
52
|
+
if isinstance(digression_property, bool):
|
|
53
|
+
digression_property = [ALL_LABEL] if digression_property else []
|
|
54
|
+
|
|
55
|
+
return digression_property
|