litellm-enterprise 0.1.20__py3-none-any.whl → 0.1.21__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.
Files changed (23) hide show
  1. litellm_enterprise/enterprise_callbacks/.pytest_cache/.gitignore +2 -0
  2. litellm_enterprise/enterprise_callbacks/.pytest_cache/CACHEDIR.TAG +4 -0
  3. litellm_enterprise/enterprise_callbacks/.pytest_cache/README.md +8 -0
  4. litellm_enterprise/enterprise_callbacks/.pytest_cache/v/cache/nodeids +1 -0
  5. litellm_enterprise/enterprise_callbacks/.pytest_cache/v/cache/stepwise +1 -0
  6. litellm_enterprise/enterprise_callbacks/generic_api_callback.py +1 -1
  7. litellm_enterprise/enterprise_callbacks/llama_guard.py +2 -10
  8. litellm_enterprise/enterprise_callbacks/llm_guard.py +2 -9
  9. litellm_enterprise/enterprise_callbacks/pagerduty/pagerduty.py +9 -12
  10. litellm_enterprise/enterprise_callbacks/send_emails/base_email.py +61 -1
  11. litellm_enterprise/integrations/custom_guardrail.py +1 -2
  12. litellm_enterprise/proxy/common_utils/check_batch_cost.py +3 -4
  13. litellm_enterprise/proxy/hooks/managed_files.py +6 -24
  14. litellm_enterprise/proxy/management_endpoints/internal_user_endpoints.py +0 -1
  15. litellm_enterprise/proxy/management_endpoints/key_management_endpoints.py +12 -0
  16. litellm_enterprise/proxy/vector_stores/endpoints.py +49 -7
  17. litellm_enterprise/types/enterprise_callbacks/send_emails.py +14 -2
  18. {litellm_enterprise-0.1.20.dist-info → litellm_enterprise-0.1.21.dist-info}/METADATA +1 -1
  19. {litellm_enterprise-0.1.20.dist-info → litellm_enterprise-0.1.21.dist-info}/RECORD +21 -18
  20. litellm_enterprise/integrations/prometheus.py +0 -2361
  21. litellm_enterprise/proxy/guardrails/endpoints.py +0 -41
  22. {litellm_enterprise-0.1.20.dist-info → litellm_enterprise-0.1.21.dist-info}/LICENSE.md +0 -0
  23. {litellm_enterprise-0.1.20.dist-info → litellm_enterprise-0.1.21.dist-info}/WHEEL +0 -0
@@ -0,0 +1,2 @@
1
+ # Created by pytest automatically.
2
+ *
@@ -0,0 +1,4 @@
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
@@ -0,0 +1,8 @@
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.
@@ -9,7 +9,7 @@ Callback to log events to a Generic API Endpoint
9
9
  import asyncio
10
10
  import os
11
11
  import traceback
12
- import uuid
12
+ from litellm._uuid import uuid
13
13
  from typing import Dict, List, Optional, Union
14
14
 
15
15
  import litellm
@@ -23,7 +23,7 @@ import litellm
23
23
  from litellm._logging import verbose_proxy_logger
24
24
  from litellm.integrations.custom_logger import CustomLogger
25
25
  from litellm.proxy._types import UserAPIKeyAuth
26
- from litellm.types.utils import Choices, ModelResponse
26
+ from litellm.types.utils import CallTypesLiteral, Choices, ModelResponse
27
27
 
28
28
 
29
29
  class _ENTERPRISE_LlamaGuard(CustomLogger):
@@ -98,15 +98,7 @@ class _ENTERPRISE_LlamaGuard(CustomLogger):
98
98
  self,
99
99
  data: dict,
100
100
  user_api_key_dict: UserAPIKeyAuth,
101
- call_type: Literal[
102
- "completion",
103
- "embeddings",
104
- "image_generation",
105
- "moderation",
106
- "audio_transcription",
107
- "responses",
108
- "mcp_call",
109
- ],
101
+ call_type: CallTypesLiteral,
110
102
  ):
111
103
  """
112
104
  - Calls the Llama Guard Endpoint
@@ -17,6 +17,7 @@ from litellm._logging import verbose_proxy_logger
17
17
  from litellm.integrations.custom_logger import CustomLogger
18
18
  from litellm.proxy._types import UserAPIKeyAuth
19
19
  from litellm.secret_managers.main import get_secret_str
20
+ from litellm.types.utils import CallTypesLiteral
20
21
  from litellm.utils import get_formatted_prompt
21
22
 
22
23
 
@@ -120,15 +121,7 @@ class _ENTERPRISE_LLMGuard(CustomLogger):
120
121
  self,
121
122
  data: dict,
122
123
  user_api_key_dict: UserAPIKeyAuth,
123
- call_type: Literal[
124
- "completion",
125
- "embeddings",
126
- "image_generation",
127
- "moderation",
128
- "audio_transcription",
129
- "responses",
130
- "mcp_call",
131
- ],
124
+ call_type: CallTypesLiteral,
132
125
  ):
133
126
  """
