rasa-pro 3.9.18__py3-none-any.whl → 3.10.16__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 (183) hide show
  1. README.md +0 -374
  2. rasa/__init__.py +1 -2
  3. rasa/__main__.py +5 -0
  4. rasa/anonymization/anonymization_rule_executor.py +2 -2
  5. rasa/api.py +27 -23
  6. rasa/cli/arguments/data.py +27 -2
  7. rasa/cli/arguments/default_arguments.py +25 -3
  8. rasa/cli/arguments/run.py +9 -9
  9. rasa/cli/arguments/train.py +11 -3
  10. rasa/cli/data.py +70 -8
  11. rasa/cli/e2e_test.py +104 -431
  12. rasa/cli/evaluate.py +1 -1
  13. rasa/cli/interactive.py +1 -0
  14. rasa/cli/llm_fine_tuning.py +398 -0
  15. rasa/cli/project_templates/calm/endpoints.yml +1 -1
  16. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  17. rasa/cli/run.py +15 -14
  18. rasa/cli/scaffold.py +10 -8
  19. rasa/cli/studio/studio.py +35 -5
  20. rasa/cli/train.py +56 -8
  21. rasa/cli/utils.py +22 -5
  22. rasa/cli/x.py +1 -1
  23. rasa/constants.py +7 -1
  24. rasa/core/actions/action.py +98 -49
  25. rasa/core/actions/action_run_slot_rejections.py +4 -1
  26. rasa/core/actions/custom_action_executor.py +9 -6
  27. rasa/core/actions/direct_custom_actions_executor.py +80 -0
  28. rasa/core/actions/e2e_stub_custom_action_executor.py +68 -0
  29. rasa/core/actions/grpc_custom_action_executor.py +2 -2
  30. rasa/core/actions/http_custom_action_executor.py +6 -5
  31. rasa/core/agent.py +21 -17
  32. rasa/core/channels/__init__.py +2 -0
  33. rasa/core/channels/audiocodes.py +1 -16
  34. rasa/core/channels/voice_aware/__init__.py +0 -0
  35. rasa/core/channels/voice_aware/jambonz.py +103 -0
  36. rasa/core/channels/voice_aware/jambonz_protocol.py +344 -0
  37. rasa/core/channels/voice_aware/utils.py +20 -0
  38. rasa/core/channels/voice_native/__init__.py +0 -0
  39. rasa/core/constants.py +6 -1
  40. rasa/core/information_retrieval/faiss.py +7 -4
  41. rasa/core/information_retrieval/information_retrieval.py +8 -0
  42. rasa/core/information_retrieval/milvus.py +9 -2
  43. rasa/core/information_retrieval/qdrant.py +1 -1
  44. rasa/core/nlg/contextual_response_rephraser.py +32 -10
  45. rasa/core/nlg/summarize.py +4 -3
  46. rasa/core/policies/enterprise_search_policy.py +113 -45
  47. rasa/core/policies/flows/flow_executor.py +122 -76
  48. rasa/core/policies/intentless_policy.py +83 -29
  49. rasa/core/processor.py +72 -54
  50. rasa/core/run.py +5 -4
  51. rasa/core/tracker_store.py +8 -4
  52. rasa/core/training/interactive.py +1 -1
  53. rasa/core/utils.py +56 -57
  54. rasa/dialogue_understanding/coexistence/llm_based_router.py +53 -13
  55. rasa/dialogue_understanding/commands/__init__.py +6 -0
  56. rasa/dialogue_understanding/commands/restart_command.py +58 -0
  57. rasa/dialogue_understanding/commands/session_start_command.py +59 -0
  58. rasa/dialogue_understanding/commands/utils.py +40 -0
  59. rasa/dialogue_understanding/generator/constants.py +10 -3
  60. rasa/dialogue_understanding/generator/flow_retrieval.py +21 -5
  61. rasa/dialogue_understanding/generator/llm_based_command_generator.py +13 -3
  62. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +134 -90
  63. rasa/dialogue_understanding/generator/nlu_command_adapter.py +47 -7
  64. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +127 -41
  65. rasa/dialogue_understanding/patterns/restart.py +37 -0
  66. rasa/dialogue_understanding/patterns/session_start.py +37 -0
  67. rasa/dialogue_understanding/processor/command_processor.py +16 -3
  68. rasa/dialogue_understanding/processor/command_processor_component.py +6 -2
  69. rasa/e2e_test/aggregate_test_stats_calculator.py +134 -0
  70. rasa/e2e_test/assertions.py +1223 -0
  71. rasa/e2e_test/assertions_schema.yml +106 -0
  72. rasa/e2e_test/constants.py +20 -0
  73. rasa/e2e_test/e2e_config.py +220 -0
  74. rasa/e2e_test/e2e_config_schema.yml +26 -0
  75. rasa/e2e_test/e2e_test_case.py +131 -8
  76. rasa/e2e_test/e2e_test_converter.py +363 -0
  77. rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
  78. rasa/e2e_test/e2e_test_coverage_report.py +364 -0
  79. rasa/e2e_test/e2e_test_result.py +26 -6
  80. rasa/e2e_test/e2e_test_runner.py +493 -71
  81. rasa/e2e_test/e2e_test_schema.yml +96 -0
  82. rasa/e2e_test/pykwalify_extensions.py +39 -0
  83. rasa/e2e_test/stub_custom_action.py +70 -0
  84. rasa/e2e_test/utils/__init__.py +0 -0
  85. rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
  86. rasa/e2e_test/utils/io.py +598 -0
  87. rasa/e2e_test/utils/validation.py +80 -0
  88. rasa/engine/graph.py +9 -3
  89. rasa/engine/recipes/default_components.py +0 -2
  90. rasa/engine/recipes/default_recipe.py +10 -2
  91. rasa/engine/storage/local_model_storage.py +40 -12
  92. rasa/engine/validation.py +78 -1
  93. rasa/env.py +9 -0
  94. rasa/graph_components/providers/story_graph_provider.py +59 -6
  95. rasa/llm_fine_tuning/__init__.py +0 -0
  96. rasa/llm_fine_tuning/annotation_module.py +241 -0
  97. rasa/llm_fine_tuning/conversations.py +144 -0
  98. rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
  99. rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
  100. rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
  101. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
  102. rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
  103. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
  104. rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
  105. rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
  106. rasa/llm_fine_tuning/storage.py +174 -0
  107. rasa/llm_fine_tuning/train_test_split_module.py +441 -0
  108. rasa/model_training.py +56 -16
  109. rasa/nlu/persistor.py +157 -36
  110. rasa/server.py +45 -10
  111. rasa/shared/constants.py +76 -16
  112. rasa/shared/core/domain.py +27 -19
  113. rasa/shared/core/events.py +28 -2
  114. rasa/shared/core/flows/flow.py +208 -13
  115. rasa/shared/core/flows/flow_path.py +84 -0
  116. rasa/shared/core/flows/flows_list.py +33 -11
  117. rasa/shared/core/flows/flows_yaml_schema.json +269 -193
  118. rasa/shared/core/flows/validation.py +112 -25
  119. rasa/shared/core/flows/yaml_flows_io.py +149 -10
  120. rasa/shared/core/trackers.py +6 -0
  121. rasa/shared/core/training_data/structures.py +20 -0
  122. rasa/shared/core/training_data/visualization.html +2 -2
  123. rasa/shared/exceptions.py +4 -0
  124. rasa/shared/importers/importer.py +64 -16
  125. rasa/shared/nlu/constants.py +2 -0
  126. rasa/shared/providers/_configs/__init__.py +0 -0
  127. rasa/shared/providers/_configs/azure_openai_client_config.py +183 -0
  128. rasa/shared/providers/_configs/client_config.py +57 -0
  129. rasa/shared/providers/_configs/default_litellm_client_config.py +130 -0
  130. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +234 -0
  131. rasa/shared/providers/_configs/openai_client_config.py +175 -0
  132. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +176 -0
  133. rasa/shared/providers/_configs/utils.py +101 -0
  134. rasa/shared/providers/_ssl_verification_utils.py +124 -0
  135. rasa/shared/providers/embedding/__init__.py +0 -0
  136. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +259 -0
  137. rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
  138. rasa/shared/providers/embedding/azure_openai_embedding_client.py +277 -0
  139. rasa/shared/providers/embedding/default_litellm_embedding_client.py +102 -0
  140. rasa/shared/providers/embedding/embedding_client.py +90 -0
  141. rasa/shared/providers/embedding/embedding_response.py +41 -0
  142. rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
  143. rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
  144. rasa/shared/providers/llm/__init__.py +0 -0
  145. rasa/shared/providers/llm/_base_litellm_client.py +251 -0
  146. rasa/shared/providers/llm/azure_openai_llm_client.py +338 -0
  147. rasa/shared/providers/llm/default_litellm_llm_client.py +84 -0
  148. rasa/shared/providers/llm/llm_client.py +76 -0
  149. rasa/shared/providers/llm/llm_response.py +50 -0
  150. rasa/shared/providers/llm/openai_llm_client.py +155 -0
  151. rasa/shared/providers/llm/self_hosted_llm_client.py +293 -0
  152. rasa/shared/providers/mappings.py +75 -0
  153. rasa/shared/utils/cli.py +30 -0
  154. rasa/shared/utils/io.py +65 -2
  155. rasa/shared/utils/llm.py +246 -200
  156. rasa/shared/utils/yaml.py +121 -15
  157. rasa/studio/auth.py +6 -4
  158. rasa/studio/config.py +13 -4
  159. rasa/studio/constants.py +1 -0
  160. rasa/studio/data_handler.py +10 -3
  161. rasa/studio/download.py +19 -13
  162. rasa/studio/train.py +2 -3
  163. rasa/studio/upload.py +19 -11
  164. rasa/telemetry.py +113 -58
  165. rasa/tracing/instrumentation/attribute_extractors.py +32 -17
  166. rasa/utils/common.py +18 -19
  167. rasa/utils/endpoints.py +7 -4
  168. rasa/utils/json_utils.py +60 -0
  169. rasa/utils/licensing.py +9 -1
  170. rasa/utils/ml_utils.py +4 -2
  171. rasa/validator.py +213 -3
  172. rasa/version.py +1 -1
  173. rasa_pro-3.10.16.dist-info/METADATA +196 -0
  174. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/RECORD +179 -113
  175. rasa/nlu/classifiers/llm_intent_classifier.py +0 -519
  176. rasa/shared/providers/openai/clients.py +0 -43
  177. rasa/shared/providers/openai/session_handler.py +0 -110
  178. rasa_pro-3.9.18.dist-info/METADATA +0 -563
  179. /rasa/{shared/providers/openai → cli/project_templates/tutorial/actions}/__init__.py +0 -0
  180. /rasa/cli/project_templates/tutorial/{actions.py → actions/actions.py} +0 -0
  181. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/NOTICE +0 -0
  182. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/WHEEL +0 -0
  183. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,172 @@
