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

@@ -114,7 +114,7 @@ class CommandGenerator:
114
114
  # slot asked by the active collect step.
115
115
  # Or return a CannotHandleCommand if no matching command is found.
116
116
  commands = self._filter_commands_during_force_slot_filling(
117
- commands, available_flows, tracker
117
+ commands, flows, tracker
118
118
  )
119
119
 
120
120
  commands_dicts = [command.as_dict() for command in commands]
@@ -383,14 +383,14 @@ class CommandGenerator:
383
383
  @staticmethod
384
384
  def _filter_commands_during_force_slot_filling(
385
385
  commands: List[Command],
386
- available_flows: FlowsList,
386
+ flows: FlowsList,
387
387
  tracker: Optional[DialogueStateTracker] = None,
388
388
  ) -> List[Command]:
389
389
  """Filter commands during a collect step that has set `force_slot_filling`.
390
390
 
391
391
  Args:
392
392
  commands: The commands to filter.
393
- available_flows: The available flows.
393
+ flows: All flows.
394
394
  tracker: The tracker.
395
395
 
396
396
  Returns:
@@ -407,7 +407,7 @@ class CommandGenerator:
407
407
  )
408
408
  return commands
409
409
 
410
- updated_flows = find_updated_flows(tracker, available_flows)
410
+ updated_flows = find_updated_flows(tracker, flows)
411
411
  if updated_flows:
412
412
  structlogger.debug(
413
413
  "command_generator.filter_commands_during_force_slot_filling.running_flows_were_updated",
@@ -416,7 +416,7 @@ class CommandGenerator:
416
416
  return [HandleCodeChangeCommand()]
417
417
 
418
418
  stack = tracker.stack
419
- step = get_current_collect_step(stack, available_flows)
419
+ step = get_current_collect_step(stack, flows)
420
420
 
421
421
  if step is None or not step.force_slot_filling:
422
422
  return commands
@@ -64,12 +64,6 @@ from rasa.shared.nlu.constants import COMMANDS
64
64
 
65
65
  structlogger = structlog.get_logger()
66
66
 
67
- CANNOT_HANDLE_REASON = (
68
- "A command generator attempted to set a slot "
69
- "with a value extracted by an extractor "
70
- "that is incompatible with the slot mapping type."
71
- )
72
-
73
67
 
74
68
  def contains_command(commands: List[Command], typ: Type[Command]) -> bool:
75
69
  """Check if a list of commands contains a command of a given type.
