litellm-enterprise 0.1.29__tar.gz → 0.1.31__tar.gz

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 (133) hide show
  1. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/PKG-INFO +1 -1
  2. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/send_emails/base_email.py +112 -7
  3. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/common_utils/check_batch_cost.py +1 -1
  4. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/hooks/managed_files.py +87 -10
  5. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/pyproject.toml +2 -2
  6. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/LICENSE.md +0 -0
  7. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/README.md +0 -0
  8. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/__init__.py +0 -0
  9. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/callback_controls.py +0 -0
  10. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/example_logging_api.py +0 -0
  11. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/llama_guard.py +0 -0
  12. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/llm_guard.py +0 -0
  13. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/pagerduty/pagerduty.py +0 -0
  14. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secret_detection.py +0 -0
  15. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/__init__.py +0 -0
  16. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/adafruit.py +0 -0
  17. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/adobe.py +0 -0
  18. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/age_secret_key.py +0 -0
  19. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/airtable_api_key.py +0 -0
  20. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/algolia_api_key.py +0 -0
  21. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/alibaba.py +0 -0
  22. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/asana.py +0 -0
  23. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/atlassian_api_token.py +0 -0
  24. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/authress_access_key.py +0 -0
  25. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/beamer_api_token.py +0 -0
  26. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/bitbucket.py +0 -0
  27. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/bittrex.py +0 -0
  28. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/clojars_api_token.py +0 -0
  29. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/codecov_access_token.py +0 -0
  30. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/coinbase_access_token.py +0 -0
  31. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/confluent.py +0 -0
  32. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/contentful_api_token.py +0 -0
  33. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/databricks_api_token.py +0 -0
  34. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/datadog_access_token.py +0 -0
  35. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/defined_networking_api_token.py +0 -0
  36. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/digitalocean.py +0 -0
  37. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/discord.py +0 -0
  38. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/doppler_api_token.py +0 -0
  39. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/droneci_access_token.py +0 -0
  40. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/dropbox.py +0 -0
  41. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/duffel_api_token.py +0 -0
  42. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/dynatrace_api_token.py +0 -0
  43. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/easypost.py +0 -0
  44. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/etsy_access_token.py +0 -0
  45. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/facebook_access_token.py +0 -0
  46. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/fastly_api_token.py +0 -0
  47. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/finicity.py +0 -0
  48. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/finnhub_access_token.py +0 -0
  49. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/flickr_access_token.py +0 -0
  50. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/flutterwave.py +0 -0
  51. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/frameio_api_token.py +0 -0
  52. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/freshbooks_access_token.py +0 -0
  53. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/gcp_api_key.py +0 -0
  54. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/github_token.py +0 -0
  55. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/gitlab.py +0 -0
  56. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/gitter_access_token.py +0 -0
  57. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/gocardless_api_token.py +0 -0
  58. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/grafana.py +0 -0
  59. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/hashicorp_tf_api_token.py +0 -0
  60. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/heroku_api_key.py +0 -0
  61. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/hubspot_api_key.py +0 -0
  62. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/huggingface.py +0 -0
  63. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/intercom_api_key.py +0 -0
  64. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/jfrog.py +0 -0
  65. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/jwt.py +0 -0
  66. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/kraken_access_token.py +0 -0
  67. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/kucoin.py +0 -0
  68. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/launchdarkly_access_token.py +0 -0
  69. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/linear.py +0 -0
  70. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/linkedin.py +0 -0
  71. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/lob.py +0 -0
  72. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/mailgun.py +0 -0
  73. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/mapbox_api_token.py +0 -0
  74. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/mattermost_access_token.py +0 -0
  75. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/messagebird.py +0 -0
  76. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/microsoft_teams_webhook.py +0 -0
  77. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/netlify_access_token.py +0 -0
  78. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/new_relic.py +0 -0
  79. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/nytimes_access_token.py +0 -0
  80. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/okta_access_token.py +0 -0
  81. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/openai_api_key.py +0 -0
  82. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/planetscale.py +0 -0
  83. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/postman_api_token.py +0 -0
  84. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/prefect_api_token.py +0 -0
  85. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/pulumi_api_token.py +0 -0
  86. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/pypi_upload_token.py +0 -0
  87. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/rapidapi_access_token.py +0 -0
  88. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/readme_api_token.py +0 -0
  89. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/rubygems_api_token.py +0 -0
  90. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/scalingo_api_token.py +0 -0
  91. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/sendbird.py +0 -0
  92. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/sendgrid_api_token.py +0 -0
  93. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/sendinblue_api_token.py +0 -0
  94. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/sentry_access_token.py +0 -0
  95. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/shippo_api_token.py +0 -0
  96. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/shopify.py +0 -0
  97. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/slack.py +0 -0
  98. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/snyk_api_token.py +0 -0
  99. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/squarespace_access_token.py +0 -0
  100. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/sumologic.py +0 -0
  101. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/telegram_bot_api_token.py +0 -0
  102. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/travisci_access_token.py +0 -0
  103. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/twitch_api_token.py +0 -0
  104. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/twitter.py +0 -0
  105. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/typeform_api_token.py +0 -0
  106. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/vault.py +0 -0
  107. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/yandex.py +0 -0
  108. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/secrets_plugins/zendesk_secret_key.py +0 -0
  109. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/send_emails/endpoints.py +0 -0
  110. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/send_emails/resend_email.py +0 -0
  111. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/send_emails/sendgrid_email.py +0 -0
  112. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/enterprise_callbacks/send_emails/smtp_email.py +0 -0
  113. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/integrations/custom_guardrail.py +0 -0
  114. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/litellm_core_utils/litellm_logging.py +0 -0
  115. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/__init__.py +0 -0
  116. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/audit_logging_endpoints.py +0 -0
  117. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/auth/__init__.py +0 -0
  118. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/auth/custom_sso_handler.py +0 -0
  119. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/auth/route_checks.py +0 -0
  120. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/auth/user_api_key_auth.py +0 -0
  121. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/common_utils/__init__.py +0 -0
  122. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/common_utils/check_responses_cost.py +0 -0
  123. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/enterprise_routes.py +0 -0
  124. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/management_endpoints/__init__.py +0 -0
  125. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/management_endpoints/internal_user_endpoints.py +0 -0
  126. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/management_endpoints/key_management_endpoints.py +0 -0
  127. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/proxy_server.py +0 -0
  128. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/readme.md +0 -0
  129. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/utils.py +0 -0
  130. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/proxy/vector_stores/endpoints.py +0 -0
  131. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/types/enterprise_callbacks/send_emails.py +0 -0
  132. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/types/proxy/audit_logging_endpoints.py +0 -0
  133. {litellm_enterprise-0.1.29 → litellm_enterprise-0.1.31}/litellm_enterprise/types/proxy/proxy_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: litellm-enterprise
