rasa-pro 3.12.0.dev10__py3-none-any.whl → 3.12.0.dev11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rasa-pro might be problematic. Click here for more details.

Files changed (37) hide show
  1. rasa/cli/inspect.py +20 -1
  2. rasa/cli/shell.py +3 -3
  3. rasa/core/actions/action.py +5 -6
  4. rasa/core/actions/forms.py +6 -3
  5. rasa/core/channels/__init__.py +2 -0
  6. rasa/core/channels/voice_stream/browser_audio.py +1 -0
  7. rasa/core/channels/voice_stream/call_state.py +7 -1
  8. rasa/core/channels/voice_stream/genesys.py +331 -0
  9. rasa/core/channels/voice_stream/tts/cartesia.py +16 -3
  10. rasa/core/channels/voice_stream/twilio_media_streams.py +2 -1
  11. rasa/core/channels/voice_stream/voice_channel.py +2 -1
  12. rasa/core/policies/flows/flow_executor.py +3 -41
  13. rasa/core/run.py +4 -3
  14. rasa/dialogue_understanding/generator/command_generator.py +104 -1
  15. rasa/dialogue_understanding/generator/llm_based_command_generator.py +40 -6
  16. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +1 -1
  17. rasa/dialogue_understanding/generator/nlu_command_adapter.py +41 -2
  18. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +1 -1
  19. rasa/dialogue_understanding/generator/utils.py +32 -1
  20. rasa/dialogue_understanding/processor/command_processor.py +10 -12
  21. rasa/dialogue_understanding_test/README.md +50 -0
  22. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +3 -3
  23. rasa/model_service.py +4 -0
  24. rasa/model_training.py +24 -27
  25. rasa/shared/core/constants.py +6 -2
  26. rasa/shared/core/domain.py +11 -20
  27. rasa/shared/core/slot_mappings.py +143 -107
  28. rasa/shared/core/slots.py +4 -2
  29. rasa/telemetry.py +43 -13
  30. rasa/utils/common.py +0 -1
  31. rasa/validator.py +31 -74
  32. rasa/version.py +1 -1
  33. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/METADATA +1 -1
  34. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/RECORD +37 -36
  35. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/NOTICE +0 -0
  36. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/WHEEL +0 -0
  37. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/entry_points.txt +0 -0
@@ -1,11 +1,13 @@
1
1
  from dataclasses import dataclass
2
- from typing import Any, Dict, List, Optional, Text
2
+ from typing import Any, Dict, List, Optional, Set, Text, Tuple
3
3
 
4
4
  import structlog
5
5
 
6
6
  from rasa.dialogue_understanding.commands import (
7
7
  Command,
8
+ CorrectSlotsCommand,
8
9
  ErrorCommand,
10
+ SetSlotCommand,
9
11
  StartFlowCommand,
10
12
  )