1
+ import os
2
+ from typing import Any, Dict, Optional
3
+
4
+ import structlog
5
+
6
+ from rasa.shared.constants import (
7
+ OPENAI_API_BASE_ENV_VAR,
8
+ OPENAI_API_TYPE_ENV_VAR,
9
+ OPENAI_API_VERSION_ENV_VAR,
10
+ OPENAI_PROVIDER,
11
+ )
12
+ from rasa.shared.providers._configs.openai_client_config import OpenAIClientConfig
13
+ from rasa.shared.providers.embedding._base_litellm_embedding_client import (
14
+ _BaseLiteLLMEmbeddingClient,
15
+ )
16
+
17
+ structlogger = structlog.get_logger()
18
+
19
+
20
+ class OpenAIEmbeddingClient(_BaseLiteLLMEmbeddingClient):
21
+ """A client for interfacing with OpenAI Embeddings.
22
+
23
+ Parameters:
24
+ model (str): The OpenAI model name.
25
+ api_base (Optional[str]): Optional, the base URL for the API endpoints.
26
+ If not provided, it will be set via environment variables.
27
+ api_type (Optional[str]): Optional, the type of the API to use.
28
+ If not provided, it will be set via environment variable.
29
+ api_version (Optional[str]): Optional, the version of the API to use.
30
+ If not provided, it will be set via environment variable.
31
+ kwargs (Optional[Dict[str, Any]]): Optional configuration parameters specific
32
+ to the embedding model deployment.
33
+
34
+ Raises:
35
+ ProviderClientValidationError: If validation of the client setup fails.
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ model: str,
41
+ api_base: Optional[str] = None,
42
+ api_type: Optional[str] = None,
43
+ api_version: Optional[str] = None,
44
+ **kwargs: Any,
45
+ ):
46
+ super().__init__() # type: ignore
47
+ self._model = model
48
+ self._api_base = api_base or os.environ.get(OPENAI_API_BASE_ENV_VAR)
49
+ self._api_type = api_type or os.environ.get(OPENAI_API_TYPE_ENV_VAR)
50
+ self._api_version = api_version or os.environ.get(OPENAI_API_VERSION_ENV_VAR)
51
+ self._extra_parameters = kwargs or {}
52
+ self.validate_client_setup()
53
+
54
+ @classmethod
55
+ def from_config(cls, config: Dict[str, Any]) -> "OpenAIEmbeddingClient":
56
+ """
57
+ Initializes the client from given configuration.
58
+
59
+ Args:
60
+ config (Dict[str, Any]): Configuration.
61
+
62
+ Raises:
63
+ ValueError: Raised in cases of invalid configuration:
64
+ - If any of the required configuration keys are missing.
65
+ - If `api_type` has a value different from `azure`.
66
+
67
+ Returns:
68
+ OpenAIEmbeddingClient: Initialized client.
69
+ """
70
+ try:
71
+ openai_config = OpenAIClientConfig.from_dict(config)
72
+ except ValueError as e:
73
+ message = "Cannot instantiate a client from the passed configuration."
74
+ structlogger.error(
75
+ "openai_embedding_client.from_config.error",
76
+ message=message,
77
+ config=config,
78
+ original_error=e,
79
+ )
80
+ raise
81
+
82
+ return cls(
83
+ model=openai_config.model,
84
+ api_base=openai_config.api_base,
85
+ api_type=openai_config.api_type,
86
+ api_version=openai_config.api_version,
87
+ **openai_config.extra_parameters,
88
+ )
89
+
90
+ @property
91
+ def config(self) -> Dict:
92
+ """
93
+ Returns the configuration for the openai embedding client.
94
+
95
+ Returns:
96
+ Dictionary containing the configuration.
97
+ """
98
+ config = OpenAIClientConfig(
99
+ model=self.model,
100
+ api_base=self.api_base,
101
+ api_type=self.api_type,
102
+ api_version=self.api_version,
103
+ extra_parameters=self._extra_parameters,
104
+ )
105
+ return config.to_dict()
106
+
107
+ @property
108
+ def model(self) -> str:
109
+ """
110
+ Returns the model name for the openai embedding client.
111
+
112
+ Returns:
113
+ String representing the model name.
114
+ """
115
+ return self._model
116
+
117
+ @property
118
+ def api_base(self) -> Optional[str]:
119
+ """
120
+ Returns the base API URL for the openai embedding client.
121
+
122
+ Returns:
123
+ String representing the base API URL.
124
+ """
125
+ return self._api_base
126
+
127
+ @property
128
+ def api_type(self) -> Optional[str]:
129
+ """
130
+ Returns the API type for the openai embedding client.
131
+
132
+ Returns:
133
+ String representing the API version.
134
+ """
135
+ return self._api_type
136
+
137
+ @property
138
+ def api_version(self) -> Optional[str]:
139
+ """
140
+ Returns the API version for the openai embedding client.
141
+
142
+ Returns:
143
+ String representing the API version.
144
+ """
145
+ return self._api_version
146
+
147
+ @property
148
+ def _litellm_extra_parameters(self) -> Dict[str, Any]:
149
+ """
150
+ Returns the model parameters for the openai embedding client.
151
+
152
+ Returns:
153
+ Dictionary containing the model parameters.
154
+ """
155
+ return self._extra_parameters
156
+
157
+ @property
158
+ def _embedding_fn_args(self) -> Dict[str, Any]:
159
+ return {
160
+ "model": self._litellm_model_name,
161
+ "api_base": self.api_base,
162
+ "api_type": self.api_type,
163
+ "api_version": self.api_version,
164
+ **self._litellm_extra_parameters,
165
+ }
166
+
167
+ @property
168
+ def _litellm_model_name(self) -> str:
169
+ """Returns the LiteLLM model name for the openai embedding client."""
170
+ if self._model and f"{OPENAI_PROVIDER}/" not in self._model:
171
+ return f"{OPENAI_PROVIDER}/{self._model}"
172
+ return self._model
File without changes
@@ -0,0 +1,251 @@
1
+ from abc import abstractmethod
2
+ from typing import Dict, List, Any, Union
3
+ import logging
4
+
5
+ import structlog
6
+ from litellm import (
7
+ completion,
8
+ acompletion,
9
+ validate_environment,
10
+ )
11
+
12
+ from rasa.shared.constants import API_BASE_CONFIG_KEY
13
+ from rasa.shared.exceptions import (
14
+ ProviderClientAPIException,
15
+ ProviderClientValidationError,
16
+ )
17
+ from rasa.shared.providers._ssl_verification_utils import (
18
+ ensure_ssl_certificates_for_litellm_non_openai_based_clients,
19
+ ensure_ssl_certificates_for_litellm_openai_based_clients,
20
+ )
21
+ from rasa.shared.providers.llm.llm_response import LLMResponse, LLMUsage
22
+ from rasa.shared.utils.io import suppress_logs
23
+
24
+ structlogger = structlog.get_logger()
25
+
26
+ _VALIDATE_ENVIRONMENT_MISSING_KEYS_KEY = "missing_keys"
27
+
28
+ # Suppress LiteLLM info and debug logs - Global level.
29
+ logging.getLogger("LiteLLM").setLevel(logging.WARNING)
30
+
31
+
32
+ class _BaseLiteLLMClient:
33
+ """An abstract base class for LiteLLM clients.
34
+
35
+ This class defines the interface and common functionality for all clients
36
+ based on LiteLLM.
37
+
38
+ The class is made private to prevent it from being part of the
39
+ public-facing interface, as it serves as an internal base class
40
+ for specific implementations of clients that are currently based on
41
+ LiteLLM.
42
+
43
+ By keeping it private, we ensure that only the derived, concrete
44
+ implementations are exposed to users, maintaining a cleaner and
45
+ more controlled API surface.
46
+ """
47
+
48
+ def __init__(self): # type: ignore
49
+ self._ensure_certificates()
50
+
51
+ @classmethod
52
+ @abstractmethod
53
+ def from_config(cls, config: Dict[str, Any]) -> "_BaseLiteLLMClient":
54
+ pass
55
+
56
+ @property
57
+ @abstractmethod
58
+ def config(self) -> dict:
59
+ """Returns the configuration for that the llm client
60
+ in dictionary form.
61
+ """
62
+ pass
63
+
64
+ @property
65
+ @abstractmethod
66
+ def _litellm_model_name(self) -> str:
67
+ """Returns the value of LiteLLM's model parameter to be used in
68
+ completion/acompletion in LiteLLM format:
69
+
70
+ <provider>/<model or deployment name>
71
+ """
72
+ pass
73
+
74
+ @property
75
+ def _litellm_extra_parameters(self) -> Dict[str, Any]:
76
+ """Returns a dictionary of extra parameters which include model
77
+ parameters as well as LiteLLM specific input parameters.
78
+
79
+ By default, this returns an empty dictionary (no extra parameters).
80
+ """
81
+ return {}
82
+
83
+ @property
84
+ def _completion_fn_args(self) -> dict:
85
+ return {
86
+ **self._litellm_extra_parameters,
87
+ "model": self._litellm_model_name,
88
+ # Since all providers covered by LiteLLM use the OpenAI format, but
89
+ # not all support every OpenAI parameter, raise an exception if
90
+ # provider/model uses unsupported parameter
91
+ "drop_params": False,
92
+ }
93
+
94
+ def validate_client_setup(self) -> None:
95
+ """Perform client validation. By default only environment variables
96
+ are validated.
97
+
98
+ Raises:
99
+ ProviderClientValidationError if validation fails.
100
+ """
101
+ self._validate_environment_variables()
102
+ self._validate_api_key_not_in_config()
103
+
104
+ def _validate_environment_variables(self) -> None:
105
+ """Validate that the required environment variables are set."""
106
+ validation_info = validate_environment(
107
+ self._litellm_model_name,
108
+ api_base=self._litellm_extra_parameters.get(API_BASE_CONFIG_KEY),
109
+ )
110
+ if missing_environment_variables := validation_info.get(
111
+ _VALIDATE_ENVIRONMENT_MISSING_KEYS_KEY
112
+ ):
113
+ event_info = (
114
+ f"Environment variables: {missing_environment_variables} "
115
+ f"not set. Required for API calls."
116
+ )
117
+ structlogger.error(
118
+ "base_litellm_client.validate_environment_variables",
119
+ event_info=event_info,
120
+ missing_environment_variables=missing_environment_variables,
121
+ )
122
+ raise ProviderClientValidationError(event_info)
123
+
124
+ def _validate_api_key_not_in_config(self) -> None:
125
+ if "api_key" in self._litellm_extra_parameters:
126
+ event_info = (
127
+ "API Key is set through `api_key` extra parameter."
128
+ "Set API keys through environment variables."
129
+ )
130
+ structlogger.error(
131
+ "base_litellm_client.validate_api_key_not_in_config",
132
+ event_info=event_info,
133
+ )
134
+ raise ProviderClientValidationError(event_info)
135
+
136
+ @suppress_logs(log_level=logging.WARNING)
137
+ def completion(self, messages: Union[List[str], str]) -> LLMResponse:
138
+ """Synchronously generate completions for given list of messages.
139
+
140
+ Args:
141
+ messages: List of messages or a single message to generate the
142
+ completion for.
143
+
144
+ Returns:
145
+ List of message completions.
146
+
147
+ Raises:
148
+ ProviderClientAPIException: If the API request fails.
149
+ """
150
+ try:
151
+ formatted_messages = self._format_messages(messages)
152
+ response = completion(
153
+ messages=formatted_messages, **self._completion_fn_args
154
+ )
155
+ return self._format_response(response)
156
+ except Exception as e:
157
+ raise ProviderClientAPIException(e)
158
+
159
+ @suppress_logs(log_level=logging.WARNING)
160
+ async def acompletion(self, messages: Union[List[str], str]) -> LLMResponse:
161
+ """Asynchronously generate completions for given list of messages.
162
+
163
+ Args:
164
+ messages: List of messages or a single message to generate the
165
+ completion for.
166
+
167
+ Returns:
168
+ List of message completions.
169
+
170
+ Raises:
171
+ ProviderClientAPIException: If the API request fails.
172
+ """
173
+ try:
174
+ formatted_messages = self._format_messages(messages)
175
+ response = await acompletion(
176
+ messages=formatted_messages, **self._completion_fn_args
177
+ )
178
+ return self._format_response(response)
179
+ except Exception as e:
180
+ message = ""
181
+ from rasa.shared.providers.llm.self_hosted_llm_client import (
182
+ SelfHostedLLMClient,
183
+ )
184
+
185
+ if isinstance(self, SelfHostedLLMClient):
186
+ message = (
187
+ "If you are using 'provider=self-hosted' to call a hosted vllm "
188
+ "server make sure your config is correctly setup. You should have "
189
+ "the following mandatory keys in your config: "
190
+ "provider=self-hosted; "
191
+ "model='<your-vllm-model-name>'; "
192
+ "api_base='your-hosted-vllm-serv'."
193
+ "In case you are getting OpenAI connection errors, such as missing "
194
+ "API key, your configuration is incorrect."
195
+ )
196
+ raise ProviderClientAPIException(e, message)
197
+
198
+ def _format_messages(self, messages: Union[List[str], str]) -> List[Dict[str, str]]:
199
+ """Formats messages (or a single message) to OpenAI format."""
200
+ if isinstance(messages, str):
201
+ messages = [messages]
202
+ return [{"content": message, "role": "user"} for message in messages]
203
+
204
+ def _format_response(self, response: Any) -> LLMResponse:
205
+ """Parses the LiteLLM response to Rasa format."""
206
+ formatted_response = LLMResponse(
207
+ id=response.id,
208
+ created=response.created,
209
+ choices=[choice.message.content for choice in response.choices],
210
+ model=response.model,
211
+ )
212
+ if (
213
+ response.model_extra
214
+ and (usage := response.model_extra.get("usage")) is not None
215
+ ):
216
+ # We use `.get()` for accessing litellm.utils.Usage attributes.
217
+ # litellm.utils.Usage does not set the attributes if
218
+ # `prompt_tokens` or `completion_tokens` are absent (None).
219
+ prompt_tokens = (
220
+ num_tokens
221
+ if isinstance(num_tokens := usage.get("prompt_tokens", 0), (int, float))
222
+ else 0
223
+ )
224
+ completion_tokens = (
225
+ num_tokens
226
+ if isinstance(
227
+ num_tokens := usage.get("completion_tokens", 0), (int, float)
228
+ )
229
+ else 0
230
+ )
231
+ formatted_response.usage = LLMUsage(prompt_tokens, completion_tokens)
232
+ structlogger.debug(
233
+ "base_litellm_client.formatted_response",
234
+ formatted_response=formatted_response.to_dict(),
235
+ )
236
+ return formatted_response
237
+
238
+ @staticmethod
239
+ def _ensure_certificates() -> None:
240
+ """Configures SSL certificates for LiteLLM. This method is invoked during
241
+ client initialization.
242
+
243
+ LiteLLM may utilize `openai` clients or other providers that require
244
+ SSL verification settings through the `SSL_VERIFY` / `SSL_CERTIFICATE`
245
+ environment variables or the `litellm.ssl_verify` /
246
+ `litellm.ssl_certificate` global settings.
247
+
248
+ This method ensures proper SSL configuration for both cases.
249
+ """
250
+ ensure_ssl_certificates_for_litellm_non_openai_based_clients()
251
+ ensure_ssl_certificates_for_litellm_openai_based_clients()