rasa-pro 3.12.28__py3-none-any.whl → 3.12.30__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.

@@ -115,7 +115,6 @@ class CorrectSlotsCommand(Command):
115
115
  The earliest collect information step that fills one of the slots and
116
116
  the flow id of that step.
117
117
  """
118
-
119
118
  collect_steps = utils.previous_collect_steps_for_active_flow(tracker, all_flows)
120
119
 
121
120
  for collect_step, flow_id in collect_steps:
@@ -269,7 +268,21 @@ class CorrectSlotsCommand(Command):
269
268
  )
270
269
  return []
271
270
 
272
- structlogger.debug("command_executor.correct_slots", command=self)
271
+ structlogger.debug("correct_slots_command", command=self)
272
+
273
+ # check if the correct slot is referring to a slot of a flow on the stack
274
+ # the slot also needs to be part of a collect step in any of those flows
275
+ # if this is not the case, we don't want to correct the slot
276
+ for slot in self.corrected_slots:
277
+ if not self.should_correct_slot(slot, tracker, all_flows):
278
+ structlogger.warning(
279
+ "correct_slots_command.skip_correct_slot",
280
+ correct_slot=slot,
281
+ reason="The slot is not part of a collect step in any of the flows "
282
+ "on the stack. Skipping correction.",
283
+ )
284
+ return []
285
+
273
286
  proposed_slots = self.corrected_slots_dict(tracker)
274
287
 
275
288
  correction_frame = self.create_correction_frame(
@@ -294,3 +307,27 @@ class CorrectSlotsCommand(Command):
294
307
  return False
295
308
 
296
309
  return True
310
+
311
+ def should_correct_slot(
312
+ self, slot: CorrectedSlot, tracker: DialogueStateTracker, all_flows: FlowsList
313
+ ) -> bool:
314
+ """Checks if the slot should be corrected.
315
+
316
+ Args:
317
+ slot: The slot to check.
318
+ tracker: The tracker.
319
+ all_flows: All flows in the assistant.
320
+ """
321
+ # get all flows on the stack
322
+ flows_on_stack = utils.user_flows_on_the_stack(tracker.stack)
323
+
324
+ # check if the slot is part of a collect step in any of the flows on the stack
325
+ for flow_id in flows_on_stack:
326
+ flow = all_flows.flow_by_id(flow_id)
327
+ if flow is None:
328
+ continue
329
+ for collect_step in flow.get_collect_steps():
330
+ if collect_step.collect == slot.name:
331
+ return True
332
+
333
+ return False
@@ -37,7 +37,6 @@ from rasa.dialogue_understanding.stack.frames import (
37
37
  BaseFlowStackFrame,
38
38
  )
39
39
  from rasa.dialogue_understanding.stack.utils import (
40
- filled_slots_for_active_flow,
41
40
  top_flow_frame,
42
41
  top_user_flow_frame,
43
42
  )
@@ -125,8 +124,9 @@ def validate_state_of_commands(commands: List[Command]) -> None:
125
124
  # check that there is only at max one cancel flow command
126
125
  if sum(isinstance(c, CancelFlowCommand) for c in commands) > 1:
127
126
  structlogger.error(
128
- "command_processor.validate_state_of_commands.multiple_cancel_flow_commands",
129
- commands=commands,
127
+ "command_processor.validate_state_of_commands."
128
+ "multiple_cancel_flow_commands",
129
+ commands=[command.__class__.__name__ for command in commands],
130
130
  )
131
131
  raise ValueError("There can only be one cancel flow command.")
132
132
 
@@ -136,8 +136,9 @@ def validate_state_of_commands(commands: List[Command]) -> None:
136
136
  ]
137
137
  if free_form_answer_commands != commands[: len(free_form_answer_commands)]:
138
138
  structlogger.error(
139
- "command_processor.validate_state_of_commands.free_form_answer_commands_not_at_beginning",
140
- commands=commands,
139
+ "command_processor.validate_state_of_commands."
140
+ "free_form_answer_commands_not_at_beginning",
141
+ commands=[command.__class__.__name__ for command in commands],
141
142
  )
142
143
  raise ValueError(
143
144
  "Free form answer commands must be at start of the predicted command list."
@@ -146,8 +147,9 @@ def validate_state_of_commands(commands: List[Command]) -> None:
146
147
  # check that there is at max only one correctslots command
147
148
  if sum(isinstance(c, CorrectSlotsCommand) for c in commands) > 1:
148
149
  structlogger.error(
149
- "command_processor.validate_state_of_commands.multiple_correct_slots_commands",
150
- commands=commands,
150
+ "command_processor.validate_state_of_commands."
151
+ "multiple_correct_slots_commands",
152
+ commands=[command.__class__.__name__ for command in commands],
151
153
  )
152
154
  raise ValueError("There can only be one correct slots command.")
153
155
 
@@ -230,11 +232,9 @@ def execute_commands(
230
232
 
231
233
  events: List[Event] = flow_hash_events
232
234
 
233
- # commands need to be reversed to make sure they end up in the right order
234
- # on the stack. e.g. if there multiple start flow commands, the first one
235
- # should be on top of the stack. this is achieved by reversing the list
236
- # and then pushing the commands onto the stack in the reversed order.
237
- reversed_commands = list(reversed(commands))
235
+ # reorder commands: in case there is no active flow, we want to make sure to
236
+ # run the start flow commands first.
237
+ final_commands = reorder_commands(commands, tracker)
238
238
 
239
239
  # we need to keep track of the ValidateSlotPatternFlowStackFrame that
240
240
  # should be pushed onto the stack before executing the StartFlowCommands.
@@ -245,7 +245,7 @@ def execute_commands(
245
245
 
246
246
  validate_state_of_commands(commands)
247
247
 
248
- for command in reversed_commands:
248
+ for command in final_commands:
249
249
  new_events = command.run_command_on_tracker(
250
250
  tracker, all_flows, original_tracker
251
251
  )
@@ -399,19 +399,12 @@ def clean_up_commands(
399
399
  """