@@ -405,7 +399,12 @@ def clean_up_commands(
405
399
  """
406
400
  domain = domain if domain else Domain.empty()
407
401
 
408
- slots_so_far, active_flow = filled_slots_for_active_flow(tracker, all_flows)
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
+ )
409
408
 
410
409
  clean_commands: List[Command] = []
411
410
 
@@ -588,6 +587,11 @@ def clean_up_slot_command(
588
587
  "command_processor.clean_up_slot_command.skip_command_slot_not_in_domain",
589
588
  command=command,
590
589
  )
590
+ resulting_commands.append(
591
+ CannotHandleCommand(
592
+ reason="The slot predicted by the LLM is not defined in the domain."
593
+ )
594
+ )
591
595
  return resulting_commands
592
596
 
593
597
  if not should_slot_be_set(slot, command, resulting_commands):
@@ -606,7 +610,10 @@ def clean_up_slot_command(
606
610
  for command in resulting_commands
607
611
  )
608
612
 
609
- cannot_handle = CannotHandleCommand(reason=CANNOT_HANDLE_REASON)
613
+ cannot_handle = CannotHandleCommand(
614
+ reason="A command generator attempted to set a slot with a value extracted "
615
+ "by an extractor that is incompatible with the slot mapping type."
616
+ )
610
617
  if not slot_command_exists_already and cannot_handle not in resulting_commands:
611
618
  resulting_commands.append(cannot_handle)
612
619
 
@@ -640,9 +647,9 @@ def clean_up_slot_command(
640
647
  resulting_commands.append(command)
641
648
  return resulting_commands
642
649
 
643
- if (slot := tracker.slots.get(command.name)) is not None and slot.value == str(
644
- command.value
645
- ):
650
+ if (slot := tracker.slots.get(command.name)) is not None and str(
651
+ slot.value
652
+ ) == str(command.value):
646
653
  # the slot is already set, we don't need to set it again
647
654
  structlogger.debug(
648
655
  "command_processor.clean_up_slot_command.skip_command_slot_already_set",
@@ -21,7 +21,7 @@ from rasa.shared.core.flows.flow_path import FlowPath, FlowPathsList, PathNode
21
21
  FLOW_NAME_COL_NAME = "Flow Name"
22
22
  NUM_STEPS_COL_NAME = "Num Steps"
23
23
  MISSING_STEPS_COL_NAME = "Missing Steps"
24
- LINE_NUMBERS_COL_NAME = "Line Numbers"
24
+ LINE_NUMBERS_COL_NAME = "Line Numbers for Missing Steps"
25
25
  COVERAGE_COL_NAME = "Coverage"
26
26
 
27
27
  FLOWS_KEY = "flows"
@@ -9,8 +9,8 @@ from rasa.e2e_test.e2e_test_case import ActualStepOutput, TestCase, TestStep, Te
9
9
  from rasa.e2e_test.e2e_test_runner import TEST_TURNS_TYPE, E2ETestRunner
10
10
  from rasa.llm_fine_tuning.conversations import Conversation, ConversationStep
11
11
  from rasa.llm_fine_tuning.storage import StorageContext
12
- from rasa.shared.core.constants import USER
13
- from rasa.shared.core.events import UserUttered
12
+ from rasa.shared.core.constants import BOT, USER
13
+ from rasa.shared.core.events import BotUttered, UserUttered
14
14
  from rasa.shared.core.trackers import DialogueStateTracker
15
15
  from rasa.shared.exceptions import FinetuningDataPreparationException
16
16
  from rasa.shared.nlu.constants import LLM_COMMANDS, LLM_PROMPT
@@ -83,16 +83,18 @@ def generate_conversation(
83
83
  Conversation.
84
84
  """
85
85
  steps = []
86
- tracker_event_indices = [
87
- i for i, event in enumerate(tracker.events) if isinstance(event, UserUttered)
88
- ]
89
-
90
- if len(test_case.steps) != len(tracker_event_indices):
91
- raise FinetuningDataPreparationException(
92
- "Number of test case steps and tracker events do not match."
93
- )
94
86
 
95
87
  if assertions_used:
88
+ tracker_event_indices = [
89
+ i
90
+ for i, event in enumerate(tracker.events)
91
+ if isinstance(event, UserUttered)
92
+ ]
93
+ if len(test_case.steps) != len(tracker_event_indices):
94
+ raise FinetuningDataPreparationException(
95
+ "Number of test case steps and tracker events do not match."
96
+ )
97
+
96
98
  # we only have user steps, extract the bot response from the bot uttered
97
99
  # events of the test turn
98
100
  for i, (original_step, tracker_event_index) in enumerate(
@@ -110,8 +112,30 @@ def generate_conversation(
110
112
  )
111
113
  steps.extend(_create_bot_test_steps(test_turns[i]))
112
114
  else:
115
+ tracker_event_indices = [
116
+ i
117
+ for i, event in enumerate(tracker.events)
118
+ if isinstance(event, UserUttered) or isinstance(event, BotUttered)
119
+ ]
120
+
121
+ # Generally, we expect one or more bot response(s) for each user utterance
122
+ # in the test case, so that we can evaluate the actual bot response.
123
+ # If the test case ends with one or more user utterance(s) instead,
124
+ # we should thus trim those from the test case steps.
125
+ # This only applies to test cases that have at least one bot utterance;
126
+ # otherwise, all test case steps would be removed.
127
+ has_bot_utterance = any(step.actor == BOT for step in test_case.steps)
128
+ i = len(test_case.steps)
129
+ if has_bot_utterance:
130
+ while i > 0 and test_case.steps[i - 1].actor == USER:
131
+ i -= 1
132
+ test_case_steps = test_case.steps[:i]
133
+
134
+ # If the number of test case steps and tracker events differ,
135
+ # using zip ensures we only process pairs that exist in both lists.
136
+ # Prevents index errors and ensures we don't process unmatched steps or events.
113
137
  for i, (original_step, tracker_event_index) in enumerate(
114
- zip(test_case.steps, tracker_event_indices)
138
+ zip(test_case_steps, tracker_event_indices)
115
139
  ):
116
140
  if original_step.actor == USER:
117
141
  previous_turn = _get_previous_actual_step_output(test_turns, i)
@@ -127,6 +151,14 @@ def generate_conversation(
127
151
  else:
128
152
  steps.append(original_step)
129
153
 
154
+ # the tracker should only include events up to the last bot utterance
155
+ # so that the resulting transcript ends with the last bot utterance too
156
+ # only applies to test cases that have at least one bot utterance
157
+ if has_bot_utterance and test_case.steps and test_case.steps[-1].actor == USER:
158
+ event_to_go_to = tracker_event_indices[len(test_case_steps)] - 1
159
+ timestamp = tracker.events[event_to_go_to].timestamp
160
+ tracker = tracker.travel_back_in_time(timestamp)
161
+
130
162
  # Some messages in an e2e test case could be mapped to commands via
131
163
  # 'NLUCommandAdapter', e.g. the message will not be annotated with a prompt and
132
164
  # commands pair. Only convert steps that have a prompt and commands present into a
@@ -181,6 +181,7 @@ class SetSlotExtractor(Enum):
181
181
  # the keys for `State` (USER, PREVIOUS_ACTION, SLOTS, ACTIVE_LOOP)
182
182
  # represent the origin of a `SubState`
183
183
  USER = "user"
184
+ BOT = "bot"
184
185
  SLOTS = "slots"
185
186
 
186
187
  USE_TEXT_FOR_FEATURIZATION = "use_text_for_featurization"
@@ -9,3 +9,5 @@ KEY_FILE_PATH = "file_path"
9
9
  KEY_PERSISTED_SLOTS = "persisted_slots"
10
10
  KEY_RUN_PATTERN_COMPLETED = "run_pattern_completed"
11
11
  KEY_TRANSLATION = "translation"
12
+ KEY_CALLED_FLOW = "called_flow"
13
+ KEY_LINKED_FLOW = "linked_flow"
@@ -4,7 +4,7 @@ import copy
4
4
  from dataclasses import dataclass, field
5
5
  from functools import cached_property
6
6
  from pathlib import Path
7
- from typing import Any, Dict, List, Optional, Set, Text, Union
7
+ from typing import Any, Dict, List, Optional, Set, Text, Tuple, Union
8
8
 
9
9
  import structlog
10
10
  from pydantic import BaseModel
@@ -15,10 +15,12 @@ from rasa.engine.language import Language
15
15
  from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
16
16
  from rasa.shared.core.flows.constants import (
17
17
  KEY_ALWAYS_INCLUDE_IN_PROMPT,
18
+ KEY_CALLED_FLOW,
18
19
  KEY_DESCRIPTION,
19
20
  KEY_FILE_PATH,
20
21
  KEY_ID,
21
22
  KEY_IF,
23
+ KEY_LINKED_FLOW,
22
24
  KEY_NAME,
23
25
  KEY_NLU_TRIGGER,
24
26
  KEY_PERSISTED_SLOTS,
@@ -41,6 +43,7 @@ from rasa.shared.core.flows.steps import (
41
43
  CallFlowStep,
42
44
  CollectInformationFlowStep,
43
45
  EndFlowStep,
46
+ LinkFlowStep,
44
47
  StartFlowStep,
45
48
  )
46
49
  from rasa.shared.core.flows.steps.constants import (
@@ -61,6 +64,8 @@ class FlowLanguageTranslation(BaseModel):
61
64
  """The human-readable name of the flow."""
62
65
 
63
66
  class Config:
67
+ """Configuration for the FlowLanguageTranslation model."""
68
+
64
69
  extra = "ignore"
65
70
 
66
71
 
@@ -232,9 +237,9 @@ class Flow:
232
237
  return translation.name if translation else None
233
238
 
234
239
  def readable_name(self, language: Optional[Language] = None) -> str:
235
- """
236
- Returns the flow's name in the specified language if available; otherwise
237
- falls back to the flow's name, and finally the flow's ID.
240
+ """Returns the flow's name in the specified language if available.
241
+
242
+ Otherwise, falls back to the flow's name, and finally the flow's ID.
238
243
 
239
244
  Args:
240
245
  language: Preferred language code.
@@ -488,6 +493,9 @@ class Flow:
488
493
  current_path: FlowPath,
489
494
  all_paths: FlowPathsList,
490
495
  visited_step_ids: Set[str],
496
+ call_stack: Optional[
497
+ List[Tuple[Optional[FlowStep], Optional[Flow], str]]
498
+ ] = None,
491
499
  ) -> None:
492
500
  """Processes the flow steps recursively.
493
501
 
@@ -496,19 +504,25 @@ class Flow:
496
504
  current_path: The current path being constructed.
497
505
  all_paths: The list where completed paths are added.
498
506
  visited_step_ids: A set of steps that have been visited to avoid cycles.
507
+ call_stack: Tuple list of (flow, path, flow_type) to track path when \
508
+ calling flows through call and link steps.
499
509
 
500
510
  Returns:
501
511
  None: This function modifies all_paths in place by appending new paths
502
512
  as they are found.
503
513
  """
514
+ if call_stack is None:
515
+ call_stack = []
516
+
504
517
  # Check if the step is relevant for testable_paths extraction.
505
- # We only create new path nodes for ActionFlowStep, CallFlowStep and
506
- # CollectInformationFlowStep because these are externally visible
507
- # changes in the assistant's behaviour (trackable in the e2e tests).
518
+ # We only create new path nodes for CollectInformationFlowStep,
519
+ # ActionFlowStep, CallFlowStep and LinkFlowStep,
520
+ # because these are externally visible changes
521
+ # in the assistant's behaviour (trackable in the e2e tests).
508
522
  # For other flow steps, we only follow their links.
509
- # We decided to ignore calls to other flows in our coverage analysis.
510
523
  should_add_node = isinstance(
511
- current_step, (CollectInformationFlowStep, ActionFlowStep, CallFlowStep)
524
+ current_step,
525
+ (CollectInformationFlowStep, ActionFlowStep, CallFlowStep, LinkFlowStep),
512
526
  )
513
527
  if should_add_node:
514
528
  # Add current step to the current path that is being constructed.
@@ -520,10 +534,45 @@ class Flow:
520
534
  )
521
535
  )
522
536
 
537
+ # Check if the current step has already been visited or
538
+ # if the end of the path has been reached.
539
+ # If so, and we’re not within a called flow, we terminate the current path.
540
+ # This also applies for when we're inside a linked flow and reach its end.
541
+ # If we're inside a called flow and reach its end,
542
+ # continue with the next steps in its parent flow.
523
543
  if current_step.id in visited_step_ids or self.is_end_of_path(current_step):
524
- # Found a cycle, or reached an end step, do not proceed further.
525
- all_paths.paths.append(copy.deepcopy(current_path))
526
- # Remove the last node from the path if it was added.
544
+ # Shallow copy is sufficient, since we only pop from the list and
545
+ # don't mutate the objects inside the tuples.
546
+ # The state of FlowStep and Flow does not change during the traversal.
547
+ call_stack_copy = call_stack.copy()
548
+ # parent_flow_type could be any of: None, i.e. main flow,
549
+ # KEY_CALLED_FLOW(=called_flow) or KEY_LINKED_FLOW(=linked_flow)
550
+ parent_step, parent_flow, parent_flow_type = (
551
+ call_stack_copy.pop() if call_stack_copy else (None, None, None)
552
+ )
553
+
554
+ # Check if within a called flow.
555
+ # If within linked flow, stop the traversal as this takes precedence.
556
+ if parent_step and parent_flow_type == KEY_CALLED_FLOW:
557
+ # As we have reached the END step of a called flow, we need to
558
+ # continue with the next links of the parent step.
559
+ if parent_flow is not None:
560
+ for link in parent_step.next.links:
561
+ parent_flow._handle_link(
562
+ current_path,
563
+ all_paths,
564
+ visited_step_ids,
565
+ link,
566
+ call_stack_copy,
567
+ )
568
+
569
+ else:
570
+ # Found a cycle, or reached an end step, do not proceed further.
571
+ all_paths.paths.append(copy.deepcopy(current_path))
572
+
573
+ # Backtrack: remove the last node after reaching a terminal step.
574
+ # Ensures the path is correctly backtracked, after a path ends or
575
+ # a cycle is detected.
527
576
  if should_add_node:
528
577
  current_path.nodes.pop()
529
578
  return
@@ -531,6 +580,62 @@ class Flow:
531
580
  # Mark current step as visited in this path.
532
581
  visited_step_ids.add(current_step.id)
533
582
 
583
+ # If the current step is a call step, we need to resolve the call
584
+ # and continue with the steps of the called flow.
585
+ if isinstance(current_step, CallFlowStep):
586
+ # Get the steps of the called flow and continue with them.
587
+ called_flow = current_step.called_flow_reference
588
+ if called_flow and (
589
+ start_step_in_called_flow := called_flow.first_step_in_flow()
590
+ ):
591
+ call_stack.append((current_step, self, KEY_CALLED_FLOW))
592
+ called_flow._go_over_steps(
593
+ start_step_in_called_flow,
594
+ current_path,
595
+ all_paths,
596
+ visited_step_ids,
597
+ call_stack,
598
+ )
599
+
600
+ # After processing the steps of the called (child) flow,
601
+ # remove them from the visited steps
602
+ # to allow the calling (parent) flow to revisit them later.
603
+ visited_step_ids.remove(current_step.id)
604
+ call_stack.pop()
605
+
606
+ # Backtrack: remove the last node
607
+ # after returning from a called (child) flow.
608
+ # Ensures the parent flow can continue exploring other branches.
609
+ if should_add_node:
610
+ current_path.nodes.pop()
611
+ return
612
+
613
+ # If the current step is a LinkFlowStep, step into the linked flow,
614
+ # process its links, and do not return from that flow anymore.
615
+ if isinstance(current_step, LinkFlowStep):
616
+ # Get the steps of the linked flow and continue with them.
617
+ linked_flow = current_step.linked_flow_reference
618
+ if linked_flow and (
619
+ start_step_in_linked_flow := linked_flow.first_step_in_flow()
620
+ ):
621
+ call_stack.append((current_step, self, KEY_LINKED_FLOW))
622
+ linked_flow._go_over_steps(
623
+ start_step_in_linked_flow,
624
+ current_path,
625
+ all_paths,
626
+ visited_step_ids,
627
+ call_stack,
628
+ )
629
+ visited_step_ids.remove(current_step.id)
630
+ call_stack.pop()
631
+
632
+ # Backtrack: remove the last node
633
+ # after returning from a linked (child) flow.
634
+ # Ensures the parent can continue after the linked flow is processed.
635
+ if should_add_node:
636
+ current_path.nodes.pop()
637
+ return
638
+
534
639
  # Iterate over all links of the current step.
535
640
  for link in current_step.next.links:
536
641
  self._handle_link(
@@ -538,12 +643,15 @@ class Flow:
538
643
  all_paths,
539
644
  visited_step_ids,
540
645
  link,
646
+ call_stack,
541
647
  )
542
648
 
543
649
  # Backtrack the current step and remove it from the path.
544
650
  visited_step_ids.remove(current_step.id)
545
651
 
546
- # Remove the last node from the path if it was added.
652
+ # Backtrack: remove the last node
653
+ # after processing all links of the current step.
654
+ # Ensures the next recursion can start once all links are explored.
547
655
  if should_add_node:
548
656
  current_path.nodes.pop()
549
657
 
@@ -553,6 +661,9 @@ class Flow:
553
661
  all_paths: FlowPathsList,
554
662
  visited_step_ids: Set[str],
555
663
  link: FlowStepLink,
664
+ call_stack: Optional[
665
+ List[Tuple[Optional[FlowStep], Optional[Flow], str]]
666
+ ] = None,
556
667
  ) -> None:
557
668
  """Handles the next step in a flow.
558
669
 
@@ -561,6 +672,8 @@ class Flow:
561
672
  all_paths: The list where completed paths are added.
562
673
  visited_step_ids: A set of steps that have been visited to avoid cycles.
563
674
  link: The link to be followed.
675
+ call_stack: Tuple list of (flow, path, flow_type) to track path when \
676
+ calling flows through call and link steps..
564
677
 
565
678
  Returns:
566
679
  None: This function modifies all_paths in place by appending new paths
@@ -575,6 +688,7 @@ class Flow:
575
688
  current_path,
576
689
  all_paths,
577
690
  visited_step_ids,
691
+ call_stack,
578
692
  )
579
693
  return
580
694
  # IfFlowStepLink and ElseFlowStepLink are conditional links.
@@ -588,6 +702,7 @@ class Flow:
588
702
  current_path,
589
703
  all_paths,
590
704
  visited_step_ids,
705
+ call_stack,
591
706
  )
592
707
  return
593
708
  else:
@@ -598,6 +713,7 @@ class Flow:
598
713
  current_path,
599
714
  all_paths,
600
715
  visited_step_ids,
716
+ call_stack,
601
717
  )
602
718
  return
603
719
 
@@ -36,6 +36,7 @@ class FlowsList:
36
36
  def __post_init__(self) -> None:
37
37
  """Initializes the FlowsList object."""
38
38
  self._resolve_called_flows()
39
+ self._resolve_linked_flows()
39
40
 
40
41
  def __iter__(self) -> Generator[Flow, None, None]:
41
42
  """Iterates over the flows."""
@@ -103,7 +104,10 @@ class FlowsList:
103
104
  )
104
105
 
105
106
  def _resolve_called_flows(self) -> None:
106
- """Resolves the called flows."""
107
+ """Resolves the called flows.
108
+
109
+ `Resolving` here means connecting the step to the actual `Flow` object.
110
+ """
107
111
  from rasa.shared.core.flows.steps import CallFlowStep
108
112
 
109
113
  for flow in self.underlying_flows:
@@ -112,6 +116,19 @@ class FlowsList:
112
116
  # only resolve the reference, if it isn't already resolved
113
117
  step.called_flow_reference = self.flow_by_id(step.call)
114
118
 
119
+ def _resolve_linked_flows(self) -> None:
120
+ """Resolves the linked flows.
121
+
122
+ `Resolving` here means connecting the step to the actual `Flow` object.
123
+ """
124
+ from rasa.shared.core.flows.steps import LinkFlowStep
125
+
126
+ for flow in self.underlying_flows:
127
+ for step in flow.steps:
128
+ if isinstance(step, LinkFlowStep) and not step.linked_flow_reference:
129
+ # only resolve the reference, if it isn't already resolved
130
+ step.linked_flow_reference = self.flow_by_id(step.link)
131
+
115
132
  def as_json_list(self) -> List[Dict[Text, Any]]:
116
133
  """Serialize the FlowsList object to list format and not to the original dict.
117
134
 
@@ -1,9 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import Any, Dict, Text
4
+ from typing import TYPE_CHECKING, Any, Dict, Text
5
5
 
6
- from rasa.shared.core.flows.flow_step import FlowStep
6
+ from rasa.shared.core.flows.flow_step import FlowStep, Optional
7
+
8
+ if TYPE_CHECKING:
9
+ from rasa.shared.core.flows.flow import Flow
7
10
 
8
11
 
9
12
  @dataclass
@@ -12,6 +15,8 @@ class LinkFlowStep(FlowStep):
12
15
 
13
16
  link: Text
14
17
  """The id of the flow that should be started subsequently."""
18
+ linked_flow_reference: Optional["Flow"] = None
19
+ """The flow that is linked to by this step."""
15
20
 
16
21
  def does_allow_for_next_step(self) -> bool:
17
22
  """Returns whether this step allows for following steps.
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.19"
3
+ __version__ = "3.12.25"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rasa-pro
3
- Version: 3.12.19
3
+ Version: 3.12.25
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
@@ -81,7 +81,7 @@ Requires-Dist: portalocker (>=2.7.0,<3.0.0)
81
81
  Requires-Dist: presidio-analyzer (>=2.2.33,<2.2.34)
82
82
  Requires-Dist: presidio-anonymizer (>=2.2.354,<3.0.0)
83
83
  Requires-Dist: prompt-toolkit (>=3.0.28,<3.0.29)
84
- Requires-Dist: protobuf (>=4.23.3,<4.25.4)
84
+ Requires-Dist: protobuf (>=4.25.8,<4.26.0)
85
85
  Requires-Dist: psutil (>=5.9.5,<6.0.0)
86
86
  Requires-Dist: psycopg2-binary (>=2.9.9,<2.10.0)
87
87
  Requires-Dist: pycountry (>=22.3.5,<23.0.0)
@@ -116,7 +116,7 @@ Requires-Dist: scikit-learn (>=1.5.1,<1.6.0)
116
116
  Requires-Dist: scipy (>=1.13.1,<1.14.0)
117
117
  Requires-Dist: sentencepiece[sentencepiece] (>=0.1.99,<0.2.0) ; extra == "transformers" or extra == "full"
118
118
  Requires-Dist: sentry-sdk (>=2.8.0,<3)
119
- Requires-Dist: setuptools (>=78.1.0,<78.2.0)
119
+ Requires-Dist: setuptools (>=78.1.1,<78.2.0)
120
120
  Requires-Dist: sklearn-crfsuite (>=0.3.6,<0.4.0)
121
121
  Requires-Dist: skops (>=0.10.0,<0.11.0)
122
122
  Requires-Dist: slack-sdk (>=3.27.1,<3.28.0)