3
- Version: 0.1.29
3
+ Version: 0.1.31
4
4
  Summary: Package for LiteLLM Enterprise features
5
5
  License-File: LICENSE.md
6
6
  Author: BerriAI
@@ -30,8 +30,15 @@ from litellm.integrations.email_templates.user_invitation_email import (
30
30
  from litellm.integrations.email_templates.templates import (
31
31
  MAX_BUDGET_ALERT_EMAIL_TEMPLATE,
32
32
  SOFT_BUDGET_ALERT_EMAIL_TEMPLATE,
33
+ TEAM_SOFT_BUDGET_ALERT_EMAIL_TEMPLATE,
34
+ )
35
+ from litellm.proxy._types import (
36
+ CallInfo,
37
+ InvitationNew,
38
+ Litellm_EntityType,
39
+ UserAPIKeyAuth,
40
+ WebhookEvent,
33
41
  )
34
- from litellm.proxy._types import CallInfo, InvitationNew, UserAPIKeyAuth, WebhookEvent
35
42
  from litellm.secret_managers.main import get_secret_bool
36
43
  from litellm.types.integrations.slack_alerting import LITELLM_LOGO_URL
37
44
  from litellm.constants import (
@@ -217,6 +224,78 @@ class BaseEmailLogger(CustomLogger):
217
224
  )
218
225
  pass
219
226
 
227
+ async def send_team_soft_budget_alert_email(self, event: WebhookEvent):
228
+ """
229
+ Send email to team members when team soft budget is crossed
230
+ Supports multiple recipients via alert_emails field from team metadata
231
+ """
232
+ # Collect all recipient emails
233
+ recipient_emails: List[str] = []
234
+
235
+ # Add additional alert emails from team metadata.soft_budget_alert_emails
236
+ if hasattr(event, "alert_emails") and event.alert_emails:
237
+ for email in event.alert_emails:
238
+ if email and email not in recipient_emails: # Avoid duplicates
239
+ recipient_emails.append(email)
240
+
241
+ # If no recipients found, skip sending
242
+ if not recipient_emails:
243
+ verbose_proxy_logger.warning(
244
+ f"No recipient emails found for team soft budget alert. event={event.model_dump(exclude_none=True)}"
245
+ )
246
+ return
247
+
248
+ # Validate that we have at least one valid email address
249
+ first_recipient_email = recipient_emails[0]
250
+ if not first_recipient_email or not first_recipient_email.strip():
251
+ verbose_proxy_logger.warning(
252
+ f"Invalid recipient email found for team soft budget alert. event={event.model_dump(exclude_none=True)}"
253
+ )
254
+ return
255
+
256
+ verbose_proxy_logger.debug(
257
+ f"send_team_soft_budget_alert_email_event: {json.dumps(event.model_dump(exclude_none=True), indent=4, default=str)}"
258
+ )
259
+
260
+ # Get email params using the first recipient email (for template formatting)
261
+ # For team alerts with alert_emails, we don't need user_id lookup since we already have email addresses
262
+ # Pass user_id=None to prevent _get_email_params from trying to look up email from a potentially None user_id
263
+ email_params = await self._get_email_params(
264
+ email_event=EmailEvent.soft_budget_crossed,
265
+ user_id=None, # Team alerts don't require user_id when alert_emails are provided
266
+ user_email=first_recipient_email,
267
+ event_message=event.event_message,
268
+ )
269
+
270
+ # Format budget values
271
+ soft_budget_str = f"${event.soft_budget}" if event.soft_budget is not None else "N/A"
272
+ spend_str = f"${event.spend}" if event.spend is not None else "$0.00"
273
+ max_budget_info = ""
274
+ if event.max_budget is not None:
275
+ max_budget_info = f"<b>Maximum Budget:</b> ${event.max_budget} <br />"
276
+
277
+ # Use team alias or generic greeting
278
+ team_alias = event.team_alias or "Team"
279
+
280
+ email_html_content = TEAM_SOFT_BUDGET_ALERT_EMAIL_TEMPLATE.format(
281
+ email_logo_url=email_params.logo_url,
282
+ team_alias=team_alias,
283
+ soft_budget=soft_budget_str,
284
+ spend=spend_str,
285
+ max_budget_info=max_budget_info,
286
+ base_url=email_params.base_url,
287
+ email_support_contact=email_params.support_contact,
288
+ )
289
+
290
+ # Send email to all recipients
291
+ await self.send_email(
292
+ from_email=self.DEFAULT_LITELLM_EMAIL,
293
+ to_email=recipient_emails,
294
+ subject=email_params.subject,
295
+ html_body=email_html_content,
296
+ )
297
+ pass
298
+
220
299
  async def send_max_budget_alert_email(self, event: WebhookEvent):
221
300
  """
222
301
  Send email to user when max budget alert threshold is reached
@@ -285,15 +364,36 @@ class BaseEmailLogger(CustomLogger):
285
364
  # - Don't re-alert, if alert already sent
286
365
  _cache: DualCache = self.internal_usage_cache
287
366
 
288
- # percent of max_budget left to spend
289
- if user_info.max_budget is None and user_info.soft_budget is None:
290
- return
291
-
292
367
  # For soft_budget alerts, check if we've already sent an alert
293
368
  if type == "soft_budget":
369
+ # For team soft budget alerts, we only need team soft_budget to be set
370
+ # For other entity types, we need either max_budget or soft_budget
371
+ if user_info.event_group == Litellm_EntityType.TEAM:
372
+ if user_info.soft_budget is None:
373
+ return
374
+ # For team soft budget alerts, require alert_emails to be configured
375
+ # Team soft budget alerts are sent via metadata.soft_budget_alerting_emails
376
+ if user_info.alert_emails is None or len(user_info.alert_emails) == 0:
377
+ verbose_proxy_logger.debug(
378
+ "Skipping team soft budget email alert: no alert_emails configured",
379
+ )
380
+ return
381
+ else:
382
+ # For non-team alerts, require either max_budget or soft_budget
383
+ if user_info.max_budget is None and user_info.soft_budget is None:
384
+ return
294
385
  if user_info.soft_budget is not None and user_info.spend >= user_info.soft_budget:
295
386
  # Generate cache key based on event type and identifier
296
- _id = user_info.token or user_info.user_id or "default_id"
387
+ # Use appropriate ID based on event_group to ensure unique cache keys per entity type
388
+ if user_info.event_group == Litellm_EntityType.TEAM:
389
+ _id = user_info.team_id or "default_id"
390
+ elif user_info.event_group == Litellm_EntityType.ORGANIZATION:
391
+ _id = user_info.organization_id or "default_id"
392
+ elif user_info.event_group == Litellm_EntityType.USER:
393
+ _id = user_info.user_id or "default_id"
394
+ else:
395
+ # For KEY and other types, use token or user_id
396
+ _id = user_info.token or user_info.user_id or "default_id"
297
397
  _cache_key = f"email_budget_alerts:soft_budget_crossed:{_id}"
298
398
 
299
399
  # Check if we've already sent this alert
@@ -318,10 +418,15 @@ class BaseEmailLogger(CustomLogger):
318
418
  projected_exceeded_date=user_info.projected_exceeded_date,
319
419
  projected_spend=user_info.projected_spend,
320
420
  event_group=user_info.event_group,
421
+ alert_emails=user_info.alert_emails,
321
422
  )
322
423
 
323
424
  try:
324
- await self.send_soft_budget_alert_email(webhook_event)
425
+ # Use team-specific function for team alerts, otherwise use standard function
426
+ if user_info.event_group == Litellm_EntityType.TEAM:
427
+ await self.send_team_soft_budget_alert_email(webhook_event)
428
+ else:
429
+ await self.send_soft_budget_alert_email(webhook_event)
325
430
 
326
431
  # Cache the alert to prevent duplicate sends
327
432
  await _cache.async_set_cache(
@@ -53,7 +53,7 @@ class CheckBatchCost:
53
53
 
54
54
  jobs = await self.prisma_client.db.litellm_managedobjecttable.find_many(
55
55
  where={
56
- "status": "validating",
56
+ "status": {"in": ["validating", "in_progress", "finalizing"]},
57
57
  "file_purpose": "batch",
58
58
  }
59
59
  )
@@ -166,7 +166,11 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
166
166
  "updated_by": user_api_key_dict.user_id,
167
167
  "status": file_object.status,
168
168
  },
169
- "update": {}, # don't do anything if it already exists
169
+ "update": {
170
+ "file_object": file_object.model_dump_json(),
171
+ "status": file_object.status,
172
+ "updated_by": user_api_key_dict.user_id,
173
+ }, # FIX: Update status and file_object on every operation to keep state in sync
170
174
  },
171
175
  )
172
176
 
@@ -354,6 +358,31 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
354
358
  )
355
359
  return False
356
360
 
361
+ async def check_file_ids_access(
362
+ self, file_ids: List[str], user_api_key_dict: UserAPIKeyAuth
363
+ ) -> None:
364
+ """
365
+ Check if the user has access to a list of file IDs.
366
+ Only checks managed (unified) file IDs.
367
+
368
+ Args:
369
+ file_ids: List of file IDs to check access for
370
+ user_api_key_dict: User API key authentication details
371
+
372
+ Raises:
373
+ HTTPException: If user doesn't have access to any of the files
374
+ """
375
+ for file_id in file_ids:
376
+ is_unified_file_id = _is_base64_encoded_unified_file_id(file_id)
377
+ if is_unified_file_id:
378
+ if not await self.can_user_call_unified_file_id(
379
+ file_id, user_api_key_dict
380
+ ):
381
+ raise HTTPException(
382
+ status_code=403,
383
+ detail=f"User {user_api_key_dict.user_id} does not have access to the file {file_id}",
384
+ )
385
+
357
386
  async def async_pre_call_hook( # noqa: PLR0915
358
387
  self,
359
388
  user_api_key_dict: UserAPIKeyAuth,
@@ -387,6 +416,9 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
387
416
  if messages:
388
417
  file_ids = self.get_file_ids_from_messages(messages)
389
418
  if file_ids:
419
+ # Check user has access to all managed files
420
+ await self.check_file_ids_access(file_ids, user_api_key_dict)
421
+
390
422
  # Check if any files are stored in storage backends and need base64 conversion
391
423
  # This is needed for Vertex AI/Gemini which requires base64 content
392
424
  is_vertex_ai = model and ("vertex_ai" in model or "gemini" in model.lower())
@@ -402,15 +434,27 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
402
434
  )
403
435
  data["model_file_id_mapping"] = model_file_id_mapping
404
436
  elif call_type == CallTypes.aresponses.value or call_type == CallTypes.responses.value:
405
- # Handle managed files in responses API input
437
+ # Handle managed files in responses API input and tools
438
+ file_ids = []
439
+
440
+ # Extract file IDs from input parameter
406
441
  input_data = data.get("input")
407
442
  if input_data:
408
- file_ids = self.get_file_ids_from_responses_input(input_data)
409
- if file_ids:
410
- model_file_id_mapping = await self.get_model_file_id_mapping(
411
- file_ids, user_api_key_dict.parent_otel_span
412
- )
413
- data["model_file_id_mapping"] = model_file_id_mapping
443
+ file_ids.extend(self.get_file_ids_from_responses_input(input_data))
444
+
445
+ # Extract file IDs from tools parameter (e.g., code_interpreter container)
446
+ tools = data.get("tools")
447
+ if tools:
448
+ file_ids.extend(self.get_file_ids_from_responses_tools(tools))
449
+
450
+ if file_ids:
451
+ # Check user has access to all managed files
452
+ await self.check_file_ids_access(file_ids, user_api_key_dict)
453
+
454
+ model_file_id_mapping = await self.get_model_file_id_mapping(
455
+ file_ids, user_api_key_dict.parent_otel_span
456
+ )
457
+ data["model_file_id_mapping"] = model_file_id_mapping
414
458
  elif call_type == CallTypes.afile_content.value:
415
459
  retrieve_file_id = cast(Optional[str], data.get("file_id"))
416
460
  potential_file_id = (
@@ -460,8 +504,6 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
460
504
  if retrieve_object_id
461
505
  else False
462
506
  )
463
- print(f"🔥potential_llm_object_id: {potential_llm_object_id}")
464
- print(f"🔥retrieve_object_id: {retrieve_object_id}")
465
507
  if potential_llm_object_id and retrieve_object_id:
466
508
  ## VALIDATE USER HAS ACCESS TO THE OBJECT ##
467
509
  if not await self.can_user_call_unified_object_id(
@@ -614,6 +656,41 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
614
656
 
615
657
  return file_ids
616
658
 
659
+ def get_file_ids_from_responses_tools(
660
+ self, tools: List[Dict[str, Any]]
661
+ ) -> List[str]:
662
+ """
663
+ Gets file ids from responses API tools parameter.
664
+
665
+ The tools can contain code_interpreter with container.file_ids:
666
+ [
667
+ {
668
+ "type": "code_interpreter",
669
+ "container": {"type": "auto", "file_ids": ["file-123", "file-456"]}
670
+ }
671
+ ]
672
+ """
673
+ file_ids: List[str] = []
674
+
675
+ if not isinstance(tools, list):
676
+ return file_ids
677
+
678
+ for tool in tools:
679
+ if not isinstance(tool, dict):
680
+ continue
681
+
682
+ # Check for code_interpreter with container file_ids
683
+ if tool.get("type") == "code_interpreter":
684
+ container = tool.get("container")
685
+ if isinstance(container, dict):
686
+ container_file_ids = container.get("file_ids")
687
+ if isinstance(container_file_ids, list):
688
+ for file_id in container_file_ids:
689
+ if isinstance(file_id, str):
690
+ file_ids.append(file_id)
691
+
692
+ return file_ids
693
+
617
694
  async def get_model_file_id_mapping(
618
695
  self, file_ids: List[str], litellm_parent_otel_span: Span
619
696
  ) -> dict:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "litellm-enterprise"
3
- version = "0.1.29"
3
+ version = "0.1.31"
4
4
  description = "Package for LiteLLM Enterprise features"
5
5
  authors = ["BerriAI"]
6
6
  readme = "README.md"
@@ -22,7 +22,7 @@ requires = ["poetry-core"]
22
22
  build-backend = "poetry.core.masonry.api"
23
23
 
24
24
  [tool.commitizen]
25
- version = "0.1.29"
25
+ version = "0.1.31"
26
26
  version_files = [
27
27
  "pyproject.toml:version",
28
28
  "../requirements.txt:litellm-enterprise==",