134
127
  - Calls the LLM Guard Endpoint
@@ -31,6 +31,7 @@ from litellm.types.integrations.pagerduty import (
31
31
  PagerDutyRequestBody,
32
32
  )
33
33
  from litellm.types.utils import (
34
+ CallTypesLiteral,
34
35
  StandardLoggingPayload,
35
36
  StandardLoggingPayloadErrorInformation,
36
37
  )
@@ -119,6 +120,7 @@ class PagerDutyAlerting(SlackAlerting):
119
120
  user_api_key_end_user_id=_meta.get("user_api_key_end_user_id"),
120
121
  user_api_key_user_email=_meta.get("user_api_key_user_email"),
121
122
  user_api_key_request_route=_meta.get("user_api_key_request_route"),
123
+ user_api_key_auth_metadata=_meta.get("user_api_key_auth_metadata"),
122
124
  )
123
125
  )
124
126
 
@@ -141,17 +143,7 @@ class PagerDutyAlerting(SlackAlerting):
141
143
  user_api_key_dict: UserAPIKeyAuth,
142
144
  cache: DualCache,
143
145
  data: dict,
144
- call_type: Literal[
145
- "completion",
146
- "text_completion",
147
- "embeddings",
148
- "image_generation",
149
- "moderation",
150
- "audio_transcription",
151
- "pass_through_endpoint",
152
- "rerank",
153
- "mcp_call",
154
- ],
146
+ call_type: CallTypesLiteral,
155
147
  ) -> Optional[Union[Exception, str, dict]]:
156
148
  """
157
149
  Example of detecting hanging requests by waiting a given threshold.
@@ -196,7 +188,11 @@ class PagerDutyAlerting(SlackAlerting):
196
188
  user_api_key_alias=user_api_key_dict.key_alias,
197
189
  user_api_key_spend=user_api_key_dict.spend,
198
190
  user_api_key_max_budget=user_api_key_dict.max_budget,
199
- user_api_key_budget_reset_at=user_api_key_dict.budget_reset_at.isoformat() if user_api_key_dict.budget_reset_at else None,
191
+ user_api_key_budget_reset_at=(
192
+ user_api_key_dict.budget_reset_at.isoformat()
193
+ if user_api_key_dict.budget_reset_at
194
+ else None
195
+ ),
200
196
  user_api_key_org_id=user_api_key_dict.org_id,
201
197
  user_api_key_team_id=user_api_key_dict.team_id,
202
198
  user_api_key_user_id=user_api_key_dict.user_id,
@@ -204,6 +200,7 @@ class PagerDutyAlerting(SlackAlerting):
204
200
  user_api_key_end_user_id=user_api_key_dict.end_user_id,
205
201
  user_api_key_user_email=user_api_key_dict.user_email,
206
202
  user_api_key_request_route=user_api_key_dict.request_route,
203
+ user_api_key_auth_metadata=user_api_key_dict.metadata,
207
204
  )
208
205
  )
209
206
 
@@ -11,6 +11,7 @@ from litellm_enterprise.types.enterprise_callbacks.send_emails import (
11
11
  EmailEvent,
12
12
  EmailParams,
13
13
  SendKeyCreatedEmailEvent,
14
+ SendKeyRotatedEmailEvent,
14
15
  )
15
16
 
16
17
  from litellm._logging import verbose_proxy_logger
@@ -19,10 +20,14 @@ from litellm.integrations.email_templates.email_footer import EMAIL_FOOTER
19
20
  from litellm.integrations.email_templates.key_created_email import (
20
21
  KEY_CREATED_EMAIL_TEMPLATE,
21
22
  )
23
+ from litellm.integrations.email_templates.key_rotated_email import (
24
+ KEY_ROTATED_EMAIL_TEMPLATE,
25
+ )
22
26
  from litellm.integrations.email_templates.user_invitation_email import (
23
27
  USER_INVITATION_EMAIL_TEMPLATE,
24
28
  )
25
29
  from litellm.proxy._types import InvitationNew, UserAPIKeyAuth, WebhookEvent
30
+ from litellm.secret_managers.main import get_secret_bool
26
31
  from litellm.types.integrations.slack_alerting import LITELLM_LOGO_URL
27
32
 
28
33
 
@@ -32,6 +37,7 @@ class BaseEmailLogger(CustomLogger):
32
37
  DEFAULT_SUBJECT_TEMPLATES = {
33
38
  EmailEvent.new_user_invitation: "LiteLLM: {event_message}",
34
39
  EmailEvent.virtual_key_created: "LiteLLM: {event_message}",
40
+ EmailEvent.virtual_key_rotated: "LiteLLM: {event_message}",
35
41
  }
36
42
 
37
43
  async def send_user_invitation_email(self, event: WebhookEvent):
@@ -83,11 +89,58 @@ class BaseEmailLogger(CustomLogger):
83
89
  f"send_key_created_email_event: {json.dumps(send_key_created_email_event, indent=4, default=str)}"
84
90
  )
85
91
 
92
+ # Check if API key should be included in email
93
+ include_api_key = get_secret_bool(secret_name="EMAIL_INCLUDE_API_KEY", default_value=True)
94
+ if include_api_key is None:
95
+ include_api_key = True # Default to True if not set
96
+ key_token_display = send_key_created_email_event.virtual_key if include_api_key else "[Key hidden for security - retrieve from dashboard]"
97
+
86
98
  email_html_content = KEY_CREATED_EMAIL_TEMPLATE.format(
87
99
  email_logo_url=email_params.logo_url,
88
100
  recipient_email=email_params.recipient_email,
89
101
  key_budget=self._format_key_budget(send_key_created_email_event.max_budget),
90
- key_token=send_key_created_email_event.virtual_key,
102
+ key_token=key_token_display,
103
+ base_url=email_params.base_url,
104
+ email_support_contact=email_params.support_contact,
105
+ email_footer=email_params.signature,
106
+ )
107
+
108
+ await self.send_email(
109
+ from_email=self.DEFAULT_LITELLM_EMAIL,
110
+ to_email=[email_params.recipient_email],
111
+ subject=email_params.subject,
112
+ html_body=email_html_content,
113
+ )
114
+ pass
115
+
116
+ async def send_key_rotated_email(
117
+ self, send_key_rotated_email_event: SendKeyRotatedEmailEvent
118
+ ):
119
+ """
120
+ Send email to user after rotating key for the user
121
+ """
122
+ email_params = await self._get_email_params(
123
+ user_id=send_key_rotated_email_event.user_id,
124
+ user_email=send_key_rotated_email_event.user_email,
125
+ email_event=EmailEvent.virtual_key_rotated,
126
+ event_message=send_key_rotated_email_event.event_message,
127
+ )
128
+
129
+ verbose_proxy_logger.debug(
130
+ f"send_key_rotated_email_event: {json.dumps(send_key_rotated_email_event, indent=4, default=str)}"
131
+ )
132
+
133
+ # Check if API key should be included in email
134
+ include_api_key = get_secret_bool(secret_name="EMAIL_INCLUDE_API_KEY", default_value=True)
135
+ if include_api_key is None:
136
+ include_api_key = True # Default to True if not set
137
+ key_token_display = send_key_rotated_email_event.virtual_key if include_api_key else "[Key hidden for security - retrieve from dashboard]"
138
+
139
+ email_html_content = KEY_ROTATED_EMAIL_TEMPLATE.format(
140
+ email_logo_url=email_params.logo_url,
141
+ recipient_email=email_params.recipient_email,
142
+ key_budget=self._format_key_budget(send_key_rotated_email_event.max_budget),
143
+ key_token=key_token_display,
91
144
  base_url=email_params.base_url,
92
145
  email_support_contact=email_params.support_contact,
93
146
  email_footer=email_params.signature,
@@ -159,6 +212,13 @@ class BaseEmailLogger(CustomLogger):
159
212
  self.DEFAULT_SUBJECT_TEMPLATES[EmailEvent.virtual_key_created],
160
213
  "key created subject template"
161
214
  )
215
+ elif email_event == EmailEvent.virtual_key_rotated:
216
+ custom_subject_key_rotated = os.getenv("EMAIL_SUBJECT_KEY_ROTATED", None)
217
+ subject_template = get_custom_or_default(
218
+ custom_subject_key_rotated,
219
+ self.DEFAULT_SUBJECT_TEMPLATES[EmailEvent.virtual_key_rotated],
220
+ "key rotated subject template"
221
+ )
162
222
  else:
163
223
  subject_template = "LiteLLM: {event_message}"
164
224
 
@@ -29,11 +29,10 @@ class EnterpriseCustomGuardrailHelper:
29
29
  if event_hook is None or not isinstance(event_hook, Mode):
30
30
  return None
31
31
 
32
- metadata: dict = data.get("litellm_metadata") or data.get("metadata", {})
33
32
  proxy_server_request = data.get("proxy_server_request", {})
34
33
 
35
34
  request_tags = StandardLoggingPayloadSetup._get_request_tags(
36
- metadata=metadata,
35
+ litellm_params=data,
37
36
  proxy_server_request=proxy_server_request,
38
37
  )
39
38
 
@@ -2,7 +2,7 @@
2
2
  Polls LiteLLM_ManagedObjectTable to check if the batch job is complete, and if the cost has been tracked.
3
3
  """