400
400
  domain = domain if domain else Domain.empty()
401
401
 
402
- slots_so_far, _ = filled_slots_for_active_flow(tracker, all_flows)
403
-
404
- # update the slots so far with the slots that were set in the tracker
405
- slots_so_far.update(
406
- {event.key for event in tracker.events if isinstance(event, SlotSet)}
407
- )
408
-
409
402
  clean_commands: List[Command] = []
410
403
 
411
404
  for command in commands:
412
405
  if isinstance(command, SetSlotCommand):
413
406
  clean_commands = clean_up_slot_command(
414
- clean_commands, command, tracker, all_flows, slots_so_far
407
+ clean_commands, command, tracker, all_flows
415
408
  )
416
409
 
417
410
  elif isinstance(command, CancelFlowCommand) and contains_command(
@@ -445,7 +438,8 @@ def clean_up_commands(
445
438
  # drop a start flow command if the starting flow is equal
446
439
  # to the currently active flow
447
440
  structlogger.debug(
448
- "command_processor.clean_up_commands.skip_command_flow_already_active",
441
+ "command_processor.clean_up_commands."
442
+ "skip_command_flow_already_active",
449
443
  command=command,
450
444
  )
451
445
  continue
@@ -476,7 +470,8 @@ def clean_up_commands(
476
470
  clean_commands = clean_up_clarify_command(clean_commands, commands, command)
477
471
  if command not in clean_commands:
478
472
  structlogger.debug(
479
- "command_processor.clean_up_commands.drop_clarify_given_other_commands",
473
+ "command_processor.clean_up_commands."
474
+ "drop_clarify_given_other_commands",
480
475
  command=command,
481
476
  )
482
477
  else:
@@ -500,6 +495,25 @@ def clean_up_commands(
500
495
  return clean_commands
501
496
 
502
497
 
498
+ def _get_slots_eligible_for_correction(tracker: DialogueStateTracker) -> Set[str]:
499
+ """Get all slots that are eligible for correction.
500
+
501
+ # We consider all slots, which are not None, that were set in the tracker
502
+ # eligible for correction.
503
+ # In the correct_slot_command we will check if a slot should actually be
504
+ # corrected.
505
+ """
506
+ # get all slots that were set in the tracker
507
+ slots_so_far = set(
508
+ [event.key for event in tracker.events if isinstance(event, SlotSet)]
509
+ )
510
+
511
+ # filter out slots that are set to None (None = empty value)
512
+ slots_so_far = {slot for slot in slots_so_far if tracker.get_slot(slot) is not None}
513
+
514
+ return slots_so_far
515
+
516
+
503
517
  def ensure_max_number_of_command_type(
504
518
  commands: List[Command], command_type: Type[Command], n: int
505
519
  ) -> List[Command]:
@@ -559,7 +573,6 @@ def clean_up_slot_command(
559
573
  command: SetSlotCommand,
560
574
  tracker: DialogueStateTracker,
561
575
  all_flows: FlowsList,
562
- slots_so_far: Set[str],
563
576
  ) -> List[Command]:
564
577
  """Clean up a slot command.
565
578
 
@@ -572,16 +585,15 @@ def clean_up_slot_command(
572
585
  command: The command to clean up.
573
586
  tracker: The dialogue state tracker.
574
587
  all_flows: All flows.
575
- slots_so_far: The slots that have been filled so far.
576
588
 
577
589
  Returns:
578
590
  The cleaned up commands.
579
591
  """
580
592
  stack = tracker.stack
581
-
582
593
  resulting_commands = commands_so_far[:]
583
-
584
594
  slot = tracker.slots.get(command.name)
595
+
596
+ # if the slot is not in the domain, we cannot set it
585
597
  if slot is None:
586
598
  structlogger.debug(
587
599
  "command_processor.clean_up_slot_command.skip_command_slot_not_in_domain",
@@ -594,6 +606,7 @@ def clean_up_slot_command(
594
606
  )
595
607
  return resulting_commands
596
608
 
609
+ # check if the slot should be set by the command
597
610
  if not should_slot_be_set(slot, command, resulting_commands):
598
611
  structlogger.debug(
599
612
  "command_processor.clean_up_slot_command.skip_command.extractor_"
@@ -619,6 +632,7 @@ def clean_up_slot_command(
619
632
 
620
633
  return resulting_commands
621
634
 
635
+ # check if the slot can be corrected by the LLM
622
636
  if (
623
637
  slot.filled_by == SetSlotExtractor.NLU.value
624
638
  and command.extractor == SetSlotExtractor.LLM.value
@@ -639,7 +653,13 @@ def clean_up_slot_command(
639
653
  )
640
654
  return resulting_commands
641
655
 
642
- if command.name in slots_so_far and command.name != ROUTE_TO_CALM_SLOT:
656
+ # get all slots that were set in the tracker and are eligible for correction
657
+ slots_eligible_for_correction = _get_slots_eligible_for_correction(tracker)
658
+
659
+ if (
660
+ command.name in slots_eligible_for_correction
661
+ and command.name != ROUTE_TO_CALM_SLOT
662
+ ):
643
663
  current_collect_info = get_current_collect_step(stack, all_flows)
644
664
 
645
665
  if current_collect_info and current_collect_info.collect == command.name:
@@ -647,49 +667,71 @@ def clean_up_slot_command(
647
667
  resulting_commands.append(command)
648
668
  return resulting_commands
649
669
 
650
- if (slot := tracker.slots.get(command.name)) is not None and str(
651
- slot.value
652
- ) == str(command.value):
653
- # the slot is already set, we don't need to set it again
654
- structlogger.debug(
655
- "command_processor.clean_up_slot_command.skip_command_slot_already_set",
656
- command=command,
657
- )
670
+ if should_slot_be_corrected(command, tracker, stack, all_flows):
671
+ # if the slot was already set before, we need to convert it into
672
+ # a correction
673
+ return convert_set_slot_to_correction(command, resulting_commands)
674
+ else:
658
675
  return resulting_commands
659
676
 
660
- top = top_flow_frame(stack)
661
- if isinstance(top, CorrectionPatternFlowStackFrame):
662
- already_corrected_slots = top.corrected_slots
663
- else:
664
- already_corrected_slots = {}
677
+ resulting_commands.append(command)
678
+ return resulting_commands
665
679
 
666
- if command.name in already_corrected_slots and str(
667
- already_corrected_slots[command.name]
668
- ) == str(command.value):
669
- structlogger.debug(
670
- "command_processor.clean_up_slot_command"
671
- ".skip_command_slot_already_corrected",
672
- command=command,
673
- )
674
- return resulting_commands
675
680
 
681
+ def should_slot_be_corrected(
682
+ command: SetSlotCommand,
683
+ tracker: DialogueStateTracker,
684
+ stack: DialogueStack,
685
+ all_flows: FlowsList,
686
+ ) -> bool:
687
+ """Check if a slot should be corrected."""
688
+ if (slot := tracker.slots.get(command.name)) is not None and str(slot.value) == str(
689
+ command.value
690
+ ):
691
+ # the slot is already set to the same value, we don't need to set it again
692
+ structlogger.debug(
693
+ "command_processor.clean_up_slot_command.skip_command_slot_already_set",
694
+ command=command,
695
+ )
696
+ return False
697
+
698
+ top = top_flow_frame(stack)
699
+ if isinstance(top, CorrectionPatternFlowStackFrame):
700
+ already_corrected_slots = top.corrected_slots
701
+ else:
702
+ already_corrected_slots = {}
703
+
704
+ if command.name in already_corrected_slots and str(
705
+ already_corrected_slots[command.name]
706
+ ) == str(command.value):
676
707
  structlogger.debug(
677
- "command_processor.clean_up_slot_command.convert_command_to_correction",
708
+ "command_processor.clean_up_slot_command"
709
+ ".skip_command_slot_already_corrected",
678
710
  command=command,
679
711
  )
712
+ return False
680
713
 
681
- # Group all corrections into one command
682
- corrected_slot = CorrectedSlot(command.name, command.value, command.extractor)
683
- for c in resulting_commands:
684
- if isinstance(c, CorrectSlotsCommand):
685
- c.corrected_slots.append(corrected_slot)
686
- break
687
- else:
688
- resulting_commands.append(
689
- CorrectSlotsCommand(corrected_slots=[corrected_slot])
690
- )
714
+ return True
715
+
716
+
717
+ def convert_set_slot_to_correction(
718
+ command: SetSlotCommand,
719
+ resulting_commands: List[Command],
720
+ ) -> List[Command]:
721
+ """Convert a set slot command to a correction command."""
722
+ structlogger.debug(
723
+ "command_processor.convert_set_slot_to_correction",
724
+ command=command,
725
+ )
726
+
727
+ # Group all corrections into one command
728
+ corrected_slot = CorrectedSlot(command.name, command.value, command.extractor)
729
+ for c in resulting_commands:
730
+ if isinstance(c, CorrectSlotsCommand):
731
+ c.corrected_slots.append(corrected_slot)
732
+ break
691
733
  else:
692
- resulting_commands.append(command)
734
+ resulting_commands.append(CorrectSlotsCommand(corrected_slots=[corrected_slot]))
693
735
 
694
736
  return resulting_commands
695
737
 
@@ -748,8 +790,9 @@ def clean_up_chitchat_command(
748
790
  0, CannotHandleCommand(RASA_PATTERN_CANNOT_HANDLE_CHITCHAT)
749
791
  )
750
792
  structlogger.warn(
751
- "command_processor.clean_up_chitchat_command.replace_chitchat_answer_with_cannot_handle",
752
- command=resulting_commands[0],
793
+ "command_processor.clean_up_chitchat_command."
794
+ "replace_chitchat_answer_with_cannot_handle",
795
+ command=resulting_commands[0], # no PII
753
796
  pattern_chitchat_uses_action_trigger_chitchat=has_action_trigger_chitchat,
754
797
  defined_intentless_policy_in_config=defines_intentless_policy,
755
798
  )
@@ -851,3 +894,49 @@ def filter_cannot_handle_command(
851
894
  for command in clean_commands
852
895
  if not isinstance(command, CannotHandleCommand)
853
896
  ]
897
+
898
+
899
+ def reorder_commands(
900
+ commands: List[Command], tracker: DialogueStateTracker
901
+ ) -> List[Command]:
902
+ """Reorder commands.
903
+
904
+ In case there is no active flow, we want to make sure to run the start flow
905
+ commands first.
906
+ """
907
+ reordered_commands = commands
908
+
909
+ top_flow_frame = top_user_flow_frame(tracker.stack)
910
+
911
+ if top_flow_frame is None:
912
+ # no active flow, we want to make sure to run the start flow commands first
913
+ start_flow_commands: List[Command] = [
914
+ command for command in commands if isinstance(command, StartFlowCommand)
915
+ ]
916
+
917
+ # if there are no start flow commands, we can return the commands as they are
918
+ if not start_flow_commands:
919
+ reordered_commands = commands
920
+
921
+ # if there is just one start flow command, we want to run it first
922
+ # as the order of commands is reserved later,
923
+ # we need to add it to the end of the list
924
+ elif len(start_flow_commands) == 1:
925
+ reordered_commands = [
926
+ command for command in commands if command not in start_flow_commands
927
+ ] + start_flow_commands
928
+
929
+ # if there are multiple start flow commands,
930
+ # we just make sure to move the first start flow command to the end of the list
931
+ # (due to the reverse execution order of commands) and keep the other commands
932
+ # as they are.
933
+ else:
934
+ reordered_commands = [
935
+ command for command in commands if command != start_flow_commands[-1]
936
+ ] + [start_flow_commands[-1]]
937
+
938
+ # commands need to be reversed to make sure they end up in the right order
939
+ # on the stack. e.g. if there multiple start flow commands, the first one
940
+ # should be on top of the stack. this is achieved by reversing the list
941
+ # and then pushing the commands onto the stack in the reversed order.
942
+ return list(reversed(reordered_commands))
rasa/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # this file will automatically be changed,
2
2
  # do not add anything but the version number here!
3
- __version__ = "3.12.28"
3
+ __version__ = "3.12.30"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rasa-pro
3
- Version: 3.12.28
3
+ Version: 3.12.30
4
4
  Summary: State-of-the-art open-core Conversational AI framework for Enterprises that natively leverages generative AI for effortless assistant development.
5
5
  Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
6
6
  Author: Rasa Technologies GmbH
@@ -375,7 +375,7 @@ rasa/dialogue_understanding/commands/chit_chat_answer_command.py,sha256=PtwNuAHJ
375
375
  rasa/dialogue_understanding/commands/clarify_command.py,sha256=mxdHWdyaQwA4uYdhVUjwAUPfl0HvqtDHU2DWKEeZal4,4290
376
376
  rasa/dialogue_understanding/commands/command.py,sha256=rhxHmllTMwvb4Uq-pDqmUdlKtu-87y8nqN5DRO-KDwE,2529
377
377
  rasa/dialogue_understanding/commands/command_syntax_manager.py,sha256=vO6sOak0g9GucEtiNximJ9bQFbHQwWJ-M5XNF1gGxz4,1893
378
- rasa/dialogue_understanding/commands/correct_slots_command.py,sha256=bIApo1i-RbF7JojHb4WiiKkZwRV6GBaUIGkdsn9Scog,10396
378
+ rasa/dialogue_understanding/commands/correct_slots_command.py,sha256=2oRix75ciUWMM4vs5bQt_BP8e4VMklepqTAoqGvUP4k,11899
379
379
  rasa/dialogue_understanding/commands/error_command.py,sha256=LTEsxkGGGZR6wEEGuTtQ4K4EK_u2UFhNK4eAKyPfyME,2436
380
380
  rasa/dialogue_understanding/commands/free_form_answer_command.py,sha256=XlQrHXrcOemzu1LHZiDhBAluiSlnUQ2V7ET5Z-aG7gc,224
381
381
  rasa/dialogue_understanding/commands/handle_code_change_command.py,sha256=Cp2e1iD0zacXmljJ8vDXHJu9Fp6BwB7cGx8NF748akw,2192
@@ -436,7 +436,7 @@ rasa/dialogue_understanding/patterns/skip_question.py,sha256=fJ1MC0WEEtS-BpnGJEf
436
436
  rasa/dialogue_understanding/patterns/user_silence.py,sha256=xP-QMnd-MsybH5z4g01hBv4OLOHcw6m3rc26LQfe2zo,1140
437
437
  rasa/dialogue_understanding/patterns/validate_slot.py,sha256=hqd5AEGT3M3HLNhMwuI9W9kZNCvgU6GyI-2xc2b4kz8,2085
438
438
  rasa/dialogue_understanding/processor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
439
- rasa/dialogue_understanding/processor/command_processor.py,sha256=BRpT28JKwNhKo5i8FwJ785KmmM6jJhln7BuUX087vf0,30343
439
+ rasa/dialogue_understanding/processor/command_processor.py,sha256=At3R1gwYMggfeC-j-YJzYTMLYKXWi2RGh0SMCEx8EXo,33522
440
440
  rasa/dialogue_understanding/processor/command_processor_component.py,sha256=rkErI_Uo7s3LsEojUSGSRbWGyGaX7GtGOYSJn0V-TI4,1650
441
441
  rasa/dialogue_understanding/stack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
442
442
  rasa/dialogue_understanding/stack/dialogue_stack.py,sha256=cYV6aQeh0EuOJHODDqK3biqXozYTX8baPgLwHhPxFqs,5244
@@ -822,9 +822,9 @@ rasa/utils/train_utils.py,sha256=ClJx-6x3-h3Vt6mskacgkcCUJTMXjFPe3zAcy_DfmaU,212
822
822
  rasa/utils/url_tools.py,sha256=dZ1HGkVdWTJB7zYEdwoDIrEuyX9HE5WsxKKFVsXBLE0,1218
823
823
  rasa/utils/yaml.py,sha256=KjbZq5C94ZP7Jdsw8bYYF7HASI6K4-C_kdHfrnPLpSI,2000
824
824
  rasa/validator.py,sha256=524VlFTYK0B3iXYveVD6BDC3K0j1QfpzJ9O-TAWczmc,83166
825
- rasa/version.py,sha256=aC6Pou7VXpWxwawa48upNJvkusxhNBoc_GAG_QsLZ-Y,118
826
- rasa_pro-3.12.28.dist-info/METADATA,sha256=z6d0ful_P2-MrVxrxMuuIauM7g9cLCLftJd-zPq_fqo,10609
827
- rasa_pro-3.12.28.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
828
- rasa_pro-3.12.28.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
829
- rasa_pro-3.12.28.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
830
- rasa_pro-3.12.28.dist-info/RECORD,,
825
+ rasa/version.py,sha256=9pHHdCcacB7k3dA4b6QLVw9JG0FDRA0ckMI39G-23fI,118
826
+ rasa_pro-3.12.30.dist-info/METADATA,sha256=G441WLaRBhJh8vVqd4RRdKP2PvQN5KruxfCbc7lh4QQ,10609
827
+ rasa_pro-3.12.30.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
828
+ rasa_pro-3.12.30.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
829
+ rasa_pro-3.12.30.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
830
+ rasa_pro-3.12.30.dist-info/RECORD,,