rasa-pro 3.12.0.dev13__py3-none-any.whl → 3.12.0rc2__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.
- README.md +10 -13
- rasa/anonymization/anonymization_rule_executor.py +16 -10
- rasa/cli/data.py +16 -0
- rasa/cli/project_templates/calm/config.yml +2 -2
- rasa/cli/project_templates/calm/domain/list_contacts.yml +1 -2
- rasa/cli/project_templates/calm/domain/remove_contact.yml +1 -2
- rasa/cli/project_templates/calm/domain/shared.yml +1 -4
- rasa/cli/project_templates/calm/endpoints.yml +2 -2
- rasa/cli/utils.py +12 -0
- rasa/core/actions/action.py +84 -191
- rasa/core/actions/action_handle_digressions.py +35 -13
- rasa/core/actions/action_run_slot_rejections.py +16 -4
- rasa/core/channels/__init__.py +2 -0
- rasa/core/channels/studio_chat.py +19 -0
- rasa/core/channels/telegram.py +42 -24
- rasa/core/channels/voice_ready/utils.py +1 -1
- rasa/core/channels/voice_stream/asr/asr_engine.py +10 -4
- rasa/core/channels/voice_stream/asr/azure.py +14 -1
- rasa/core/channels/voice_stream/asr/deepgram.py +20 -4
- rasa/core/channels/voice_stream/audiocodes.py +264 -0
- rasa/core/channels/voice_stream/browser_audio.py +4 -1
- rasa/core/channels/voice_stream/call_state.py +3 -0
- rasa/core/channels/voice_stream/genesys.py +6 -2
- rasa/core/channels/voice_stream/tts/azure.py +9 -1
- rasa/core/channels/voice_stream/tts/cartesia.py +14 -8
- rasa/core/channels/voice_stream/voice_channel.py +23 -2
- rasa/core/constants.py +2 -0
- rasa/core/nlg/contextual_response_rephraser.py +18 -1
- rasa/core/nlg/generator.py +83 -15
- rasa/core/nlg/response.py +6 -3
- rasa/core/nlg/translate.py +55 -0
- rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
- rasa/core/policies/flows/flow_executor.py +19 -7
- rasa/core/processor.py +71 -9
- rasa/dialogue_understanding/commands/can_not_handle_command.py +20 -2
- rasa/dialogue_understanding/commands/cancel_flow_command.py +24 -6
- rasa/dialogue_understanding/commands/change_flow_command.py +20 -2
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +20 -2
- rasa/dialogue_understanding/commands/clarify_command.py +29 -3
- rasa/dialogue_understanding/commands/command.py +1 -16
- rasa/dialogue_understanding/commands/command_syntax_manager.py +55 -0
- rasa/dialogue_understanding/commands/handle_digressions_command.py +1 -7
- rasa/dialogue_understanding/commands/human_handoff_command.py +20 -2
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +20 -2
- rasa/dialogue_understanding/commands/prompt_command.py +94 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +20 -2
- rasa/dialogue_understanding/commands/set_slot_command.py +24 -2
- rasa/dialogue_understanding/commands/skip_question_command.py +20 -2
- rasa/dialogue_understanding/commands/start_flow_command.py +22 -2
- rasa/dialogue_understanding/commands/utils.py +71 -4
- rasa/dialogue_understanding/generator/__init__.py +2 -0
- rasa/dialogue_understanding/generator/command_parser.py +15 -12
- rasa/dialogue_understanding/generator/constants.py +3 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +12 -5
- rasa/dialogue_understanding/generator/llm_command_generator.py +5 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +17 -3
- rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
- rasa/dialogue_understanding/generator/{single_step → prompt_templates}/command_prompt_template.jinja2 +2 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +77 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_default.jinja2 +68 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +84 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +522 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +12 -310
- rasa/dialogue_understanding/patterns/collect_information.py +1 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +16 -0
- rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
- rasa/dialogue_understanding/processor/command_processor.py +39 -0
- rasa/dialogue_understanding/stack/utils.py +38 -0
- rasa/dialogue_understanding_test/du_test_case.py +58 -18
- rasa/dialogue_understanding_test/du_test_result.py +14 -10
- rasa/dialogue_understanding_test/io.py +14 -0
- rasa/e2e_test/assertions.py +6 -8
- rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +5 -1
- rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2 +4 -0
- rasa/e2e_test/utils/io.py +0 -37
- rasa/engine/graph.py +1 -0
- rasa/engine/language.py +140 -0
- rasa/engine/recipes/config_files/default_config.yml +4 -0
- rasa/engine/recipes/default_recipe.py +2 -0
- rasa/engine/recipes/graph_recipe.py +2 -0
- rasa/engine/storage/local_model_storage.py +1 -0
- rasa/engine/storage/storage.py +4 -1
- rasa/llm_fine_tuning/conversations.py +1 -1
- rasa/model_manager/runner_service.py +7 -4
- rasa/model_manager/socket_bridge.py +7 -6
- rasa/shared/constants.py +15 -13
- rasa/shared/core/constants.py +2 -0
- rasa/shared/core/flows/constants.py +11 -0
- rasa/shared/core/flows/flow.py +83 -19
- rasa/shared/core/flows/flows_yaml_schema.json +31 -3
- rasa/shared/core/flows/steps/collect.py +1 -36
- rasa/shared/core/flows/utils.py +28 -4
- rasa/shared/core/flows/validation.py +1 -1
- rasa/shared/core/slot_mappings.py +208 -5
- rasa/shared/core/slots.py +137 -1
- rasa/shared/core/trackers.py +74 -1
- rasa/shared/importers/importer.py +50 -2
- rasa/shared/nlu/training_data/schemas/responses.yml +19 -12
- rasa/shared/providers/_configs/azure_entra_id_config.py +541 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +138 -3
- rasa/shared/providers/_configs/client_config.py +3 -1
- rasa/shared/providers/_configs/default_litellm_client_config.py +3 -1
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +3 -1
- rasa/shared/providers/_configs/litellm_router_client_config.py +3 -1
- rasa/shared/providers/_configs/model_group_config.py +4 -2
- rasa/shared/providers/_configs/oauth_config.py +33 -0
- rasa/shared/providers/_configs/openai_client_config.py +3 -1
- rasa/shared/providers/_configs/rasa_llm_client_config.py +3 -1
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +3 -1
- rasa/shared/providers/constants.py +6 -0
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +28 -3
- rasa/shared/providers/embedding/litellm_router_embedding_client.py +3 -1
- rasa/shared/providers/llm/_base_litellm_client.py +42 -17
- rasa/shared/providers/llm/azure_openai_llm_client.py +81 -25
- rasa/shared/providers/llm/default_litellm_llm_client.py +3 -1
- rasa/shared/providers/llm/litellm_router_llm_client.py +29 -8
- rasa/shared/providers/llm/llm_client.py +23 -7
- rasa/shared/providers/llm/openai_llm_client.py +9 -3
- rasa/shared/providers/llm/rasa_llm_client.py +11 -2
- rasa/shared/providers/llm/self_hosted_llm_client.py +30 -11
- rasa/shared/providers/router/_base_litellm_router_client.py +3 -1
- rasa/shared/providers/router/router_client.py +3 -1
- rasa/shared/utils/constants.py +3 -0
- rasa/shared/utils/llm.py +33 -7
- rasa/shared/utils/pykwalify_extensions.py +24 -0
- rasa/shared/utils/schemas/domain.yml +26 -0
- rasa/telemetry.py +2 -1
- rasa/tracing/config.py +2 -0
- rasa/tracing/constants.py +12 -0
- rasa/tracing/instrumentation/instrumentation.py +36 -0
- rasa/tracing/instrumentation/metrics.py +41 -0
- rasa/tracing/metric_instrument_provider.py +40 -0
- rasa/validator.py +372 -7
- rasa/version.py +1 -1
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/METADATA +13 -14
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/RECORD +139 -124
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional, Text
|
|
2
|
+
|
|
3
|
+
from rasa.engine.language import Language
|
|
4
|
+
from rasa.shared.core.flows.constants import KEY_TRANSLATION
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_translated_text(
|
|
8
|
+
text: Optional[Text],
|
|
9
|
+
translation: Dict[Text, Any],
|
|
10
|
+
language: Optional[Language] = None,
|
|
11
|
+
) -> Optional[Text]:
|
|
12
|
+
"""Get the translated text from the message.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
text: The default text to use if no translation is found.
|
|
16
|
+
translation: The translations for the text.
|
|
17
|
+
language: The language to use for the translation.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
The translated text if found, otherwise the default text.
|
|
21
|
+
"""
|
|
22
|
+
language_code = language.code if language else None
|
|
23
|
+
return translation.get(language_code, text)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_translated_buttons(
|
|
27
|
+
buttons: Optional[List[Dict[Text, Any]]], language: Optional[Language] = None
|
|
28
|
+
) -> Optional[List[Dict[Text, Any]]]:
|
|
29
|
+
"""Get the translated buttons from the message.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
buttons: The default buttons to use if no translation is found.
|
|
33
|
+
language: The language to use for the translation.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
The translated buttons if found; otherwise, the default buttons.
|
|
37
|
+
"""
|
|
38
|
+
if buttons is None:
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
language_code = language.code if language else None
|
|
42
|
+
translated_buttons = []
|
|
43
|
+
for button in buttons:
|
|
44
|
+
translation = button.get(KEY_TRANSLATION, {})
|
|
45
|
+
language_translation = translation.get(language_code, {})
|
|
46
|
+
|
|
47
|
+
# Maintain the original key order to ensure
|
|
48
|
+
# accurate comparisons of BotUtter events.
|
|
49
|
+
translated_button = {
|
|
50
|
+
key: language_translation.get(key, button.get(key))
|
|
51
|
+
for key, value in button.items()
|
|
52
|
+
if key != KEY_TRANSLATION
|
|
53
|
+
}
|
|
54
|
+
translated_buttons.append(translated_button)
|
|
55
|
+
return translated_buttons
|
|
@@ -4,7 +4,7 @@ If the answer is not known or cannot be determined from the provided documents o
|
|
|
4
4
|
Use the following documents to answer the question:
|
|
5
5
|
{% for doc in docs %}
|
|
6
6
|
{{ loop.cycle("*")}}. {{ doc.metadata }}
|
|
7
|
-
{{ doc.
|
|
7
|
+
{{ doc.text }}
|
|
8
8
|
{% endfor %}
|
|
9
9
|
|
|
10
10
|
{% if citation_enabled %}
|
|
@@ -85,9 +85,8 @@ from rasa.shared.core.flows.steps import (
|
|
|
85
85
|
NoOperationFlowStep,
|
|
86
86
|
SetSlotsFlowStep,
|
|
87
87
|
)
|
|
88
|
-
from rasa.shared.core.flows.steps.collect import SlotRejection
|
|
89
88
|
from rasa.shared.core.flows.steps.constants import START_STEP
|
|
90
|
-
from rasa.shared.core.slots import Slot
|
|
89
|
+
from rasa.shared.core.slots import Slot, SlotRejection
|
|
91
90
|
from rasa.shared.core.trackers import (
|
|
92
91
|
DialogueStateTracker,
|
|
93
92
|
)
|
|
@@ -243,7 +242,10 @@ def events_for_collect_step_execution(
|
|
|
243
242
|
|
|
244
243
|
|
|
245
244
|
def trigger_pattern_continue_interrupted(
|
|
246
|
-
current_frame: DialogueStackFrame,
|
|
245
|
+
current_frame: DialogueStackFrame,
|
|
246
|
+
stack: DialogueStack,
|
|
247
|
+
flows: FlowsList,
|
|
248
|
+
tracker: DialogueStateTracker,
|
|
247
249
|
) -> List[Event]:
|
|
248
250
|
"""Trigger the pattern to continue an interrupted flow if needed."""
|
|
249
251
|
events: List[Event] = []
|
|
@@ -266,7 +268,9 @@ def trigger_pattern_continue_interrupted(
|
|
|
266
268
|
):
|
|
267
269
|
stack.push(
|
|
268
270
|
ContinueInterruptedPatternFlowStackFrame(
|
|
269
|
-
previous_flow_name=interrupted_user_flow.readable_name(
|
|
271
|
+
previous_flow_name=interrupted_user_flow.readable_name(
|
|
272
|
+
language=tracker.current_language
|
|
273
|
+
),
|
|
270
274
|
)
|
|
271
275
|
)
|
|
272
276
|
events.append(
|
|
@@ -283,8 +287,13 @@ def trigger_pattern_clarification(
|
|
|
283
287
|
if not isinstance(current_frame, UserFlowStackFrame):
|
|
284
288
|
return None
|
|
285
289
|
|
|
286
|
-
if current_frame.frame_type
|
|
287
|
-
|
|
290
|
+
if current_frame.frame_type in [
|
|
291
|
+
FlowStackFrameType.CALL,
|
|
292
|
+
FlowStackFrameType.INTERRUPT,
|
|
293
|
+
]:
|
|
294
|
+
# we want to return to the flow that called
|
|
295
|
+
# the current flow or the flow that was interrupted
|
|
296
|
+
# by the current flow
|
|
288
297
|
return None
|
|
289
298
|
|
|
290
299
|
pending_flows = [
|
|
@@ -309,6 +318,9 @@ def trigger_pattern_completed(
|
|
|
309
318
|
or isinstance(current_frame, SearchPatternFlowStackFrame)
|
|
310
319
|
):
|
|
311
320
|
completed_flow = current_frame.flow(flows)
|
|
321
|
+
if not completed_flow.run_pattern_completed:
|
|
322
|
+
return
|
|
323
|
+
|
|
312
324
|
completed_flow_name = completed_flow.readable_name() if completed_flow else None
|
|
313
325
|
stack.push(
|
|
314
326
|
CompletedPatternFlowStackFrame(
|
|
@@ -670,7 +682,7 @@ def _run_end_step(
|
|
|
670
682
|
trigger_pattern_clarification(current_frame, stack, flows)
|
|
671
683
|
else:
|
|
672
684
|
resumed_events = trigger_pattern_continue_interrupted(
|
|
673
|
-
current_frame, stack, flows
|
|
685
|
+
current_frame, stack, flows, tracker
|
|
674
686
|
)
|
|
675
687
|
reset_events: List[Event] = reset_scoped_slots(current_frame, flow, tracker)
|
|
676
688
|
return ContinueFlowWithNextStep(
|
rasa/core/processor.py
CHANGED
|
@@ -25,6 +25,7 @@ from rasa.core.channels.channel import (
|
|
|
25
25
|
OutputChannel,
|
|
26
26
|
UserMessage,
|
|
27
27
|
)
|
|
28
|
+
from rasa.core.constants import KEY_IS_CALM_SYSTEM, KEY_IS_COEXISTENCE_ASSISTANT
|
|
28
29
|
from rasa.core.http_interpreter import RasaNLUHttpInterpreter
|
|
29
30
|
from rasa.core.lock_store import LockStore
|
|
30
31
|
from rasa.core.nlg import NaturalLanguageGenerator
|
|
@@ -35,6 +36,12 @@ from rasa.dialogue_understanding.commands import (
|
|
|
35
36
|
NoopCommand,
|
|
36
37
|
SetSlotCommand,
|
|
37
38
|
)
|
|
39
|
+
from rasa.dialogue_understanding.commands.utils import (
|
|
40
|
+
create_validate_frames_from_slot_set_events,
|
|
41
|
+
)
|
|
42
|
+
from rasa.dialogue_understanding.patterns.validate_slot import (
|
|
43
|
+
ValidateSlotPatternFlowStackFrame,
|
|
44
|
+
)
|
|
38
45
|
from rasa.dialogue_understanding.utils import add_commands_to_message_parse_data
|
|
39
46
|
from rasa.engine import loader
|
|
40
47
|
from rasa.engine.constants import (
|
|
@@ -201,10 +208,7 @@ class MessageProcessor:
|
|
|
201
208
|
)
|
|
202
209
|
return None
|
|
203
210
|
|
|
204
|
-
|
|
205
|
-
tracker = await self.run_action_extract_slots(
|
|
206
|
-
message.output_channel, tracker
|
|
207
|
-
)
|
|
211
|
+
tracker = await self.run_action_extract_slots(message.output_channel, tracker)
|
|
208
212
|
|
|
209
213
|
await self._run_prediction_loop(message.output_channel, tracker)
|
|
210
214
|
|
|
@@ -218,7 +222,9 @@ class MessageProcessor:
|
|
|
218
222
|
return None
|
|
219
223
|
|
|
220
224
|
async def run_action_extract_slots(
|
|
221
|
-
self,
|
|
225
|
+
self,
|
|
226
|
+
output_channel: OutputChannel,
|
|
227
|
+
tracker: DialogueStateTracker,
|
|
222
228
|
) -> DialogueStateTracker:
|
|
223
229
|
"""Run action to extract slots and update the tracker accordingly.
|
|
224
230
|
|
|
@@ -233,6 +239,10 @@ class MessageProcessor:
|
|
|
233
239
|
ACTION_EXTRACT_SLOTS, self.domain, self.action_endpoint
|
|
234
240
|
)
|
|
235
241
|
metadata = await self._add_flows_to_metadata()
|
|
242
|
+
metadata[KEY_IS_CALM_SYSTEM] = self.message_contains_commands(
|
|
243
|
+
tracker.latest_message
|
|
244
|
+
)
|
|
245
|
+
metadata[KEY_IS_COEXISTENCE_ASSISTANT] = self._is_coexistence_assistant(tracker)
|
|
236
246
|
|
|
237
247
|
extraction_events = await action_extract_slots.run(
|
|
238
248
|
output_channel, self.nlg, tracker, self.domain, metadata
|
|
@@ -1251,6 +1261,12 @@ class MessageProcessor:
|
|
|
1251
1261
|
# events and return values are used to update
|
|
1252
1262
|
# the tracker state after an action has been taken
|
|
1253
1263
|
try:
|
|
1264
|
+
validate_frames: List[ValidateSlotPatternFlowStackFrame] = []
|
|
1265
|
+
# check if the last action was a correction action
|
|
1266
|
+
# before validating the corrected slots
|
|
1267
|
+
if tracker.latest_action_name == ACTION_CORRECT_FLOW_SLOT:
|
|
1268
|
+
tracker, validate_frames = self.validate_corrected_slots(tracker)
|
|
1269
|
+
|
|
1254
1270
|
# Use temporary tracker as we might need to discard the policy events in
|
|
1255
1271
|
# case of a rejection.
|
|
1256
1272
|
temporary_tracker = tracker.copy()
|
|
@@ -1262,6 +1278,12 @@ class MessageProcessor:
|
|
|
1262
1278
|
|
|
1263
1279
|
if isinstance(action, FormAction):
|
|
1264
1280
|
flows_metadata = await self._add_flows_to_metadata()
|
|
1281
|
+
flows_metadata[KEY_IS_CALM_SYSTEM] = self.message_contains_commands(
|
|
1282
|
+
temporary_tracker.latest_message
|
|
1283
|
+
)
|
|
1284
|
+
flows_metadata[KEY_IS_COEXISTENCE_ASSISTANT] = (
|
|
1285
|
+
self._is_coexistence_assistant(temporary_tracker)
|
|
1286
|
+
)
|
|
1265
1287
|
metadata = prediction.action_metadata or {}
|
|
1266
1288
|
metadata.update(flows_metadata)
|
|
1267
1289
|
|
|
@@ -1276,6 +1298,14 @@ class MessageProcessor:
|
|
|
1276
1298
|
events = await action.run(
|
|
1277
1299
|
output_channel, nlg, temporary_tracker, self.domain
|
|
1278
1300
|
)
|
|
1301
|
+
|
|
1302
|
+
if validate_frames:
|
|
1303
|
+
stack = tracker.stack
|
|
1304
|
+
for frame in validate_frames:
|
|
1305
|
+
stack.push(frame)
|
|
1306
|
+
new_events = tracker.create_stack_updated_events(stack)
|
|
1307
|
+
tracker.update_with_events(new_events)
|
|
1308
|
+
|
|
1279
1309
|
self._log_action_and_events_on_tracker(tracker, action, events, prediction)
|
|
1280
1310
|
except ActionExecutionRejection:
|
|
1281
1311
|
events = [
|
|
@@ -1479,18 +1509,50 @@ class MessageProcessor:
|
|
|
1479
1509
|
Returns:
|
|
1480
1510
|
bool: True if any node in the graph schema uses `FlowPolicy`.
|
|
1481
1511
|
"""
|
|
1512
|
+
flow_policy_class_path = "rasa.core.policies.flow_policy.FlowPolicy"
|
|
1513
|
+
return self._is_component_present_in_graph_nodes(flow_policy_class_path)
|
|
1514
|
+
|
|
1515
|
+
@staticmethod
|
|
1516
|
+
def _is_coexistence_assistant(tracker: DialogueStateTracker) -> bool:
|
|
1517
|
+
"""Inspect the tracker to decide if we are in coexistence.
|
|
1518
|
+
|
|
1519
|
+
Returns:
|
|
1520
|
+
bool: True if the tracker contains the routine slot.
|
|
1521
|
+
"""
|
|
1522
|
+
return tracker.slots.get(ROUTE_TO_CALM_SLOT) is not None
|
|
1523
|
+
|
|
1524
|
+
def _is_component_present_in_graph_nodes(self, component_path: Text) -> bool:
|
|
1525
|
+
"""Check if a component is present in the graph nodes.
|
|
1526
|
+
|
|
1527
|
+
Args:
|
|
1528
|
+
component_path: The path of the component to check for.
|
|
1529
|
+
|
|
1530
|
+
Returns:
|
|
1531
|
+
`True` if the component is present in the graph nodes, `False` otherwise.
|
|
1532
|
+
"""
|
|
1482
1533
|
# Get the graph schema's nodes from the graph runner.
|
|
1483
1534
|
nodes: dict[str, Any] = self.graph_runner._graph_schema.nodes # type: ignore[attr-defined]
|
|
1484
1535
|
|
|
1485
|
-
flow_policy_class_path = "rasa.core.policies.flow_policy.FlowPolicy"
|
|
1486
|
-
# Iterate over the nodes and check if any node uses `FlowPolicy`.
|
|
1487
1536
|
for node_name, schema_node in nodes.items():
|
|
1488
1537
|
if (
|
|
1489
1538
|
schema_node.uses is not None
|
|
1490
1539
|
and f"{schema_node.uses.__module__}.{schema_node.uses.__name__}"
|
|
1491
|
-
==
|
|
1540
|
+
== component_path
|
|
1492
1541
|
):
|
|
1493
1542
|
return True
|
|
1494
1543
|
|
|
1495
|
-
# Return False if no node is found using `FlowPolicy`.
|
|
1496
1544
|
return False
|
|
1545
|
+
|
|
1546
|
+
def validate_corrected_slots(
|
|
1547
|
+
self,
|
|
1548
|
+
tracker: DialogueStateTracker,
|
|
1549
|
+
) -> Tuple[DialogueStateTracker, List[ValidateSlotPatternFlowStackFrame]]:
|
|
1550
|
+
"""Validate the slots that were corrected in the tracker."""
|
|
1551
|
+
prior_tracker_events = list(reversed(tracker.events))
|
|
1552
|
+
tracker, validate_frames = create_validate_frames_from_slot_set_events(
|
|
1553
|
+
tracker,
|
|
1554
|
+
prior_tracker_events,
|
|
1555
|
+
should_break=True,
|
|
1556
|
+
)
|
|
1557
|
+
|
|
1558
|
+
return tracker, validate_frames
|
|
@@ -5,6 +5,10 @@ from dataclasses import dataclass
|
|
|
5
5
|
from typing import Any, Dict, List, Optional, Text
|
|
6
6
|
|
|
7
7
|
from rasa.dialogue_understanding.commands.command import Command
|
|
8
|
+
from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
9
|
+
CommandSyntaxManager,
|
|
10
|
+
CommandSyntaxVersion,
|
|
11
|
+
)
|
|
8
12
|
from rasa.dialogue_understanding.patterns.cannot_handle import (
|
|
9
13
|
CannotHandlePatternFlowStackFrame,
|
|
10
14
|
)
|
|
@@ -74,7 +78,14 @@ class CannotHandleCommand(Command):
|
|
|
74
78
|
|
|
75
79
|
def to_dsl(self) -> str:
|
|
76
80
|
"""Converts the command to a DSL string."""
|
|
77
|
-
|
|
81
|
+
mapper = {
|
|
82
|
+
CommandSyntaxVersion.v1: "CannotHandle()",
|
|
83
|
+
CommandSyntaxVersion.v2: "cannot handle",
|
|
84
|
+
}
|
|
85
|
+
return mapper.get(
|
|
86
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
87
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
88
|
+
)
|
|
78
89
|
|
|
79
90
|
@classmethod
|
|
80
91
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> CannotHandleCommand:
|
|
@@ -86,4 +97,11 @@ class CannotHandleCommand(Command):
|
|
|
86
97
|
|
|
87
98
|
@staticmethod
|
|
88
99
|
def regex_pattern() -> str:
|
|
89
|
-
|
|
100
|
+
mapper = {
|
|
101
|
+
CommandSyntaxVersion.v1: r"CannotHandle\(\)",
|
|
102
|
+
CommandSyntaxVersion.v2: r"""^[\s\W\d]*cannot handle['"`]*$""",
|
|
103
|
+
}
|
|
104
|
+
return mapper.get(
|
|
105
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
106
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
107
|
+
)
|
|
@@ -8,12 +8,14 @@ from typing import Any, Dict, List
|
|
|
8
8
|
import structlog
|
|
9
9
|
|
|
10
10
|
from rasa.dialogue_understanding.commands.command import Command
|
|
11
|
+
from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
12
|
+
CommandSyntaxManager,
|
|
13
|
+
CommandSyntaxVersion,
|
|
14
|
+
)
|
|
11
15
|
from rasa.dialogue_understanding.patterns.cancel import CancelPatternFlowStackFrame
|
|
12
16
|
from rasa.dialogue_understanding.patterns.clarify import ClarifyPatternFlowStackFrame
|
|
13
17
|
from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
|
|
14
|
-
from rasa.dialogue_understanding.stack.frames import
|
|
15
|
-
UserFlowStackFrame,
|
|
16
|
-
)
|
|
18
|
+
from rasa.dialogue_understanding.stack.frames import UserFlowStackFrame
|
|
17
19
|
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import FlowStackFrameType
|
|
18
20
|
from rasa.dialogue_understanding.stack.utils import top_user_flow_frame
|
|
19
21
|
from rasa.shared.core.events import Event, FlowCancelled
|
|
@@ -111,7 +113,9 @@ class CancelFlowCommand(Command):
|
|
|
111
113
|
|
|
112
114
|
stack.push(
|
|
113
115
|
CancelPatternFlowStackFrame(
|
|
114
|
-
canceled_name=current_flow.readable_name(
|
|
116
|
+
canceled_name=current_flow.readable_name(
|
|
117
|
+
language=tracker.current_language
|
|
118
|
+
),
|
|
115
119
|
canceled_frames=canceled_frames,
|
|
116
120
|
)
|
|
117
121
|
)
|
|
@@ -144,7 +148,14 @@ class CancelFlowCommand(Command):
|
|
|
144
148
|
|
|
145
149
|
def to_dsl(self) -> str:
|
|
146
150
|
"""Converts the command to a DSL string."""
|
|
147
|
-
|
|
151
|
+
mapper = {
|
|
152
|
+
CommandSyntaxVersion.v1: "CancelFlow()",
|
|
153
|
+
CommandSyntaxVersion.v2: "cancel flow",
|
|
154
|
+
}
|
|
155
|
+
return mapper.get(
|
|
156
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
157
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
158
|
+
)
|
|
148
159
|
|
|
149
160
|
@classmethod
|
|
150
161
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> CancelFlowCommand:
|
|
@@ -153,7 +164,14 @@ class CancelFlowCommand(Command):
|
|
|
153
164
|
|
|
154
165
|
@staticmethod
|
|
155
166
|
def regex_pattern() -> str:
|
|
156
|
-
|
|
167
|
+
mapper = {
|
|
168
|
+
CommandSyntaxVersion.v1: r"CancelFlow\(\)",
|
|
169
|
+
CommandSyntaxVersion.v2: r"""^[\s\W\d]*cancel flow['"`]*$""",
|
|
170
|
+
}
|
|
171
|
+
return mapper.get(
|
|
172
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
173
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
174
|
+
)
|
|
157
175
|
|
|
158
176
|
|
|
159
177
|
def cancel_all_pending_clarification_options(
|
|
@@ -5,6 +5,10 @@ from dataclasses import dataclass
|
|
|
5
5
|
from typing import Any, Dict, List
|
|
6
6
|
|
|
7
7
|
from rasa.dialogue_understanding.commands.command import Command
|
|
8
|
+
from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
9
|
+
CommandSyntaxManager,
|
|
10
|
+
CommandSyntaxVersion,
|
|
11
|
+
)
|
|
8
12
|
from rasa.shared.core.events import Event
|
|
9
13
|
from rasa.shared.core.flows import FlowsList
|
|
10
14
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -48,7 +52,14 @@ class ChangeFlowCommand(Command):
|
|
|
48
52
|
|
|
49
53
|
def to_dsl(self) -> str:
|
|
50
54
|
"""Converts the command to a DSL string."""
|
|
51
|
-
|
|
55
|
+
mapper = {
|
|
56
|
+
CommandSyntaxVersion.v1: "ChangeFlow()",
|
|
57
|
+
CommandSyntaxVersion.v2: "change",
|
|
58
|
+
}
|
|
59
|
+
return mapper.get(
|
|
60
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
61
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
62
|
+
)
|
|
52
63
|
|
|
53
64
|
@staticmethod
|
|
54
65
|
def from_dsl(match: re.Match, **kwargs: Any) -> ChangeFlowCommand:
|
|
@@ -57,4 +68,11 @@ class ChangeFlowCommand(Command):
|
|
|
57
68
|
|
|
58
69
|
@staticmethod
|
|
59
70
|
def regex_pattern() -> str:
|
|
60
|
-
|
|
71
|
+
mapper = {
|
|
72
|
+
CommandSyntaxVersion.v1: r"ChangeFlow\(\)",
|
|
73
|
+
CommandSyntaxVersion.v2: r"""^[\s\W\d]*change['"`]*$""",
|
|
74
|
+
}
|
|
75
|
+
return mapper.get(
|
|
76
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
77
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
78
|
+
)
|
|
@@ -4,6 +4,10 @@ import re
|
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from typing import Any, Dict, List
|
|
6
6
|
|
|
7
|
+
from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
8
|
+
CommandSyntaxManager,
|
|
9
|
+
CommandSyntaxVersion,
|
|
10
|
+
)
|
|
7
11
|
from rasa.dialogue_understanding.commands.free_form_answer_command import (
|
|
8
12
|
FreeFormAnswerCommand,
|
|
9
13
|
)
|
|
@@ -59,7 +63,14 @@ class ChitChatAnswerCommand(FreeFormAnswerCommand):
|
|
|
59
63
|
|
|
60
64
|
def to_dsl(self) -> str:
|
|
61
65
|
"""Converts the command to a DSL string."""
|
|
62
|
-
|
|
66
|
+
mapper = {
|
|
67
|
+
CommandSyntaxVersion.v1: "ChitChat()",
|
|
68
|
+
CommandSyntaxVersion.v2: "offtopic reply",
|
|
69
|
+
}
|
|
70
|
+
return mapper.get(
|
|
71
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
72
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
73
|
+
)
|
|
63
74
|
|
|
64
75
|
@classmethod
|
|
65
76
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> ChitChatAnswerCommand:
|
|
@@ -68,4 +79,11 @@ class ChitChatAnswerCommand(FreeFormAnswerCommand):
|
|
|
68
79
|
|
|
69
80
|
@staticmethod
|
|
70
81
|
def regex_pattern() -> str:
|
|
71
|
-
|
|
82
|
+
mapper = {
|
|
83
|
+
CommandSyntaxVersion.v1: r"ChitChat\(\)",
|
|
84
|
+
CommandSyntaxVersion.v2: r"""^[\s\W\d]*offtopic reply['"`]*$""",
|
|
85
|
+
}
|
|
86
|
+
return mapper.get(
|
|
87
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
88
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
89
|
+
)
|
|
@@ -7,6 +7,10 @@ from typing import Any, Dict, List, Optional
|
|
|
7
7
|
import structlog
|
|
8
8
|
|
|
9
9
|
from rasa.dialogue_understanding.commands.command import Command
|
|
10
|
+
from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
11
|
+
CommandSyntaxManager,
|
|
12
|
+
CommandSyntaxVersion,
|
|
13
|
+
)
|
|
10
14
|
from rasa.dialogue_understanding.commands.utils import extract_cleaned_options
|
|
11
15
|
from rasa.dialogue_understanding.patterns.clarify import ClarifyPatternFlowStackFrame
|
|
12
16
|
from rasa.shared.core.events import Event
|
|
@@ -74,7 +78,13 @@ class ClarifyCommand(Command):
|
|
|
74
78
|
|
|
75
79
|
stack = tracker.stack
|
|
76
80
|
relevant_flows = [all_flows.flow_by_id(opt) for opt in clean_options]
|
|
77
|
-
|
|
81
|
+
|
|
82
|
+
names = [
|
|
83
|
+
flow.readable_name(language=tracker.current_language)
|
|
84
|
+
for flow in relevant_flows
|
|
85
|
+
if flow is not None
|
|
86
|
+
]
|
|
87
|
+
|
|
78
88
|
stack.push(ClarifyPatternFlowStackFrame(names=names))
|
|
79
89
|
return tracker.create_stack_updated_events(stack)
|
|
80
90
|
|
|
@@ -89,7 +99,14 @@ class ClarifyCommand(Command):
|
|
|
89
99
|
|
|
90
100
|
def to_dsl(self) -> str:
|
|
91
101
|
"""Converts the command to a DSL string."""
|
|
92
|
-
|
|
102
|
+
mapper = {
|
|
103
|
+
CommandSyntaxVersion.v1: f"Clarify({', '.join(self.options)})",
|
|
104
|
+
CommandSyntaxVersion.v2: f"disambiguate flows {' '.join(self.options)}",
|
|
105
|
+
}
|
|
106
|
+
return mapper.get(
|
|
107
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
108
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
109
|
+
)
|
|
93
110
|
|
|
94
111
|
@classmethod
|
|
95
112
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> Optional[ClarifyCommand]:
|
|
@@ -99,4 +116,13 @@ class ClarifyCommand(Command):
|
|
|
99
116
|
|
|
100
117
|
@staticmethod
|
|
101
118
|
def regex_pattern() -> str:
|
|
102
|
-
|
|
119
|
+
mapper = {
|
|
120
|
+
CommandSyntaxVersion.v1: r"Clarify\(([\"\'a-zA-Z0-9_, ]*)\)",
|
|
121
|
+
CommandSyntaxVersion.v2: (
|
|
122
|
+
r"""^[\s\W\d]*disambiguate flows (["'a-zA-Z0-9_, ]*)['"`]*$"""
|
|
123
|
+
),
|
|
124
|
+
}
|
|
125
|
+
return mapper.get(
|
|
126
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
127
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
128
|
+
)
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
import re
|
|
5
4
|
from dataclasses import dataclass
|
|
6
|
-
from typing import Any, Dict, List
|
|
5
|
+
from typing import Any, Dict, List
|
|
7
6
|
|
|
8
7
|
import rasa.shared.utils.common
|
|
9
8
|
from rasa.shared.core.events import Event
|
|
@@ -85,17 +84,3 @@ class Command:
|
|
|
85
84
|
The events to apply to the tracker.
|
|
86
85
|
"""
|
|
87
86
|
raise NotImplementedError()
|
|
88
|
-
|
|
89
|
-
def to_dsl(self) -> str:
|
|
90
|
-
"""Converts the command to a DSL string."""
|
|
91
|
-
raise NotImplementedError()
|
|
92
|
-
|
|
93
|
-
@classmethod
|
|
94
|
-
def from_dsl(cls, match: re.Match, **kwargs: Any) -> Optional[Command]:
|
|
95
|
-
"""Converts the DSL string to a command."""
|
|
96
|
-
raise NotImplementedError()
|
|
97
|
-
|
|
98
|
-
@staticmethod
|
|
99
|
-
def regex_pattern() -> str:
|
|
100
|
-
"""Returns the regex pattern for the command."""
|
|
101
|
-
raise NotImplementedError()
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import structlog
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CommandSyntaxVersion(Enum):
|
|
8
|
+
"""Defines different syntax versions for commands."""
|
|
9
|
+
|
|
10
|
+
v1 = "v1"
|
|
11
|
+
v2 = "v2"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
structlogger = structlog.get_logger()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CommandSyntaxManager:
|
|
18
|
+
"""A class to manage the command syntax version. It is used to set and get the
|
|
19
|
+
command syntax version. This class provides a way to introduce new syntax versions
|
|
20
|
+
for commands in the future. Hence, it is for internal use only.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
_version = None # Directly store the version as a class attribute
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def set_syntax_version(cls, version: CommandSyntaxVersion) -> None:
|
|
27
|
+
"""Sets the command syntax version on the class itself.
|
|
28
|
+
This method is called only once at the time of LLMCommandGenerator
|
|
29
|
+
initialization to set the command syntax version, which ensures that the command
|
|
30
|
+
syntax version remains consistent throughout the lifetime of the generator.
|
|
31
|
+
"""
|
|
32
|
+
if cls._version:
|
|
33
|
+
structlogger.debug(
|
|
34
|
+
"command_syntax_manager.syntax_version_already_set",
|
|
35
|
+
event_info=(
|
|
36
|
+
f"The command syntax version has already been set. Overwriting "
|
|
37
|
+
f"the existing version with the new version - {version}."
|
|
38
|
+
),
|
|
39
|
+
)
|
|
40
|
+
cls._version = version
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def get_syntax_version(cls) -> Optional[CommandSyntaxVersion]:
|
|
44
|
+
"""Fetches the stored command syntax version."""
|
|
45
|
+
return cls._version
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def get_default_syntax_version() -> CommandSyntaxVersion:
|
|
49
|
+
"""Returns the default command syntax version."""
|
|
50
|
+
return CommandSyntaxVersion.v1
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def reset_syntax_version(cls) -> None:
|
|
54
|
+
"""Resets the command syntax version. Implemented for use in testing."""
|
|
55
|
+
cls._version = None
|
|
@@ -14,7 +14,6 @@ from rasa.dialogue_understanding.patterns.handle_digressions import (
|
|
|
14
14
|
)
|
|
15
15
|
from rasa.dialogue_understanding.stack.utils import (
|
|
16
16
|
top_flow_frame,
|
|
17
|
-
user_flows_on_the_stack,
|
|
18
17
|
)
|
|
19
18
|
from rasa.shared.core.events import Event
|
|
20
19
|
from rasa.shared.core.flows import FlowsList
|
|
@@ -71,12 +70,7 @@ class HandleDigressionsCommand(Command):
|
|
|
71
70
|
stack = tracker.stack
|
|
72
71
|
original_stack = original_tracker.stack
|
|
73
72
|
|
|
74
|
-
if self.flow in
|
|
75
|
-
structlogger.debug(
|
|
76
|
-
"command_executor.skip_command.already_started_flow", command=self
|
|
77
|
-
)
|
|
78
|
-
return []
|
|
79
|
-
elif self.flow not in all_flows.flow_ids:
|
|
73
|
+
if self.flow not in all_flows.flow_ids:
|
|
80
74
|
structlogger.debug(
|
|
81
75
|
"command_executor.push_cannot_handle.start_invalid_flow_id",
|
|
82
76
|
command=self,
|
|
@@ -7,6 +7,10 @@ from typing import Any, Dict, List
|
|
|
7
7
|
import structlog
|
|
8
8
|
|
|
9
9
|
from rasa.dialogue_understanding.commands.command import Command
|
|
10
|
+
from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
11
|
+
CommandSyntaxManager,
|
|
12
|
+
CommandSyntaxVersion,
|
|
13
|
+
)
|
|
10
14
|
from rasa.dialogue_understanding.patterns.human_handoff import (
|
|
11
15
|
HumanHandoffPatternFlowStackFrame,
|
|
12
16
|
)
|
|
@@ -66,7 +70,14 @@ class HumanHandoffCommand(Command):
|
|
|
66
70
|
|
|
67
71
|
def to_dsl(self) -> str:
|
|
68
72
|
"""Converts the command to a DSL string."""
|
|
69
|
-
|
|
73
|
+
mapper = {
|
|
74
|
+
CommandSyntaxVersion.v1: "HumanHandoff()",
|
|
75
|
+
CommandSyntaxVersion.v2: "hand over",
|
|
76
|
+
}
|
|
77
|
+
return mapper.get(
|
|
78
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
79
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
80
|
+
)
|
|
70
81
|
|
|
71
82
|
@classmethod
|
|
72
83
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> HumanHandoffCommand:
|
|
@@ -75,4 +86,11 @@ class HumanHandoffCommand(Command):
|
|
|
75
86
|
|
|
76
87
|
@staticmethod
|
|
77
88
|
def regex_pattern() -> str:
|
|
78
|
-
|
|
89
|
+
mapper = {
|
|
90
|
+
CommandSyntaxVersion.v1: r"HumanHandoff\(\)",
|
|
91
|
+
CommandSyntaxVersion.v2: r"""^[\s\W\d]*hand over['"`]*$""",
|
|
92
|
+
}
|
|
93
|
+
return mapper.get(
|
|
94
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
95
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
96
|
+
)
|