rasa-pro 3.12.0.dev12__py3-none-any.whl → 3.12.0rc1__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/anonymization/anonymization_rule_executor.py +16 -10
- rasa/cli/data.py +16 -0
- rasa/cli/inspect.py +20 -1
- rasa/cli/project_templates/calm/config.yml +2 -2
- rasa/cli/project_templates/calm/endpoints.yml +2 -2
- rasa/cli/shell.py +3 -3
- rasa/cli/utils.py +12 -0
- rasa/core/actions/action.py +99 -193
- rasa/core/actions/action_handle_digressions.py +142 -0
- rasa/core/actions/action_run_slot_rejections.py +16 -4
- rasa/core/actions/forms.py +10 -5
- rasa/core/channels/__init__.py +4 -0
- rasa/core/channels/studio_chat.py +19 -0
- rasa/core/channels/telegram.py +42 -24
- rasa/core/channels/voice_ready/audiocodes.py +42 -23
- 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 +5 -1
- rasa/core/channels/voice_stream/call_state.py +10 -1
- rasa/core/channels/voice_stream/genesys.py +335 -0
- rasa/core/channels/voice_stream/tts/azure.py +11 -2
- rasa/core/channels/voice_stream/tts/cartesia.py +29 -10
- rasa/core/channels/voice_stream/twilio_media_streams.py +2 -1
- rasa/core/channels/voice_stream/voice_channel.py +25 -3
- rasa/core/constants.py +2 -0
- rasa/core/migrate.py +2 -2
- 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 +47 -46
- rasa/core/processor.py +72 -9
- rasa/core/run.py +4 -3
- rasa/dialogue_understanding/commands/can_not_handle_command.py +20 -2
- rasa/dialogue_understanding/commands/cancel_flow_command.py +80 -4
- 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/correct_slots_command.py +11 -2
- rasa/dialogue_understanding/commands/handle_digressions_command.py +150 -0
- 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 +29 -15
- rasa/dialogue_understanding/commands/skip_question_command.py +20 -2
- rasa/dialogue_understanding/commands/start_flow_command.py +61 -2
- rasa/dialogue_understanding/commands/utils.py +98 -4
- rasa/dialogue_understanding/constants.py +1 -0
- rasa/dialogue_understanding/generator/__init__.py +2 -0
- rasa/dialogue_understanding/generator/command_generator.py +110 -73
- rasa/dialogue_understanding/generator/command_parser.py +16 -13
- rasa/dialogue_understanding/generator/constants.py +3 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +170 -5
- rasa/dialogue_understanding/generator/llm_command_generator.py +5 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +26 -4
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +44 -3
- rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +60 -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/{single_step/command_prompt_template.jinja2 → prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2} +1 -1
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +460 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +12 -318
- rasa/dialogue_understanding/generator/utils.py +32 -1
- rasa/dialogue_understanding/patterns/collect_information.py +1 -1
- rasa/dialogue_understanding/patterns/correction.py +13 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +78 -2
- rasa/dialogue_understanding/patterns/handle_digressions.py +81 -0
- rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
- rasa/dialogue_understanding/processor/command_processor.py +154 -28
- rasa/dialogue_understanding/utils.py +31 -0
- rasa/dialogue_understanding_test/README.md +50 -0
- rasa/dialogue_understanding_test/du_test_case.py +28 -8
- rasa/dialogue_understanding_test/du_test_result.py +13 -9
- rasa/dialogue_understanding_test/io.py +14 -0
- rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +3 -3
- 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/model_manager/runner_service.py +7 -4
- rasa/model_manager/socket_bridge.py +7 -6
- rasa/model_manager/warm_rasa_process.py +0 -1
- rasa/model_training.py +24 -27
- rasa/shared/constants.py +15 -13
- rasa/shared/core/constants.py +30 -3
- rasa/shared/core/domain.py +13 -20
- rasa/shared/core/events.py +13 -2
- rasa/shared/core/flows/constants.py +11 -0
- rasa/shared/core/flows/flow.py +100 -19
- rasa/shared/core/flows/flows_yaml_schema.json +69 -3
- rasa/shared/core/flows/steps/collect.py +19 -37
- rasa/shared/core/flows/utils.py +43 -4
- rasa/shared/core/flows/validation.py +1 -1
- rasa/shared/core/slot_mappings.py +350 -111
- rasa/shared/core/slots.py +154 -3
- rasa/shared/core/trackers.py +77 -2
- rasa/shared/importers/importer.py +50 -2
- rasa/shared/nlu/constants.py +1 -0
- 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 +31 -8
- rasa/shared/utils/pykwalify_extensions.py +24 -0
- rasa/shared/utils/schemas/domain.yml +26 -1
- rasa/telemetry.py +45 -14
- 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/utils/common.py +0 -1
- rasa/validator.py +561 -89
- rasa/version.py +1 -1
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/METADATA +2 -1
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/RECORD +153 -134
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Dict, List
|
|
5
|
+
|
|
6
|
+
import structlog
|
|
7
|
+
|
|
8
|
+
from rasa.dialogue_understanding.commands.command import Command
|
|
9
|
+
from rasa.dialogue_understanding.patterns.cannot_handle import (
|
|
10
|
+
CannotHandlePatternFlowStackFrame,
|
|
11
|
+
)
|
|
12
|
+
from rasa.dialogue_understanding.patterns.handle_digressions import (
|
|
13
|
+
HandleDigressionsPatternFlowStackFrame,
|
|
14
|
+
)
|
|
15
|
+
from rasa.dialogue_understanding.stack.utils import (
|
|
16
|
+
top_flow_frame,
|
|
17
|
+
user_flows_on_the_stack,
|
|
18
|
+
)
|
|
19
|
+
from rasa.shared.core.events import Event
|
|
20
|
+
from rasa.shared.core.flows import FlowsList
|
|
21
|
+
from rasa.shared.core.flows.steps import CollectInformationFlowStep
|
|
22
|
+
from rasa.shared.core.flows.utils import ALL_LABEL
|
|
23
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
24
|
+
from rasa.shared.nlu.constants import HANDLE_DIGRESSIONS_COMMAND
|
|
25
|
+
|
|
26
|
+
structlogger = structlog.get_logger()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class HandleDigressionsCommand(Command):
|
|
31
|
+
"""A command to handle digressions during an active flow."""
|
|
32
|
+
|
|
33
|
+
flow: str
|
|
34
|
+
"""The interrupting flow."""
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def command(cls) -> str:
|
|
38
|
+
"""Returns the command type."""
|
|
39
|
+
return HANDLE_DIGRESSIONS_COMMAND
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def from_dict(cls, data: Dict[str, Any]) -> HandleDigressionsCommand:
|
|
43
|
+
"""Converts the dictionary to a command.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
The converted dictionary.
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
return HandleDigressionsCommand(flow=data["flow"])
|
|
50
|
+
except KeyError as e:
|
|
51
|
+
raise ValueError(
|
|
52
|
+
f"Missing parameter '{e}' while parsing HandleDigressionsCommand."
|
|
53
|
+
) from e
|
|
54
|
+
|
|
55
|
+
def run_command_on_tracker(
|
|
56
|
+
self,
|
|
57
|
+
tracker: DialogueStateTracker,
|
|
58
|
+
all_flows: FlowsList,
|
|
59
|
+
original_tracker: DialogueStateTracker,
|
|
60
|
+
) -> List[Event]:
|
|
61
|
+
"""Runs the command on the tracker.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
tracker: The tracker to run the command on.
|
|
65
|
+
all_flows: All flows in the assistant.
|
|
66
|
+
original_tracker: The tracker before any command was executed.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
The events to apply to the tracker.
|
|
70
|
+
"""
|
|
71
|
+
stack = tracker.stack
|
|
72
|
+
original_stack = original_tracker.stack
|
|
73
|
+
|
|
74
|
+
if self.flow in user_flows_on_the_stack(stack):
|
|
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:
|
|
80
|
+
structlogger.debug(
|
|
81
|
+
"command_executor.push_cannot_handle.start_invalid_flow_id",
|
|
82
|
+
command=self,
|
|
83
|
+
)
|
|
84
|
+
stack.push(CannotHandlePatternFlowStackFrame())
|
|
85
|
+
return tracker.create_stack_updated_events(stack)
|
|
86
|
+
|
|
87
|
+
# this allows to include called user flows in the stack search
|
|
88
|
+
latest_user_frame = top_flow_frame(original_stack, ignore_call_frames=False)
|
|
89
|
+
|
|
90
|
+
if latest_user_frame is None:
|
|
91
|
+
structlogger.debug(
|
|
92
|
+
"command_executor.skip_command.no_top_flow", command=self
|
|
93
|
+
)
|
|
94
|
+
return []
|
|
95
|
+
|
|
96
|
+
original_top_flow = latest_user_frame.flow(all_flows)
|
|
97
|
+
current_step = original_top_flow.step_by_id(latest_user_frame.step_id)
|
|
98
|
+
if not isinstance(current_step, CollectInformationFlowStep):
|
|
99
|
+
structlogger.debug(
|
|
100
|
+
"command_executor.skip_command.not_at_a_collect_step", command=self
|
|
101
|
+
)
|
|
102
|
+
return []
|
|
103
|
+
|
|
104
|
+
ask_confirm_digressions = set(
|
|
105
|
+
current_step.ask_confirm_digressions
|
|
106
|
+
+ original_top_flow.ask_confirm_digressions
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
block_digressions = set(
|
|
110
|
+
current_step.block_digressions + original_top_flow.block_digressions
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if block_digressions:
|
|
114
|
+
if ALL_LABEL in block_digressions:
|
|
115
|
+
block_digressions.remove(ALL_LABEL)
|
|
116
|
+
block_digressions.add(self.flow)
|
|
117
|
+
|
|
118
|
+
if ask_confirm_digressions:
|
|
119
|
+
if ALL_LABEL in ask_confirm_digressions:
|
|
120
|
+
ask_confirm_digressions.remove(ALL_LABEL)
|
|
121
|
+
ask_confirm_digressions.add(self.flow)
|
|
122
|
+
|
|
123
|
+
structlogger.debug(
|
|
124
|
+
"command_executor.push_handle_digressions",
|
|
125
|
+
interrupting_flow_id=self.flow,
|
|
126
|
+
interrupted_flow_id=original_top_flow.id,
|
|
127
|
+
interrupted_step_id=current_step.id,
|
|
128
|
+
ask_confirm_digressions=ask_confirm_digressions,
|
|
129
|
+
block_digressions=block_digressions,
|
|
130
|
+
)
|
|
131
|
+
stack.push(
|
|
132
|
+
HandleDigressionsPatternFlowStackFrame(
|
|
133
|
+
interrupting_flow_id=self.flow,
|
|
134
|
+
interrupted_flow_id=original_top_flow.id,
|
|
135
|
+
interrupted_step_id=current_step.id,
|
|
136
|
+
ask_confirm_digressions=ask_confirm_digressions,
|
|
137
|
+
block_digressions=block_digressions,
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
return tracker.create_stack_updated_events(stack)
|
|
142
|
+
|
|
143
|
+
def __hash__(self) -> int:
|
|
144
|
+
return hash(self.flow)
|
|
145
|
+
|
|
146
|
+
def __eq__(self, other: object) -> bool:
|
|
147
|
+
if not isinstance(other, HandleDigressionsCommand):
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
return other.flow == self.flow
|
|
@@ -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"^[^\w]*hand over$",
|
|
92
|
+
}
|
|
93
|
+
return mapper.get(
|
|
94
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
95
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
96
|
+
)
|
|
@@ -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 KnowledgeAnswerCommand(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: "SearchAndReply()",
|
|
68
|
+
CommandSyntaxVersion.v2: "provide info",
|
|
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) -> KnowledgeAnswerCommand:
|
|
@@ -68,4 +79,11 @@ class KnowledgeAnswerCommand(FreeFormAnswerCommand):
|
|
|
68
79
|
|
|
69
80
|
@staticmethod
|
|
70
81
|
def regex_pattern() -> str:
|
|
71
|
-
|
|
82
|
+
mapper = {
|
|
83
|
+
CommandSyntaxVersion.v1: r"SearchAndReply\(\)",
|
|
84
|
+
CommandSyntaxVersion.v2: r"^[^\w]*provide info$",
|
|
85
|
+
}
|
|
86
|
+
return mapper.get(
|
|
87
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
88
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
89
|
+
)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any, Dict, List, Optional, Protocol, runtime_checkable
|
|
5
|
+
|
|
6
|
+
from rasa.shared.core.events import Event
|
|
7
|
+
from rasa.shared.core.flows import FlowsList
|
|
8
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@runtime_checkable
|
|
12
|
+
class PromptCommand(Protocol):
|
|
13
|
+
"""
|
|
14
|
+
A protocol for commands predicted by the LLM model and incorporated into the prompt.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def command(cls) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Returns the command name.
|
|
21
|
+
|
|
22
|
+
This class method should be implemented to return the name of the command.
|
|
23
|
+
"""
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def from_dict(cls, data: Dict[str, Any]) -> PromptCommand:
|
|
28
|
+
"""
|
|
29
|
+
Converts the dictionary to a command.
|
|
30
|
+
|
|
31
|
+
This class method should be implemented to create a command instance from the
|
|
32
|
+
given dictionary.
|
|
33
|
+
"""
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
def run_command_on_tracker(
|
|
37
|
+
self,
|
|
38
|
+
tracker: DialogueStateTracker,
|
|
39
|
+
all_flows: FlowsList,
|
|
40
|
+
original_tracker: DialogueStateTracker,
|
|
41
|
+
) -> List[Event]:
|
|
42
|
+
"""
|
|
43
|
+
Runs the command on the tracker.
|
|
44
|
+
|
|
45
|
+
This method should be implemented to execute the command on the given tracker.
|
|
46
|
+
"""
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
def __hash__(self) -> int:
|
|
50
|
+
"""
|
|
51
|
+
Returns the hash of the command.
|
|
52
|
+
|
|
53
|
+
This method should be implemented to return the hash of the command.
|
|
54
|
+
Useful for comparing commands and storing them in sets.
|
|
55
|
+
"""
|
|
56
|
+
...
|
|
57
|
+
|
|
58
|
+
def __eq__(self, other: object) -> bool:
|
|
59
|
+
"""
|
|
60
|
+
Compares the command with another object.
|
|
61
|
+
|
|
62
|
+
This method should be implemented to compare the command with another object.
|
|
63
|
+
"""
|
|
64
|
+
...
|
|
65
|
+
|
|
66
|
+
def to_dsl(self) -> str:
|
|
67
|
+
"""
|
|
68
|
+
Converts the command to a DSL string.
|
|
69
|
+
|
|
70
|
+
This method should be implemented to convert the command to a DSL string.
|
|
71
|
+
A DSL string is a string representation of the command that is used in the
|
|
72
|
+
prompt.
|
|
73
|
+
"""
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_dsl(cls, match: re.Match, **kwargs: Any) -> Optional[PromptCommand]:
|
|
78
|
+
"""
|
|
79
|
+
Converts the regex match to a command.
|
|
80
|
+
|
|
81
|
+
This class method should be implemented to create a command instance from the
|
|
82
|
+
given DSL string.
|
|
83
|
+
"""
|
|
84
|
+
...
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def regex_pattern() -> str:
|
|
88
|
+
"""
|
|
89
|
+
Returns the regex pattern for the command.
|
|
90
|
+
|
|
91
|
+
This method should be implemented to return the regex pattern that matches the
|
|
92
|
+
command in the prompt.
|
|
93
|
+
"""
|
|
94
|
+
...
|
|
@@ -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.dialogue_understanding.patterns.repeat import (
|
|
9
13
|
RepeatBotMessagesPatternFlowStackFrame,
|
|
10
14
|
)
|
|
@@ -60,7 +64,14 @@ class RepeatBotMessagesCommand(Command):
|
|
|
60
64
|
|
|
61
65
|
def to_dsl(self) -> str:
|
|
62
66
|
"""Converts the command to a DSL string."""
|
|
63
|
-
|
|
67
|
+
mapper = {
|
|
68
|
+
CommandSyntaxVersion.v1: "RepeatLastBotMessages()",
|
|
69
|
+
CommandSyntaxVersion.v2: "repeat message",
|
|
70
|
+
}
|
|
71
|
+
return mapper.get(
|
|
72
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
73
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
74
|
+
)
|
|
64
75
|
|
|
65
76
|
@classmethod
|
|
66
77
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> RepeatBotMessagesCommand:
|
|
@@ -69,4 +80,11 @@ class RepeatBotMessagesCommand(Command):
|
|
|
69
80
|
|
|
70
81
|
@staticmethod
|
|
71
82
|
def regex_pattern() -> str:
|
|
72
|
-
|
|
83
|
+
mapper = {
|
|
84
|
+
CommandSyntaxVersion.v1: r"RepeatLastBotMessages\(\)",
|
|
85
|
+
CommandSyntaxVersion.v2: r"^[^\w]*repeat message$",
|
|
86
|
+
}
|
|
87
|
+
return mapper.get(
|
|
88
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
89
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
90
|
+
)
|
|
@@ -2,12 +2,15 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from enum import Enum
|
|
6
5
|
from typing import Any, Dict, List
|
|
7
6
|
|
|
8
7
|
import structlog
|
|
9
8
|
|
|
10
9
|
from rasa.dialogue_understanding.commands.command import Command
|
|
10
|
+
from rasa.dialogue_understanding.commands.command_syntax_manager import (
|
|
11
|
+
CommandSyntaxManager,
|
|
12
|
+
CommandSyntaxVersion,
|
|
13
|
+
)
|
|
11
14
|
from rasa.dialogue_understanding.commands.utils import (
|
|
12
15
|
clean_extracted_value,
|
|
13
16
|
get_nullable_slot_value,
|
|
@@ -19,6 +22,7 @@ from rasa.dialogue_understanding.stack.utils import (
|
|
|
19
22
|
get_collect_steps_excluding_ask_before_filling_for_active_flow,
|
|
20
23
|
)
|
|
21
24
|
from rasa.shared.constants import ROUTE_TO_CALM_SLOT
|
|
25
|
+
from rasa.shared.core.constants import SetSlotExtractor
|
|
22
26
|
from rasa.shared.core.events import Event, SlotSet
|
|
23
27
|
from rasa.shared.core.flows import FlowsList
|
|
24
28
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -27,17 +31,6 @@ from rasa.shared.nlu.constants import SET_SLOT_COMMAND
|
|
|
27
31
|
structlogger = structlog.get_logger()
|
|
28
32
|
|
|
29
33
|
|
|
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
|
-
|
|
41
34
|
def get_flows_predicted_to_start_from_tracker(
|
|
42
35
|
tracker: DialogueStateTracker,
|
|
43
36
|
) -> List[str]:
|
|
@@ -137,6 +130,7 @@ class SetSlotCommand(Command):
|
|
|
137
130
|
in {
|
|
138
131
|
SetSlotExtractor.LLM.value,
|
|
139
132
|
SetSlotExtractor.COMMAND_PAYLOAD_READER.value,
|
|
133
|
+
SetSlotExtractor.NLU.value,
|
|
140
134
|
}
|
|
141
135
|
):
|
|
142
136
|
# Get the other predicted flows from the most recent message on the tracker.
|
|
@@ -154,7 +148,9 @@ class SetSlotCommand(Command):
|
|
|
154
148
|
return []
|
|
155
149
|
|
|
156
150
|
structlogger.debug("command_executor.set_slot", command=self)
|
|
157
|
-
return [
|
|
151
|
+
return [
|
|
152
|
+
SlotSet(self.name, slot.coerce_value(self.value), filled_by=self.extractor)
|
|
153
|
+
]
|
|
158
154
|
|
|
159
155
|
def __hash__(self) -> int:
|
|
160
156
|
return hash(self.value) + hash(self.name)
|
|
@@ -170,7 +166,14 @@ class SetSlotCommand(Command):
|
|
|
170
166
|
|
|
171
167
|
def to_dsl(self) -> str:
|
|
172
168
|
"""Converts the command to a DSL string."""
|
|
173
|
-
|
|
169
|
+
mapper = {
|
|
170
|
+
CommandSyntaxVersion.v1: f"SetSlot({self.name}, {self.value})",
|
|
171
|
+
CommandSyntaxVersion.v2: f"set slot {self.name} {self.value}",
|
|
172
|
+
}
|
|
173
|
+
return mapper.get(
|
|
174
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
175
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
176
|
+
)
|
|
174
177
|
|
|
175
178
|
@classmethod
|
|
176
179
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> SetSlotCommand:
|
|
@@ -181,4 +184,15 @@ class SetSlotCommand(Command):
|
|
|
181
184
|
|
|
182
185
|
@staticmethod
|
|
183
186
|
def regex_pattern() -> str:
|
|
184
|
-
|
|
187
|
+
mapper = {
|
|
188
|
+
CommandSyntaxVersion.v1: (
|
|
189
|
+
r"""SetSlot\(['"]?([a-zA-Z_][a-zA-Z0-9_-]*)['"]?, ?['"]?(.*)['"]?\)"""
|
|
190
|
+
),
|
|
191
|
+
CommandSyntaxVersion.v2: (
|
|
192
|
+
r"""^[^\w]*set slot ['"]?([a-zA-Z_][a-zA-Z0-9_-]*)['"]? ['"]?(.+?)['"]?$""" # noqa: E501
|
|
193
|
+
),
|
|
194
|
+
}
|
|
195
|
+
return mapper.get(
|
|
196
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
197
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
198
|
+
)
|
|
@@ -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.skip_question import (
|
|
11
15
|
SkipQuestionPatternFlowStackFrame,
|
|
12
16
|
)
|
|
@@ -75,7 +79,14 @@ class SkipQuestionCommand(Command):
|
|
|
75
79
|
|
|
76
80
|
def to_dsl(self) -> str:
|
|
77
81
|
"""Converts the command to a DSL string."""
|
|
78
|
-
|
|
82
|
+
mapper = {
|
|
83
|
+
CommandSyntaxVersion.v1: "SkipQuestion()",
|
|
84
|
+
CommandSyntaxVersion.v2: "skip question",
|
|
85
|
+
}
|
|
86
|
+
return mapper.get(
|
|
87
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
88
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
89
|
+
)
|
|
79
90
|
|
|
80
91
|
@classmethod
|
|
81
92
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> SkipQuestionCommand:
|
|
@@ -84,4 +95,11 @@ class SkipQuestionCommand(Command):
|
|
|
84
95
|
|
|
85
96
|
@staticmethod
|
|
86
97
|
def regex_pattern() -> str:
|
|
87
|
-
|
|
98
|
+
mapper = {
|
|
99
|
+
CommandSyntaxVersion.v1: r"SkipQuestion\(\)",
|
|
100
|
+
CommandSyntaxVersion.v2: r"^[^\w]*skip question$",
|
|
101
|
+
}
|
|
102
|
+
return mapper.get(
|
|
103
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
104
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
105
|
+
)
|
|
@@ -7,6 +7,15 @@ 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
|
+
)
|
|
14
|
+
from rasa.dialogue_understanding.patterns.clarify import FLOW_PATTERN_CLARIFICATION
|
|
15
|
+
from rasa.dialogue_understanding.patterns.continue_interrupted import (
|
|
16
|
+
ContinueInterruptedPatternFlowStackFrame,
|
|
17
|
+
)
|
|
18
|
+
from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
|
|
10
19
|
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
11
20
|
FlowStackFrameType,
|
|
12
21
|
UserFlowStackFrame,
|
|
@@ -68,6 +77,10 @@ class StartFlowCommand(Command):
|
|
|
68
77
|
applied_events: List[Event] = []
|
|
69
78
|
|
|
70
79
|
if self.flow in user_flows_on_the_stack(stack):
|
|
80
|
+
top_frame = stack.top()
|
|
81
|
+
if top_frame is not None and top_frame.type() == FLOW_PATTERN_CLARIFICATION:
|
|
82
|
+
return self.change_flow_frame_position_in_the_stack(stack, tracker)
|
|
83
|
+
|
|
71
84
|
structlogger.debug(
|
|
72
85
|
"command_executor.skip_command.already_started_flow", command=self
|
|
73
86
|
)
|
|
@@ -110,7 +123,14 @@ class StartFlowCommand(Command):
|
|
|
110
123
|
|
|
111
124
|
def to_dsl(self) -> str:
|
|
112
125
|
"""Converts the command to a DSL string."""
|
|
113
|
-
|
|
126
|
+
mapper = {
|
|
127
|
+
CommandSyntaxVersion.v1: f"StartFlow({self.flow})",
|
|
128
|
+
CommandSyntaxVersion.v2: f"start flow {self.flow}",
|
|
129
|
+
}
|
|
130
|
+
return mapper.get(
|
|
131
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
132
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
133
|
+
)
|
|
114
134
|
|
|
115
135
|
@classmethod
|
|
116
136
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> Optional[StartFlowCommand]:
|
|
@@ -119,4 +139,43 @@ class StartFlowCommand(Command):
|
|
|
119
139
|
|
|
120
140
|
@staticmethod
|
|
121
141
|
def regex_pattern() -> str:
|
|
122
|
-
|
|
142
|
+
mapper = {
|
|
143
|
+
CommandSyntaxVersion.v1: r"StartFlow\(['\"]?([a-zA-Z0-9_-]+)['\"]?\)",
|
|
144
|
+
CommandSyntaxVersion.v2: r"^[^\w]*start flow ['\"]?([a-zA-Z0-9_-]+)['\"]?",
|
|
145
|
+
}
|
|
146
|
+
return mapper.get(
|
|
147
|
+
CommandSyntaxManager.get_syntax_version(),
|
|
148
|
+
mapper[CommandSyntaxManager.get_default_syntax_version()],
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
def change_flow_frame_position_in_the_stack(
|
|
152
|
+
self, stack: DialogueStack, tracker: DialogueStateTracker
|
|
153
|
+
) -> List[Event]:
|
|
154
|
+
"""Changes the position of the flow frame in the stack.
|
|
155
|
+
|
|
156
|
+
This is a special case when pattern clarification is the active flow and
|
|
157
|
+
the same flow is selected to start. In this case, the existing flow frame
|
|
158
|
+
should be moved up in the stack.
|
|
159
|
+
"""
|
|
160
|
+
frames = stack.frames[:]
|
|
161
|
+
|
|
162
|
+
for idx, frame in enumerate(frames):
|
|
163
|
+
if isinstance(frame, UserFlowStackFrame) and frame.flow_id == self.flow:
|
|
164
|
+
structlogger.debug(
|
|
165
|
+
"command_executor.change_flow_position_during_clarification",
|
|
166
|
+
command=self,
|
|
167
|
+
index=idx,
|
|
168
|
+
)
|
|
169
|
+
# pop the continue interrupted flow frame if it exists
|
|
170
|
+
next_frame = frames[idx + 1] if idx + 1 < len(frames) else None
|
|
171
|
+
if (
|
|
172
|
+
isinstance(next_frame, ContinueInterruptedPatternFlowStackFrame)
|
|
173
|
+
and next_frame.previous_flow_name == self.flow
|
|
174
|
+
):
|
|
175
|
+
stack.frames.pop(idx + 1)
|
|
176
|
+
# move up the existing flow from the stack
|
|
177
|
+
stack.frames.pop(idx)
|
|
178
|
+
stack.push(frame)
|
|
179
|
+
return tracker.create_stack_updated_events(stack)
|
|
180
|
+
|
|
181
|
+
return []
|