4
4
 
5
- import uuid
5
+ from litellm._uuid import uuid
6
6
  from datetime import datetime
7
7
  from typing import TYPE_CHECKING, Optional, cast
8
8
 
@@ -57,7 +57,6 @@ class CheckBatchCost:
57
57
  "file_purpose": "batch",
58
58
  }
59
59
  )
60
-
61
60
  completed_jobs = []
62
61
 
63
62
  for job in jobs:
@@ -139,7 +138,7 @@ class CheckBatchCost:
139
138
  custom_llm_provider = deployment_info.litellm_params.custom_llm_provider
140
139
  litellm_model_name = deployment_info.litellm_params.model
141
140
 
142
- _, llm_provider, _, _ = get_llm_provider(
141
+ model_name, llm_provider, _, _ = get_llm_provider(
143
142
  model=litellm_model_name,
144
143
  custom_llm_provider=custom_llm_provider,
145
144
  )
@@ -148,9 +147,9 @@ class CheckBatchCost:
148
147
  await calculate_batch_cost_and_usage(
149
148
  file_content_dictionary=file_content_as_dict,
150
149
  custom_llm_provider=llm_provider, # type: ignore
150
+ model_name=model_name,
151
151
  )
152
152
  )
153
-
154
153
  logging_obj = LiteLLMLogging(
155
154
  model=batch_models[0],
156
155
  messages=[{"role": "user", "content": "<retrieve_batch>"}],
@@ -4,12 +4,12 @@
4
4
  import asyncio
5
5
  import base64
6
6
  import json
7
- import uuid
8
7
  from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Union, cast
9
8
 
10
9
  from fastapi import HTTPException
11
10
 
12
11
  from litellm import Router, verbose_logger
12
+ from litellm._uuid import uuid
13
13
  from litellm.caching.caching import DualCache
14
14
  from litellm.integrations.custom_logger import CustomLogger
15
15
  from litellm.litellm_core_utils.prompt_templates.common_utils import extract_file_data
@@ -36,6 +36,7 @@ from litellm.types.llms.openai import (
36
36
  OpenAIFilesPurpose,
37
37
  )
38
38
  from litellm.types.utils import (
39
+ CallTypesLiteral,
39
40
  LiteLLMBatch,
40
41
  LiteLLMFineTuningJob,
41
42
  LLMResponseTypes,
@@ -152,7 +153,7 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
152
153
  "status": file_object.status,
153
154
  },
154
155
  "update": {}, # don't do anything if it already exists
155
- }
156
+ },
156
157
  )
157
158
 
158
159
  async def get_unified_file_id(
@@ -224,9 +225,10 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
224
225
  where={"unified_object_id": unified_object_id}
225
226
  )
226
227
  )
228
+
227
229
  if managed_object:
228
230
  return managed_object.created_by == user_id
229
- return False
231
+ return True # don't raise error if managed object is not found
230
232
 
231
233
  async def get_user_created_file_ids(
232
234
  self, user_api_key_dict: UserAPIKeyAuth, model_object_ids: List[str]
@@ -271,27 +273,7 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
271
273
  user_api_key_dict: UserAPIKeyAuth,
272
274
  cache: DualCache,
273
275
  data: Dict,
274
- call_type: Literal[
275
- "completion",
276
- "text_completion",
277
- "embeddings",
278
- "image_generation",
279
- "moderation",
280
- "audio_transcription",
281
- "pass_through_endpoint",
282
- "rerank",
283
- "acreate_batch",
284
- "aretrieve_batch",
285
- "acreate_file",
286
- "afile_list",
287
- "afile_delete",
288
- "afile_content",
289
- "acreate_fine_tuning_job",
290
- "aretrieve_fine_tuning_job",
291
- "alist_fine_tuning_jobs",
292
- "acancel_fine_tuning_job",
293
- "mcp_call",
294
- ],
276
+ call_type: CallTypesLiteral,
295
277
  ) -> Union[Exception, str, Dict, None]:
296
278
  """
297
279
  - Detect litellm_proxy/ file_id
@@ -2,7 +2,6 @@
2
2
  Enterprise internal user management endpoints
3
3
  """
4
4
 
5
- import os
6
5
 
7
6
  from fastapi import APIRouter, Depends, HTTPException
8
7
 
