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.

Files changed (153) hide show
  1. rasa/anonymization/anonymization_rule_executor.py +16 -10
  2. rasa/cli/data.py +16 -0
  3. rasa/cli/inspect.py +20 -1
  4. rasa/cli/project_templates/calm/config.yml +2 -2
  5. rasa/cli/project_templates/calm/endpoints.yml +2 -2
  6. rasa/cli/shell.py +3 -3
  7. rasa/cli/utils.py +12 -0
  8. rasa/core/actions/action.py +99 -193
  9. rasa/core/actions/action_handle_digressions.py +142 -0
  10. rasa/core/actions/action_run_slot_rejections.py +16 -4
  11. rasa/core/actions/forms.py +10 -5
  12. rasa/core/channels/__init__.py +4 -0
  13. rasa/core/channels/studio_chat.py +19 -0
  14. rasa/core/channels/telegram.py +42 -24
  15. rasa/core/channels/voice_ready/audiocodes.py +42 -23
  16. rasa/core/channels/voice_ready/utils.py +1 -1
  17. rasa/core/channels/voice_stream/asr/asr_engine.py +10 -4
  18. rasa/core/channels/voice_stream/asr/azure.py +14 -1
  19. rasa/core/channels/voice_stream/asr/deepgram.py +20 -4
  20. rasa/core/channels/voice_stream/audiocodes.py +264 -0
  21. rasa/core/channels/voice_stream/browser_audio.py +5 -1
  22. rasa/core/channels/voice_stream/call_state.py +10 -1
  23. rasa/core/channels/voice_stream/genesys.py +335 -0
  24. rasa/core/channels/voice_stream/tts/azure.py +11 -2
  25. rasa/core/channels/voice_stream/tts/cartesia.py +29 -10
  26. rasa/core/channels/voice_stream/twilio_media_streams.py +2 -1
  27. rasa/core/channels/voice_stream/voice_channel.py +25 -3
  28. rasa/core/constants.py +2 -0
  29. rasa/core/migrate.py +2 -2
  30. rasa/core/nlg/contextual_response_rephraser.py +18 -1
  31. rasa/core/nlg/generator.py +83 -15
  32. rasa/core/nlg/response.py +6 -3
  33. rasa/core/nlg/translate.py +55 -0
  34. rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
  35. rasa/core/policies/flows/flow_executor.py +47 -46
  36. rasa/core/processor.py +72 -9
  37. rasa/core/run.py +4 -3
  38. rasa/dialogue_understanding/commands/can_not_handle_command.py +20 -2
  39. rasa/dialogue_understanding/commands/cancel_flow_command.py +80 -4
  40. rasa/dialogue_understanding/commands/change_flow_command.py +20 -2
  41. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +20 -2
  42. rasa/dialogue_understanding/commands/clarify_command.py +29 -3
  43. rasa/dialogue_understanding/commands/command.py +1 -16
  44. rasa/dialogue_understanding/commands/command_syntax_manager.py +55 -0
  45. rasa/dialogue_understanding/commands/correct_slots_command.py +11 -2
  46. rasa/dialogue_understanding/commands/handle_digressions_command.py +150 -0
  47. rasa/dialogue_understanding/commands/human_handoff_command.py +20 -2
  48. rasa/dialogue_understanding/commands/knowledge_answer_command.py +20 -2
  49. rasa/dialogue_understanding/commands/prompt_command.py +94 -0
  50. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +20 -2
  51. rasa/dialogue_understanding/commands/set_slot_command.py +29 -15
  52. rasa/dialogue_understanding/commands/skip_question_command.py +20 -2
  53. rasa/dialogue_understanding/commands/start_flow_command.py +61 -2
  54. rasa/dialogue_understanding/commands/utils.py +98 -4
  55. rasa/dialogue_understanding/constants.py +1 -0
  56. rasa/dialogue_understanding/generator/__init__.py +2 -0
  57. rasa/dialogue_understanding/generator/command_generator.py +110 -73
  58. rasa/dialogue_understanding/generator/command_parser.py +16 -13
  59. rasa/dialogue_understanding/generator/constants.py +3 -0
  60. rasa/dialogue_understanding/generator/llm_based_command_generator.py +170 -5
  61. rasa/dialogue_understanding/generator/llm_command_generator.py +5 -3
  62. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +26 -4
  63. rasa/dialogue_understanding/generator/nlu_command_adapter.py +44 -3
  64. rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
  65. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +60 -0
  66. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +77 -0
  67. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_default.jinja2 +68 -0
  68. rasa/dialogue_understanding/generator/{single_step/command_prompt_template.jinja2 → prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2} +1 -1
  69. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +460 -0
  70. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +12 -318
  71. rasa/dialogue_understanding/generator/utils.py +32 -1
  72. rasa/dialogue_understanding/patterns/collect_information.py +1 -1
  73. rasa/dialogue_understanding/patterns/correction.py +13 -1
  74. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +78 -2
  75. rasa/dialogue_understanding/patterns/handle_digressions.py +81 -0
  76. rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
  77. rasa/dialogue_understanding/processor/command_processor.py +154 -28
  78. rasa/dialogue_understanding/utils.py +31 -0
  79. rasa/dialogue_understanding_test/README.md +50 -0
  80. rasa/dialogue_understanding_test/du_test_case.py +28 -8
  81. rasa/dialogue_understanding_test/du_test_result.py +13 -9
  82. rasa/dialogue_understanding_test/io.py +14 -0
  83. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +3 -3
  84. rasa/e2e_test/utils/io.py +0 -37
  85. rasa/engine/graph.py +1 -0
  86. rasa/engine/language.py +140 -0
  87. rasa/engine/recipes/config_files/default_config.yml +4 -0
  88. rasa/engine/recipes/default_recipe.py +2 -0
  89. rasa/engine/recipes/graph_recipe.py +2 -0
  90. rasa/engine/storage/local_model_storage.py +1 -0
  91. rasa/engine/storage/storage.py +4 -1
  92. rasa/model_manager/runner_service.py +7 -4
  93. rasa/model_manager/socket_bridge.py +7 -6
  94. rasa/model_manager/warm_rasa_process.py +0 -1
  95. rasa/model_training.py +24 -27
  96. rasa/shared/constants.py +15 -13
  97. rasa/shared/core/constants.py +30 -3
  98. rasa/shared/core/domain.py +13 -20
  99. rasa/shared/core/events.py +13 -2
  100. rasa/shared/core/flows/constants.py +11 -0
  101. rasa/shared/core/flows/flow.py +100 -19
  102. rasa/shared/core/flows/flows_yaml_schema.json +69 -3
  103. rasa/shared/core/flows/steps/collect.py +19 -37
  104. rasa/shared/core/flows/utils.py +43 -4
  105. rasa/shared/core/flows/validation.py +1 -1
  106. rasa/shared/core/slot_mappings.py +350 -111
  107. rasa/shared/core/slots.py +154 -3
  108. rasa/shared/core/trackers.py +77 -2
  109. rasa/shared/importers/importer.py +50 -2
  110. rasa/shared/nlu/constants.py +1 -0
  111. rasa/shared/nlu/training_data/schemas/responses.yml +19 -12
  112. rasa/shared/providers/_configs/azure_entra_id_config.py +541 -0
  113. rasa/shared/providers/_configs/azure_openai_client_config.py +138 -3
  114. rasa/shared/providers/_configs/client_config.py +3 -1
  115. rasa/shared/providers/_configs/default_litellm_client_config.py +3 -1
  116. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +3 -1
  117. rasa/shared/providers/_configs/litellm_router_client_config.py +3 -1
  118. rasa/shared/providers/_configs/model_group_config.py +4 -2
  119. rasa/shared/providers/_configs/oauth_config.py +33 -0
  120. rasa/shared/providers/_configs/openai_client_config.py +3 -1
  121. rasa/shared/providers/_configs/rasa_llm_client_config.py +3 -1
  122. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +3 -1
  123. rasa/shared/providers/constants.py +6 -0
  124. rasa/shared/providers/embedding/azure_openai_embedding_client.py +28 -3
  125. rasa/shared/providers/embedding/litellm_router_embedding_client.py +3 -1
  126. rasa/shared/providers/llm/_base_litellm_client.py +42 -17
  127. rasa/shared/providers/llm/azure_openai_llm_client.py +81 -25
  128. rasa/shared/providers/llm/default_litellm_llm_client.py +3 -1
  129. rasa/shared/providers/llm/litellm_router_llm_client.py +29 -8
  130. rasa/shared/providers/llm/llm_client.py +23 -7
  131. rasa/shared/providers/llm/openai_llm_client.py +9 -3
  132. rasa/shared/providers/llm/rasa_llm_client.py +11 -2
  133. rasa/shared/providers/llm/self_hosted_llm_client.py +30 -11
  134. rasa/shared/providers/router/_base_litellm_router_client.py +3 -1
  135. rasa/shared/providers/router/router_client.py +3 -1
  136. rasa/shared/utils/constants.py +3 -0
  137. rasa/shared/utils/llm.py +31 -8
  138. rasa/shared/utils/pykwalify_extensions.py +24 -0
  139. rasa/shared/utils/schemas/domain.yml +26 -1
  140. rasa/telemetry.py +45 -14
  141. rasa/tracing/config.py +2 -0
  142. rasa/tracing/constants.py +12 -0
  143. rasa/tracing/instrumentation/instrumentation.py +36 -0
  144. rasa/tracing/instrumentation/metrics.py +41 -0
  145. rasa/tracing/metric_instrument_provider.py +40 -0
  146. rasa/utils/common.py +0 -1
  147. rasa/validator.py +561 -89
  148. rasa/version.py +1 -1
  149. {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/METADATA +2 -1
  150. {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/RECORD +153 -134
  151. {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/NOTICE +0 -0
  152. {rasa_pro-3.12.0.dev12.dist-info → rasa_pro-3.12.0rc1.dist-info}/WHEEL +0 -0
  153. {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
- return "hand over"
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
- return r"^hand over$"
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
- return "provide info"
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
- return r"^provide info$"
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
- return "repeat message"
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
- return r"^repeat message$"
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 [SlotSet(self.name, slot.coerce_value(self.value))]
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
- return f"set slot {self.name} {self.value}"
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
- return r"""^set slot ['"]?([a-zA-Z_][a-zA-Z0-9_-]*)['"]? ['"]?(.+?)['"]?$"""
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
- return "skip"
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
- return r"^skip$"
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
- return f"start flow {self.flow}"
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
- return r"^start flow ['\"]?([a-zA-Z0-9_-]+)['\"]?$"
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 []