rasa-pro 3.12.35__py3-none-any.whl → 3.12.37__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 (26) hide show
  1. rasa/core/actions/action_clean_stack.py +32 -0
  2. rasa/core/actions/constants.py +4 -0
  3. rasa/core/actions/custom_action_executor.py +70 -12
  4. rasa/core/actions/grpc_custom_action_executor.py +41 -2
  5. rasa/core/actions/http_custom_action_executor.py +49 -25
  6. rasa/core/channels/voice_stream/voice_channel.py +2 -0
  7. rasa/dialogue_understanding/generator/llm_based_command_generator.py +6 -3
  8. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +18 -8
  9. rasa/dialogue_understanding/processor/command_processor.py +12 -3
  10. rasa/shared/core/flows/flow.py +8 -2
  11. rasa/shared/providers/_configs/azure_openai_client_config.py +4 -5
  12. rasa/shared/providers/_configs/default_litellm_client_config.py +4 -4
  13. rasa/shared/providers/_configs/litellm_router_client_config.py +3 -2
  14. rasa/shared/providers/_configs/openai_client_config.py +5 -7
  15. rasa/shared/providers/_configs/rasa_llm_client_config.py +4 -4
  16. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +4 -4
  17. rasa/shared/providers/llm/_base_litellm_client.py +42 -13
  18. rasa/shared/providers/llm/litellm_router_llm_client.py +38 -15
  19. rasa/shared/providers/llm/self_hosted_llm_client.py +34 -32
  20. rasa/utils/endpoints.py +6 -0
  21. rasa/version.py +1 -1
  22. {rasa_pro-3.12.35.dist-info → rasa_pro-3.12.37.dist-info}/METADATA +4 -4
  23. {rasa_pro-3.12.35.dist-info → rasa_pro-3.12.37.dist-info}/RECORD +26 -26
  24. {rasa_pro-3.12.35.dist-info → rasa_pro-3.12.37.dist-info}/NOTICE +0 -0
  25. {rasa_pro-3.12.35.dist-info → rasa_pro-3.12.37.dist-info}/WHEEL +0 -0
  26. {rasa_pro-3.12.35.dist-info → rasa_pro-3.12.37.dist-info}/entry_points.txt +0 -0
@@ -4,9 +4,11 @@ from typing import Any, Dict, List, Optional
4
4
 
5
5
  import structlog
6
6
 
7
+ import rasa.dialogue_understanding.stack.utils
7
8
  from rasa.core.actions.action import Action
8
9
  from rasa.core.channels import OutputChannel
9
10
  from rasa.core.nlg import NaturalLanguageGenerator
11
+ from rasa.dialogue_understanding.patterns.code_change import FLOW_PATTERN_CODE_CHANGE_ID
10
12
  from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