11
13
  from rasa.dialogue_understanding.utils import (
@@ -198,6 +200,94 @@ class CommandGenerator:
198
200
  """
199
201
  raise NotImplementedError()
200
202
 
203
+ def _check_commands_overlap(
204
+ self, prior_commands: List[Command], commands: List[Command]
205
+ ) -> List[Command]:
206
+ """Check if there is overlap between the prior commands and the current ones.
207
+
208
+ Args:
209
+ prior_commands: The prior commands.
210
+ commands: The commands to check.
211
+
212
+ Returns:
213
+ The final commands.
214
+ """
215
+ if not prior_commands:
216
+ return commands
217
+
218
+ prior_commands, commands = self._check_slot_command_overlap(
219
+ prior_commands, commands
220
+ )
221
+
222
+ prior_start_flow_names = {
223
+ command.flow
224
+ for command in prior_commands
225
+ if isinstance(command, StartFlowCommand)
226
+ }
227
+ current_start_flow_names = {
228
+ command.flow
229
+ for command in commands
230
+ if isinstance(command, StartFlowCommand)
231
+ }
232
+
233
+ return self._check_start_flow_command_overlap(
234
+ prior_commands,
235
+ commands,
236
+ prior_start_flow_names,
237
+ current_start_flow_names,
238
+ )
239
+
240
+ def _check_start_flow_command_overlap(
241
+ self,
242
+ prior_commands: List[Command],
243
+ commands: List[Command],
244
+ prior_start_flow_names: Set[str],
245
+ current_start_flow_names: Set[str],
246
+ ) -> List[Command]:
247
+ """Get the final commands.
248
+
249
+ Args:
250
+ prior_commands: The prior commands.
251
+ commands: The currently predicted commands to check.
252
+ prior_start_flow_names: The names of the flows from the prior commands.
253
+ current_start_flow_names: The names of the flows from the current commands.
254
+
255
+ Returns:
256
+ The final commands.
257
+ """
258
+ raise NotImplementedError()
259
+
260
+ def _check_slot_command_overlap(
261
+ self,
262
+ prior_commands: List[Command],
263
+ commands: List[Command],
264
+ ) -> Tuple[List[Command], List[Command]]:
265
+ """Check if the current commands overlap with the prior commands."""
266
+ prior_slot_names = gather_slot_names(prior_commands)
267
+ current_slot_names = gather_slot_names(commands)
268
+ overlapping_slot_names = prior_slot_names.intersection(current_slot_names)
269
+
270
+ structlogger.debug(
271
+ "command_generator.check_slot_command_overlap",
272
+ overlapping_slot_names=overlapping_slot_names,
273
+ )
274
+
275
+ if not overlapping_slot_names:
276
+ return prior_commands, commands
277
+
278
+ return self._filter_slot_commands(
279
+ prior_commands, commands, overlapping_slot_names
280
+ )
281
+
282
+ def _filter_slot_commands(
283
+ self,
284
+ prior_commands: List[Command],
285
+ commands: List[Command],
286
+ overlapping_slot_names: Set[str],
287
+ ) -> Tuple[List[Command], List[Command]]:
288
+ """Filter out the overlapping slot commands."""
289
+ raise NotImplementedError()
290
+
201
291
  def _check_commands_against_startable_flows(
202
292
  self, commands: List[Command], startable_flows: FlowsList
203
293
  ) -> List[Command]:
@@ -279,3 +369,16 @@ class CommandGenerator:
279
369
  return [
280
370
  Command.command_from_json(command) for command in message.get(COMMANDS, [])
281
371
  ]
372
+
373
+
374
+ def gather_slot_names(commands: List[Command]) -> Set[str]:
375
+ """Gather all slot names from the commands."""
376
+ slot_names = set()
377
+ for command in commands:
378
+ if isinstance(command, SetSlotCommand):
379
+ slot_names.add(command.name)
380
+ if isinstance(command, CorrectSlotsCommand):
381
+ for slot in command.corrected_slots:
382
+ slot_names.add(slot.name)
383
+
384
+ return slot_names
@@ -1,10 +1,11 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from functools import lru_cache
3
- from typing import Any, Dict, List, Optional, Text, Tuple, Union
3
+ from typing import Any, Dict, List, Optional, Set, Text, Tuple, Union
4
4
 
5
5
  import structlog
6
6
  from jinja2 import Template
7
7
 
8
+ import rasa.dialogue_understanding.generator.utils
8
9
  import rasa.shared.utils.io
9
10
  from rasa.dialogue_understanding.commands import (
10
11
  Command,
@@ -27,9 +28,7 @@ from rasa.engine.recipes.default_recipe import DefaultV1Recipe
27
28
  from rasa.engine.storage.resource import Resource
28
29
  from rasa.engine.storage.storage import ModelStorage
29
30
  from rasa.shared.core.constants import (
30
- KEY_MAPPING_TYPE,
31
31
  SetSlotExtractor,
32
- SlotMappingType,
33
32
  )
34
33
  from rasa.shared.core.domain import Domain
35
34
  from rasa.shared.core.flows import Flow, FlowsList, FlowStep
@@ -547,11 +546,8 @@ class LLMBasedCommandGenerator(
547
546
  for slot in llm_fillable_slots:
548
547
  should_fill_slot = False
549
548
  for mapping in slot.mappings: # type: ignore[union-attr]
550
- mapping_type = SlotMappingType(mapping.get(KEY_MAPPING_TYPE))
551
-
552
549
  should_fill_slot = slot_filling_manager.should_fill_slot(
553
550
  slot.name, # type: ignore[union-attr]
554
- mapping_type,
555
551
  mapping,
556
552
  )
557
553
 
@@ -578,3 +574,41 @@ class LLMBasedCommandGenerator(
578
574
  ]
579
575
 
580
576
  return filtered_commands
577
+
578
+ def _check_start_flow_command_overlap(
579
+ self,
580
+ prior_commands: List[Command],
581
+ commands: List[Command],
582
+ prior_start_flow_names: Set[str],
583
+ current_start_flow_names: Set[str],
584
+ ) -> List[Command]:
585
+ """Prioritize the prior commands over the LLM-issued commands."""
586
+ different_flow_names = current_start_flow_names.difference(
587
+ prior_start_flow_names
588
+ )
589
+
590
+ if not different_flow_names:
591
+ return prior_commands + commands
592
+
593
+ # discard the flow names that are different to prior start flow commands
594
+ filtered_commands = [
595
+ command
596
+ for command in commands
597
+ if not isinstance(command, StartFlowCommand)
598
+ or command.flow not in different_flow_names
599
+ ]
600
+ return prior_commands + filtered_commands
601
+
602
+ def _filter_slot_commands(
603
+ self,
604
+ prior_commands: List[Command],
605
+ commands: List[Command],
606
+ overlapping_slot_names: Set[str],
607
+ ) -> Tuple[List[Command], List[Command]]:
608
+ """Prioritize prior commands over LLM ones in the case of same slot."""
609
+ filtered_commands = (
610
+ rasa.dialogue_understanding.generator.utils.filter_slot_commands(
611
+ commands, overlapping_slot_names
612
+ )
613
+ )
614
+ return prior_commands, filtered_commands
@@ -229,7 +229,7 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
229
229
  domain = kwargs.get("domain")
230
230
  commands = self._check_commands_against_slot_mappings(commands, tracker, domain)
231
231
 
232
- return prior_commands + commands
232
+ return self._check_commands_overlap(prior_commands, commands)
233
233
 
234
234
  @classmethod
235
235
  def parse_commands(
@@ -1,7 +1,8 @@
1
- from typing import Any, Dict, List, Optional, Text
1
+ from typing import Any, Dict, List, Optional, Set, Text, Tuple
2
2
 
3
3
  import structlog
4
4
 
5
+ import rasa.dialogue_understanding.generator.utils
5
6
  from rasa.dialogue_understanding.commands import (
6
7
  Command,
7
8
  SetSlotCommand,
@@ -148,7 +149,7 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
148
149
  commands=commands,
149
150
  )
150
151
 
151
- return prior_commands + commands
152
+ return self._check_commands_overlap(prior_commands, commands)
152
153
 
153
154
  @staticmethod
154
155
  def convert_nlu_to_commands(
@@ -210,6 +211,44 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
210
211
  )
211
212
  return commands
212
213
 
214
+ def _check_start_flow_command_overlap(
215
+ self,
216
+ prior_commands: List[Command],
217
+ commands: List[Command],
218
+ prior_start_flow_names: Set[str],
219
+ current_start_flow_names: Set[str],
220
+ ) -> List[Command]:
221
+ """Prioritize the current NLU commands over the prior commands."""
222
+ different_flow_names = prior_start_flow_names.difference(
223
+ current_start_flow_names
224
+ )
225
+
226
+ if not different_flow_names:
227
+ return prior_commands + commands
228
+
229
+ filtered_commands = [
230
+ command
231
+ for command in prior_commands
232
+ if not isinstance(command, StartFlowCommand)
233
+ or command.flow not in different_flow_names
234
+ ]
235
+
236
+ return filtered_commands + commands
237
+
238
+ def _filter_slot_commands(
239
+ self,
240
+ prior_commands: List[Command],
241
+ commands: List[Command],
242
+ overlapping_slot_names: Set[str],
243
+ ) -> Tuple[List[Command], List[Command]]:
244
+ """Prioritize NLU commands over prior_commands in the case of same slot."""
245
+ filtered_prior_commands = (
246
+ rasa.dialogue_understanding.generator.utils.filter_slot_commands(
247
+ prior_commands, overlapping_slot_names
248
+ )
249
+ )
250
+ return filtered_prior_commands, commands
251
+
213
252
 
214
253
  def _issue_set_slot_commands(
215
254
  message: Message,
@@ -236,7 +236,7 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
236
236
  domain = kwargs.get("domain")
237
237
  commands = self._check_commands_against_slot_mappings(commands, tracker, domain)
238
238
 
239
- return prior_commands + commands
239
+ return self._check_commands_overlap(prior_commands, commands)
240
240
 
241
241
  async def _predict_commands(
242
242
  self,
@@ -1,14 +1,16 @@
1
- from typing import Dict, Type
1
+ from typing import Dict, List, Set, Type
2
2
 
3
3
  from rasa.dialogue_understanding.commands import (
4
4
  CancelFlowCommand,
5
5
  CannotHandleCommand,
6
6
  ChitChatAnswerCommand,
7
7
  Command,
8
+ CorrectSlotsCommand,
8
9
  HumanHandoffCommand,
9
10
  KnowledgeAnswerCommand,
10
11
  RestartCommand,
11
12
  SessionStartCommand,
13
+ SetSlotCommand,
12
14
  SkipQuestionCommand,
13
15
  )
14
16
  from rasa.dialogue_understanding.commands.user_silence_command import UserSilenceCommand
@@ -43,3 +45,32 @@ triggerable_pattern_to_command_class: Dict[str, Type[Command]] = {
43
45
  CannotHandlePatternFlowStackFrame.flow_id: CannotHandleCommand,
44
46
  RestartPatternFlowStackFrame.flow_id: RestartCommand,
45
47
  }
48
+
49
+
50
+ def filter_slot_commands(
51
+ commands: List[Command], overlapping_slot_names: Set[str]
52
+ ) -> List[Command]:
53
+ """Filter out slot commands that set overlapping slots."""
54
+ filtered_commands = []
55
+
56
+ for command in commands:
57
+ if (
58
+ isinstance(command, SetSlotCommand)
59
+ and command.name in overlapping_slot_names
60
+ ):
61
+ continue
62
+
63
+ if isinstance(command, CorrectSlotsCommand):
64
+ allowed_slots = [
65
+ slot
66
+ for slot in command.corrected_slots
67
+ if slot.name not in overlapping_slot_names
68
+ ]
69
+ if not allowed_slots:
70
+ continue
71
+
72
+ command.corrected_slots = allowed_slots
73
+
74
+ filtered_commands.append(command)
75
+
76
+ return filtered_commands
@@ -45,13 +45,12 @@ from rasa.shared.constants import (
45
45
  from rasa.shared.core.constants import (
46
46
  ACTION_TRIGGER_CHITCHAT,
47
47
  FLOW_HASHES_SLOT,
48
- KEY_ALLOW_NLU_CORRECTION,
49
- KEY_MAPPING_TYPE,
50
48
  SlotMappingType,
51
49
  )
52
50
  from rasa.shared.core.events import Event, SlotSet
53
51
  from rasa.shared.core.flows import FlowsList
54
52
  from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
53
+ from rasa.shared.core.slot_mappings import SlotMapping
55
54
  from rasa.shared.core.slots import Slot
56
55
  from rasa.shared.core.trackers import DialogueStateTracker
57
56
  from rasa.shared.core.training_data.structures import StoryGraph
@@ -582,9 +581,9 @@ def clean_up_slot_command(
582
581
  ):
583
582
  allow_nlu_correction = any(
584
583
  [
585
- mapping.get(KEY_ALLOW_NLU_CORRECTION, False)
584
+ mapping.allow_nlu_correction is True
586
585
  for mapping in slot.mappings
587
- if mapping.get(KEY_MAPPING_TYPE) == SlotMappingType.FROM_LLM.value
586
+ if mapping.type == SlotMappingType.FROM_LLM
588
587
  ]
589
588
  )
590
589
 
@@ -742,12 +741,9 @@ def should_slot_be_set(
742
741
  slot_mappings = slot.mappings
743
742
 
744
743
  if not slot.mappings:
745
- slot_mappings = [{KEY_MAPPING_TYPE: SlotMappingType.FROM_LLM.value}]
744
+ slot_mappings = [SlotMapping(type=SlotMappingType.FROM_LLM)]
746
745
 
747
- mapping_types = [
748
- SlotMappingType(mapping.get(KEY_MAPPING_TYPE, SlotMappingType.FROM_LLM.value))
749
- for mapping in slot_mappings
750
- ]
746
+ mapping_types = [mapping.type for mapping in slot_mappings]
751
747
 
752
748
  slot_has_nlu_mapping = any(
753
749
  [mapping_type.is_predefined_type() for mapping_type in mapping_types]
@@ -755,8 +751,8 @@ def should_slot_be_set(
755
751
  slot_has_llm_mapping = any(
756
752
  [mapping_type == SlotMappingType.FROM_LLM for mapping_type in mapping_types]
757
753
  )
758
- slot_has_custom_mapping = any(
759
- [mapping_type == SlotMappingType.CUSTOM for mapping_type in mapping_types]
754
+ slot_has_controlled_mapping = any(
755
+ [mapping_type == SlotMappingType.CONTROLLED for mapping_type in mapping_types]
760
756
  )
761
757
 
762
758
  if set_slot_commands_so_far and command.extractor == SetSlotExtractor.LLM.value:
@@ -785,7 +781,9 @@ def should_slot_be_set(
785
781
  ):
786
782
  return False
787
783
 
788
- if slot_has_custom_mapping and not (slot_has_nlu_mapping or slot_has_llm_mapping):
784
+ if slot_has_controlled_mapping and not (
785
+ slot_has_nlu_mapping or slot_has_llm_mapping
786
+ ):
789
787
  return False
790
788
 
791
789
  return True
@@ -377,3 +377,53 @@ Test cases in **to_review** may require manual intervention because the E2E test
377
377
  Review these cases to ensure that the converted test cases are correct and the list of commands and
378
378
  bot responses is complete.
379
379
 
380
+
381
+ ## Converting DUT test from one DSL to a another DSL
382
+
383
+ If you need to transform your commands from one DSL format to another
384
+ (for instance, updating `StartFlow(flow_name)` to `start flow_name` or `SetSlot(slot_name, slot_value)` to `set slot_name slot_value`),
385
+ you can use a standalone Python script:
386
+
387
+ ```bash
388
+ python convert_dut_dsl.py --dut-tests-dir <path> --output-dir <path> --dsl-mappings <path>
389
+ ```
390
+
391
+ The script has the following required parameters:
392
+
393
+ - `--dut-tests-dir <path>`: The directory (relative or absolute) containing your
394
+ existing Dialogue Understanding Tests (DUT). The script will look for `.yaml` or
395
+ `.yml` files within this folder (and subfolders).
396
+ - `--output-dir <path>`: The directory where transformed files will be saved. The folder
397
+ structure from your `dut-tests-dir` is preserved.
398
+ - `--dsl-mappings <path>`: The YAML file defining your DSL mapping rules.
399
+
400
+ The YAML file containing the mappings must adhere to the following format:
401
+ ```yaml
402
+ mappings:
403
+
404
+ - from_dsl_regex: "^StartFlow\\(([^)]*)\\)$"
405
+ to_dsl_pattern: "start {1}"
406
+
407
+ - from_dsl_regex: "^SetSlot\\(([^,]+),\\s*(.*)\\)$"
408
+ to_dsl_pattern: "set {1} {2}"
409
+
410
+ - from_dsl_regex: "Clarify\(([\"\'a-zA-Z0-9_, ]*)\)"
411
+ to_dsl_pattern: "clarify {1}"
412
+ input_separators:
413
+ - ","
414
+ - " "
415
+ output_separator: " "
416
+
417
+ # ... add more mappings here
418
+
419
+ ```
420
+
421
+ - `from_dsl_regex`: A regular expression (string) used to match the old DSL command.
422
+ Must include any necessary anchors (like ^ and $) and capturing groups ( ... ) for
423
+ dynamic parts.
424
+ - `to_dsl_pattern`: A string that contains placeholders like `{1}`, `{2}`, etc. Each
425
+ placeholder corresponds to a capturing group in from_dsl_regex, in order of
426
+ appearance.
427
+ - `input_separators`: Optional list of separators of the captured groups that can be replaced
428
+ with the `output_separator`
429
+ - `output_separator`: Output separator to replace separators from the list of `input_separators` in the captured group.
@@ -20,7 +20,7 @@ from rasa.dialogue_understanding_test.test_case_simulation.exception import (
20
20
  )
21
21
  from rasa.dialogue_understanding_test.utils import filter_metadata
22
22
  from rasa.e2e_test.e2e_test_case import Fixture, Metadata
23
- from rasa.shared.core.constants import KEY_MAPPING_TYPE, SlotMappingType
23
+ from rasa.shared.core.constants import SlotMappingType
24
24
  from rasa.shared.core.events import BotUttered, SlotSet, UserUttered
25
25
  from rasa.shared.core.trackers import DialogueStateTracker
26
26
  from rasa.shared.nlu.constants import COMMANDS, ENTITIES, INTENT
@@ -328,8 +328,8 @@ class TestCaseTrackerSimulator:
328
328
  command.extractor = SetSlotExtractor.COMMAND_PAYLOAD_READER.value
329
329
  # Use the SetSlotExtractor.NLU extractor if the slot mapping type is
330
330
  # not FROM_LLM.
331
- elif SlotMappingType.FROM_LLM.value not in [
332
- mapping[KEY_MAPPING_TYPE] for mapping in slot_definition.mappings
331
+ elif SlotMappingType.FROM_LLM not in [
332
+ mapping.type for mapping in slot_definition.mappings
333
333
  ]:
334
334
  command.extractor = SetSlotExtractor.NLU.value
335
335
 
rasa/model_service.py CHANGED
@@ -61,6 +61,7 @@ def main() -> None:
61
61
  The API server can receive requests to train models, run bots, and manage
62
62
  the lifecycle of models and bots.
63
63
  """
64
+ import rasa.telemetry
64
65
  import rasa.utils.licensing
65
66
 
66
67
  log_level = logging.DEBUG
@@ -74,6 +75,9 @@ def main() -> None:
74
75
 
75
76
  rasa.utils.licensing.validate_license_from_env()
76
77
 
78
+ rasa.telemetry.initialize_telemetry()
79
+ rasa.telemetry.initialize_error_reporting()
80
+
77
81
  try:
78
82
  model_api.prepare_working_directories()
79
83
  except Exception as e:
rasa/model_training.py CHANGED
@@ -352,34 +352,31 @@ async def _train_graph(
352
352
  model_name = determine_model_name(fixed_model_name, training_type)
353
353
  full_model_path = Path(output_path, model_name)
354
354
 
355
- with telemetry.track_model_training(
356
- file_importer, model_type=training_type.model_type
357
- ):
358
- await trainer.train(
359
- model_configuration,
360
- file_importer,
361
- full_model_path,
362
- force_retraining=force_full_training,
363
- is_finetuning=is_finetuning,
355
+ await trainer.train(
356
+ model_configuration,
357
+ file_importer,
358
+ full_model_path,
359
+ force_retraining=force_full_training,
360
+ is_finetuning=is_finetuning,
361
+ )
362
+ if remote_storage:
363
+ push_model_to_remote_storage(full_model_path, remote_storage)
364
+ if not keep_local_model_copy:
365
+ full_model_path.unlink()
366
+ structlogger.info(
367
+ "model_training.train.finished_training",
368
+ event_info=(
369
+ f"Your Rasa model {model_name} is trained "
370
+ f"and saved at remote storage provider '{remote_storage}'."
371
+ ),
372
+ )
373
+ else:
374
+ structlogger.info(
375
+ "model_training.train.finished_training",
376
+ event_info=(
377
+ f"Your Rasa model is trained and saved at '{full_model_path}'."
378
+ ),
364
379
  )
365
- if remote_storage:
366
- push_model_to_remote_storage(full_model_path, remote_storage)
367
- if not keep_local_model_copy:
368
- full_model_path.unlink()
369
- structlogger.info(
370
- "model_training.train.finished_training",
371
- event_info=(
372
- f"Your Rasa model {model_name} is trained "
373
- f"and saved at remote storage provider '{remote_storage}'."
374
- ),
375
- )
376
- else:
377
- structlogger.info(
378
- "model_training.train.finished_training",
379
- event_info=(
380
- f"Your Rasa model is trained and saved at '{full_model_path}'."
381
- ),
382
- )
383
380
 
384
381
  return TrainingResult(str(full_model_path), 0)
385
382
 
@@ -143,6 +143,8 @@ SLOT_MAPPINGS = "mappings"
143
143
  MAPPING_CONDITIONS = "conditions"
144
144
  KEY_MAPPING_TYPE = "type"
145
145
  KEY_ALLOW_NLU_CORRECTION = "allow_nlu_correction"
146
+ KEY_ACTION = "action"
147
+ KEY_RUN_ACTION_EVERY_TURN = "run_action_every_turn"
146
148
 
147
149
 
148
150
  class SlotMappingType(Enum):
@@ -153,7 +155,7 @@ class SlotMappingType(Enum):
153
155
  FROM_TRIGGER_INTENT = "from_trigger_intent"
154
156
  FROM_TEXT = "from_text"
155
157
  FROM_LLM = "from_llm"
156
- CUSTOM = "custom"
158
+ CONTROLLED = "controlled"
157
159
 
158
160
  def __str__(self) -> str:
159
161
  """Returns the string representation that should be used in config files."""
@@ -161,7 +163,9 @@ class SlotMappingType(Enum):
161
163
 
162
164
  def is_predefined_type(self) -> bool:
163
165
  """Returns True if the mapping type is NLU-predefined."""
164
- return not (self == SlotMappingType.CUSTOM or self == SlotMappingType.FROM_LLM)
166
+ return not (
167
+ self == SlotMappingType.CONTROLLED or self == SlotMappingType.FROM_LLM
168
+ )
165
169
 
166
170
 
167
171
  class SetSlotExtractor(Enum):
@@ -46,10 +46,8 @@ from rasa.shared.constants import (
46
46
  )
47
47
  from rasa.shared.core.constants import (
48
48
  ACTION_SHOULD_SEND_DOMAIN,
49
- ACTIVE_LOOP,
50
49
  KEY_MAPPING_TYPE,
51
50
  KNOWLEDGE_BASE_SLOT_NAMES,
52
- MAPPING_CONDITIONS,
53
51
  SLOT_MAPPINGS,
54
52
  SlotMappingType,
55
53
  )
@@ -290,8 +288,6 @@ class Domain:
290
288
  responses = data.get(KEY_RESPONSES, {})
291
289
 
292
290
  domain_slots = data.get(KEY_SLOTS, {})
293
- if domain_slots:
294
- rasa.shared.core.slot_mappings.validate_slot_mappings(domain_slots)
295
291
  slots = cls.collect_slots(domain_slots)
296
292
  domain_actions = data.get(KEY_ACTIONS, [])
297
293
  actions = cls._collect_action_names(domain_actions)
@@ -1569,23 +1565,18 @@ class Domain:
1569
1565
  matching_entities = []
1570
1566
 
1571
1567
  for mapping in slot.mappings:
1572
- mapping_conditions = mapping.get(MAPPING_CONDITIONS)
1573
- if mapping[KEY_MAPPING_TYPE] != str(
1574
- SlotMappingType.FROM_ENTITY
1575
- ) or (
1568
+ mapping_conditions = mapping.conditions
1569
+ if mapping.type != SlotMappingType.FROM_ENTITY or (
1576
1570
  mapping_conditions
1577
- and mapping_conditions[0].get(ACTIVE_LOOP) is not None
1571
+ and mapping_conditions[0].active_loop is not None
1578
1572
  ):
1579
1573
  continue
1580
1574
 
1581
1575
  for entity in entities:
1582
1576
  if (
1583
- entity.get(ENTITY_ATTRIBUTE_TYPE)
1584
- == mapping.get(ENTITY_ATTRIBUTE_TYPE)
1585
- and entity.get(ENTITY_ATTRIBUTE_ROLE)
1586
- == mapping.get(ENTITY_ATTRIBUTE_ROLE)
1587
- and entity.get(ENTITY_ATTRIBUTE_GROUP)
1588
- == mapping.get(ENTITY_ATTRIBUTE_GROUP)
1577
+ entity.get(ENTITY_ATTRIBUTE_TYPE) == mapping.entity
1578
+ and entity.get(ENTITY_ATTRIBUTE_ROLE) == mapping.role
1579
+ and entity.get(ENTITY_ATTRIBUTE_GROUP) == mapping.group
1589
1580
  ):
1590
1581
  matching_entities.append(entity.get("value"))
1591
1582
 
@@ -2017,19 +2008,19 @@ class Domain:
2017
2008
  is the total number of mappings which have conditions attached.
2018
2009
  """
2019
2010
  total_mappings = 0
2020
- custom_mappings = 0
2011
+ controlled_mappings = 0
2021
2012
  conditional_mappings = 0
2022
2013
 
2023
2014
  for slot in self.slots:
2024
2015
  total_mappings += len(slot.mappings)
2025
2016
  for mapping in slot.mappings:
2026
- if mapping[KEY_MAPPING_TYPE] == str(SlotMappingType.CUSTOM):
2027
- custom_mappings += 1
2017
+ if mapping.type == SlotMappingType.CONTROLLED:
2018
+ controlled_mappings += 1
2028
2019
 
2029
- if MAPPING_CONDITIONS in mapping:
2020
+ if mapping.conditions:
2030
2021
  conditional_mappings += 1
2031
2022
 
2032
- return (total_mappings, custom_mappings, conditional_mappings)
2023
+ return total_mappings, controlled_mappings, conditional_mappings
2033
2024
 
2034
2025
  def does_custom_action_explicitly_need_domain(self, action_name: Text) -> bool:
2035
2026
  """Assert if action has explicitly stated that it needs domain.