@@ -22,9 +22,21 @@ def add_team_member_key_duration(
22
22
  return data
23
23
 
24
24
 
25
+ def add_team_organization_id(
26
+ team_table: Optional[LiteLLM_TeamTable],
27
+ data: GenerateKeyRequest,
28
+ ) -> GenerateKeyRequest:
29
+ if team_table is None:
30
+ return data
31
+ setattr(data, "organization_id", team_table.organization_id)
32
+ return data
33
+
34
+
25
35
  def apply_enterprise_key_management_params(
26
36
  data: GenerateKeyRequest,
27
37
  team_table: Optional[LiteLLM_TeamTable],
28
38
  ) -> GenerateKeyRequest:
39
+
29
40
  data = add_team_member_key_duration(team_table, data)
41
+ data = add_team_organization_id(team_table, data)
30
42
  return data
@@ -9,14 +9,19 @@ All /vector_store management endpoints
9
9
  """
10
10
 
11
11
  import copy
12
+ import json
12
13
  from typing import List, Optional
13
14
 
14
- from fastapi import APIRouter, Depends, HTTPException, Request, Response
15
+ from fastapi import APIRouter, Depends, HTTPException
15
16
 
16
17
  import litellm
17
18
  from litellm._logging import verbose_proxy_logger
18
19
  from litellm.litellm_core_utils.safe_json_dumps import safe_dumps
19
- from litellm.proxy._types import UserAPIKeyAuth
20
+ from litellm.proxy._types import (
21
+ LiteLLM_ManagedVectorStoresTable,
22
+ ResponseLiteLLM_ManagedVectorStore,
23
+ UserAPIKeyAuth,
24
+ )
20
25
  from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
21
26
  from litellm.types.vector_stores import (
22
27
  LiteLLM_ManagedVectorStore,
@@ -29,6 +34,7 @@ from litellm.vector_stores.vector_store_registry import VectorStoreRegistry
29
34
 
30
35
  router = APIRouter()
31
36
 
37
+
32
38
  ########################################################
33
39
  # Management Endpoints
34
40
  ########################################################
@@ -79,7 +85,9 @@ async def new_vector_store(
79
85
  litellm_params_json: Optional[str] = None
80
86
  _input_litellm_params: dict = vector_store.get("litellm_params", {}) or {}
81
87
  if _input_litellm_params is not None:
82
- litellm_params_dict = GenericLiteLLMParams(**_input_litellm_params).model_dump(exclude_none=True)
88
+ litellm_params_dict = GenericLiteLLMParams(
89
+ **_input_litellm_params
90
+ ).model_dump(exclude_none=True)
83
91
  litellm_params_json = safe_dumps(litellm_params_dict)
84
92
  del vector_store["litellm_params"]
85
93
 
@@ -227,6 +235,7 @@ async def delete_vector_store(
227
235
  "/vector_store/info",
228
236
  tags=["vector store management"],
229
237
  dependencies=[Depends(user_api_key_auth)],
238
+ response_model=ResponseLiteLLM_ManagedVectorStore,
230
239
  )
231
240
  async def get_vector_store_info(
232
241
  data: VectorStoreInfoRequest,
@@ -239,8 +248,39 @@ async def get_vector_store_info(
239
248
  raise HTTPException(status_code=500, detail="Database not connected")
240
249
 
241
250
  try:
242
- vector_store = await prisma_client.db.litellm_managedvectorstorestable.find_unique(
243
- where={"vector_store_id": data.vector_store_id}
251
+ if litellm.vector_store_registry is not None:
252
+ vector_store = litellm.vector_store_registry.get_litellm_managed_vector_store_from_registry(
253
+ vector_store_id=data.vector_store_id
254
+ )
255
+ if vector_store is not None:
256
+ vector_store_metadata = vector_store.get("vector_store_metadata")
257
+ # Parse metadata if it's a JSON string
258
+ parsed_metadata: Optional[dict] = None
259
+ if isinstance(vector_store_metadata, str):
260
+ parsed_metadata = json.loads(vector_store_metadata)
261
+ elif isinstance(vector_store_metadata, dict):
262
+ parsed_metadata = vector_store_metadata
263
+
264
+ vector_store_pydantic_obj = LiteLLM_ManagedVectorStoresTable(
265
+ vector_store_id=vector_store.get("vector_store_id") or "",
266
+ custom_llm_provider=vector_store.get("custom_llm_provider") or "",
267
+ vector_store_name=vector_store.get("vector_store_name") or None,
268
+ vector_store_description=vector_store.get(
269
+ "vector_store_description"
270
+ )
271
+ or None,
272
+ vector_store_metadata=parsed_metadata,
273
+ created_at=vector_store.get("created_at") or None,
274
+ updated_at=vector_store.get("updated_at") or None,
275
+ litellm_credential_name=vector_store.get("litellm_credential_name"),
276
+ litellm_params=vector_store.get("litellm_params") or None,
277
+ )
278
+ return {"vector_store": vector_store_pydantic_obj}
279
+
280
+ vector_store = (
281
+ await prisma_client.db.litellm_managedvectorstorestable.find_unique(
282
+ where={"vector_store_id": data.vector_store_id}
283
+ )
244
284
  )
245
285
  if vector_store is None:
246
286
  raise HTTPException(
@@ -248,7 +288,7 @@ async def get_vector_store_info(
248
288
  detail=f"Vector store with ID {data.vector_store_id} not found",
249
289
  )
250
290
 
251
- vector_store_dict = vector_store.model_dump()
291
+ vector_store_dict = vector_store.model_dump() # type: ignore[attr-defined]
252
292
  return {"vector_store": vector_store_dict}
253
293
  except Exception as e:
254
294
  verbose_proxy_logger.exception(f"Error getting vector store info: {str(e)}")
@@ -274,7 +314,9 @@ async def update_vector_store(
274
314
  update_data = data.model_dump(exclude_unset=True)
275
315
  vector_store_id = update_data.pop("vector_store_id")
276
316
  if update_data.get("vector_store_metadata") is not None:
277
- update_data["vector_store_metadata"] = safe_dumps(update_data["vector_store_metadata"])
317
+ update_data["vector_store_metadata"] = safe_dumps(
318
+ update_data["vector_store_metadata"]
319
+ )
278
320
 
279
321
  updated = await prisma_client.db.litellm_managedvectorstorestable.update(
280
322
  where={"vector_store_id": vector_store_id},
@@ -1,10 +1,11 @@
1
1
  import enum
2
- from typing import Dict, List
2
+ from typing import Dict, List, Optional
3
3
 
4
4
  from pydantic import BaseModel, Field
5
5
 
6
6
  from litellm.proxy._types import WebhookEvent
7
7
 
8
+
8
9
  class EmailParams(BaseModel):
9
10
  logo_url: str
10
11
  support_contact: str
@@ -22,9 +23,19 @@ class SendKeyCreatedEmailEvent(WebhookEvent):
22
23
  """
23
24
 
24
25
 
26
+ class SendKeyRotatedEmailEvent(WebhookEvent):
27
+ virtual_key: str
28
+ key_alias: Optional[str] = None
29
+ """
30
+ The virtual key that was rotated
31
+ this will be sk-123xxx, since we will be emailing this to the user to start using the new key
32
+ """
33
+
34
+
25
35
  class EmailEvent(str, enum.Enum):
26
36
  virtual_key_created = "Virtual Key Created"
27
37
  new_user_invitation = "New User Invitation"
38
+ virtual_key_rotated = "Virtual Key Rotated"
28
39
 
29
40
  class EmailEventSettings(BaseModel):
30
41
  event: EmailEvent
@@ -37,8 +48,9 @@ class DefaultEmailSettings(BaseModel):
37
48
  """Default settings for email events"""
38
49
  settings: Dict[EmailEvent, bool] = Field(
39
50
  default_factory=lambda: {
40
- EmailEvent.virtual_key_created: False, # Off by default
51
+ EmailEvent.virtual_key_created: True, # On by default
41
52
  EmailEvent.new_user_invitation: True, # On by default
53
+ EmailEvent.virtual_key_rotated: True, # On by default
42
54
  }
43
55
  )
44
56
  def to_dict(self) -> Dict[str, bool]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: litellm-enterprise
3
- Version: 0.1.20
3
+ Version: 0.1.21
4
4
  Summary: Package for LiteLLM Enterprise features
5
5
  Author: BerriAI
6
6
  Requires-Python: >=3.8, !=2.7.*, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*
@@ -1,10 +1,15 @@
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
2
7
  litellm_enterprise/enterprise_callbacks/callback_controls.py,sha256=BhUOHoqR5u8ANaSweKnzgw96Zqu7Eh4mXXUfYQH9Xe4,4756
3
8
  litellm_enterprise/enterprise_callbacks/example_logging_api.py,sha256=06CM6wa5CC7Mal3Gm-P6m6tJuikbcg5BJ9-kzfpl_Y4,776
4
- litellm_enterprise/enterprise_callbacks/generic_api_callback.py,sha256=UOS2XRGevj4P3Ri7zxJrj1na1jdPzwsmLTH1dBhymbg,9161
5
- litellm_enterprise/enterprise_callbacks/llama_guard.py,sha256=LgwXBCvhBSHAWOm4XXoIQUzB3mm6eNjFNp7gj7lehpA,5017
6
- litellm_enterprise/enterprise_callbacks/llm_guard.py,sha256=knJ52fjm3-_TvTafJ560i4YXCoMnWFxTrsB7Jcpyxso,6600
7
- litellm_enterprise/enterprise_callbacks/pagerduty/pagerduty.py,sha256=eMyy6_NP4zEuroDpqdJQmMfEXgA-SnypTvRTWfBJEqc,12404
9
+ litellm_enterprise/enterprise_callbacks/generic_api_callback.py,sha256=8x_ghfAvG72A4wrzeWcz5PVo6DhMPQjKUmrwsb-tuig,9180
10
+ litellm_enterprise/enterprise_callbacks/llama_guard.py,sha256=9GSYTujO2bI6jWmtpTYz1UcOpJfBNSuAVWrl4rJIXO0,4839
11
+ litellm_enterprise/enterprise_callbacks/llm_guard.py,sha256=AXqlcct74S7N6DHAxYbh6icrsQ-7umIyOkOuZAmXD-w,6453
12
+ litellm_enterprise/enterprise_callbacks/pagerduty/pagerduty.py,sha256=40UI8RjRZ-lfoCyCITipHHK6CmYR5iOI27F48cvc-xk,12400
8
13
  litellm_enterprise/enterprise_callbacks/secret_detection.py,sha256=D5h5dS4T5PM-zWqUy-svTfZrxDGbJQbFFJExofXX4_o,19640
9
14
  litellm_enterprise/enterprise_callbacks/secrets_plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
15
  litellm_enterprise/enterprise_callbacks/secrets_plugins/adafruit.py,sha256=djYtVMzXF21ay1w6cg-oT6D0f3b-Aa_5Bh29OiOD_O4,596
@@ -100,33 +105,31 @@ litellm_enterprise/enterprise_callbacks/secrets_plugins/typeform_api_token.py,sh
100
105
  litellm_enterprise/enterprise_callbacks/secrets_plugins/vault.py,sha256=fqtHTQTC6QaNMIZpuvntBnCSAgAhY2Ka-XOz4ZLafGk,653
101
106
  litellm_enterprise/enterprise_callbacks/secrets_plugins/yandex.py,sha256=BVtFVzCTtpAkRJVudeZIEBBz1W8wueDzpu6TBvxngxo,1183
102
107
  litellm_enterprise/enterprise_callbacks/secrets_plugins/zendesk_secret_key.py,sha256=3E21lWz12WUAmdnKDZH8znfTp6hRJbE3yImtfEP52qE,613
103
- litellm_enterprise/enterprise_callbacks/send_emails/base_email.py,sha256=EdXt5htXWdr0TxV5pazmYSAu42NP0kkwopLPnJYNuCs,12717
108
+ litellm_enterprise/enterprise_callbacks/send_emails/base_email.py,sha256=w4omD5Z7gMZABxn7DmAlOiCX6f7VwJ1KMKq_NXpdkLc,15523
104
109
  litellm_enterprise/enterprise_callbacks/send_emails/endpoints.py,sha256=hOEpM_q8MJAXlKMOtC9KbgvDVr_YFtF3reu9bjXkpsI,7017
105
110
  litellm_enterprise/enterprise_callbacks/send_emails/resend_email.py,sha256=lLG9W2hEOjn7lvMDKoaZGVCzr72HfreJuScMNOkE7FQ,1426
106
111
  litellm_enterprise/enterprise_callbacks/send_emails/smtp_email.py,sha256=_K3vGhyALVJWIzIk2oiHQbQPlYARdpPe-GA9hdl0vTg,1130
107
- litellm_enterprise/integrations/custom_guardrail.py,sha256=YE77sQ61A2tG6ZbqK90yDHUL1I6NreK8TwDFrFQSTdk,1635
108
- litellm_enterprise/integrations/prometheus.py,sha256=1WLELwsCCrmQWqKucbNFmmCUpoT4NJCZ8eoG9HHbG6o,91704
112
+ litellm_enterprise/integrations/custom_guardrail.py,sha256=ZLVpqUZq9bR0vEFqVrlTJk0bYCZuFsXlw9XsdyK9t2E,1555
109
113
  litellm_enterprise/litellm_core_utils/litellm_logging.py,sha256=BKkQLPqebFbN-KeCbipGIPgdxHEfQkczImdhhzxKoFg,868
110
114
  litellm_enterprise/proxy/audit_logging_endpoints.py,sha256=BnHczmi4bnW1GpMNsq4CvnbwL3rgQ-pnrtFd5WBbbHY,5304
111
115
  litellm_enterprise/proxy/auth/__init__.py,sha256=wTXtbDcLrD_qecxJfEJtraeCvGfldDgLz8qdVggLoSI,301
112
116
  litellm_enterprise/proxy/auth/custom_sso_handler.py,sha256=ITML9dRKL-LuJhU3WKKVPDp0ECfYxvxTvuX8GpSM0gE,3439
113
117
  litellm_enterprise/proxy/auth/route_checks.py,sha256=FbXwbrOkFr1dODH6XxoIpLG1nKowC7kyNaRR0WR6ujU,2490
114
118
  litellm_enterprise/proxy/auth/user_api_key_auth.py,sha256=7t5Q-JoKFyoymylaOT8KWAAOFVz0JOTl7PPOmTkpj5c,1144
115
- litellm_enterprise/proxy/common_utils/check_batch_cost.py,sha256=67-vJKFURaZheUENJBU7gWRN5CSgws7RInI7S82wlaw,7287
119
+ litellm_enterprise/proxy/common_utils/check_batch_cost.py,sha256=V0CCHtN-JV-_d-ydXV-cVs3zCImt1699JnICGF3oPOk,7360
116
120
  litellm_enterprise/proxy/enterprise_routes.py,sha256=TkFeQa6mtVIvEhTP7X5dcSDKTOks0hG_dWrL1_oCU4w,1122
117
- litellm_enterprise/proxy/guardrails/endpoints.py,sha256=ubkygTc3oCmbVnFljAZGzAiM6LctKyZeSIeL9HK6F8U,1330
118
- litellm_enterprise/proxy/hooks/managed_files.py,sha256=8WtFarjtVzREgMCXmgmcm720Bx_F3UdQg8Ry8zbVznM,32690
121
+ litellm_enterprise/proxy/hooks/managed_files.py,sha256=E5yY9qza6HzcOtAI_9zgHLV_F-dz8VpOM3KoEhGKp2E,32195
119
122
  litellm_enterprise/proxy/management_endpoints/__init__.py,sha256=zfaqryxzmFu6se-w4yR2nlHKxDOOtHAWEehA2xFbFNg,270
120
- litellm_enterprise/proxy/management_endpoints/internal_user_endpoints.py,sha256=zPVdOE5Ss3Zc1Dy11uf0eZa1BY7goUqmv3DzTjRt3UE,2185
121
- litellm_enterprise/proxy/management_endpoints/key_management_endpoints.py,sha256=CEE41tfcjUHw36dPKzGI_zciO4q0IUalFftO_EkZ_l8,832
123
+ litellm_enterprise/proxy/management_endpoints/internal_user_endpoints.py,sha256=GEoOVujrtKXDHfko2KQaLn-ms64zkutFE9PP5IhBBLM,2175
124
+ litellm_enterprise/proxy/management_endpoints/key_management_endpoints.py,sha256=-IXRzVrNQ3_krL-gxngelYQftwyPlB_HmgI3RN-HdvM,1147
122
125
  litellm_enterprise/proxy/proxy_server.py,sha256=fzOeTyiyevLWi2767-2W1Co7reR-0wnoUIhOgVlJFQc,1183
123
126
  litellm_enterprise/proxy/readme.md,sha256=ZcigMJYSHWs4SWnYriWjrSVDJKsu44c2HsbYbma0EHU,397
124
127
  litellm_enterprise/proxy/utils.py,sha256=y4ADfhlEG_mH0x5rfIg7D9FjS586lVgQ9DL0tTdgrMQ,962
125
- litellm_enterprise/proxy/vector_stores/endpoints.py,sha256=FAhtMas4iT5GLWSaqDDfLf6U_6vACLury4cTwtIpN38,10525
126
- litellm_enterprise/types/enterprise_callbacks/send_emails.py,sha256=oRgr7oBKGSCOkVE8u9gF07GoqhXkdhwjLtmeGXInEJc,1549
128
+ litellm_enterprise/proxy/vector_stores/endpoints.py,sha256=AkP503_JQY0DCFk_kPVYh7xSqSBabVBIphjRiAA0GvA,12445
129
+ litellm_enterprise/types/enterprise_callbacks/send_emails.py,sha256=XLhpdGvBFxPkV7hcgQ1gELVF0vTs5d2LLOoXPzjr4K4,1929
127
130
  litellm_enterprise/types/proxy/audit_logging_endpoints.py,sha256=oSJVAuRD9r6ZjRCqNBFM-J5HSgOltsXts400b2aynRE,894
128
131
  litellm_enterprise/types/proxy/proxy_server.py,sha256=kdhtxsU2uok6-XO_ebugCv7PzYYmGgv4vh-XemHJnpM,146
129
- litellm_enterprise-0.1.20.dist-info/LICENSE.md,sha256=nq3D9ZqOvRDT6hLkypQFTc3XsE15kbkg5rkkLJVSqKY,2251
130
- litellm_enterprise-0.1.20.dist-info/METADATA,sha256=09OhDOR9DjGfbMZLWgOVoiw9qYPz_r6NruMCB0HZlrg,1314
131
- litellm_enterprise-0.1.20.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
132
- litellm_enterprise-0.1.20.dist-info/RECORD,,
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,,