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.
- litellm_enterprise/enterprise_callbacks/callback_controls.py +9 -2
- litellm_enterprise/proxy/enterprise_routes.py +0 -4
- litellm_enterprise/proxy/hooks/managed_files.py +59 -4
- litellm_enterprise/proxy/vector_stores/endpoints.py +25 -17
- {litellm_enterprise-0.1.21.dist-info → litellm_enterprise-0.1.23.dist-info}/METADATA +5 -2
- {litellm_enterprise-0.1.21.dist-info → litellm_enterprise-0.1.23.dist-info}/RECORD +8 -14
- {litellm_enterprise-0.1.21.dist-info → litellm_enterprise-0.1.23.dist-info}/WHEEL +1 -1
- litellm_enterprise/enterprise_callbacks/.pytest_cache/.gitignore +0 -2
- litellm_enterprise/enterprise_callbacks/.pytest_cache/CACHEDIR.TAG +0 -4
- litellm_enterprise/enterprise_callbacks/.pytest_cache/README.md +0 -8
- litellm_enterprise/enterprise_callbacks/.pytest_cache/v/cache/nodeids +0 -1
- litellm_enterprise/enterprise_callbacks/.pytest_cache/v/cache/stepwise +0 -1
- litellm_enterprise/enterprise_callbacks/generic_api_callback.py +0 -266
- {litellm_enterprise-0.1.21.dist-info → litellm_enterprise-0.1.23.dist-info/licenses}/LICENSE.md +0 -0
|
@@ -40,7 +40,7 @@ class EnterpriseCallbackControls:
|
|
|
40
40
|
#########################################################
|
|
41
41
|
# premium user check
|
|
42
42
|
#########################################################
|
|
43
|
-
if not EnterpriseCallbackControls.
|
|
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
|
|
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
|
-
|
|
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,
|
|
774
|
-
await llm_router.afile_delete(model=model_id, file_id=
|
|
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
|
|
148
|
-
|
|
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
|
-
#
|
|
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
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: litellm-enterprise
|
|
3
|
-
Version: 0.1.
|
|
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
|
|
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=
|
|
121
|
-
litellm_enterprise/proxy/hooks/managed_files.py,sha256=
|
|
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=
|
|
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.
|
|
133
|
-
litellm_enterprise-0.1.
|
|
134
|
-
litellm_enterprise-0.1.
|
|
135
|
-
litellm_enterprise-0.1.
|
|
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,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 +0,0 @@
|
|
|
1
|
-
[]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[]
|
|
@@ -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
|
{litellm_enterprise-0.1.21.dist-info → litellm_enterprise-0.1.23.dist-info/licenses}/LICENSE.md
RENAMED
|
File without changes
|