11
13
  from rasa.dialogue_understanding.stack.frames import (
12
14
  BaseFlowStackFrame,
@@ -41,6 +43,15 @@ class ActionCleanStack(Action):
41
43
  """Clean the stack."""
42
44
  structlogger.debug("action_clean_stack.run")
43
45
  new_frames = []
46
+ top_flow_frame = rasa.dialogue_understanding.stack.utils.top_flow_frame(
47
+ tracker.stack, ignore_call_frames=False
48
+ )
49
+ top_user_flow_frame = (
50
+ rasa.dialogue_understanding.stack.utils.top_user_flow_frame(
51
+ tracker.stack, ignore_call_and_link_frames=False
52
+ )
53
+ )
54
+
44
55
  # Set all frames to their end step, filter out any non-BaseFlowStackFrames
45
56
  for frame in tracker.stack.frames:
46
57
  if isinstance(frame, BaseFlowStackFrame):
@@ -56,4 +67,25 @@ class ActionCleanStack(Action):
56
67
  new_frames.append(frame)
57
68
  new_stack = DialogueStack.from_dict([frame.as_dict() for frame in new_frames])
58
69
 
70
+ # Check if the action is being called from within a user flow
71
+ if (
72
+ top_flow_frame
73
+ and top_flow_frame.flow_id != FLOW_PATTERN_CODE_CHANGE_ID
74
+ and top_user_flow_frame
75
+ and top_user_flow_frame.flow_id == top_flow_frame.flow_id
76
+ ):
77
+ # The action is being called from within a user flow on the stack.
78
+ # If there are other frames on the stack, we need to make sure
79
+ # the last executed frame is the end step of the current user flow so
80
+ # that we can trigger pattern_completed for this user flow.
81
+ new_stack.pop()
82
+ structlogger.debug(
83
+ "action_clean_stack.pushing_user_frame_at_the_bottom_of_stack",
84
+ flow_id=top_user_flow_frame.flow_id,
85
+ )
86
+ new_stack.push(
87
+ top_user_flow_frame,
88
+ index=0,
89
+ )
90
+
59
91
  return tracker.create_stack_updated_events(new_stack)
@@ -3,3 +3,7 @@ SELECTIVE_DOMAIN = "enable_selective_domain"
3
3
 
4
4
  SSL_CLIENT_CERT_FIELD = "ssl_client_cert"
5
5
  SSL_CLIENT_KEY_FIELD = "ssl_client_key"
6
+
7
+ # Special marker key used by EndpointConfig to indicate 449 status
8
+ # without raising an exception
9
+ MISSING_DOMAIN_MARKER = "missing_domain"
@@ -2,7 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import abc
4
4
  import logging
5
- from typing import TYPE_CHECKING, Any, Dict, Text
5
+ from enum import Enum
6
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Text
7
+
8
+ from pydantic import BaseModel
6
9
 
7
10
  import rasa
8
11
  from rasa.core.actions.action_exceptions import DomainNotFound
@@ -19,6 +22,23 @@ if TYPE_CHECKING:
19
22
  logger = logging.getLogger(__name__)
20
23
 
21
24
 
25
+ class ActionResultType(Enum):
26
+ SUCCESS = "success"
27
+ RETRY_WITH_DOMAIN = "retry_with_domain"
28
+
29
+
30
+ class ActionResult(BaseModel):
31
+ """Result of custom action execution.
32
+
33
+ This is used to avoid raising exceptions for expected conditions
34
+ like missing domain (449 status code), which would otherwise be
35
+ captured by tracing as errors.
36
+ """
37
+
38
+ result_type: ActionResultType
39
+ response: Optional[Dict[Text, Any]] = None
40
+
41
+
22
42
  class CustomActionExecutor(abc.ABC):
23
43
  """Interface for custom action executors.
24
44
 
@@ -45,6 +65,34 @@ class CustomActionExecutor(abc.ABC):
45
65
  """
46
66
  pass
47
67
 
68
+ async def run_with_result(
69
+ self,
70
+ tracker: "DialogueStateTracker",
71
+ domain: "Domain",
72
+ include_domain: bool = False,
73
+ ) -> ActionResult:
74
+ """Executes the custom action and returns a result.
75
+
76
+ This method is used to avoid raising exceptions for expected conditions
77
+ like missing domain, which would otherwise be captured by tracing as errors.
78
+
79
+ By default, this method calls the run method and wraps the response
80
+ for backward compatibility.
81
+
82
+ Args:
83
+ tracker: The current state of the dialogue.
84
+ domain: The domain object containing domain-specific information.
85
+ include_domain: If True, the domain is included in the request.
86
+
87
+ Returns:
88
+ ActionResult containing the response and result type.
89
+ """
90
+ try:
91
+ response = await self.run(tracker, domain, include_domain)
92
+ return ActionResult(result_type=ActionResultType.SUCCESS, response=response)
93
+ except DomainNotFound:
94
+ return ActionResult(result_type=ActionResultType.RETRY_WITH_DOMAIN)
95
+
48
96
 
49
97
  class NoEndpointCustomActionExecutor(CustomActionExecutor):
50
98
  """Implementation of a custom action executor when endpoint is not set.
@@ -163,13 +211,13 @@ class RetryCustomActionExecutor(CustomActionExecutor):
163
211
  domain: "Domain",
164
212
  include_domain: bool = False,
165
213
  ) -> Dict[Text, Any]:
166
- """Runs the wrapped custom action executor.
214
+ """Runs the wrapped custom action executor with retry logic.
167
215
 
168
216
  First request to the action server is made with/without the domain
169
217
  as specified by the `include_domain` parameter.
170
218
 
171
- If the action server responds with a `DomainNotFound` error, by running the
172
- custom action executor again with the domain information.
219
+ If the action server responds with a missing domain indication,
220
+ retries the request with the domain included.
173
221
 
174
222
  Args:
175
223
  tracker: The current state of the dialogue.
@@ -178,14 +226,24 @@ class RetryCustomActionExecutor(CustomActionExecutor):
178
226
 
179
227
  Returns:
180
228
  The response from the execution of the custom action.
229
+
230
+ Raises:
231
+ DomainNotFound: If the action server still requires domain after retry.
181
232
  """
182
- try:
183
- return await self._custom_action_executor.run(
184
- tracker,
185
- domain,
186
- include_domain=include_domain,
187
- )
188
- except DomainNotFound:
189
- return await self._custom_action_executor.run(
233
+ result = await self._custom_action_executor.run_with_result(
234
+ tracker,
235
+ domain,
236
+ include_domain=include_domain,
237
+ )
238
+
239
+ if result.result_type == ActionResultType.RETRY_WITH_DOMAIN:
240
+ # Retry with domain included
241
+ result = await self._custom_action_executor.run_with_result(
190
242
  tracker, domain, include_domain=True
191
243
  )
244
+
245
+ # If still missing domain after retry, raise error
246
+ if result.result_type == ActionResultType.RETRY_WITH_DOMAIN:
247
+ raise DomainNotFound()
248
+
249
+ return result.response if result.response is not None else {}
@@ -11,6 +11,8 @@ from rasa_sdk.grpc_py import action_webhook_pb2, action_webhook_pb2_grpc
11
11
  from rasa.core.actions.action_exceptions import DomainNotFound
12
12
  from rasa.core.actions.constants import SSL_CLIENT_CERT_FIELD, SSL_CLIENT_KEY_FIELD
13
13
  from rasa.core.actions.custom_action_executor import (
14
+ ActionResult,
15
+ ActionResultType,
14
16
  CustomActionExecutor,
15
17
  CustomActionRequestWriter,
16
18
  )
@@ -101,13 +103,51 @@ class GRPCCustomActionExecutor(CustomActionExecutor):
101
103
 
102
104
  Returns:
103
105
  Response from the action server.
106
+ Returns empty dict if domain is missing.
107
+
108
+ Raises:
109
+ RasaException: If an error occurs while making the gRPC request
110
+ (other than missing domain).
104
111
  """
112
+ result = await self.run_with_result(tracker, domain, include_domain)
113
+
114
+ # Return empty dict for retry cases to avoid raising exceptions
115
+ # RetryCustomActionExecutor will handle the retry logic
116
+ if result.result_type == ActionResultType.RETRY_WITH_DOMAIN:
117
+ return {}
118
+
119
+ return result.response if result.response is not None else {}
120
+
121
+ async def run_with_result(
122
+ self,
123
+ tracker: "DialogueStateTracker",
124
+ domain: "Domain",
125
+ include_domain: bool = False,
126
+ ) -> ActionResult:
127
+ """Execute the custom action and return an ActionResult.
128
+
129
+ This method avoids raising DomainNotFound exception for missing domain,
130
+ instead returning an ActionResult with RETRY_WITH_DOMAIN type.
131
+ This prevents tracing from capturing this expected condition as an error.
105
132
 
133
+ Args:
134
+ tracker: Tracker for the current conversation.
135
+ domain: Domain of the assistant.
136
+ include_domain: If True, the domain is included in the request.
137
+
138
+ Returns:
139
+ ActionResult containing the response and result type.
140
+ """
106
141
  request = self._create_payload(
107
142
  tracker=tracker, domain=domain, include_domain=include_domain
108
143
  )
109
144
 
110
- return self._request(request)
145
+ try:
146
+ response = self._request(request)
147
+ return ActionResult(result_type=ActionResultType.SUCCESS, response=response)
148
+ except DomainNotFound:
149
+ # Return retry result instead of raising DomainNotFound
150
+ return ActionResult(result_type=ActionResultType.RETRY_WITH_DOMAIN)
111
151
 
112
152
  def _request(
113
153
  self,
@@ -121,7 +161,6 @@ class GRPCCustomActionExecutor(CustomActionExecutor):
121
161
  Returns:
122
162
  Response from the action server.
123
163
  """
124
-
125
164
  client = self._create_grpc_client()
126
165
  metadata = self._build_metadata()
127
166
  try:
@@ -4,8 +4,11 @@ from typing import TYPE_CHECKING, Any, Dict, Optional
4
4
 
5
5
  import aiohttp
6
6
 
7
- from rasa.core.actions.action_exceptions import ActionExecutionRejection, DomainNotFound
7
+ from rasa.core.actions.action_exceptions import ActionExecutionRejection
8
+ from rasa.core.actions.constants import MISSING_DOMAIN_MARKER
8
9
  from rasa.core.actions.custom_action_executor import (
10
+ ActionResult,
11
+ ActionResultType,
9
12
  CustomActionExecutor,
10
13
  CustomActionRequestWriter,
11
14
  )
@@ -18,12 +21,12 @@ from rasa.shared.core.domain import Domain
18
21
  from rasa.shared.core.trackers import DialogueStateTracker
19
22
  from rasa.shared.exceptions import RasaException
20
23
  from rasa.utils.common import get_bool_env_variable
24
+ from rasa.utils.endpoints import ClientResponseError, EndpointConfig
21
25
 
22
26
  if TYPE_CHECKING:
23
27
  from rasa.shared.core.domain import Domain
24
28
  from rasa.shared.core.trackers import DialogueStateTracker
25
29
 
26
- from rasa.utils.endpoints import ClientResponseError, EndpointConfig
27
30
 
28
31
  logger = logging.getLogger(__name__)
29
32
 
@@ -62,9 +65,40 @@ class HTTPCustomActionExecutor(CustomActionExecutor):
62
65
 
63
66
  Returns:
64
67
  A dictionary containing the response from the custom action endpoint.
68
+ Returns empty dict if domain is missing (449 status).
65
69
 
66
70
  Raises:
67
- RasaException: If an error occurs while making the HTTP request.
71
+ RasaException: If an error occurs while making the HTTP request
72
+ (other than missing domain).
73
+ """
74
+ result = await self.run_with_result(tracker, domain, include_domain)
75
+
76
+ # Return empty dict for retry cases to avoid raising exceptions
77
+ # RetryCustomActionExecutor will handle the retry logic
78
+ if result.result_type == ActionResultType.RETRY_WITH_DOMAIN:
79
+ return {}
80
+
81
+ return result.response if result.response is not None else {}
82
+
83
+ async def run_with_result(
84
+ self,
85
+ tracker: "DialogueStateTracker",
86
+ domain: Optional["Domain"] = None,
87
+ include_domain: bool = False,
88
+ ) -> ActionResult:
89
+ """Execute the custom action and return an ActionResult.
90
+
91
+ This method avoids raising DomainNotFound exception for 449 status code,
92
+ instead returning an ActionResult with RETRY_WITH_DOMAIN type.
93
+ This prevents tracing from capturing this expected condition as an error.
94
+
95
+ Args:
96
+ tracker: The current state of the dialogue.
97
+ domain: The domain object containing domain-specific information.
98
+ include_domain: If True, the domain is included in the request.
99
+
100
+ Returns:
101
+ ActionResult containing the response and result type.
68
102
  """
69
103
  from rasa.core.actions.action import RemoteActionJSONValidator
70
104
 
@@ -77,14 +111,23 @@ class HTTPCustomActionExecutor(CustomActionExecutor):
77
111
  tracker=tracker, domain=domain, include_domain=include_domain
78
112
  )
79
113
 
80
- response = await self._perform_request_with_retries(json_body)
114
+ assert self.action_endpoint is not None
115
+ response = await self.action_endpoint.request(
116
+ json=json_body,
117
+ method="post",
118
+ timeout=DEFAULT_REQUEST_TIMEOUT,
119
+ compress=self.should_compress,
120
+ )
121
+
122
+ # Check if we got the special marker for 449 status (missing domain)
123
+ if isinstance(response, dict) and response.get(MISSING_DOMAIN_MARKER):
124
+ return ActionResult(result_type=ActionResultType.RETRY_WITH_DOMAIN)
81
125
 
82
126
  if response is None:
83
127
  response = {}
84
128
 
85
129
  RemoteActionJSONValidator.validate(response)
86
-
87
- return response
130
+ return ActionResult(result_type=ActionResultType.SUCCESS, response=response)
88
131
 
89
132
  except ClientResponseError as e:
90
133
  if e.status == 400:
@@ -131,22 +174,3 @@ class HTTPCustomActionExecutor(CustomActionExecutor):
131
174
  "and returns a 200 once the action is executed. "
132
175
  "Error: {}".format(self.action_name, status, e)
133
176
  )
134
-
135
- async def _perform_request_with_retries(
136
- self,
137
- json_body: Dict[str, Any],
138
- ) -> Any:
139
- """Attempts to perform the request with retries if necessary."""
140
- assert self.action_endpoint is not None
141
- try:
142
- return await self.action_endpoint.request(
143
- json=json_body,
144
- method="post",
145
- timeout=DEFAULT_REQUEST_TIMEOUT,
146
- compress=self.should_compress,
147
- )
148
- except ClientResponseError as e:
149
- # Repeat the request because Domain was not in the payload
150
- if e.status == 449:
151
- raise DomainNotFound()
152
- raise e
@@ -153,6 +153,8 @@ class VoiceOutputChannel(OutputChannel):
153
153
  async def send_start_marker(self, recipient_id: str) -> None:
154
154
  """Send a marker message before the first audio chunk."""
155
155
  # Default implementation uses the generic marker message
156
+ call_state.is_bot_speaking = True # type: ignore[attr-defined]
157
+ VoiceInputChannel._cancel_silence_timeout_watcher()
156
158
  await self.send_marker_message(recipient_id)
157
159
 
158
160
  async def send_intermediate_marker(self, recipient_id: str) -> None:
@@ -60,7 +60,9 @@ structlogger = structlog.get_logger()
60
60
  class LLMBasedCommandGenerator(
61
61
  LLMHealthCheckMixin, GraphComponent, CommandGenerator, ABC
62
62
  ):
63
- """An abstract class defining interface and common functionality
63
+ """This class provides common functionality for all LLM-based command generators.
64
+
65
+ An abstract class defining interface and common functionality
64
66
  of an LLM-based command generators.
65
67
  """
66
68
 
@@ -172,8 +174,9 @@ class LLMBasedCommandGenerator(
172
174
  def train(
173
175
  self, training_data: TrainingData, flows: FlowsList, domain: Domain
174
176
  ) -> Resource:
175
- """Train the llm based command generator. Stores all flows into a vector
176
- store.
177
+ """Trains the LLM-based command generator and prepares flow retrieval data.
178
+
179
+ Stores all flows into a vector store.
177
180
  """
178
181
  self.perform_llm_health_check(
179
182
  self.config.get(LLM_CONFIG_KEY),
@@ -567,7 +567,23 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
567
567
  log_context: Optional[Literal["init", "fingerprint_addon"]] = None,
568
568
  ) -> Optional[str]:
569
569
  """Get the prompt template from the config or the default prompt template."""
570
- # Get the default prompt template based on the model name.
570
+ if prompt_template is not None:
571
+ return prompt_template
572
+
573
+ # Try to load the template from the given path or fallback to the default for
574
+ # the component.
575
+ custom_prompt_template_path = config.get(PROMPT_TEMPLATE_CONFIG_KEY)
576
+ if custom_prompt_template_path is not None:
577
+ custom_prompt_template = get_prompt_template(
578
+ custom_prompt_template_path,
579
+ None, # Default will be based on the model
580
+ log_source_component=CompactLLMCommandGenerator.__name__,
581
+ log_source_method=log_context,
582
+ )
583
+ if custom_prompt_template is not None:
584
+ return custom_prompt_template
585
+
586
+ # Fallback to the default prompt template based on the model.
571
587
  default_command_prompt_template = get_default_prompt_template_based_on_model(
572
588
  llm_config=config.get(LLM_CONFIG_KEY, {}) or {},
573
589
  model_prompt_mapping=MODEL_PROMPT_MAPPER,
@@ -577,10 +593,4 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
577
593
  log_source_method=log_context,
578
594
  )
579
595
 
580
- # Return the prompt template either from the config or the default prompt.
581
- return prompt_template or get_prompt_template(
582
- config.get(PROMPT_TEMPLATE_CONFIG_KEY),
583
- default_command_prompt_template,
584
- log_source_component=CompactLLMCommandGenerator.__name__,
585
- log_source_method=log_context,
586
- )
596
+ return default_command_prompt_template
@@ -477,6 +477,18 @@ def clean_up_commands(
477
477
  else:
478
478
  clean_commands.append(command)
479
479
 
480
+ # ensure that there is only one command of a certain command type
481
+ clean_commands = ensure_max_number_of_command_type(
482
+ clean_commands, CannotHandleCommand, 1
483
+ )
484
+ clean_commands = ensure_max_number_of_command_type(
485
+ clean_commands, RepeatBotMessagesCommand, 1
486
+ )
487
+ clean_commands = ensure_max_number_of_command_type(
488
+ clean_commands, ChitChatAnswerCommand, 1
489
+ )
490
+
491
+ # filter out cannot handle commands if there are other commands present
480
492
  # when coexistence is enabled, by default there will be a SetSlotCommand
481
493
  # for the ROUTE_TO_CALM_SLOT slot.
482
494
  if tracker.has_coexistence_routing_slot and len(clean_commands) > 2:
@@ -484,9 +496,6 @@ def clean_up_commands(
484
496
  elif not tracker.has_coexistence_routing_slot and len(clean_commands) > 1:
485
497
  clean_commands = filter_cannot_handle_command(clean_commands)
486
498
 
487
- clean_commands = ensure_max_number_of_command_type(
488
- clean_commands, RepeatBotMessagesCommand, 1
489
- )
490
499
  structlogger.debug(
491
500
  "command_processor.clean_up_commands.final_commands",
492
501
  command=clean_commands,
@@ -296,9 +296,15 @@ class Flow:
296
296
 
297
297
  def get_collect_steps(self) -> List[CollectInformationFlowStep]:
298
298
  """Return all CollectInformationFlowSteps in the flow."""
299
- collect_steps = []
299
+ collect_steps: List[CollectInformationFlowStep] = []
300
300
  for step in self.steps_with_calls_resolved:
301
- if isinstance(step, CollectInformationFlowStep):
301
+ # Only add collect steps that are not already in the list.
302
+ # This is to avoid returning duplicate collect steps from called flows
303
+ # in case the called flow is called multiple times.
304
+ if (
305
+ isinstance(step, CollectInformationFlowStep)
306
+ and step not in collect_steps
307
+ ):
302
308
  collect_steps.append(step)
303
309
  return collect_steps
304
310
 
@@ -167,8 +167,9 @@ class OAuthConfigWrapper(OAuth, BaseModel):
167
167
 
168
168
  @dataclass
169
169
  class AzureOpenAIClientConfig:
170
- """Parses configuration for Azure OpenAI client, resolves aliases and
171
- raises deprecation warnings.
170
+ """Parses configuration for Azure OpenAI client.
171
+
172
+ Resolves aliases and raises deprecation warnings.
172
173
 
173
174
  Raises:
174
175
  ValueError: Raised in cases of invalid configuration:
@@ -301,9 +302,7 @@ class AzureOpenAIClientConfig:
301
302
 
302
303
 
303
304
  def is_azure_openai_config(config: dict) -> bool:
304
- """Check whether the configuration is meant to configure
305
- an Azure OpenAI client.
306
- """
305
+ """Check whether the configuration is meant to configure an Azure OpenAI client."""
307
306
  # Resolve any aliases that are specific to Azure OpenAI configuration
308
307
  config = AzureOpenAIClientConfig.resolve_config_aliases(config)
309
308
 
@@ -40,8 +40,9 @@ FORBIDDEN_KEYS = [
40
40
 
41
41
  @dataclass
42
42
  class DefaultLiteLLMClientConfig:
43
- """Parses configuration for default LiteLLM client, resolves aliases and
44
- raises deprecation warnings.
43
+ """Parses configuration for default LiteLLM client.
44
+
45
+ Resolves aliases and raises deprecation warnings.
45
46
 
46
47
  Raises:
47
48
  ValueError: Raised in cases of invalid configuration:
@@ -72,8 +73,7 @@ class DefaultLiteLLMClientConfig:
72
73
 
73
74
  @classmethod
74
75
  def from_dict(cls, config: dict) -> DefaultLiteLLMClientConfig:
75
- """
76
- Initializes a dataclass from the passed config.
76
+ """Initializes a dataclass from the passed config.
77
77
 
78
78
  Args:
79
79
  config: (dict) The config from which to initialize.
@@ -38,8 +38,9 @@ _LITELLM_UNSUPPORTED_KEYS = [
38
38
 
39
39
  @dataclass
40
40
  class LiteLLMRouterClientConfig:
41
- """Parses configuration for a LiteLLM Router client. The configuration is expected
42
- to be in the following format:
41
+ """Parses configuration for a LiteLLM Router client.
42
+
43
+ The configuration is expected to be in the following format:
43
44
 
44
45
  {
45
46
  "id": "model_group_id",
@@ -64,8 +64,9 @@ FORBIDDEN_KEYS = [
64
64
 
65
65
  @dataclass
66
66
  class OpenAIClientConfig:
67
- """Parses configuration for Azure OpenAI client, resolves aliases and
68
- raises deprecation warnings.
67
+ """Parses configuration for OpenAI client.
68
+
69
+ Resolves aliases and raises deprecation warnings.
69
70
 
70
71
  Raises:
71
72
  ValueError: Raised in cases of invalid configuration:
@@ -118,8 +119,7 @@ class OpenAIClientConfig:
118
119
 
119
120
  @classmethod
120
121
  def from_dict(cls, config: dict) -> OpenAIClientConfig:
121
- """
122
- Initializes a dataclass from the passed config.
122
+ """Initializes a dataclass from the passed config.
123
123
 
124
124
  Args:
125
125
  config: (dict) The config from which to initialize.
@@ -168,9 +168,7 @@ class OpenAIClientConfig:
168
168
 
169
169
 
170
170
  def is_openai_config(config: dict) -> bool:
171
- """Check whether the configuration is meant to configure
172
- an OpenAI client.
173
- """
171
+ """Check whether the configuration is meant to configure an OpenAI client."""
174
172
  # Process the config to handle all the aliases
175
173
  config = OpenAIClientConfig.resolve_config_aliases(config)
176
174
 
@@ -22,8 +22,9 @@ structlogger = structlog.get_logger()
22
22
 
23
23
  @dataclass
24
24
  class RasaLLMClientConfig:
25
- """Parses configuration for a Rasa Hosted LiteLLM client,
26
- checks required keys present.
25
+ """Parses configuration for a Rasa Hosted LiteLLM client.
26
+
27
+ Checks required keys present.
27
28
 
28
29
  Raises:
29
30
  ValueError: Raised in cases of invalid configuration:
@@ -40,8 +41,7 @@ class RasaLLMClientConfig:
40
41
 
41
42
  @classmethod
42
43
  def from_dict(cls, config: dict) -> RasaLLMClientConfig:
43
- """
44
- Initializes a dataclass from the passed config.
44
+ """Initializes a dataclass from the passed config.
45
45
 
46
46
  Args:
47
47
  config: (dict) The config from which to initialize.
@@ -61,8 +61,9 @@ FORBIDDEN_KEYS = [
61
61
 
62
62
  @dataclass
63
63
  class SelfHostedLLMClientConfig:
64
- """Parses configuration for Self Hosted LiteLLM client, resolves aliases and
65
- raises deprecation warnings.
64
+ """Parses configuration for Self Hosted LiteLLM client.
65
+
66
+ Resolves aliases and raises deprecation warnings.
66
67
 
67
68
  Raises:
68
69
  ValueError: Raised in cases of invalid configuration:
@@ -116,8 +117,7 @@ class SelfHostedLLMClientConfig:
116
117
 
117
118
  @classmethod
118
119
  def from_dict(cls, config: dict) -> SelfHostedLLMClientConfig:
119
- """
120
- Initializes a dataclass from the passed config.
120
+ """Initializes a dataclass from the passed config.
121
121
 
122
122
  Args:
123
123
  config: (dict) The config from which to initialize.
@@ -1,12 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  import logging
4
5
  from abc import abstractmethod
5
- from typing import Any, Dict, List, Union, cast
6
+ from typing import Any, Dict, List, NoReturn, Union, cast
6
7
 
7
8
  import structlog
8
9
  from litellm import acompletion, completion, validate_environment
9
10
 
11
+ from rasa.core.constants import DEFAULT_REQUEST_TIMEOUT
10
12
  from rasa.shared.constants import (
11
13
  _VALIDATE_ENVIRONMENT_MISSING_KEYS_KEY,
12
14
  API_BASE_CONFIG_KEY,
@@ -57,26 +59,24 @@ class _BaseLiteLLMClient:
57
59
  @property
58
60
  @abstractmethod
59
61
  def config(self) -> dict:
60
- """Returns the configuration for that the llm client
61
- in dictionary form.
62
- """
62
+ """Returns the configuration for that the llm client in dictionary form."""
63
63
  pass
64
64
 
65
65
  @property
66
66
  @abstractmethod
67
67
  def _litellm_model_name(self) -> str:
68
- """Returns the value of LiteLLM's model parameter to be used in
69
- completion/acompletion in LiteLLM format:
68
+ """Returns the value of LiteLLM's model parameter.
70
69
 
70
+ To be used in completion/acompletion in LiteLLM format:
71
71
  <provider>/<model or deployment name>
72
72
  """
73
73
  pass
74
74
 
75
75
  @property
76
76
  def _litellm_extra_parameters(self) -> Dict[str, Any]:
77
- """Returns a dictionary of extra parameters which include model
78
- parameters as well as LiteLLM specific input parameters.
77
+ """Returns a dictionary of extra parameters.
79
78
 
79
+ Includes model parameters as well as LiteLLM specific input parameters.
80
80
  By default, this returns an empty dictionary (no extra parameters).
81
81
  """
82
82
  return {}
@@ -96,8 +96,9 @@ class _BaseLiteLLMClient:
96
96
  }
97
97
 
98
98
  def validate_client_setup(self) -> None:
99
- """Perform client validation. By default only environment variables
100
- are validated.
99
+ """Perform client validation.
100
+
101
+ By default only environment variables are validated.
101
102
 
102
103
  Raises:
103
104
  ProviderClientValidationError if validation fails.
@@ -178,8 +179,16 @@ class _BaseLiteLLMClient:
178
179
  try:
179
180
  formatted_messages = self._get_formatted_messages(messages)
180
181
  arguments = resolve_environment_variables(self._completion_fn_args)
181
- response = await acompletion(messages=formatted_messages, **arguments)
182
+ timeout = self._litellm_extra_parameters.get(
183
+ "timeout", DEFAULT_REQUEST_TIMEOUT
184
+ )
185
+ response = await asyncio.wait_for(
186
+ acompletion(messages=formatted_messages, **arguments),
187
+ timeout=timeout,
188
+ )
182
189
  return self._format_response(response)
190
+ except asyncio.TimeoutError:
191
+ self._handle_timeout_error()
183
192
  except Exception as e:
184
193
  message = ""
185
194
  from rasa.shared.providers.llm.self_hosted_llm_client import (
@@ -199,6 +208,25 @@ class _BaseLiteLLMClient:
199
208
  )
200
209
  raise ProviderClientAPIException(e, message)
201
210
 
211
+ def _handle_timeout_error(self) -> NoReturn:
212
+ """Handle asyncio.TimeoutError and raise ProviderClientAPIException.
213
+
214
+ Raises:
215
+ ProviderClientAPIException: Always raised with formatted timeout error.
216
+ """
217
+ timeout = self._litellm_extra_parameters.get("timeout", DEFAULT_REQUEST_TIMEOUT)
218
+ error_message = (
219
+ f"APITimeoutError - Request timed out. Error_str: "
220
+ f"Request timed out. - timeout value={timeout:.6f}, "
221
+ f"time taken={timeout:.6f} seconds"
222
+ )
223
+ # nosemgrep: semgrep.rules.pii-positional-arguments-in-logging
224
+ # Error message contains only numeric timeout values, not PII
225
+ structlogger.error(
226
+ f"{self.__class__.__name__.lower()}.llm.timeout", error=error_message
227
+ )
228
+ raise ProviderClientAPIException(asyncio.TimeoutError(error_message)) from None
229
+
202
230
  def _get_formatted_messages(
203
231
  self, messages: Union[List[dict], List[str], str]
204
232
  ) -> List[Dict[str, str]]:
@@ -280,8 +308,9 @@ class _BaseLiteLLMClient:
280
308
 
281
309
  @staticmethod
282
310
  def _ensure_certificates() -> None:
283
- """Configures SSL certificates for LiteLLM. This method is invoked during
284
- client initialization.
311
+ """Configures SSL certificates for LiteLLM.
312
+
313
+ This method is invoked during client initialization.
285
314
 
286
315
  LiteLLM may utilize `openai` clients or other providers that require
287
316
  SSL verification settings through the `SSL_VERIFY` / `SSL_CERTIFICATE`
@@ -1,10 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  import logging
4
5
  from typing import Any, Dict, List, Union
5
6
 
6
7
  import structlog
7
8
 
9
+ from rasa.core.constants import DEFAULT_REQUEST_TIMEOUT
8
10
  from rasa.shared.exceptions import ProviderClientAPIException
9
11
  from rasa.shared.providers._configs.litellm_router_client_config import (
10
12
  LiteLLMRouterClientConfig,
@@ -79,13 +81,14 @@ class LiteLLMRouterLLMClient(_BaseLiteLLMRouterClient, _BaseLiteLLMClient):
79
81
 
80
82
  @suppress_logs(log_level=logging.WARNING)
81
83
  def _text_completion(self, prompt: Union[List[str], str]) -> LLMResponse:
82
- """
83
- Synchronously generate completions for given prompt.
84
+ """Synchronously generate completions for given prompt.
84
85
 
85
86
  Args:
86
87
  prompt: Prompt to generate the completion for.
88
+
87
89
  Returns:
88
90
  List of message completions.
91
+
89
92
  Raises:
90
93
  ProviderClientAPIException: If the API request fails.
91
94
  """
@@ -103,28 +106,36 @@ class LiteLLMRouterLLMClient(_BaseLiteLLMRouterClient, _BaseLiteLLMClient):
103
106
 
104
107
  @suppress_logs(log_level=logging.WARNING)
105
108
  async def _atext_completion(self, prompt: Union[List[str], str]) -> LLMResponse:
106
- """
107
- Asynchronously generate completions for given prompt.
109
+ """Asynchronously generate completions for given prompt.
108
110
 
109
111
  Args:
110
112
  prompt: Prompt to generate the completion for.
113
+
111
114
  Returns:
112
115
  List of message completions.
116
+
113
117
  Raises:
114
118
  ProviderClientAPIException: If the API request fails.
115
119
  """
116
120
  try:
117
- response = await self.router_client.atext_completion(
118
- prompt=prompt, **self._completion_fn_args
121
+ timeout = self._litellm_extra_parameters.get(
122
+ "timeout", DEFAULT_REQUEST_TIMEOUT
123
+ )
124
+ response = await asyncio.wait_for(
125
+ self.router_client.atext_completion(
126
+ prompt=prompt, **self._completion_fn_args
127
+ ),
128
+ timeout=timeout,
119
129
  )
120
130
  return self._format_text_completion_response(response)
131
+ except asyncio.TimeoutError:
132
+ self._handle_timeout_error()
121
133
  except Exception as e:
122
134
  raise ProviderClientAPIException(e)
123
135
 
124
136
  @suppress_logs(log_level=logging.WARNING)
125
137
  def completion(self, messages: Union[List[dict], List[str], str]) -> LLMResponse:
126
- """
127
- Synchronously generate completions for given list of messages.
138
+ """Synchronously generate completions for given list of messages.
128
139
 
129
140
  Method overrides the base class method to call the appropriate
130
141
  completion method based on the configuration. If the chat completions
@@ -140,8 +151,10 @@ class LiteLLMRouterLLMClient(_BaseLiteLLMRouterClient, _BaseLiteLLMClient):
140
151
  - a list of messages. Each message is a string and will be formatted
141
152
  as a user message.
142
153
  - a single message as a string which will be formatted as user message.
154
+
143
155
  Returns:
144
156
  List of message completions.
157
+
145
158
  Raises:
146
159
  ProviderClientAPIException: If the API request fails.
147
160
  """
@@ -160,8 +173,7 @@ class LiteLLMRouterLLMClient(_BaseLiteLLMRouterClient, _BaseLiteLLMClient):
160
173
  async def acompletion(
161
174
  self, messages: Union[List[dict], List[str], str]
162
175
  ) -> LLMResponse:
163
- """
164
- Asynchronously generate completions for given list of messages.
176
+ """Asynchronously generate completions for given list of messages.
165
177
 
166
178
  Method overrides the base class method to call the appropriate
167
179
  completion method based on the configuration. If the chat completions
@@ -177,8 +189,10 @@ class LiteLLMRouterLLMClient(_BaseLiteLLMRouterClient, _BaseLiteLLMClient):
177
189
  - a list of messages. Each message is a string and will be formatted
178
190
  as a user message.
179
191
  - a single message as a string which will be formatted as user message.
192
+
180
193
  Returns:
181
194
  List of message completions.
195
+
182
196
  Raises:
183
197
  ProviderClientAPIException: If the API request fails.
184
198
  """
@@ -186,19 +200,28 @@ class LiteLLMRouterLLMClient(_BaseLiteLLMRouterClient, _BaseLiteLLMClient):
186
200
  return await self._atext_completion(messages)
187
201
  try:
188
202
  formatted_messages = self._get_formatted_messages(messages)
189
- response = await self.router_client.acompletion(
190
- messages=formatted_messages, **self._completion_fn_args
203
+ timeout = self._litellm_extra_parameters.get(
204
+ "timeout", DEFAULT_REQUEST_TIMEOUT
205
+ )
206
+ response = await asyncio.wait_for(
207
+ self.router_client.acompletion(
208
+ messages=formatted_messages,
209
+ **self._completion_fn_args,
210
+ ),
211
+ timeout=timeout,
191
212
  )
192
213
  return self._format_response(response)
214
+ except asyncio.TimeoutError:
215
+ self._handle_timeout_error()
193
216
  except Exception as e:
194
217
  raise ProviderClientAPIException(e)
195
218
 
196
219
  @property
197
220
  def _completion_fn_args(self) -> Dict[str, Any]:
198
- """Returns the completion arguments for invoking a call through
199
- LiteLLM's completion functions.
200
- """
221
+ """Returns the completion arguments.
201
222
 
223
+ For invoking a call through LiteLLM's completion functions.
224
+ """
202
225
  return {
203
226
  **self._litellm_extra_parameters,
204
227
  LITE_LLM_MODEL_FIELD: self.model_group_id,
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  import logging
4
5
  import os
5
6
  from typing import Any, Dict, List, Optional, Union
@@ -7,6 +8,7 @@ from typing import Any, Dict, List, Optional, Union
7
8
  import structlog
8
9
  from litellm import atext_completion, text_completion
9
10
 
11
+ from rasa.core.constants import DEFAULT_REQUEST_TIMEOUT
10
12
  from rasa.shared.constants import (
11
13
  API_KEY,
12
14
  SELF_HOSTED_VLLM_API_KEY_ENV_VAR,
@@ -28,7 +30,7 @@ structlogger = structlog.get_logger()
28
30
 
29
31
 
30
32
  class SelfHostedLLMClient(_BaseLiteLLMClient):
31
- """A client for interfacing with Self Hosted LLM endpoints that uses
33
+ """A client for interfacing with Self Hosted LLM endpoints.
32
34
 
33
35
  Parameters:
34
36
  model (str): The model or deployment name.
@@ -95,8 +97,7 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
95
97
 
96
98
  @property
97
99
  def provider(self) -> str:
98
- """
99
- Returns the provider name for the self hosted llm client.
100
+ """Returns the provider name for the self hosted llm client.
100
101
 
101
102
  Returns:
102
103
  String representing the provider name.
@@ -105,8 +106,7 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
105
106
 
106
107
  @property
107
108
  def model(self) -> str:
108
- """
109
- Returns the model name for the self hosted llm client.
109
+ """Returns the model name for the self hosted llm client.
110
110
 
111
111
  Returns:
112
112
  String representing the model name.
@@ -115,8 +115,7 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
115
115
 
116
116
  @property
117
117
  def api_base(self) -> str:
118
- """
119
- Returns the base URL for the API endpoint.
118
+ """Returns the base URL for the API endpoint.
120
119
 
121
120
  Returns:
122
121
  String representing the base URL.
@@ -125,8 +124,7 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
125
124
 
126
125
  @property
127
126
  def api_type(self) -> Optional[str]:
128
- """
129
- Returns the type of the API endpoint. Currently only OpenAI is supported.
127
+ """Returns the type of the API endpoint. Currently only OpenAI is supported.
130
128
 
131
129
  Returns:
132
130
  String representing the API type.
@@ -135,8 +133,7 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
135
133
 
136
134
  @property
137
135
  def api_version(self) -> Optional[str]:
138
- """
139
- Returns the version of the API endpoint.
136
+ """Returns the version of the API endpoint.
140
137
 
141
138
  Returns:
142
139
  String representing the API version.
@@ -145,8 +142,8 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
145
142
 
146
143
  @property
147
144
  def config(self) -> Dict:
148
- """
149
- Returns the configuration for the self hosted llm client.
145
+ """Returns the configuration for the self hosted llm client.
146
+
150
147
  Returns:
151
148
  Dictionary containing the configuration.
152
149
  """
@@ -163,9 +160,9 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
163
160
 
164
161
  @property
165
162
  def _litellm_model_name(self) -> str:
166
- """Returns the value of LiteLLM's model parameter to be used in
167
- completion/acompletion in LiteLLM format:
163
+ """Returns the value of LiteLLM's model parameter.
168
164
 
165
+ To be used in completion/acompletion in LiteLLM format:
169
166
  <hosted_vllm>/<model or deployment name>
170
167
  """
171
168
  if self.model and f"{SELF_HOSTED_VLLM_PREFIX}/" not in self.model:
@@ -174,15 +171,17 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
174
171
 
175
172
  @property
176
173
  def _litellm_extra_parameters(self) -> Dict[str, Any]:
177
- """Returns optional configuration parameters specific
178
- to the client provider and deployed model.
174
+ """Returns optional configuration parameters.
175
+
176
+ Specific to the client provider and deployed model.
179
177
  """
180
178
  return self._extra_parameters
181
179
 
182
180
  @property
183
181
  def _completion_fn_args(self) -> Dict[str, Any]:
184
- """Returns the completion arguments for invoking a call through
185
- LiteLLM's completion functions.
182
+ """Returns the completion arguments.
183
+
184
+ For invoking a call through LiteLLM's completion functions.
186
185
  """
187
186
  fn_args = super()._completion_fn_args
188
187
  fn_args.update(
@@ -195,13 +194,14 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
195
194
 
196
195
  @suppress_logs(log_level=logging.WARNING)
197
196
  def _text_completion(self, prompt: Union[List[str], str]) -> LLMResponse:
198
- """
199
- Synchronously generate completions for given prompt.
197
+ """Synchronously generate completions for given prompt.
200
198
 
201
199
  Args:
202
200
  prompt: Prompt to generate the completion for.
201
+
203
202
  Returns:
204
203
  List of message completions.
204
+
205
205
  Raises:
206
206
  ProviderClientAPIException: If the API request fails.
207
207
  """
@@ -213,26 +213,28 @@ class SelfHostedLLMClient(_BaseLiteLLMClient):
213
213
 
214
214
  @suppress_logs(log_level=logging.WARNING)
215
215
  async def _atext_completion(self, prompt: Union[List[str], str]) -> LLMResponse:
216
- """
217
- Asynchronously generate completions for given prompt.
216
+ """Asynchronously generate completions for given prompt.
218
217
 
219
218
  Args:
220
- messages: The message can be,
221
- - a list of preformatted messages. Each message should be a dictionary
222
- with the following keys:
223
- - content: The message content.
224
- - role: The role of the message (e.g. user or system).
225
- - a list of messages. Each message is a string and will be formatted
226
- as a user message.
227
- - a single message as a string which will be formatted as user message.
219
+ prompt: Prompt to generate the completion for.
220
+
228
221
  Returns:
229
222
  List of message completions.
223
+
230
224
  Raises:
231
225
  ProviderClientAPIException: If the API request fails.
232
226
  """
233
227
  try:
234
- response = await atext_completion(prompt=prompt, **self._completion_fn_args)
228
+ timeout = self._litellm_extra_parameters.get(
229
+ "timeout", DEFAULT_REQUEST_TIMEOUT
230
+ )
231
+ response = await asyncio.wait_for(
232
+ atext_completion(prompt=prompt, **self._completion_fn_args),
233
+ timeout=timeout,
234
+ )
235
235
  return self._format_text_completion_response(response)
236
+ except asyncio.TimeoutError:
237
+ self._handle_timeout_error()
236
238
  except Exception as e:
237
239
  raise ProviderClientAPIException(e)
238
240
 
rasa/utils/endpoints.py CHANGED
@@ -8,6 +8,7 @@ import structlog
8
8
  from aiohttp.client_exceptions import ContentTypeError
9
9
  from sanic.request import Request
10
10
 
11
+ from rasa.core.actions.constants import MISSING_DOMAIN_MARKER
11
12
  from rasa.core.constants import DEFAULT_REQUEST_TIMEOUT
12
13
  from rasa.shared.exceptions import FileNotFoundException
13
14
  from rasa.shared.utils.yaml import read_config_file
@@ -207,6 +208,11 @@ class EndpointConfig:
207
208
  ssl=sslcontext,
208
209
  **kwargs,
209
210
  ) as response:
211
+ if response.status == 449:
212
+ # Return a special marker that HTTPCustomActionExecutor can detect
213
+ # This avoids raising an exception for this expected case
214
+ return {MISSING_DOMAIN_MARKER: True}
215
+
210
216
  if response.status >= 400:
211
217
  raise ClientResponseError(
212
218
  response.status,
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.35"
3
+ __version__ = "3.12.37"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rasa-pro
3
- Version: 3.12.35
3
+ Version: 3.12.37
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
@@ -60,8 +60,8 @@ Requires-Dist: jsonpatch (>=1.33,<2.0)
60
60
  Requires-Dist: jsonpickle (>=3.3.0,<3.4)
61
61
  Requires-Dist: jsonschema (>=4.22)
62
62
  Requires-Dist: keras (==2.14.0)
63
- Requires-Dist: langchain (>=0.2.17,<0.3.0)
64
- Requires-Dist: langchain-community (>=0.2.19,<0.3.0)
63
+ Requires-Dist: langchain (>=0.3.27,<0.4.0)
64
+ Requires-Dist: langchain-community (>=0.3.29,<0.4.0)
65
65
  Requires-Dist: langcodes (>=3.5.0,<4.0.0)
66
66
  Requires-Dist: litellm (>=1.69.0,<1.70.0)
67
67
  Requires-Dist: matplotlib (>=3.7,<3.8)
@@ -138,7 +138,7 @@ Requires-Dist: tensorflow_hub (>=0.13.0,<0.14.0)
138
138
  Requires-Dist: terminaltables (>=3.1.10,<3.2.0)
139
139
  Requires-Dist: tiktoken (>=0.7.0,<0.8.0)
140
140
  Requires-Dist: tqdm (>=4.66.2,<5.0.0)
141
- Requires-Dist: transformers (>=4.36.2,<4.37.0) ; extra == "transformers" or extra == "full"
141
+ Requires-Dist: transformers (>=4.38.2,<4.39.0) ; extra == "transformers" or extra == "full"
142
142
  Requires-Dist: twilio (>=8.4,<8.5)
143
143
  Requires-Dist: types-protobuf (==4.25.0.20240417)
144
144
  Requires-Dist: typing-extensions (>=4.7.1,<5.0.0)
@@ -93,7 +93,7 @@ rasa/constants.py,sha256=2a_0Cn-xiJIyZ7ze2N2N59X3CmE8MHVib6B_zIGv_OI,1408
93
93
  rasa/core/__init__.py,sha256=wTSmsFlgK0Ylvuyq20q9APwpT5xyVJYZfzhs4rrkciM,456
94
94
  rasa/core/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
95
  rasa/core/actions/action.py,sha256=gsxIFNgSKeNV2yBaqwR4_K5-cvWCKapcFTeSFo0qA2c,42667
96
- rasa/core/actions/action_clean_stack.py,sha256=xUP-2ipPsPAnAiwP17c-ezmHPSrV4JSUZr-eSgPQwIs,2279
96
+ rasa/core/actions/action_clean_stack.py,sha256=Zs3Pq9za8HamJq3H6IYTXd8dKE-NC0ThSWgdbTNmCFU,3670
97
97
  rasa/core/actions/action_exceptions.py,sha256=hghzXYN6VeHC-O_O7WiPesCNV86ZTkHgG90ZnQcbai8,724
98
98
  rasa/core/actions/action_hangup.py,sha256=o5iklHG-F9IcRgWis5C6AumVXznxzAV3o9zdduhozEM,994
99
99
  rasa/core/actions/action_repeat_bot_messages.py,sha256=T7bJH0fsxFQgbkCZZ5dnPi8v18-2X9QZZLfAHmmn7WI,3466
@@ -101,13 +101,13 @@ rasa/core/actions/action_run_slot_rejections.py,sha256=Rng5h-h5b63HisUeSFZXQ3FnN
101
101
  rasa/core/actions/action_trigger_chitchat.py,sha256=krOPqCXBihxOskqmm05A4mFEm4lj4ohvzuddy7rELVQ,1084
102
102
  rasa/core/actions/action_trigger_flow.py,sha256=IydYAGafTtoY6XSgCX124xJQhzudUg8JAICstqsV3VA,3487
103
103
  rasa/core/actions/action_trigger_search.py,sha256=QfYqnaGRCqRYJ4msYsLAbnVYW5ija_tqhCcKIN8aEfw,1064
104
- rasa/core/actions/constants.py,sha256=gfgdWmj-OJ5xTcTAS1OcXQ3dgcTiHO98NC-SGyKlTjs,161
105
- rasa/core/actions/custom_action_executor.py,sha256=qafASBdM3-hByDqbkNxgXfx5yMSsJh_nB3B7x9ye0TY,6176
104
+ rasa/core/actions/constants.py,sha256=7ek4eYaaDzDudP40pFJ38nU2f-Kh2cnvhEff8mr3jsE,301
105
+ rasa/core/actions/custom_action_executor.py,sha256=mcs8xfZn9lbp5uV2JLhDFC64ivnH5J7ZzpFxaHpJ1jc,8212
106
106
  rasa/core/actions/direct_custom_actions_executor.py,sha256=zGHI3cXVRfyzaaGSH7VePXHQxsDAvF0iAZSEcOuM-_M,4026
107
107
  rasa/core/actions/e2e_stub_custom_action_executor.py,sha256=D-kECC1QjVLv4owNxstW2xJPPsXTGfGepvquMeWB_ec,2282
108
108
  rasa/core/actions/forms.py,sha256=MPGxp3vg-EgFcU5UQYqWM2tycSFIuoF6vWvNSSWPhSA,26967
109
- rasa/core/actions/grpc_custom_action_executor.py,sha256=EDxdSIDA4H4Mu-QZk-pPGV2N41ZsbY8W9laV6l1WlDQ,9103
110
- rasa/core/actions/http_custom_action_executor.py,sha256=oC5OM-p11wHOXXVl7vrTUjhwI6JZh5qCaQpWtl0I0WE,5434
109
+ rasa/core/actions/grpc_custom_action_executor.py,sha256=GMzO_JaocQJjoPZ0yFvBkFHKwhl6SlFZOnt4By-1ZAI,10761
110
+ rasa/core/actions/http_custom_action_executor.py,sha256=GLYxCjoj-GohrVaqxjNtm9npN47kYZfHa06u15ThTBQ,6662
111
111
  rasa/core/actions/loops.py,sha256=3-kt_Sn_Y05PLYoYMsnuIn9e5mxYp31DJIx2omqy0dU,3531
112
112
  rasa/core/actions/two_stage_fallback.py,sha256=k8PkD25fvH3kThG9lpC6oLMK7o15kV4yEbv2E2nyans,6065
113
113
  rasa/core/agent.py,sha256=NX3qqrzi2Qi5isJw5yR7dyN4hIZnhmaV1GoVySX9Omk,20750
@@ -291,7 +291,7 @@ rasa/core/channels/voice_stream/tts/tts_cache.py,sha256=K4S2d8zWX2h2ylYALp7IdqFS
291
291
  rasa/core/channels/voice_stream/tts/tts_engine.py,sha256=JMCWGHxT8QiqKoBeI6F4RX_-Q9EEqG3vUtkgOUnlt-w,1812
292
292
  rasa/core/channels/voice_stream/twilio_media_streams.py,sha256=cM09rwGpbyFD9lCfmWBjHE1XS-F4ufpSbvwJACHpVmI,9094
293
293
  rasa/core/channels/voice_stream/util.py,sha256=d0Tl0tGAnVj3SgGovsUMHx-QL44nrPI29OTYKYleH0U,1987
294
- rasa/core/channels/voice_stream/voice_channel.py,sha256=Eid_leQr2hHyE9EVTD19iQrO2cuYtPkeXI97jFDQWfk,19914
294
+ rasa/core/channels/voice_stream/voice_channel.py,sha256=sR23RYw2czPoDzM__2WfnDqHPIVkVoWesuz7OVqKylI,20046
295
295
  rasa/core/channels/webexteams.py,sha256=z_o_jnc6B7hsHpd6XorImFkF43wB4yx_kiTPKAjPSuo,4805
296
296
  rasa/core/concurrent_lock_store.py,sha256=ycd-aeJJWXIokMRimCdQFHdwuMfl512hZSUHE8oSd2c,7722
297
297
  rasa/core/constants.py,sha256=dEokmEf6XkOFA_xpuwjqwNtlZv-a5Tz5dLMRc7Vu4CU,4070
@@ -400,7 +400,7 @@ rasa/dialogue_understanding/generator/command_parser.py,sha256=wf6FSgqBw5F0legg0
400
400
  rasa/dialogue_understanding/generator/constants.py,sha256=ulqmLIwrBOZLyhsCChI_4CdOnA0I8MfuBxxuKGyFp7U,1130
401
401
  rasa/dialogue_understanding/generator/flow_document_template.jinja2,sha256=f4H6vVd-_nX_RtutMh1xD3ZQE_J2OyuPHAtiltfiAPY,253
402
402
  rasa/dialogue_understanding/generator/flow_retrieval.py,sha256=D-D6bvYt_GDLoRQzhvlTEPnmZI4ceESLJBLWrMgUyrA,18120
403
- rasa/dialogue_understanding/generator/llm_based_command_generator.py,sha256=P1Hwjt8ph2oQQ2PzWaaBRcU36ia4mN21nTzhLtEF5Wc,23586
403
+ rasa/dialogue_understanding/generator/llm_based_command_generator.py,sha256=VHUecm7-alZ8POedNYzQoQWALqRx8VUPXnNVOCfVTOY,23705
404
404
  rasa/dialogue_understanding/generator/llm_command_generator.py,sha256=z7jhIJ3W_5GFH-p15kVoWbigMIoY8fIJjc_j_uX7yxw,2581
405
405
  rasa/dialogue_understanding/generator/multi_step/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
406
406
  rasa/dialogue_understanding/generator/multi_step/fill_slots_prompt.jinja2,sha256=Y0m673tAML3cFPaLM-urMXDsBYUUcXIw9YUpkAhGUuA,2933
@@ -412,7 +412,7 @@ rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.j
412
412
  rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2,sha256=z-cnFVfIE_kEnY1o52YE2CdCWwgYTv7R3xVxsjXWlnw,3808
413
413
  rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2,sha256=4076ARsy0E0iADBX6li19IoM3F4F-2wK3bL6UEOvCdo,3620
414
414
  rasa/dialogue_understanding/generator/single_step/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
415
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py,sha256=Lm688m3m_Z2ZvIrpTQlmxeA2Op-S0ViSPk3wIknyCmM,22413
415
+ rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py,sha256=6ND3gofyw3WIJY2pVDy2gBpa7AZoJLNnCQ6CKBs-H_I,22817
416
416
  rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py,sha256=RWTPdeBfdGUmdFSUzdQejcbJJLhc_815G0g6AabTK04,5100
417
417
  rasa/dialogue_understanding/generator/utils.py,sha256=jxtb-AfngN59y2rHynqJDK80xM_yooEvr3aW1MWl6H0,2760
418
418
  rasa/dialogue_understanding/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -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=At3R1gwYMggfeC-j-YJzYTMLYKXWi2RGh0SMCEx8EXo,33522
439
+ rasa/dialogue_understanding/processor/command_processor.py,sha256=bLjqIMvsjLMFQdghuffsTHzQEw8xkTaTE-BXA3gV2kQ,33889
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
@@ -634,7 +634,7 @@ rasa/shared/core/domain.py,sha256=piJu4Kr2exC9ehC3e2oNaxPxXkeIhOYoQJQQOuzMw18,81
634
634
  rasa/shared/core/events.py,sha256=kTUWSpDepj3kpjjXveYXz3h2XcIQV3Sq8h7MTbx5fMw,86489
635
635
  rasa/shared/core/flows/__init__.py,sha256=Z4pBY0qcEbHeOwgmKsyg2Nz4dX9CF67fFCwj2KXSMpg,180
636
636
  rasa/shared/core/flows/constants.py,sha256=uno5qtsWl8lxELsDe04_5tJH1tBgj6uRRr_g83s10xA,404
637
- rasa/shared/core/flows/flow.py,sha256=7EY_Jlqo21dB7yYNxB0zw1uRUImy0_zZ2bYrwKR8kHk,28382
637
+ rasa/shared/core/flows/flow.py,sha256=Avb7hwO_NUFwnR53Jp4DhHxZA6s3CDcKNtGDSYONwn0,28712
638
638
  rasa/shared/core/flows/flow_path.py,sha256=xstwahZBU5cfMY46mREA4NoOGlKLBRAqeP_mJ3UZqOI,2283
639
639
  rasa/shared/core/flows/flow_step.py,sha256=ZvjXz1Fs5FR1_BlGBitOEYRnLhzk-bBYv1CC2Oi6iWQ,4537
640
640
  rasa/shared/core/flows/flow_step_links.py,sha256=U9c4MFASieJGp_-XMhR0hrxFQISCJAF4TQ0wEy4IjB0,10530
@@ -711,16 +711,16 @@ rasa/shared/nlu/training_data/util.py,sha256=SCd97o6dDhbodasRK3JuaiAA1Xcy0faEMTj
711
711
  rasa/shared/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
712
712
  rasa/shared/providers/_configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
713
713
  rasa/shared/providers/_configs/azure_entra_id_config.py,sha256=MnvWRlCN-nFv5wb8AtFPM1tymCr72jmhI-MQgZZphAs,19392
714
- rasa/shared/providers/_configs/azure_openai_client_config.py,sha256=xUmPM3MRMPdje0q_2MH4FHj77uiMjZ6H2yky37UATUg,10804
714
+ rasa/shared/providers/_configs/azure_openai_client_config.py,sha256=yHG8pEWRKnqC1G7LaSVhOaXqpZc94hGJjw12t73F4b8,10796
715
715
  rasa/shared/providers/_configs/client_config.py,sha256=nQ469h1XI970_7Vs49hNIpBIwlAeiAg-cwV0JFp7Hg0,1618
716
- rasa/shared/providers/_configs/default_litellm_client_config.py,sha256=tViurJ1NDbiBn9b5DbzhFHO1pJM889MC-GakWhEX07E,4352
716
+ rasa/shared/providers/_configs/default_litellm_client_config.py,sha256=FZL8HX-7TxG78nkWoszaHn7Q5cdUrlKI9HprYXZ4A9Y,4344
717
717
  rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py,sha256=q8ddTFwddDhx654ZQmg9eP_yo77N3Xg77hAmfXOmzPg,8200
718
- rasa/shared/providers/_configs/litellm_router_client_config.py,sha256=OX7egiQXkGSYxIfEOFrGFwCIKFJc3IgBKrZGqdjeMVQ,7265
718
+ rasa/shared/providers/_configs/litellm_router_client_config.py,sha256=KsL4XeaOTzAAf3gQq9jouxj05NViB6GoXiYn2A567Vg,7266
719
719
  rasa/shared/providers/_configs/model_group_config.py,sha256=gcvRY86StqCLqAOxLh-2sWEPxMNnwt43vR3QaviElZI,5618
720
720
  rasa/shared/providers/_configs/oauth_config.py,sha256=eMHaXdSwiYqe4LC_UhDPJcrE7tqv3HDc8ghgkhwcYo4,791
721
- rasa/shared/providers/_configs/openai_client_config.py,sha256=NVlm76Ug0LHxEEVqEJeEavCtRYQZBw7NzwgCtvTG1zs,5990
722
- rasa/shared/providers/_configs/rasa_llm_client_config.py,sha256=elpbqVNSgkAiM0Dg-0N3ayVkSi6TAERepdZG7Bv8NdI,2245
723
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py,sha256=l2JnypPXFL6KVxhftKTYvh-NqpXJ8--pjbJ-IQHoPRs,5963
721
+ rasa/shared/providers/_configs/openai_client_config.py,sha256=7LVfZGvbDuFMcBVDCanpYSHq__HO_ndpnDXGyTEP-6Y,5967
722
+ rasa/shared/providers/_configs/rasa_llm_client_config.py,sha256=6pxrhasLwrgbLMPJlMWG8Q0m4EsegIb108BhFugeDu4,2237
723
+ rasa/shared/providers/_configs/self_hosted_llm_client_config.py,sha256=AaoX-_Ik1UVJ-rb_w47wwk8Yb3f70lZS34sAqKzWRtk,5955
724
724
  rasa/shared/providers/_configs/utils.py,sha256=u2Ram05YwQ7-frm_r8n9rafjZoF8i0qSC7XjYQRuPgo,3732
725
725
  rasa/shared/providers/_ssl_verification_utils.py,sha256=vUnP0vocf0GQ0wG8IQpPcCet4c1C9-wQWQNckNWbDBk,4165
726
726
  rasa/shared/providers/_utils.py,sha256=EZIrz3ugcI-9PWgC7v0VMUNYondAAOeeRLIE8ZmResw,5886
@@ -736,15 +736,15 @@ rasa/shared/providers/embedding/huggingface_local_embedding_client.py,sha256=Zo3
736
736
  rasa/shared/providers/embedding/litellm_router_embedding_client.py,sha256=eafDk6IgQtL_kiKgpa6sJs1oATyRi2NT2leUFQsED2s,4551
737
737
  rasa/shared/providers/embedding/openai_embedding_client.py,sha256=XNRGE7apo2v3kWRrtgxE-Gq4rvNko3IiXtvgC4krDYE,5429
738
738
  rasa/shared/providers/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
739
- rasa/shared/providers/llm/_base_litellm_client.py,sha256=Ua5Kt6VGe5vRzSzWWWx2Q3LH2PCDd8V7V4zfYD464yU,11634
739
+ rasa/shared/providers/llm/_base_litellm_client.py,sha256=4vAbQihXHscPHOpxIWvVqhVMyu4f2X-JZDjZGDxiaSY,12872
740
740
  rasa/shared/providers/llm/azure_openai_llm_client.py,sha256=ui85vothxR2P_-eLc4nLgbpjnpEKY2BXnIjLxBZoYz8,12504
741
741
  rasa/shared/providers/llm/default_litellm_llm_client.py,sha256=xx-o-NX_mtx6AszK--ZRj8n8JyEJuVu1-42dt8AynBM,4083
742
- rasa/shared/providers/llm/litellm_router_llm_client.py,sha256=68kQGl5OAhbp39xFlo4YVAx7gn-hJzDBHjNENZeilBQ,7961
742
+ rasa/shared/providers/llm/litellm_router_llm_client.py,sha256=3EzRtWyGYqrBTKP7lFbq1tnzwhCcPJaLPfpzfhsoTnQ,8608
743
743
  rasa/shared/providers/llm/llm_client.py,sha256=-hTCRsL-A3GCMRHtcyCgcCyra-9OJ8GUC-mURoRXH0k,3242
744
744
  rasa/shared/providers/llm/llm_response.py,sha256=8mOpZdmh4-3yM7aOmNO0yEYUmRDErfoP7ZDMUuHr2Cc,3504
745
745
  rasa/shared/providers/llm/openai_llm_client.py,sha256=rSdLj29Hl1Wm5G6Uwo77j4WqogK_3QIbTA7fyt63YAg,5013
746
746
  rasa/shared/providers/llm/rasa_llm_client.py,sha256=44Tvtnkq4mxDIxtdrGUkwBWAvX1OLaswqmpAsyBH8e8,3504
747
- rasa/shared/providers/llm/self_hosted_llm_client.py,sha256=X3QyA5nZbQap0tomg0dQozbY39Ry0y-lLnj-EowK6dI,10270
747
+ rasa/shared/providers/llm/self_hosted_llm_client.py,sha256=aPjRrwXClfcRayFLyq_grSyKrDoUvFQQzLvHELA10vM,10099
748
748
  rasa/shared/providers/mappings.py,sha256=QSD3XWvhYCtBLNpGycN30vEnLULYIaqCsAtmfPfSZ3U,3674
749
749
  rasa/shared/providers/router/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
750
750
  rasa/shared/providers/router/_base_litellm_router_client.py,sha256=JV9lYnhIG_CWMtPB5nofjNdRO5V-Wl0DH-HyPm__eJ0,11003
@@ -791,7 +791,7 @@ rasa/utils/beta.py,sha256=h2xwGagMh2SnpMuqhkEAEjL7C_CyU6b1te7sbtF-lm4,3240
791
791
  rasa/utils/cli.py,sha256=L-DT4nPdVBWfc2m1COHrziLitVWJxazSreb6JLbTho4,865
792
792
  rasa/utils/common.py,sha256=n7SkgvhBVPFmtS4FS7osH9R0dzTgrlzt_4wsohY5rWg,21281
793
793
  rasa/utils/converter.py,sha256=H4LHpoAK7MXMmvNZG_uSn0gbccCJvHtsA2-6Zya4u6M,1656
794
- rasa/utils/endpoints.py,sha256=htalZ5AXvXxNlVeTUgk3LJ-OKzt-dr5GTgRQTyC-0-0,10073
794
+ rasa/utils/endpoints.py,sha256=5JqSUZbN20AlS9lM7KzhRVKwc8Xa17YZlbO1gXVVtig,10401
795
795
  rasa/utils/io.py,sha256=LIAdQQqUPA-V_mdpgeQzPDzA4rmsdZLyVKc8j_0Z70Y,7161
796
796
  rasa/utils/json_utils.py,sha256=SKtJzzsIRCAgNEQiBvWDDm9euMRBgJ-TyvCi2tXHH1w,1689
797
797
  rasa/utils/licensing.py,sha256=f9K2geFK9j1loq6X9t3HGCzRBfxD-Pg7NStWX0lLu4k,20490
@@ -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=sWcVwljFO7WhVbgK0J2_FKAangbLK_IeQpVUDzJm86U,118
826
- rasa_pro-3.12.35.dist-info/METADATA,sha256=ztQPUxfXWp64HcQKD3ppcpX6CsSBy5523ELF5y1mmfY,10609
827
- rasa_pro-3.12.35.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
828
- rasa_pro-3.12.35.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
829
- rasa_pro-3.12.35.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
830
- rasa_pro-3.12.35.dist-info/RECORD,,
825
+ rasa/version.py,sha256=iZ8zfgJNNtWAHrQj41VHNaYqkzPy-7OgLMgEU2siJ8I,118
826
+ rasa_pro-3.12.37.dist-info/METADATA,sha256=pQWqdn9j79NkqnJP843g8EPrrgaQKsIIN2_6-HzAf3I,10609
827
+ rasa_pro-3.12.37.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
828
+ rasa_pro-3.12.37.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
829
+ rasa_pro-3.12.37.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
830
+ rasa_pro-3.12.37.dist-info/RECORD,,