rasa-pro 3.12.0.dev9__py3-none-any.whl → 3.12.0.dev11__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 +40 -40
- 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_service.py +4 -0
- 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/providers/llm/_base_litellm_client.py +0 -40
- rasa/shared/utils/llm.py +1 -86
- 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.dev9.dist-info → rasa_pro-3.12.0.dev11.dist-info}/METADATA +1 -1
- {rasa_pro-3.12.0.dev9.dist-info → rasa_pro-3.12.0.dev11.dist-info}/RECORD +72 -68
- {rasa_pro-3.12.0.dev9.dist-info → rasa_pro-3.12.0.dev11.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.0.dev9.dist-info → rasa_pro-3.12.0.dev11.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.0.dev9.dist-info → rasa_pro-3.12.0.dev11.dist-info}/entry_points.txt +0 -0
rasa/shared/utils/llm.py
CHANGED
|
@@ -6,7 +6,6 @@ from typing import (
|
|
|
6
6
|
Any,
|
|
7
7
|
Callable,
|
|
8
8
|
Dict,
|
|
9
|
-
List,
|
|
10
9
|
Optional,
|
|
11
10
|
Text,
|
|
12
11
|
Type,
|
|
@@ -238,90 +237,6 @@ def tracker_as_readable_transcript(
|
|
|
238
237
|
return "\n".join(transcript)
|
|
239
238
|
|
|
240
239
|
|
|
241
|
-
def sanitize_command_for_prompt(cmd_dict):
|
|
242
|
-
command = ""
|
|
243
|
-
if cmd_dict["command"] == "start flow":
|
|
244
|
-
command = f"start {cmd_dict['flow']}"
|
|
245
|
-
elif cmd_dict["command"] == "set slot":
|
|
246
|
-
command = f"set {cmd_dict['name']} {cmd_dict['value']}"
|
|
247
|
-
elif cmd_dict["command"] == "skip question":
|
|
248
|
-
command = "skip"
|
|
249
|
-
elif cmd_dict["command"] == "clarify":
|
|
250
|
-
command = f"clarify {' '.join(cmd_dict['options'])}"
|
|
251
|
-
elif cmd_dict["command"] == "knowledge":
|
|
252
|
-
command = "search"
|
|
253
|
-
elif cmd_dict["command"] == "chitchat":
|
|
254
|
-
command = "chat"
|
|
255
|
-
elif cmd_dict["command"] == "cancel flow":
|
|
256
|
-
command = "cancel"
|
|
257
|
-
else:
|
|
258
|
-
command = cmd_dict["command"]
|
|
259
|
-
|
|
260
|
-
return command
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
def tracker_as_message_list(
|
|
264
|
-
tracker: "DialogueStateTracker",
|
|
265
|
-
max_turns: Optional[int] = 20,
|
|
266
|
-
) -> List[str]:
|
|
267
|
-
"""Creates a readable dialogue from a tracker.
|
|
268
|
-
|
|
269
|
-
Args:
|
|
270
|
-
tracker: the tracker to convert
|
|
271
|
-
max_turns: the maximum number of turns to include in the transcript
|
|
272
|
-
|
|
273
|
-
Example:
|
|
274
|
-
>>> tracker = Tracker(
|
|
275
|
-
... sender_id="test",
|
|
276
|
-
... slots=[],
|
|
277
|
-
... events=[
|
|
278
|
-
... UserUttered("hello"),
|
|
279
|
-
... BotUttered("hi"),
|
|
280
|
-
... ],
|
|
281
|
-
... )
|
|
282
|
-
>>> tracker_as_readable_transcript(tracker)
|
|
283
|
-
USER: hello
|
|
284
|
-
AI: hi
|
|
285
|
-
|
|
286
|
-
Returns:
|
|
287
|
-
A string representing the transcript of the tracker
|
|
288
|
-
"""
|
|
289
|
-
messages = []
|
|
290
|
-
|
|
291
|
-
# using `applied_events` rather than `events` means that only events after the
|
|
292
|
-
# most recent `Restart` or `SessionStarted` are included in the transcript
|
|
293
|
-
# last_commands = None
|
|
294
|
-
for event in tracker.applied_events():
|
|
295
|
-
if isinstance(event, UserUttered):
|
|
296
|
-
if event.has_triggered_error:
|
|
297
|
-
first_error = event.error_commands[0]
|
|
298
|
-
error_type = first_error.get("error_type")
|
|
299
|
-
message = ERROR_PLACEHOLDER.get(
|
|
300
|
-
error_type, ERROR_PLACEHOLDER["default"]
|
|
301
|
-
)
|
|
302
|
-
else:
|
|
303
|
-
message = sanitize_message_for_prompt(event.text)
|
|
304
|
-
# last_commands = event.commands
|
|
305
|
-
messages.append({"role": "user", "content": message})
|
|
306
|
-
# messages.append({"role": "system", "content": ' \n '.join([sanitize_command_for_prompt(cmd) for cmd in last_commands])}) # noqa: E501
|
|
307
|
-
# transcript.append(f"{human_prefix}: {message}")
|
|
308
|
-
|
|
309
|
-
elif isinstance(event, BotUttered):
|
|
310
|
-
messages.append(
|
|
311
|
-
{
|
|
312
|
-
"role": "assistant",
|
|
313
|
-
"content": f"{sanitize_message_for_prompt(event.text)}",
|
|
314
|
-
}
|
|
315
|
-
)
|
|
316
|
-
# transcript.append(f"{ai_prefix}: {sanitize_message_for_prompt(event.text)}") # noqa: E501
|
|
317
|
-
|
|
318
|
-
if max_turns:
|
|
319
|
-
messages = messages[-max_turns:]
|
|
320
|
-
# transcript = transcript[-max_turns:]
|
|
321
|
-
|
|
322
|
-
return messages
|
|
323
|
-
|
|
324
|
-
|
|
325
240
|
def sanitize_message_for_prompt(text: Optional[str]) -> str:
|
|
326
241
|
"""Removes new lines from a string.
|
|
327
242
|
|
|
@@ -765,7 +680,7 @@ def allowed_values_for_slot(slot: Slot) -> Union[str, None]:
|
|
|
765
680
|
if isinstance(slot, BooleanSlot):
|
|
766
681
|
return str([True, False])
|
|
767
682
|
if isinstance(slot, CategoricalSlot):
|
|
768
|
-
return str([v for v in slot.values if v != "__other__"]
|
|
683
|
+
return str([v for v in slot.values if v != "__other__"])
|
|
769
684
|
else:
|
|
770
685
|
return None
|
|
771
686
|
|
rasa/telemetry.py
CHANGED
|
@@ -15,7 +15,7 @@ from collections import defaultdict
|
|
|
15
15
|
from datetime import datetime
|
|
16
16
|
from functools import wraps
|
|
17
17
|
from pathlib import Path
|
|
18
|
-
from typing import Any, Callable, Dict, List, Optional, Text
|
|
18
|
+
from typing import Any, Callable, Dict, List, Optional, Text, Tuple
|
|
19
19
|
|
|
20
20
|
import importlib_resources
|
|
21
21
|
import requests
|
|
@@ -35,6 +35,7 @@ from rasa.constants import (
|
|
|
35
35
|
)
|
|
36
36
|
from rasa.engine.storage.local_model_storage import LocalModelStorage
|
|
37
37
|
from rasa.shared.constants import (
|
|
38
|
+
ASSISTANT_ID_KEY,
|
|
38
39
|
CONFIG_LANGUAGE_KEY,
|
|
39
40
|
CONFIG_PIPELINE_KEY,
|
|
40
41
|
CONFIG_POLICIES_KEY,
|
|
@@ -111,6 +112,7 @@ CI_ENVIRONMENT_TELL = [
|
|
|
111
112
|
# https://rasa.com/docs/rasa-pro/telemetry/reference
|
|
112
113
|
TRAINING_STARTED_EVENT = "Training Started"
|
|
113
114
|
TRAINING_COMPLETED_EVENT = "Training Completed"
|
|
115
|
+
TRAINING_FAILED_EVENT = "Training Failed"
|
|
114
116
|
TELEMETRY_DISABLED_EVENT = "Telemetry Disabled"
|
|
115
117
|
TELEMETRY_DATA_SPLIT_EVENT = "Training Data Split"
|
|
116
118
|
TELEMETRY_DATA_VALIDATED_EVENT = "Training Data Validated"
|
|
@@ -976,6 +978,7 @@ def track_model_training(
|
|
|
976
978
|
"language": config.get(CONFIG_LANGUAGE_KEY),
|
|
977
979
|
"training_id": training_id,
|
|
978
980
|
"type": model_type,
|
|
981
|
+
"assistant_id": config.get(ASSISTANT_ID_KEY),
|
|
979
982
|
"pipeline": config.get(CONFIG_PIPELINE_KEY),
|
|
980
983
|
"policies": config.get(CONFIG_POLICIES_KEY),
|
|
981
984
|
"train_schema": config.get(CONFIG_TRAIN_SCHEMA),
|
|
@@ -1021,13 +1024,28 @@ def track_model_training(
|
|
|
1021
1024
|
tracking_data,
|
|
1022
1025
|
)
|
|
1023
1026
|
start = datetime.now()
|
|
1024
|
-
|
|
1027
|
+
try:
|
|
1028
|
+
yield
|
|
1029
|
+
except (Exception, SystemExit):
|
|
1030
|
+
runtime = datetime.now() - start
|
|
1031
|
+
_track(
|
|
1032
|
+
TRAINING_FAILED_EVENT,
|
|
1033
|
+
{
|
|
1034
|
+
"training_id": training_id,
|
|
1035
|
+
"assistant_id": config.get(ASSISTANT_ID_KEY),
|
|
1036
|
+
"type": model_type,
|
|
1037
|
+
"runtime": int(runtime.total_seconds()),
|
|
1038
|
+
},
|
|
1039
|
+
)
|
|
1040
|
+
raise
|
|
1041
|
+
|
|
1025
1042
|
runtime = datetime.now() - start
|
|
1026
1043
|
|
|
1027
1044
|
_track(
|
|
1028
1045
|
TRAINING_COMPLETED_EVENT,
|
|
1029
1046
|
{
|
|
1030
1047
|
"training_id": training_id,
|
|
1048
|
+
"assistant_id": config.get(ASSISTANT_ID_KEY),
|
|
1031
1049
|
"type": model_type,
|
|
1032
1050
|
"runtime": int(runtime.total_seconds()),
|
|
1033
1051
|
},
|
|
@@ -1326,24 +1344,28 @@ def track_server_start(
|
|
|
1326
1344
|
"""
|
|
1327
1345
|
from rasa.core.utils import AvailableEndpoints
|
|
1328
1346
|
|
|
1329
|
-
def
|
|
1347
|
+
def project_fingerprint_and_assistant_id_from_model(
|
|
1330
1348
|
_model_directory: Optional[Text],
|
|
1331
|
-
) -> Optional[Text]:
|
|
1349
|
+
) -> Tuple[Optional[Text], Optional[Text]]:
|
|
1332
1350
|
"""Gets project fingerprint from an app's loaded model."""
|
|
1333
1351
|
if not model_directory:
|
|
1334
|
-
return None
|
|
1352
|
+
return None, None
|
|
1335
1353
|
|
|
1336
1354
|
try:
|
|
1337
1355
|
model_archive = model.get_local_model(_model_directory)
|
|
1338
1356
|
metadata = LocalModelStorage.metadata_from_archive(model_archive)
|
|
1339
1357
|
|
|
1340
|
-
return metadata.project_fingerprint
|
|
1358
|
+
return metadata.project_fingerprint, metadata.assistant_id
|
|
1341
1359
|
except Exception:
|
|
1342
|
-
return None
|
|
1360
|
+
return None, None
|
|
1343
1361
|
|
|
1344
1362
|
if not endpoints:
|
|
1345
1363
|
endpoints = AvailableEndpoints()
|
|
1346
1364
|
|
|
1365
|
+
project, assistant_id = project_fingerprint_and_assistant_id_from_model(
|
|
1366
|
+
model_directory
|
|
1367
|
+
)
|
|
1368
|
+
|
|
1347
1369
|
_track(
|
|
1348
1370
|
TELEMETRY_SERVER_STARTED_EVENT,
|
|
1349
1371
|
{
|
|
@@ -1365,7 +1387,8 @@ def track_server_start(
|
|
|
1365
1387
|
"endpoints_event_broker": endpoints.event_broker.type
|
|
1366
1388
|
if endpoints.event_broker
|
|
1367
1389
|
else None,
|
|
1368
|
-
"project":
|
|
1390
|
+
"project": project,
|
|
1391
|
+
"assistant_id": assistant_id,
|
|
1369
1392
|
},
|
|
1370
1393
|
)
|
|
1371
1394
|
|
|
@@ -1383,23 +1406,30 @@ def track_project_init(path: Text) -> None:
|
|
|
1383
1406
|
|
|
1384
1407
|
|
|
1385
1408
|
@ensure_telemetry_enabled
|
|
1386
|
-
def track_shell_started(model_type: Text) -> None:
|
|
1409
|
+
def track_shell_started(model_type: Text, assistant_id: Text) -> None:
|
|
1387
1410
|
"""Track when a user starts a bot using rasa shell.
|
|
1388
1411
|
|
|
1389
1412
|
Args:
|
|
1390
1413
|
model_type: Type of the model, core / nlu or rasa.
|
|
1391
1414
|
"""
|
|
1392
|
-
_track(
|
|
1415
|
+
_track(
|
|
1416
|
+
TELEMETRY_SHELL_STARTED_EVENT,
|
|
1417
|
+
{"type": model_type, "assistant_id": assistant_id},
|
|
1418
|
+
)
|
|
1393
1419
|
|
|
1394
1420
|
|
|
1395
1421
|
@ensure_telemetry_enabled
|
|
1396
|
-
def track_inspect_started(
|
|
1422
|
+
def track_inspect_started(channel: Text, assistant_id: Text) -> None:
|
|
1397
1423
|
"""Track when a user starts a bot using rasa inspect.
|
|
1398
1424
|
|
|
1399
1425
|
Args:
|
|
1400
|
-
|
|
1426
|
+
channel: Type of channel used.
|
|
1427
|
+
assistant_id: ID of the assistant being inspected.
|
|
1401
1428
|
"""
|
|
1402
|
-
_track(
|
|
1429
|
+
_track(
|
|
1430
|
+
TELEMETRY_INSPECT_STARTED_EVENT,
|
|
1431
|
+
{"type": channel, "assistant_id": assistant_id},
|
|
1432
|
+
)
|
|
1403
1433
|
|
|
1404
1434
|
|
|
1405
1435
|
@ensure_telemetry_enabled
|
rasa/utils/common.py
CHANGED
|
@@ -70,7 +70,6 @@ EXPECTED_WARNINGS: List[Tuple[Type[Warning], str]] = [
|
|
|
70
70
|
"Converting sparse IndexedSlices.* to a dense Tensor of unknown "
|
|
71
71
|
"shape. This may consume a large amount of memory.",
|
|
72
72
|
),
|
|
73
|
-
(UserWarning, "Slot auto-fill has been removed in 3.0 .*"),
|
|
74
73
|
# Cannot fix this deprecation warning since we need to support two
|
|
75
74
|
# numpy versions as long as we keep python 37 around
|
|
76
75
|
(DeprecationWarning, "the `interpolation=` argument to quantile was renamed"),
|
rasa/validator.py
CHANGED
|
@@ -35,9 +35,7 @@ from rasa.shared.core.command_payload_reader import (
|
|
|
35
35
|
CommandPayloadReader,
|
|
36
36
|
)
|
|
37
37
|
from rasa.shared.core.constants import (
|
|
38
|
-
|
|
39
|
-
MAPPING_CONDITIONS,
|
|
40
|
-
MAPPING_TYPE,
|
|
38
|
+
KEY_ALLOW_NLU_CORRECTION,
|
|
41
39
|
SlotMappingType,
|
|
42
40
|
)
|
|
43
41
|
from rasa.shared.core.domain import (
|
|
@@ -45,13 +43,14 @@ from rasa.shared.core.domain import (
|
|
|
45
43
|
Domain,
|
|
46
44
|
)
|
|
47
45
|
from rasa.shared.core.events import ActionExecuted, ActiveLoop, UserUttered
|
|
48
|
-
from rasa.shared.core.flows import FlowsList
|
|
46
|
+
from rasa.shared.core.flows import Flow, FlowsList
|
|
49
47
|
from rasa.shared.core.flows.flow_step_links import IfFlowStepLink
|
|
50
48
|
from rasa.shared.core.flows.steps.action import ActionFlowStep
|
|
51
49
|
from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
|
|
52
50
|
from rasa.shared.core.flows.steps.link import LinkFlowStep
|
|
53
51
|
from rasa.shared.core.flows.steps.set_slots import SetSlotsFlowStep
|
|
54
52
|
from rasa.shared.core.flows.utils import (
|
|
53
|
+
ALL_LABEL,
|
|
55
54
|
get_duplicate_slot_persistence_config_error_message,
|
|
56
55
|
get_invalid_slot_persistence_config_error_message,
|
|
57
56
|
warn_deprecated_collect_step_config,
|
|
@@ -518,9 +517,9 @@ class Validator:
|
|
|
518
517
|
|
|
519
518
|
for slot in self.domain.slots:
|
|
520
519
|
for mapping in slot.mappings:
|
|
521
|
-
for condition in mapping.
|
|
522
|
-
condition_active_loop = condition.
|
|
523
|
-
mapping_type =
|
|
520
|
+
for condition in mapping.conditions:
|
|
521
|
+
condition_active_loop = condition.active_loop
|
|
522
|
+
mapping_type = mapping.type
|
|
524
523
|
if (
|
|
525
524
|
condition_active_loop
|
|
526
525
|
and condition_active_loop not in self.domain.form_names
|
|
@@ -1264,6 +1263,7 @@ class Validator:
|
|
|
1264
1263
|
self.verify_unique_flows(),
|
|
1265
1264
|
self.verify_predicates(),
|
|
1266
1265
|
self.verify_slot_persistence_configuration(),
|
|
1266
|
+
self.verify_digression_configuration(),
|
|
1267
1267
|
]
|
|
1268
1268
|
|
|
1269
1269
|
all_good = all(flow_validation_conditions)
|
|
@@ -1392,34 +1392,22 @@ class Validator:
|
|
|
1392
1392
|
|
|
1393
1393
|
for slot in self.domain._user_slots:
|
|
1394
1394
|
nlu_mappings = any(
|
|
1395
|
-
[
|
|
1396
|
-
SlotMappingType(
|
|
1397
|
-
mapping.get("type", SlotMappingType.FROM_LLM.value)
|
|
1398
|
-
).is_predefined_type()
|
|
1399
|
-
for mapping in slot.mappings
|
|
1400
|
-
]
|
|
1395
|
+
[mapping.type.is_predefined_type() for mapping in slot.mappings]
|
|
1401
1396
|
)
|
|
1402
1397
|
llm_mappings = any(
|
|
1403
|
-
[
|
|
1404
|
-
SlotMappingType(mapping.get("type", SlotMappingType.FROM_LLM.value))
|
|
1405
|
-
== SlotMappingType.FROM_LLM
|
|
1406
|
-
for mapping in slot.mappings
|
|
1407
|
-
]
|
|
1398
|
+
[mapping.type == SlotMappingType.FROM_LLM for mapping in slot.mappings]
|
|
1408
1399
|
)
|
|
1409
|
-
|
|
1400
|
+
controlled_mappings = any(
|
|
1410
1401
|
[
|
|
1411
|
-
|
|
1412
|
-
== SlotMappingType.CUSTOM
|
|
1402
|
+
mapping.type == SlotMappingType.CONTROLLED
|
|
1413
1403
|
for mapping in slot.mappings
|
|
1414
1404
|
]
|
|
1415
1405
|
)
|
|
1416
1406
|
|
|
1417
|
-
all_good = self.
|
|
1418
|
-
llm_mappings, nlu_mappings, custom_mappings, slot.name, all_good
|
|
1419
|
-
)
|
|
1407
|
+
all_good = self._allow_nlu_correction_is_valid(slot, nlu_mappings, all_good)
|
|
1420
1408
|
|
|
1421
1409
|
all_good = self._custom_action_name_is_defined_in_the_domain(
|
|
1422
|
-
|
|
1410
|
+
controlled_mappings, slot, all_good
|
|
1423
1411
|
)
|
|
1424
1412
|
|
|
1425
1413
|
all_good = self._config_contains_nlu_command_adapter(
|
|
@@ -1433,23 +1421,45 @@ class Validator:
|
|
|
1433
1421
|
return all_good
|
|
1434
1422
|
|
|
1435
1423
|
@staticmethod
|
|
1436
|
-
def
|
|
1437
|
-
|
|
1438
|
-
nlu_mappings: bool,
|
|
1439
|
-
custom_mappings: bool,
|
|
1440
|
-
slot_name: str,
|
|
1441
|
-
all_good: bool,
|
|
1424
|
+
def _allow_nlu_correction_is_valid(
|
|
1425
|
+
slot: Slot, nlu_mappings: bool, all_good: bool
|
|
1442
1426
|
) -> bool:
|
|
1443
|
-
|
|
1427
|
+
"""Verify that `allow_nlu_correction` property is used correctly in a `from_llm` mappings only.""" # noqa: E501
|
|
1428
|
+
if not slot.mappings:
|
|
1429
|
+
return all_good
|
|
1430
|
+
|
|
1431
|
+
invalid_usage = False
|
|
1432
|
+
|
|
1433
|
+
for mapping in slot.mappings:
|
|
1434
|
+
allow_nlu_correction = mapping.allow_nlu_correction
|
|
1435
|
+
if allow_nlu_correction and mapping.type != SlotMappingType.FROM_LLM:
|
|
1436
|
+
invalid_usage = True
|
|
1437
|
+
|
|
1438
|
+
if allow_nlu_correction and not nlu_mappings:
|
|
1439
|
+
structlogger.error(
|
|
1440
|
+
"validator.validate_slot_mappings_in_CALM.nlu_mappings_not_present",
|
|
1441
|
+
slot_name=slot.name,
|
|
1442
|
+
event_info=(
|
|
1443
|
+
f"The slot '{slot.name}' does not have any "
|
|
1444
|
+
f"NLU-based slot mappings. "
|
|
1445
|
+
f"The property `allow_nlu_correction` is only "
|
|
1446
|
+
f"applicable when the slot "
|
|
1447
|
+
f"contains both NLU-based and LLM-based slot mappings."
|
|
1448
|
+
),
|
|
1449
|
+
)
|
|
1450
|
+
all_good = False
|
|
1451
|
+
|
|
1452
|
+
if invalid_usage:
|
|
1444
1453
|
structlogger.error(
|
|
1445
|
-
"validator.validate_slot_mappings_in_CALM.
|
|
1446
|
-
slot_name=
|
|
1454
|
+
"validator.validate_slot_mappings_in_CALM.allow_nlu_correction",
|
|
1455
|
+
slot_name=slot.name,
|
|
1447
1456
|
event_info=(
|
|
1448
|
-
f"The slot '{
|
|
1449
|
-
f"
|
|
1450
|
-
f"
|
|
1457
|
+
f"The slot '{slot.name}' has at least 1 slot mapping with "
|
|
1458
|
+
f"'{KEY_ALLOW_NLU_CORRECTION}' set to 'true', but "
|
|
1459
|
+
f"the slot mapping type is not 'from_llm'. "
|
|
1460
|
+
f"Please set the slot mapping type to 'from_llm' "
|
|
1461
|
+
f"to allow the LLM to correct this slot."
|
|
1451
1462
|
),
|
|
1452
|
-
docs_link=DOCS_URL_DOMAIN + "#calm-slot-mappings",
|
|
1453
1463
|
)
|
|
1454
1464
|
all_good = False
|
|
1455
1465
|
|
|
@@ -1457,55 +1467,32 @@ class Validator:
|
|
|
1457
1467
|
|
|
1458
1468
|
def _custom_action_name_is_defined_in_the_domain(
|
|
1459
1469
|
self,
|
|
1460
|
-
|
|
1470
|
+
controlled_mappings: bool,
|
|
1461
1471
|
slot: Slot,
|
|
1462
1472
|
all_good: bool,
|
|
1463
1473
|
) -> bool:
|
|
1464
|
-
if not
|
|
1465
|
-
return all_good
|
|
1466
|
-
|
|
1467
|
-
if not self.flows:
|
|
1468
|
-
return all_good
|
|
1469
|
-
|
|
1470
|
-
is_custom_action_defined = any(
|
|
1471
|
-
[
|
|
1472
|
-
mapping.get("action") is not None
|
|
1473
|
-
and mapping.get("action") in self.domain.action_names_or_texts
|
|
1474
|
-
for mapping in slot.mappings
|
|
1475
|
-
]
|
|
1476
|
-
)
|
|
1477
|
-
|
|
1478
|
-
if is_custom_action_defined:
|
|
1474
|
+
if not controlled_mappings:
|
|
1479
1475
|
return all_good
|
|
1480
1476
|
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
event_info=(
|
|
1501
|
-
f"The slot '{slot.name}' has a custom slot mapping, but "
|
|
1502
|
-
f"neither the action '{custom_action_ask_name}' nor "
|
|
1503
|
-
f"another custom action are defined in the domain file. "
|
|
1504
|
-
f"Please add one of the actions to your domain file."
|
|
1505
|
-
),
|
|
1506
|
-
docs_link=DOCS_URL_DOMAIN + "#custom-slot-mappings",
|
|
1507
|
-
)
|
|
1508
|
-
all_good = False
|
|
1477
|
+
for mapping in slot.mappings:
|
|
1478
|
+
if (
|
|
1479
|
+
mapping.run_action_every_turn is not None
|
|
1480
|
+
and mapping.run_action_every_turn
|
|
1481
|
+
not in self.domain.action_names_or_texts
|
|
1482
|
+
):
|
|
1483
|
+
structlogger.error(
|
|
1484
|
+
"validator.validate_slot_mappings_in_CALM.custom_action_not_in_domain",
|
|
1485
|
+
slot_name=slot.name,
|
|
1486
|
+
action_name=mapping.run_action_every_turn,
|
|
1487
|
+
event_info=(
|
|
1488
|
+
f"The slot '{slot.name}' has a custom action "
|
|
1489
|
+
f"'{mapping.run_action_every_turn}' "
|
|
1490
|
+
f"defined in its slot mappings, "
|
|
1491
|
+
f"but the action is not listed in the domain actions. "
|
|
1492
|
+
f"Please add the action to your domain file."
|
|
1493
|
+
),
|
|
1494
|
+
)
|
|
1495
|
+
all_good = False
|
|
1509
1496
|
|
|
1510
1497
|
return all_good
|
|
1511
1498
|
|
|
@@ -1658,3 +1645,123 @@ class Validator:
|
|
|
1658
1645
|
)
|
|
1659
1646
|
|
|
1660
1647
|
return all_good
|
|
1648
|
+
|
|
1649
|
+
def verify_digression_configuration(self) -> bool:
|
|
1650
|
+
"""Validates the digression configuration in flows."""
|
|
1651
|
+
all_good = True
|
|
1652
|
+
|
|
1653
|
+
for flow in self.flows.underlying_flows:
|
|
1654
|
+
all_good = self._validate_ask_confirm_digressions(flow, all_good)
|
|
1655
|
+
all_good = self._validate_block_digressions(flow, all_good)
|
|
1656
|
+
|
|
1657
|
+
return all_good
|
|
1658
|
+
|
|
1659
|
+
def _validate_ask_confirm_digressions(self, flow: Flow, all_good: bool) -> bool:
|
|
1660
|
+
"""Validates the ask_confirm_digressions configuration in a flow."""
|
|
1661
|
+
for flow_id in flow.ask_confirm_digressions:
|
|
1662
|
+
if flow_id == ALL_LABEL:
|
|
1663
|
+
continue
|
|
1664
|
+
if flow_id not in self.flows.flow_ids:
|
|
1665
|
+
structlogger.error(
|
|
1666
|
+
"validator.verify_digression_configuration.ask_confirm_digressions",
|
|
1667
|
+
flow=flow.id,
|
|
1668
|
+
event_info=(
|
|
1669
|
+
f"The flow '{flow_id}' is listed in the "
|
|
1670
|
+
f"`ask_confirm_digressions` configuration of flow "
|
|
1671
|
+
f"'{flow.id}', but it is not found in the "
|
|
1672
|
+
f"flows file. Please make sure that the flow id is correct."
|
|
1673
|
+
),
|
|
1674
|
+
)
|
|
1675
|
+
all_good = False
|
|
1676
|
+
|
|
1677
|
+
if flow_id in flow.block_digressions:
|
|
1678
|
+
structlogger.error(
|
|
1679
|
+
"validator.verify_digression_configuration.overlap_digressions",
|
|
1680
|
+
flow=flow.id,
|
|
1681
|
+
event_info=(
|
|
1682
|
+
f"The flow '{flow_id}' is listed in both the "
|
|
1683
|
+
f"`ask_confirm_digressions` and `block_digressions` "
|
|
1684
|
+
f"configuration of flow '{flow.id}'. "
|
|
1685
|
+
f"Please make sure that the flow id is not listed in both "
|
|
1686
|
+
f"configurations."
|
|
1687
|
+
),
|
|
1688
|
+
)
|
|
1689
|
+
all_good = False
|
|
1690
|
+
|
|
1691
|
+
for step in flow.get_collect_steps():
|
|
1692
|
+
for flow_id in step.ask_confirm_digressions:
|
|
1693
|
+
if flow_id == ALL_LABEL:
|
|
1694
|
+
continue
|
|
1695
|
+
|
|
1696
|
+
if flow_id not in self.flows.flow_ids:
|
|
1697
|
+
structlogger.error(
|
|
1698
|
+
"validator.verify_digression_configuration.ask_confirm_digressions",
|
|
1699
|
+
flow=flow.id,
|
|
1700
|
+
step_id=step.id,
|
|
1701
|
+
event_info=(
|
|
1702
|
+
f"The flow '{flow_id}' is listed in the "
|
|
1703
|
+
f"`ask_confirm_digressions` configuration of step "
|
|
1704
|
+
f"'{step.id}' in flow '{flow.id}', but it is "
|
|
1705
|
+
f"not found in the flows file. "
|
|
1706
|
+
f"Please make sure that the flow id is correct."
|
|
1707
|
+
),
|
|
1708
|
+
)
|
|
1709
|
+
all_good = False
|
|
1710
|
+
|
|
1711
|
+
if flow_id in step.block_digressions:
|
|
1712
|
+
structlogger.error(
|
|
1713
|
+
"validator.verify_digression_configuration.overlap_digressions",
|
|
1714
|
+
flow=flow.id,
|
|
1715
|
+
step_id=step.id,
|
|
1716
|
+
event_info=(
|
|
1717
|
+
f"The flow '{flow_id}' is listed in both the "
|
|
1718
|
+
f"`ask_confirm_digressions` and `block_digressions` "
|
|
1719
|
+
f"configuration of step '{step.id}' in flow '{flow.id}'. "
|
|
1720
|
+
f"Please make sure that the flow id is not listed in both "
|
|
1721
|
+
f"configurations."
|
|
1722
|
+
),
|
|
1723
|
+
)
|
|
1724
|
+
all_good = False
|
|
1725
|
+
|
|
1726
|
+
return all_good
|
|
1727
|
+
|
|
1728
|
+
def _validate_block_digressions(self, flow: Flow, all_good: bool) -> bool:
|
|
1729
|
+
"""Validates the block_digressions configuration in a flow."""
|
|
1730
|
+
for flow_id in flow.block_digressions:
|
|
1731
|
+
if flow_id == ALL_LABEL:
|
|
1732
|
+
continue
|
|
1733
|
+
|
|
1734
|
+
if flow_id not in self.flows.flow_ids:
|
|
1735
|
+
structlogger.error(
|
|
1736
|
+
"validator.verify_digression_configuration.block_digressions",
|
|
1737
|
+
flow=flow.id,
|
|
1738
|
+
event_info=(
|
|
1739
|
+
f"The flow '{flow_id}' is listed in the `block_digressions` "
|
|
1740
|
+
f"configuration of flow '{flow.id}', but it is not found "
|
|
1741
|
+
f"in the flows file. Please make sure that the flow id "
|
|
1742
|
+
f"is correct."
|
|
1743
|
+
),
|
|
1744
|
+
)
|
|
1745
|
+
all_good = False
|
|
1746
|
+
|
|
1747
|
+
for step in flow.get_collect_steps():
|
|
1748
|
+
for flow_id in step.block_digressions:
|
|
1749
|
+
if flow_id == ALL_LABEL:
|
|
1750
|
+
continue
|
|
1751
|
+
|
|
1752
|
+
if flow_id not in self.flows.flow_ids:
|
|
1753
|
+
structlogger.error(
|
|
1754
|
+
"validator.verify_digression_configuration.block_digressions",
|
|
1755
|
+
flow=flow.id,
|
|
1756
|
+
step_id=step.id,
|
|
1757
|
+
event_info=(
|
|
1758
|
+
f"The flow '{flow_id}' is listed in the "
|
|
1759
|
+
f"`block_digressions` configuration of step "
|
|
1760
|
+
f"'{step.id}' in flow '{flow.id}', but it is "
|
|
1761
|
+
f"not found in the flows file. "
|
|
1762
|
+
f"Please make sure that the flow id is correct."
|
|
1763
|
+
),
|
|
1764
|
+
)
|
|
1765
|
+
all_good = False
|
|
1766
|
+
|
|
1767
|
+
return all_good
|
rasa/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rasa-pro
|
|
3
|
-
Version: 3.12.0.
|
|
3
|
+
Version: 3.12.0.dev11
|
|
4
4
|
Summary: State-of-the-art open-core Conversational AI framework for Enterprises that natively leverages generative AI for effortless assistant development.
|
|
5
5
|
Home-page: https://rasa.com
|
|
6
6
|
Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
|