litellm-enterprise 0.1.21__py3-none-any.whl → 0.1.23__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.
@@ -40,7 +40,7 @@ class EnterpriseCallbackControls:
40
40
  #########################################################
41
41
  # premium user check
42
42
  #########################################################
43
- if not EnterpriseCallbackControls._premium_user_check():
43
+ if not EnterpriseCallbackControls._should_allow_dynamic_callback_disabling():
44
44
  return False
45
45
  #########################################################
46
46
  if isinstance(callback, str):
@@ -84,8 +84,15 @@ class EnterpriseCallbackControls:
84
84
  return None
85
85
 
86
86
  @staticmethod
87
- def _premium_user_check():
87
+ def _should_allow_dynamic_callback_disabling():
88
+ import litellm
88
89
  from litellm.proxy.proxy_server import premium_user
90
+
91
+ # Check if admin has disabled this feature
92
+ if litellm.allow_dynamic_callback_disabling is not True:
93
+ verbose_logger.debug("Dynamic callback disabling is disabled by admin via litellm.allow_dynamic_callback_disabling")
94
+ return False
95
+
89
96
  if premium_user:
90
97
  return True
91
98
  verbose_logger.warning(f"Disabling callbacks using request headers is an enterprise feature. {CommonProxyErrors.not_premium_user.value}")
@@ -5,14 +5,10 @@ from litellm_enterprise.enterprise_callbacks.send_emails.endpoints import (
5
5
  )
6
6
 
7
7
  from .audit_logging_endpoints import router as audit_logging_router
8
- from .guardrails.endpoints import router as guardrails_router
9
8
  from .management_endpoints import management_endpoints_router
10
9
  from .utils import _should_block_robots
11
- from .vector_stores.endpoints import router as vector_stores_router
12
10
 
13
11
  router = APIRouter()
14
- router.include_router(vector_stores_router)
15
- router.include_router(guardrails_router)
16
12
  router.include_router(email_events_router)
17
13
  router.include_router(audit_logging_router)
18
14
  router.include_router(management_endpoints_router)
@@ -296,6 +296,16 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
296
296
  file_ids, user_api_key_dict.parent_otel_span
297
297
  )
298
298
 
299
+ data["model_file_id_mapping"] = model_file_id_mapping
300
+ elif call_type == CallTypes.aresponses.value or call_type == CallTypes.responses.value:
301
+ # Handle managed files in responses API input
302
+ input_data = data.get("input")
303
+ if input_data:
304
+ file_ids = self.get_file_ids_from_responses_input(input_data)
305
+ if file_ids:
306
+ model_file_id_mapping = await self.get_model_file_id_mapping(
307
+ file_ids, user_api_key_dict.parent_otel_span
308
+ )
299
309
  data["model_file_id_mapping"] = model_file_id_mapping
300
310
  elif call_type == CallTypes.afile_content.value:
301
311
  retrieve_file_id = cast(Optional[str], data.get("file_id"))
@@ -453,6 +463,47 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
453
463
  file_ids.append(file_id)
454
464
  return file_ids
455
465
 
466
+ def get_file_ids_from_responses_input(
467
+ self, input: Union[str, List[Dict[str, Any]]]
468
+ ) -> List[str]:
469
+ """
470
+ Gets file ids from responses API input.
471
+
472
+ The input can be:
473
+ - A string (no files)
474
+ - A list of input items, where each item can have:
475
+ - type: "input_file" with file_id
476
+ - content: a list that can contain items with type: "input_file" and file_id
477
+ """
478
+ file_ids: List[str] = []
479
+
480
+ if isinstance(input, str):
481
+ return file_ids
482
+
483
+ if not isinstance(input, list):
484
+ return file_ids
485
+
486
+ for item in input:
487
+ if not isinstance(item, dict):
488
+ continue
489
+
490
+ # Check for direct input_file type
491
+ if item.get("type") == "input_file":
492
+ file_id = item.get("file_id")
493
+ if file_id:
494
+ file_ids.append(file_id)
495
+
496
+ # Check for input_file in content array
497
+ content = item.get("content")
498
+ if isinstance(content, list):
499
+ for content_item in content:
500
+ if isinstance(content_item, dict) and content_item.get("type") == "input_file":
501
+ file_id = content_item.get("file_id")
502
+ if file_id:
503
+ file_ids.append(file_id)
504
+
505
+ return file_ids
506
+
456
507
  async def get_model_file_id_mapping(
457
508
  self, file_ids: List[str], litellm_parent_otel_span: Span
458
509
  ) -> dict:
@@ -478,7 +529,6 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
478
529
  for file_id in file_ids:
479
530
  ## CHECK IF FILE ID IS MANAGED BY LITELM
480
531
  is_base64_unified_file_id = _is_base64_encoded_unified_file_id(file_id)
481
-
482
532
  if is_base64_unified_file_id:
483
533
  litellm_managed_file_ids.append(file_id)
484
534
 
@@ -489,6 +539,7 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
489
539
  unified_file_object = await self.get_unified_file_id(
490
540
  file_id, litellm_parent_otel_span
491
541
  )
542
+
492
543
  if unified_file_object:
493
544
  file_id_mapping[file_id] = unified_file_object.model_mappings
494
545
 
@@ -764,18 +815,21 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
764
815
  llm_router: Router,
765
816
  **data: Dict,
766
817
  ) -> OpenAIFileObject:
767
- file_id = convert_b64_uid_to_unified_uid(file_id)
818
+
819
+ # file_id = convert_b64_uid_to_unified_uid(file_id)
768
820
  model_file_id_mapping = await self.get_model_file_id_mapping(
769
821
  [file_id], litellm_parent_otel_span
770
822
  )
823
+
771
824
  specific_model_file_id_mapping = model_file_id_mapping.get(file_id)
772
825
  if specific_model_file_id_mapping:
773
- for model_id, file_id in specific_model_file_id_mapping.items():
774
- await llm_router.afile_delete(model=model_id, file_id=file_id, **data) # type: ignore
826
+ for model_id, model_file_id in specific_model_file_id_mapping.items():
827
+ await llm_router.afile_delete(model=model_id, file_id=model_file_id, **data) # type: ignore
775
828
 
776
829
  stored_file_object = await self.delete_unified_file_id(
777
830
  file_id, litellm_parent_otel_span
778
831
  )
832
+
779
833
  if stored_file_object:
780
834
  return stored_file_object
781
835
  else:
@@ -796,6 +850,7 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
796
850
  model_file_id_mapping
797
851
  or await self.get_model_file_id_mapping([file_id], litellm_parent_otel_span)
798
852
  )
853
+
799
854
  specific_model_file_id_mapping = model_file_id_mapping.get(file_id)
800
855
 
801
856
  if specific_model_file_id_mapping:
@@ -141,28 +141,36 @@ async def list_vector_stores(
141
141
  """
142
142
  from litellm.proxy.proxy_server import prisma_client
143
143
 
144
- seen_vector_store_ids = set()
145
-
146
144
  try:
147
- # Get in-memory vector stores
148
- in_memory_vector_stores: List[LiteLLM_ManagedVectorStore] = []
149
- if litellm.vector_store_registry is not None:
150
- in_memory_vector_stores = copy.deepcopy(
151
- litellm.vector_store_registry.vector_stores
152
- )
153
-
154
- # Get vector stores from database
145
+ # Get vector stores from database (source of truth)
146
+ # Only return what's in the database to ensure consistency across instances
155
147
  vector_stores_from_db = await VectorStoreRegistry._get_vector_stores_from_db(
156
148
  prisma_client=prisma_client
157
149
  )
150
+
151
+ # Also clean up in-memory registry to remove any deleted vector stores
152
+ if litellm.vector_store_registry is not None:
153
+ db_vector_store_ids = {
154
+ vs.get("vector_store_id")
155
+ for vs in vector_stores_from_db
156
+ if vs.get("vector_store_id")
157
+ }
158
+ # Remove any in-memory vector stores that no longer exist in database
159
+ vector_stores_to_remove = []
160
+ for vs in litellm.vector_store_registry.vector_stores:
161
+ vs_id = vs.get("vector_store_id")
162
+ if vs_id and vs_id not in db_vector_store_ids:
163
+ vector_stores_to_remove.append(vs_id)
164
+ for vs_id in vector_stores_to_remove:
165
+ litellm.vector_store_registry.delete_vector_store_from_registry(
166
+ vector_store_id=vs_id
167
+ )
168
+ verbose_proxy_logger.debug(
169
+ f"Removed deleted vector store {vs_id} from in-memory registry"
170
+ )
158
171
 
159
- # Combine in-memory and database vector stores
160
- combined_vector_stores: List[LiteLLM_ManagedVectorStore] = []
161
- for vector_store in in_memory_vector_stores + vector_stores_from_db:
162
- vector_store_id = vector_store.get("vector_store_id", None)
163
- if vector_store_id not in seen_vector_store_ids:
164
- combined_vector_stores.append(vector_store)
165
- seen_vector_store_ids.add(vector_store_id)
172
+ # Use database as single source of truth for listing
173
+ combined_vector_stores: List[LiteLLM_ManagedVectorStore] = vector_stores_from_db
166
174
 
167
175
  total_count = len(combined_vector_stores)
168
176
  total_pages = (total_count + page_size - 1) // page_size
@@ -1,7 +1,8 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: litellm-enterprise
3
- Version: 0.1.21
3
+ Version: 0.1.23
4
4
  Summary: Package for LiteLLM Enterprise features
5
+ License-File: LICENSE.md
5
6
  Author: BerriAI
6
7
  Requires-Python: >=3.8, !=2.7.*, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*
7
8
  Classifier: Programming Language :: Python :: 3
@@ -9,6 +10,8 @@ Classifier: Programming Language :: Python :: 3.9
9
10
  Classifier: Programming Language :: Python :: 3.10
10
11
  Classifier: Programming Language :: Python :: 3.11
11
12
  Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
12
15
  Project-URL: Documentation, https://docs.litellm.ai
13
16
  Project-URL: Homepage, https://litellm.ai
14
17
  Project-URL: Repository, https://github.com/BerriAI/litellm
@@ -1,12 +1,6 @@
1
1
  litellm_enterprise/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- litellm_enterprise/enterprise_callbacks/.pytest_cache/.gitignore,sha256=Ptcxtl0GFQwTji2tsL4Gl1UIiKa0frjEXsya26i46b0,37
3
- litellm_enterprise/enterprise_callbacks/.pytest_cache/CACHEDIR.TAG,sha256=N9yI75oKvt2-gQU6bdj9-xOvthMEXqHrSlyBWnSjveQ,191
4
- litellm_enterprise/enterprise_callbacks/.pytest_cache/README.md,sha256=c_1vzN2ALEGaay2YPWwxc7fal1WKxLWJ7ewt_kQ9ua0,302
5
- litellm_enterprise/enterprise_callbacks/.pytest_cache/v/cache/nodeids,sha256=T1PNoYwrqgwDVLtfmj7L5e0Sq02OEbqHPC8RFhICuUU,2
6
- litellm_enterprise/enterprise_callbacks/.pytest_cache/v/cache/stepwise,sha256=T1PNoYwrqgwDVLtfmj7L5e0Sq02OEbqHPC8RFhICuUU,2
7
- litellm_enterprise/enterprise_callbacks/callback_controls.py,sha256=BhUOHoqR5u8ANaSweKnzgw96Zqu7Eh4mXXUfYQH9Xe4,4756
2
+ litellm_enterprise/enterprise_callbacks/callback_controls.py,sha256=06zuuXEmkhHaVr4Mpc9DbBRpgZoHs7JDxvYv1fQxtQU,5101
8
3
  litellm_enterprise/enterprise_callbacks/example_logging_api.py,sha256=06CM6wa5CC7Mal3Gm-P6m6tJuikbcg5BJ9-kzfpl_Y4,776
9
- litellm_enterprise/enterprise_callbacks/generic_api_callback.py,sha256=8x_ghfAvG72A4wrzeWcz5PVo6DhMPQjKUmrwsb-tuig,9180
10
4
  litellm_enterprise/enterprise_callbacks/llama_guard.py,sha256=9GSYTujO2bI6jWmtpTYz1UcOpJfBNSuAVWrl4rJIXO0,4839
11
5
  litellm_enterprise/enterprise_callbacks/llm_guard.py,sha256=AXqlcct74S7N6DHAxYbh6icrsQ-7umIyOkOuZAmXD-w,6453
12
6
  litellm_enterprise/enterprise_callbacks/pagerduty/pagerduty.py,sha256=40UI8RjRZ-lfoCyCITipHHK6CmYR5iOI27F48cvc-xk,12400
@@ -117,19 +111,19 @@ litellm_enterprise/proxy/auth/custom_sso_handler.py,sha256=ITML9dRKL-LuJhU3WKKVP
117
111
  litellm_enterprise/proxy/auth/route_checks.py,sha256=FbXwbrOkFr1dODH6XxoIpLG1nKowC7kyNaRR0WR6ujU,2490
118
112
  litellm_enterprise/proxy/auth/user_api_key_auth.py,sha256=7t5Q-JoKFyoymylaOT8KWAAOFVz0JOTl7PPOmTkpj5c,1144
119
113
  litellm_enterprise/proxy/common_utils/check_batch_cost.py,sha256=V0CCHtN-JV-_d-ydXV-cVs3zCImt1699JnICGF3oPOk,7360
120
- litellm_enterprise/proxy/enterprise_routes.py,sha256=TkFeQa6mtVIvEhTP7X5dcSDKTOks0hG_dWrL1_oCU4w,1122
121
- litellm_enterprise/proxy/hooks/managed_files.py,sha256=E5yY9qza6HzcOtAI_9zgHLV_F-dz8VpOM3KoEhGKp2E,32195
114
+ litellm_enterprise/proxy/enterprise_routes.py,sha256=ToJVSSNaYUotzgIg-kWsfsqh2E0GnQirOPkpE4YkHNg,907
115
+ litellm_enterprise/proxy/hooks/managed_files.py,sha256=n8_HsBFr7YmiJqTHMISTlJNo_3TxZ9AEwk0Bxcpa4_k,34228
122
116
  litellm_enterprise/proxy/management_endpoints/__init__.py,sha256=zfaqryxzmFu6se-w4yR2nlHKxDOOtHAWEehA2xFbFNg,270
123
117
  litellm_enterprise/proxy/management_endpoints/internal_user_endpoints.py,sha256=GEoOVujrtKXDHfko2KQaLn-ms64zkutFE9PP5IhBBLM,2175
124
118
  litellm_enterprise/proxy/management_endpoints/key_management_endpoints.py,sha256=-IXRzVrNQ3_krL-gxngelYQftwyPlB_HmgI3RN-HdvM,1147
125
119
  litellm_enterprise/proxy/proxy_server.py,sha256=fzOeTyiyevLWi2767-2W1Co7reR-0wnoUIhOgVlJFQc,1183
126
120
  litellm_enterprise/proxy/readme.md,sha256=ZcigMJYSHWs4SWnYriWjrSVDJKsu44c2HsbYbma0EHU,397
127
121
  litellm_enterprise/proxy/utils.py,sha256=y4ADfhlEG_mH0x5rfIg7D9FjS586lVgQ9DL0tTdgrMQ,962
128
- litellm_enterprise/proxy/vector_stores/endpoints.py,sha256=AkP503_JQY0DCFk_kPVYh7xSqSBabVBIphjRiAA0GvA,12445
122
+ litellm_enterprise/proxy/vector_stores/endpoints.py,sha256=6Guh6zIH00dh2XXStn6GblTGpGyE4hZJ9WThVZggDQg,12944
129
123
  litellm_enterprise/types/enterprise_callbacks/send_emails.py,sha256=XLhpdGvBFxPkV7hcgQ1gELVF0vTs5d2LLOoXPzjr4K4,1929
130
124
  litellm_enterprise/types/proxy/audit_logging_endpoints.py,sha256=oSJVAuRD9r6ZjRCqNBFM-J5HSgOltsXts400b2aynRE,894
131
125
  litellm_enterprise/types/proxy/proxy_server.py,sha256=kdhtxsU2uok6-XO_ebugCv7PzYYmGgv4vh-XemHJnpM,146
132
- litellm_enterprise-0.1.21.dist-info/LICENSE.md,sha256=nq3D9ZqOvRDT6hLkypQFTc3XsE15kbkg5rkkLJVSqKY,2251
133
- litellm_enterprise-0.1.21.dist-info/METADATA,sha256=frIz5pheYia1kG7hBurrsgEvN--feEe46C3V4o0_ru8,1314
134
- litellm_enterprise-0.1.21.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
135
- litellm_enterprise-0.1.21.dist-info/RECORD,,
126
+ litellm_enterprise-0.1.23.dist-info/METADATA,sha256=diEqEOTj7rCVk-AVP3ns6m7_dJgjz4NXNyWpUmj6XQ4,1441
127
+ litellm_enterprise-0.1.23.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
128
+ litellm_enterprise-0.1.23.dist-info/licenses/LICENSE.md,sha256=nq3D9ZqOvRDT6hLkypQFTc3XsE15kbkg5rkkLJVSqKY,2251
129
+ litellm_enterprise-0.1.23.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,2 +0,0 @@
1
- # Created by pytest automatically.
2
- *
@@ -1,4 +0,0 @@
1
- Signature: 8a477f597d28d172789f06886806bc55
2
- # This file is a cache directory tag created by pytest.
3
- # For information about cache directory tags, see:
4
- # https://bford.info/cachedir/spec.html
@@ -1,8 +0,0 @@
1
- # pytest cache directory #
2
-
3
- This directory contains data from the pytest's cache plugin,
4
- which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
5
-
6
- **Do not** commit this to version control.
7
-
8
- See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information.
@@ -1,266 +0,0 @@
1
- """
2
- Callback to log events to a Generic API Endpoint
3
-
4
- - Creates a StandardLoggingPayload
5
- - Adds to batch queue
6
- - Flushes based on CustomBatchLogger settings
7
- """
8
-
9
- import asyncio
10
- import os
11
- import traceback
12
- from litellm._uuid import uuid
13
- from typing import Dict, List, Optional, Union
14
-
15
- import litellm
16
- from litellm._logging import verbose_logger
17
- from litellm.integrations.custom_batch_logger import CustomBatchLogger
18
- from litellm.litellm_core_utils.safe_json_dumps import safe_dumps
19
- from litellm.llms.custom_httpx.http_handler import (
20
- get_async_httpx_client,
21
- httpxSpecialProvider,
22
- )
23
- from litellm.types.utils import StandardLoggingPayload
24
-
25
-
26
- class GenericAPILogger(CustomBatchLogger):
27
- def __init__(
28
- self,
29
- endpoint: Optional[str] = None,
30
- headers: Optional[dict] = None,
31
- **kwargs,
32
- ):
33
- """
34
- Initialize the GenericAPILogger
35
-
36
- Args:
37
- endpoint: Optional[str] = None,
38
- headers: Optional[dict] = None,
39
- """
40
- #########################################################
41
- # Init httpx client
42
- #########################################################
43
- self.async_httpx_client = get_async_httpx_client(
44
- llm_provider=httpxSpecialProvider.LoggingCallback
45
- )
46
- endpoint = endpoint or os.getenv("GENERIC_LOGGER_ENDPOINT")
47
- if endpoint is None:
48
- raise ValueError(
49
- "endpoint not set for GenericAPILogger, GENERIC_LOGGER_ENDPOINT not found in environment variables"
50
- )
51
-
52
- self.headers: Dict = self._get_headers(headers)
53
- self.endpoint: str = endpoint
54
- verbose_logger.debug(
55
- f"in init GenericAPILogger, endpoint {self.endpoint}, headers {self.headers}"
56
- )
57
-
58
- #########################################################
59
- # Init variables for batch flushing logs
60
- #########################################################
61
- self.flush_lock = asyncio.Lock()
62
- super().__init__(**kwargs, flush_lock=self.flush_lock)
63
- asyncio.create_task(self.periodic_flush())
64
- self.log_queue: List[Union[Dict, StandardLoggingPayload]] = []
65
-
66
- def _get_headers(self, headers: Optional[dict] = None):
67
- """
68
- Get headers for the Generic API Logger
69
-
70
- Returns:
71
- Dict: Headers for the Generic API Logger
72
-
73
- Args:
74
- headers: Optional[dict] = None
75
- """
76
- # Process headers from different sources
77
- headers_dict = {
78
- "Content-Type": "application/json",
79
- }
80
-
81
- # 1. First check for headers from env var
82
- env_headers = os.getenv("GENERIC_LOGGER_HEADERS")
83
- if env_headers:
84
- try:
85
- # Parse headers in format "key1=value1,key2=value2" or "key1=value1"
86
- header_items = env_headers.split(",")
87
- for item in header_items:
88
- if "=" in item:
89
- key, value = item.split("=", 1)
90
- headers_dict[key.strip()] = value.strip()
91
- except Exception as e:
92
- verbose_logger.warning(
93
- f"Error parsing headers from environment variables: {str(e)}"
94
- )
95
-
96
- # 2. Update with litellm generic headers if available
97
- if litellm.generic_logger_headers:
98
- headers_dict.update(litellm.generic_logger_headers)
99
-
100
- # 3. Override with directly provided headers if any
101
- if headers:
102
- headers_dict.update(headers)
103
-
104
- return headers_dict
105
-
106
- async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
107
- """
108
- Async Log success events to Generic API Endpoint
109
-
110
- - Creates a StandardLoggingPayload
111
- - Adds to batch queue
112
- - Flushes based on CustomBatchLogger settings
113
-
114
- Raises:
115
- Raises a NON Blocking verbose_logger.exception if an error occurs
116
- """
117
- from litellm.proxy.utils import _premium_user_check
118
-
119
- _premium_user_check()
120
-
121
- try:
122
- verbose_logger.debug(
123
- "Generic API Logger - Enters logging function for model %s", kwargs
124
- )
125
- standard_logging_payload = kwargs.get("standard_logging_object", None)
126
-
127
- # Backwards compatibility with old logging payload
128
- if litellm.generic_api_use_v1 is True:
129
- payload = self._get_v1_logging_payload(
130
- kwargs=kwargs,
131
- response_obj=response_obj,
132
- start_time=start_time,
133
- end_time=end_time,
134
- )
135
- self.log_queue.append(payload)
136
- else:
137
- # New logging payload, StandardLoggingPayload
138
- self.log_queue.append(standard_logging_payload)
139
-
140
- if len(self.log_queue) >= self.batch_size:
141
- await self.async_send_batch()
142
-
143
- except Exception as e:
144
- verbose_logger.exception(
145
- f"Generic API Logger Error - {str(e)}\n{traceback.format_exc()}"
146
- )
147
- pass
148
-
149
- async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
150
- """
151
- Async Log failure events to Generic API Endpoint
152
-
153
- - Creates a StandardLoggingPayload
154
- - Adds to batch queue
155
- """
156
- from litellm.proxy.utils import _premium_user_check
157
-
158
- _premium_user_check()
159
-
160
- try:
161
- verbose_logger.debug(
162
- "Generic API Logger - Enters logging function for model %s", kwargs
163
- )
164
- standard_logging_payload = kwargs.get("standard_logging_object", None)
165
-
166
- if litellm.generic_api_use_v1 is True:
167
- payload = self._get_v1_logging_payload(
168
- kwargs=kwargs,
169
- response_obj=response_obj,
170
- start_time=start_time,
171
- end_time=end_time,
172
- )
173
- self.log_queue.append(payload)
174
- else:
175
- self.log_queue.append(standard_logging_payload)
176
-
177
- if len(self.log_queue) >= self.batch_size:
178
- await self.async_send_batch()
179
-
180
- except Exception as e:
181
- verbose_logger.exception(
182
- f"Generic API Logger Error - {str(e)}\n{traceback.format_exc()}"
183
- )
184
-
185
- async def async_send_batch(self):
186
- """
187
- Sends the batch of messages to Generic API Endpoint
188
- """
189
- try:
190
- if not self.log_queue:
191
- return
192
-
193
- verbose_logger.debug(
194
- f"Generic API Logger - about to flush {len(self.log_queue)} events"
195
- )
196
-
197
- # make POST request to Generic API Endpoint
198
- response = await self.async_httpx_client.post(
199
- url=self.endpoint,
200
- headers=self.headers,
201
- data=safe_dumps(self.log_queue),
202
- )
203
-
204
- verbose_logger.debug(
205
- f"Generic API Logger - sent batch to {self.endpoint}, status code {response.status_code}"
206
- )
207
-
208
- except Exception as e:
209
- verbose_logger.exception(
210
- f"Generic API Logger Error sending batch - {str(e)}\n{traceback.format_exc()}"
211
- )
212
- finally:
213
- self.log_queue.clear()
214
-
215
- def _get_v1_logging_payload(
216
- self, kwargs, response_obj, start_time, end_time
217
- ) -> dict:
218
- """
219
- Maintained for backwards compatibility with old logging payload
220
-
221
- Returns a dict of the payload to send to the Generic API Endpoint
222
- """
223
- verbose_logger.debug(
224
- f"GenericAPILogger Logging - Enters logging function for model {kwargs}"
225
- )
226
-
227
- # construct payload to send custom logger
228
- # follows the same params as langfuse.py
229
- litellm_params = kwargs.get("litellm_params", {})
230
- metadata = (
231
- litellm_params.get("metadata", {}) or {}
232
- ) # if litellm_params['metadata'] == None
233
- messages = kwargs.get("messages")
234
- cost = kwargs.get("response_cost", 0.0)
235
- optional_params = kwargs.get("optional_params", {})
236
- call_type = kwargs.get("call_type", "litellm.completion")
237
- cache_hit = kwargs.get("cache_hit", False)
238
- usage = response_obj["usage"]
239
- id = response_obj.get("id", str(uuid.uuid4()))
240
-
241
- # Build the initial payload
242
- payload = {
243
- "id": id,
244
- "call_type": call_type,
245
- "cache_hit": cache_hit,
246
- "startTime": start_time,
247
- "endTime": end_time,
248
- "model": kwargs.get("model", ""),
249
- "user": kwargs.get("user", ""),
250
- "modelParameters": optional_params,
251
- "messages": messages,
252
- "response": response_obj,
253
- "usage": usage,
254
- "metadata": metadata,
255
- "cost": cost,
256
- }
257
-
258
- # Ensure everything in the payload is converted to str
259
- for key, value in payload.items():
260
- try:
261
- payload[key] = str(value)
262
- except Exception:
263
- # non blocking if it can't cast to a str
264
- pass
265
-
266
- return payload