mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
Merge branch 'main' of https://github.com/BerriAI/litellm into litellm_fix_index_query_call
This commit is contained in:
commit
2ff9ef1301
37 changed files with 212 additions and 136 deletions
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Schedule Demo
|
||||
url: https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat
|
||||
url: https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions
|
||||
about: Speak directly with Krrish and Ishaan, the founders, to discuss issues, share feedback, or explore improvements for LiteLLM
|
||||
- name: Discord
|
||||
url: https://discord.com/invite/wuPM9dRgDw
|
||||
|
|
|
|||
2
.github/workflows/interpret_load_test.py
vendored
2
.github/workflows/interpret_load_test.py
vendored
|
|
@ -123,7 +123,7 @@ if __name__ == "__main__":
|
|||
+ docker_run_command
|
||||
+ "\n\n"
|
||||
+ "### Don't want to maintain your internal proxy? get in touch 🎉"
|
||||
+ "\nHosted Proxy Alpha: https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat"
|
||||
+ "\nHosted Proxy Alpha: https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions"
|
||||
+ "\n\n"
|
||||
+ "## Load Test LiteLLM Proxy Results"
|
||||
+ "\n\n"
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ Support for more providers. Missing a provider or LLM Platform, raise a [feature
|
|||
# Enterprise
|
||||
For companies that need better security, user management and professional support
|
||||
|
||||
[Talk to founders](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Talk to founders](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
This covers:
|
||||
- ✅ **Features under the [LiteLLM Commercial License](https://docs.litellm.ai/docs/proxy/enterprise):**
|
||||
|
|
|
|||
|
|
@ -178,4 +178,4 @@ Benchmark Results for 'When will BerriAI IPO?':
|
|||
```
|
||||
|
||||
## Support
|
||||
**🤝 Schedule a 1-on-1 Session:** Book a [1-on-1 session](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat) with Krrish and Ishaan, the founders, to discuss any issues, provide feedback, or explore how we can improve LiteLLM for you.
|
||||
**🤝 Schedule a 1-on-1 Session:** Book a [1-on-1 session](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) with Krrish and Ishaan, the founders, to discuss any issues, provide feedback, or explore how we can improve LiteLLM for you.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Image from '@theme/IdealImage';
|
|||
|
||||
:::info
|
||||
- ✨ SSO is free for up to 5 users. After that, an enterprise license is required. [Get Started with Enterprise here](https://www.litellm.ai/enterprise)
|
||||
- Who is Enterprise for? Companies giving access to 100+ users **OR** 10+ AI use-cases. If you're not sure, [get in touch with us](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat) to discuss your needs.
|
||||
- Who is Enterprise for? Companies giving access to 100+ users **OR** 10+ AI use-cases. If you're not sure, [get in touch with us](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) to discuss your needs.
|
||||
:::
|
||||
|
||||
For companies that need SSO, user management and professional support for LiteLLM Proxy
|
||||
|
|
@ -36,7 +36,7 @@ Manage Yourself - you can deploy our Docker Image or build a custom image from o
|
|||
|
||||
### What’s the cost of the Self-Managed Enterprise edition?
|
||||
|
||||
Self-Managed Enterprise deployments require our team to understand your exact needs. [Get in touch with us to learn more](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
Self-Managed Enterprise deployments require our team to understand your exact needs. [Get in touch with us to learn more](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
|
||||
### How does deployment with Enterprise License work?
|
||||
|
|
@ -106,7 +106,7 @@ Professional Support can assist with LLM/Provider integrations, deployment, upgr
|
|||
|
||||
Pricing is based on usage. We can figure out a price that works for your team, on the call.
|
||||
|
||||
[**Contact Us to learn more**](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[**Contact Us to learn more**](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import TabItem from '@theme/TabItem';
|
|||
|
||||
:::info
|
||||
|
||||
This is an Enterprise only endpoint [Get Started with Enterprise here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
This is an Enterprise only endpoint [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Log LLM Logs to [Google Cloud Storage Buckets](https://cloud.google.com/storage?
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ Use this when you want non-proxy admins to access `/spend` endpoints
|
|||
|
||||
:::info
|
||||
|
||||
Schedule a [meeting with us to get your Enterprise License](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
Schedule a [meeting with us to get your Enterprise License](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ After regenerating the key, the user will receive an email notification with:
|
|||
|
||||
:::info
|
||||
|
||||
Customizing Email Branding is an Enterprise Feature [Get in touch with us for a Free Trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
Customizing Email Branding is an Enterprise Feature [Get in touch with us for a Free Trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import TabItem from '@theme/TabItem';
|
|||
# ✨ Enterprise Features
|
||||
:::tip
|
||||
|
||||
To get a license, get in touch with us [here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
To get a license, get in touch with us [here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ curl -i http://localhost:4000/v1/chat/completions \
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@ curl -i -X POST http://localhost:4000/v1/chat/completions \
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ curl -i http://localhost:4000/v1/chat/completions \
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
:::info
|
||||
|
||||
You need a LiteLLM License to unlock this feature. [Grab time](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat), to get one today!
|
||||
You need a LiteLLM License to unlock this feature. [Grab time](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions), to get one today!
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -1109,7 +1109,7 @@ Log LLM Logs to [Google Cloud Storage Buckets](https://cloud.google.com/storage?
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -1194,7 +1194,7 @@ Log LLM Logs/SpendLogs to [Google Cloud Storage PubSub Topic](https://cloud.goog
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -1497,7 +1497,7 @@ Log LLM Logs to [Azure Data Lake Storage](https://learn.microsoft.com/en-us/azur
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ LiteLLM tracks changes to the following entities and actions:
|
|||
|
||||
:::tip
|
||||
|
||||
Requires Enterprise License, Get in touch with us [here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
Requires Enterprise License, Get in touch with us [here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Use this if you want to use an Oauth2.0 token to make `/chat`, `/embeddings` req
|
|||
|
||||
:::info
|
||||
|
||||
This is an Enterprise Feature - [get in touch with us if you want a free trial to test if this feature meets your needs]((https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat))
|
||||
This is an Enterprise Feature - [get in touch with us if you want a free trial to test if this feature meets your needs]((https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions))
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export LITELLM_LOG="ERROR"
|
|||
|
||||
:::info
|
||||
|
||||
Need Help or want dedicated support ? Talk to a founder [here]: (https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
Need Help or want dedicated support ? Talk to a founder [here]: (https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import TabItem from '@theme/TabItem';
|
|||
|
||||
:::info
|
||||
|
||||
Requires a LiteLLM Enterprise License. [Get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat).
|
||||
Requires a LiteLLM Enterprise License. [Get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions).
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ LiteLLM Proxy supports team-based tag routing, allowing you to associate specifi
|
|||
|
||||
:::info
|
||||
|
||||
This is an enterprise feature, [Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
This is an enterprise feature, [Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ Team 3 -> Disabled Logging (for GDPR compliance)
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ Use the `/key/generate` or `/key/update` endpoints to add logging callbacks to a
|
|||
|
||||
:::info
|
||||
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
This is an Enterprise feature.
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Use JWT's to auth admins / users / projects into the proxy.
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import TabItem from '@theme/TabItem';
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import Image from '@theme/IdealImage';
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import Image from '@theme/IdealImage';
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import Image from '@theme/IdealImage';
|
|||
|
||||
[Enterprise Pricing](https://www.litellm.ai/#pricing)
|
||||
|
||||
[Contact us here to get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
|
||||
[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ Benchmark Results for 'When will BerriAI IPO?':
|
|||
+-----------------+----------------------------------------------------------------------------------+---------------------------+------------+
|
||||
```
|
||||
## Support
|
||||
**🤝 Schedule a 1-on-1 Session:** Book a [1-on-1 session](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat) with Krrish and Ishaan, the founders, to discuss any issues, provide feedback, or explore how we can improve LiteLLM for you.
|
||||
**🤝 Schedule a 1-on-1 Session:** Book a [1-on-1 session](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) with Krrish and Ishaan, the founders, to discuss any issues, provide feedback, or explore how we can improve LiteLLM for you.
|
||||
|
||||
|
||||
<!--
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ With regard to the BerriAI Software:
|
|||
This software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the BerriAI Subscription Terms of Service, available
|
||||
via [call](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat) or email (info@berri.ai) (the "Enterprise Terms"), or other
|
||||
via [call](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) or email (info@berri.ai) (the "Enterprise Terms"), or other
|
||||
agreement governing the use of the Software, as agreed by you and BerriAI,
|
||||
and otherwise have a valid BerriAI Enterprise license for the
|
||||
correct number of user seats. Subject to the foregoing sentence, you are free to
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ Code in this folder is licensed under a commercial license. Please review the [L
|
|||
|
||||
**These features are covered under the LiteLLM Enterprise contract**
|
||||
|
||||
👉 **Using in an Enterprise / Need specific features ?** Meet with us [here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat?month=2024-02)
|
||||
👉 **Using in an Enterprise / Need specific features ?** Meet with us [here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions?month=2024-02)
|
||||
|
||||
See all Enterprise Features here 👉 [Docs](https://docs.litellm.ai/docs/proxy/enterprise)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ from litellm_enterprise.types.enterprise_callbacks.send_emails import (
|
|||
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm.caching.caching import DualCache
|
||||
from litellm.constants import (
|
||||
EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE,
|
||||
EMAIL_BUDGET_ALERT_TTL,
|
||||
)
|
||||
from litellm.integrations.custom_logger import CustomLogger
|
||||
from litellm.integrations.email_templates.email_footer import EMAIL_FOOTER
|
||||
from litellm.integrations.email_templates.key_created_email import (
|
||||
|
|
@ -24,14 +28,14 @@ from litellm.integrations.email_templates.key_created_email import (
|
|||
from litellm.integrations.email_templates.key_rotated_email import (
|
||||
KEY_ROTATED_EMAIL_TEMPLATE,
|
||||
)
|
||||
from litellm.integrations.email_templates.user_invitation_email import (
|
||||
USER_INVITATION_EMAIL_TEMPLATE,
|
||||
)
|
||||
from litellm.integrations.email_templates.templates import (
|
||||
MAX_BUDGET_ALERT_EMAIL_TEMPLATE,
|
||||
SOFT_BUDGET_ALERT_EMAIL_TEMPLATE,
|
||||
TEAM_SOFT_BUDGET_ALERT_EMAIL_TEMPLATE,
|
||||
)
|
||||
from litellm.integrations.email_templates.user_invitation_email import (
|
||||
USER_INVITATION_EMAIL_TEMPLATE,
|
||||
)
|
||||
from litellm.proxy._types import (
|
||||
CallInfo,
|
||||
InvitationNew,
|
||||
|
|
@ -41,10 +45,6 @@ from litellm.proxy._types import (
|
|||
)
|
||||
from litellm.secret_managers.main import get_secret_bool
|
||||
from litellm.types.integrations.slack_alerting import LITELLM_LOGO_URL
|
||||
from litellm.constants import (
|
||||
EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE,
|
||||
EMAIL_BUDGET_ALERT_TTL,
|
||||
)
|
||||
|
||||
|
||||
class BaseEmailLogger(CustomLogger):
|
||||
|
|
@ -121,10 +121,16 @@ class BaseEmailLogger(CustomLogger):
|
|||
)
|
||||
|
||||
# Check if API key should be included in email
|
||||
include_api_key = get_secret_bool(secret_name="EMAIL_INCLUDE_API_KEY", default_value=True)
|
||||
include_api_key = get_secret_bool(
|
||||
secret_name="EMAIL_INCLUDE_API_KEY", default_value=True
|
||||
)
|
||||
if include_api_key is None:
|
||||
include_api_key = True # Default to True if not set
|
||||
key_token_display = send_key_created_email_event.virtual_key if include_api_key else "[Key hidden for security - retrieve from dashboard]"
|
||||
key_token_display = (
|
||||
send_key_created_email_event.virtual_key
|
||||
if include_api_key
|
||||
else "[Key hidden for security - retrieve from dashboard]"
|
||||
)
|
||||
|
||||
email_html_content = KEY_CREATED_EMAIL_TEMPLATE.format(
|
||||
email_logo_url=email_params.logo_url,
|
||||
|
|
@ -162,10 +168,16 @@ class BaseEmailLogger(CustomLogger):
|
|||
)
|
||||
|
||||
# Check if API key should be included in email
|
||||
include_api_key = get_secret_bool(secret_name="EMAIL_INCLUDE_API_KEY", default_value=True)
|
||||
include_api_key = get_secret_bool(
|
||||
secret_name="EMAIL_INCLUDE_API_KEY", default_value=True
|
||||
)
|
||||
if include_api_key is None:
|
||||
include_api_key = True # Default to True if not set
|
||||
key_token_display = send_key_rotated_email_event.virtual_key if include_api_key else "[Key hidden for security - retrieve from dashboard]"
|
||||
key_token_display = (
|
||||
send_key_rotated_email_event.virtual_key
|
||||
if include_api_key
|
||||
else "[Key hidden for security - retrieve from dashboard]"
|
||||
)
|
||||
|
||||
email_html_content = KEY_ROTATED_EMAIL_TEMPLATE.format(
|
||||
email_logo_url=email_params.logo_url,
|
||||
|
|
@ -201,7 +213,9 @@ class BaseEmailLogger(CustomLogger):
|
|||
)
|
||||
|
||||
# Format budget values
|
||||
soft_budget_str = f"${event.soft_budget}" if event.soft_budget is not None else "N/A"
|
||||
soft_budget_str = (
|
||||
f"${event.soft_budget}" if event.soft_budget is not None else "N/A"
|
||||
)
|
||||
spend_str = f"${event.spend}" if event.spend is not None else "$0.00"
|
||||
max_budget_info = ""
|
||||
if event.max_budget is not None:
|
||||
|
|
@ -231,13 +245,13 @@ class BaseEmailLogger(CustomLogger):
|
|||
"""
|
||||
# Collect all recipient emails
|
||||
recipient_emails: List[str] = []
|
||||
|
||||
|
||||
# Add additional alert emails from team metadata.soft_budget_alert_emails
|
||||
if hasattr(event, "alert_emails") and event.alert_emails:
|
||||
for email in event.alert_emails:
|
||||
if email and email not in recipient_emails: # Avoid duplicates
|
||||
recipient_emails.append(email)
|
||||
|
||||
|
||||
# If no recipients found, skip sending
|
||||
if not recipient_emails:
|
||||
verbose_proxy_logger.warning(
|
||||
|
|
@ -268,7 +282,9 @@ class BaseEmailLogger(CustomLogger):
|
|||
)
|
||||
|
||||
# Format budget values
|
||||
soft_budget_str = f"${event.soft_budget}" if event.soft_budget is not None else "N/A"
|
||||
soft_budget_str = (
|
||||
f"${event.soft_budget}" if event.soft_budget is not None else "N/A"
|
||||
)
|
||||
spend_str = f"${event.spend}" if event.spend is not None else "$0.00"
|
||||
max_budget_info = ""
|
||||
if event.max_budget is not None:
|
||||
|
|
@ -286,7 +302,7 @@ class BaseEmailLogger(CustomLogger):
|
|||
base_url=email_params.base_url,
|
||||
email_support_contact=email_params.support_contact,
|
||||
)
|
||||
|
||||
|
||||
# Send email to all recipients
|
||||
await self.send_email(
|
||||
from_email=self.DEFAULT_LITELLM_EMAIL,
|
||||
|
|
@ -313,11 +329,17 @@ class BaseEmailLogger(CustomLogger):
|
|||
|
||||
# Format budget values
|
||||
spend_str = f"${event.spend}" if event.spend is not None else "$0.00"
|
||||
max_budget_str = f"${event.max_budget}" if event.max_budget is not None else "N/A"
|
||||
|
||||
max_budget_str = (
|
||||
f"${event.max_budget}" if event.max_budget is not None else "N/A"
|
||||
)
|
||||
|
||||
# Calculate percentage and alert threshold
|
||||
percentage = int(EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE * 100)
|
||||
alert_threshold_str = f"${event.max_budget * EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE:.2f}" if event.max_budget is not None else "N/A"
|
||||
alert_threshold_str = (
|
||||
f"${event.max_budget * EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE:.2f}"
|
||||
if event.max_budget is not None
|
||||
else "N/A"
|
||||
)
|
||||
|
||||
email_html_content = MAX_BUDGET_ALERT_EMAIL_TEMPLATE.format(
|
||||
email_logo_url=email_params.logo_url,
|
||||
|
|
@ -382,7 +404,10 @@ class BaseEmailLogger(CustomLogger):
|
|||
# For non-team alerts, require either max_budget or soft_budget
|
||||
if user_info.max_budget is None and user_info.soft_budget is None:
|
||||
return
|
||||
if user_info.soft_budget is not None and user_info.spend >= user_info.soft_budget:
|
||||
if (
|
||||
user_info.soft_budget is not None
|
||||
and user_info.spend >= user_info.soft_budget
|
||||
):
|
||||
# Generate cache key based on event type and identifier
|
||||
# Use appropriate ID based on event_group to ensure unique cache keys per entity type
|
||||
if user_info.event_group == Litellm_EntityType.TEAM:
|
||||
|
|
@ -395,7 +420,7 @@ class BaseEmailLogger(CustomLogger):
|
|||
# For KEY and other types, use token or user_id
|
||||
_id = user_info.token or user_info.user_id or "default_id"
|
||||
_cache_key = f"email_budget_alerts:soft_budget_crossed:{_id}"
|
||||
|
||||
|
||||
# Check if we've already sent this alert
|
||||
result = await _cache.async_get_cache(key=_cache_key)
|
||||
if result is None:
|
||||
|
|
@ -420,14 +445,14 @@ class BaseEmailLogger(CustomLogger):
|
|||
event_group=user_info.event_group,
|
||||
alert_emails=user_info.alert_emails,
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
# Use team-specific function for team alerts, otherwise use standard function
|
||||
if user_info.event_group == Litellm_EntityType.TEAM:
|
||||
await self.send_team_soft_budget_alert_email(webhook_event)
|
||||
else:
|
||||
await self.send_soft_budget_alert_email(webhook_event)
|
||||
|
||||
|
||||
# Cache the alert to prevent duplicate sends
|
||||
await _cache.async_set_cache(
|
||||
key=_cache_key,
|
||||
|
|
@ -444,20 +469,27 @@ class BaseEmailLogger(CustomLogger):
|
|||
# For max_budget_alert, check if we've already sent an alert
|
||||
if type == "max_budget_alert":
|
||||
if user_info.max_budget is not None and user_info.spend is not None:
|
||||
alert_threshold = user_info.max_budget * EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE
|
||||
|
||||
alert_threshold = (
|
||||
user_info.max_budget * EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE
|
||||
)
|
||||
|
||||
# Only alert if we've crossed the threshold but haven't exceeded max_budget yet
|
||||
if user_info.spend >= alert_threshold and user_info.spend < user_info.max_budget:
|
||||
if (
|
||||
user_info.spend >= alert_threshold
|
||||
and user_info.spend < user_info.max_budget
|
||||
):
|
||||
# Generate cache key based on event type and identifier
|
||||
_id = user_info.token or user_info.user_id or "default_id"
|
||||
_cache_key = f"email_budget_alerts:max_budget_alert:{_id}"
|
||||
|
||||
|
||||
# Check if we've already sent this alert
|
||||
result = await _cache.async_get_cache(key=_cache_key)
|
||||
if result is None:
|
||||
# Calculate percentage
|
||||
percentage = int(EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE * 100)
|
||||
|
||||
percentage = int(
|
||||
EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE * 100
|
||||
)
|
||||
|
||||
# Create WebhookEvent for max budget alert
|
||||
event_message = f"Max Budget Alert - {percentage}% of Maximum Budget Reached"
|
||||
webhook_event = WebhookEvent(
|
||||
|
|
@ -478,10 +510,10 @@ class BaseEmailLogger(CustomLogger):
|
|||
projected_spend=user_info.projected_spend,
|
||||
event_group=user_info.event_group,
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
await self.send_max_budget_alert_email(webhook_event)
|
||||
|
||||
|
||||
# Cache the alert to prevent duplicate sends
|
||||
await _cache.async_set_cache(
|
||||
key=_cache_key,
|
||||
|
|
@ -525,9 +557,14 @@ class BaseEmailLogger(CustomLogger):
|
|||
unused_custom_fields = []
|
||||
|
||||
# Function to safely get custom value or default
|
||||
def get_custom_or_default(custom_value: Optional[str], default_value: str, field_name: str) -> str:
|
||||
if custom_value is not None: # Only check premium if trying to use custom value
|
||||
def get_custom_or_default(
|
||||
custom_value: Optional[str], default_value: str, field_name: str
|
||||
) -> str:
|
||||
if (
|
||||
custom_value is not None
|
||||
): # Only check premium if trying to use custom value
|
||||
from litellm.proxy.proxy_server import premium_user
|
||||
|
||||
if premium_user is not True:
|
||||
unused_custom_fields.append(field_name)
|
||||
return default_value
|
||||
|
|
@ -536,38 +573,48 @@ class BaseEmailLogger(CustomLogger):
|
|||
|
||||
# Get parameters, falling back to defaults if custom values aren't allowed
|
||||
logo_url = get_custom_or_default(custom_logo, LITELLM_LOGO_URL, "logo URL")
|
||||
support_contact = get_custom_or_default(custom_support, self.DEFAULT_SUPPORT_EMAIL, "support contact")
|
||||
base_url = os.getenv("PROXY_BASE_URL", "http://0.0.0.0:4000") # Not a premium feature
|
||||
signature = get_custom_or_default(custom_signature, EMAIL_FOOTER, "email signature")
|
||||
support_contact = get_custom_or_default(
|
||||
custom_support, self.DEFAULT_SUPPORT_EMAIL, "support contact"
|
||||
)
|
||||
base_url = os.getenv(
|
||||
"PROXY_BASE_URL", "http://0.0.0.0:4000"
|
||||
) # Not a premium feature
|
||||
signature = get_custom_or_default(
|
||||
custom_signature, EMAIL_FOOTER, "email signature"
|
||||
)
|
||||
|
||||
# Get custom subject template based on email event type
|
||||
if email_event == EmailEvent.new_user_invitation:
|
||||
subject_template = get_custom_or_default(
|
||||
custom_subject_invitation,
|
||||
self.DEFAULT_SUBJECT_TEMPLATES[EmailEvent.new_user_invitation],
|
||||
"invitation subject template"
|
||||
"invitation subject template",
|
||||
)
|
||||
elif email_event == EmailEvent.virtual_key_created:
|
||||
subject_template = get_custom_or_default(
|
||||
custom_subject_key_created,
|
||||
self.DEFAULT_SUBJECT_TEMPLATES[EmailEvent.virtual_key_created],
|
||||
"key created subject template"
|
||||
"key created subject template",
|
||||
)
|
||||
elif email_event == EmailEvent.virtual_key_rotated:
|
||||
custom_subject_key_rotated = os.getenv("EMAIL_SUBJECT_KEY_ROTATED", None)
|
||||
subject_template = get_custom_or_default(
|
||||
custom_subject_key_rotated,
|
||||
self.DEFAULT_SUBJECT_TEMPLATES[EmailEvent.virtual_key_rotated],
|
||||
"key rotated subject template"
|
||||
"key rotated subject template",
|
||||
)
|
||||
else:
|
||||
subject_template = "LiteLLM: {event_message}"
|
||||
|
||||
subject = subject_template.format(event_message=event_message) if event_message else "LiteLLM Notification"
|
||||
subject = (
|
||||
subject_template.format(event_message=event_message)
|
||||
if event_message
|
||||
else "LiteLLM Notification"
|
||||
)
|
||||
|
||||
recipient_email: Optional[
|
||||
str
|
||||
] = user_email or await self._lookup_user_email_from_db(user_id=user_id)
|
||||
recipient_email: Optional[str] = (
|
||||
user_email or await self._lookup_user_email_from_db(user_id=user_id)
|
||||
)
|
||||
if recipient_email is None:
|
||||
raise ValueError(
|
||||
f"User email not found for user_id: {user_id}. User email is required to send email."
|
||||
|
|
@ -585,11 +632,9 @@ class BaseEmailLogger(CustomLogger):
|
|||
warning_msg = (
|
||||
f"Email sent with default values instead of custom values for: {fields_str}. "
|
||||
"This is an Enterprise feature. To use custom email fields, please upgrade to LiteLLM Enterprise. "
|
||||
"Schedule a meeting here: https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat"
|
||||
)
|
||||
verbose_proxy_logger.warning(
|
||||
f"{warning_msg}"
|
||||
"Schedule a meeting here: https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions"
|
||||
)
|
||||
verbose_proxy_logger.warning(f"{warning_msg}")
|
||||
|
||||
return EmailParams(
|
||||
logo_url=logo_url,
|
||||
|
|
@ -636,44 +681,49 @@ class BaseEmailLogger(CustomLogger):
|
|||
if not user_id:
|
||||
verbose_proxy_logger.debug("No user_id provided for invitation link")
|
||||
return base_url
|
||||
|
||||
|
||||
if not await self._is_prisma_client_available():
|
||||
return base_url
|
||||
|
||||
|
||||
# Wait for any concurrent invitation creation to complete
|
||||
await self._wait_for_invitation_creation()
|
||||
|
||||
|
||||
# Get or create invitation
|
||||
invitation = await self._get_or_create_invitation(user_id)
|
||||
if not invitation:
|
||||
verbose_proxy_logger.warning(f"Failed to get/create invitation for user_id: {user_id}")
|
||||
verbose_proxy_logger.warning(
|
||||
f"Failed to get/create invitation for user_id: {user_id}"
|
||||
)
|
||||
return base_url
|
||||
|
||||
|
||||
return self._construct_invitation_link(invitation.id, base_url)
|
||||
|
||||
async def _is_prisma_client_available(self) -> bool:
|
||||
"""Check if Prisma client is available"""
|
||||
from litellm.proxy.proxy_server import prisma_client
|
||||
|
||||
|
||||
if prisma_client is None:
|
||||
verbose_proxy_logger.debug("Prisma client not found. Unable to lookup invitation")
|
||||
verbose_proxy_logger.debug(
|
||||
"Prisma client not found. Unable to lookup invitation"
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
async def _wait_for_invitation_creation(self) -> None:
|
||||
"""
|
||||
Wait for any concurrent invitation creation to complete.
|
||||
|
||||
|
||||
The UI calls /invitation/new to generate the invitation link.
|
||||
We wait to ensure any pending invitation creation is completed.
|
||||
"""
|
||||
import asyncio
|
||||
|
||||
await asyncio.sleep(10)
|
||||
|
||||
async def _get_or_create_invitation(self, user_id: str):
|
||||
"""
|
||||
Get existing invitation or create a new one for the user
|
||||
|
||||
|
||||
Returns:
|
||||
Invitation object with id attribute, or None if failed
|
||||
"""
|
||||
|
|
@ -681,31 +731,41 @@ class BaseEmailLogger(CustomLogger):
|
|||
create_invitation_for_user,
|
||||
)
|
||||
from litellm.proxy.proxy_server import prisma_client
|
||||
|
||||
|
||||
if prisma_client is None:
|
||||
verbose_proxy_logger.error("Prisma client is None in _get_or_create_invitation")
|
||||
verbose_proxy_logger.error(
|
||||
"Prisma client is None in _get_or_create_invitation"
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
try:
|
||||
# Try to get existing invitation
|
||||
existing_invitations = await prisma_client.db.litellm_invitationlink.find_many(
|
||||
where={"user_id": user_id},
|
||||
order={"created_at": "desc"},
|
||||
existing_invitations = (
|
||||
await prisma_client.db.litellm_invitationlink.find_many(
|
||||
where={"user_id": user_id},
|
||||
order={"created_at": "desc"},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if existing_invitations and len(existing_invitations) > 0:
|
||||
verbose_proxy_logger.debug(f"Found existing invitation for user_id: {user_id}")
|
||||
verbose_proxy_logger.debug(
|
||||
f"Found existing invitation for user_id: {user_id}"
|
||||
)
|
||||
return existing_invitations[0]
|
||||
|
||||
|
||||
# Create new invitation if none exists
|
||||
verbose_proxy_logger.debug(f"Creating new invitation for user_id: {user_id}")
|
||||
verbose_proxy_logger.debug(
|
||||
f"Creating new invitation for user_id: {user_id}"
|
||||
)
|
||||
return await create_invitation_for_user(
|
||||
data=InvitationNew(user_id=user_id),
|
||||
user_api_key_dict=UserAPIKeyAuth(user_id=user_id),
|
||||
)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.error(f"Error getting/creating invitation for user_id {user_id}: {e}")
|
||||
verbose_proxy_logger.error(
|
||||
f"Error getting/creating invitation for user_id {user_id}: {e}"
|
||||
)
|
||||
return None
|
||||
|
||||
def _construct_invitation_link(self, invitation_id: str, base_url: str) -> str:
|
||||
|
|
|
|||
|
|
@ -214,29 +214,41 @@ def process_sso_jwt_access_token(
|
|||
if isinstance(result, dict):
|
||||
result_team_ids: Optional[List[str]] = result.get("team_ids", [])
|
||||
if not result_team_ids:
|
||||
team_ids = sso_jwt_handler.get_team_ids_from_jwt(access_token_payload)
|
||||
team_ids = sso_jwt_handler.get_team_ids_from_jwt(
|
||||
access_token_payload
|
||||
)
|
||||
result["team_ids"] = team_ids
|
||||
else:
|
||||
result_team_ids = getattr(result, "team_ids", []) if result else []
|
||||
if not result_team_ids:
|
||||
team_ids = sso_jwt_handler.get_team_ids_from_jwt(access_token_payload)
|
||||
team_ids = sso_jwt_handler.get_team_ids_from_jwt(
|
||||
access_token_payload
|
||||
)
|
||||
setattr(result, "team_ids", team_ids)
|
||||
|
||||
# Extract user role from access token if not already set from UserInfo
|
||||
existing_role = result.get("user_role") if isinstance(result, dict) else getattr(result, "user_role", None)
|
||||
existing_role = (
|
||||
result.get("user_role")
|
||||
if isinstance(result, dict)
|
||||
else getattr(result, "user_role", None)
|
||||
)
|
||||
if existing_role is None:
|
||||
user_role: Optional[LitellmUserRoles] = None
|
||||
|
||||
# Try role_mappings first (group-based role determination)
|
||||
if role_mappings is not None and role_mappings.roles:
|
||||
group_claim = role_mappings.group_claim
|
||||
user_groups_raw: Any = get_nested_value(access_token_payload, group_claim)
|
||||
user_groups_raw: Any = get_nested_value(
|
||||
access_token_payload, group_claim
|
||||
)
|
||||
|
||||
user_groups: List[str] = []
|
||||
if isinstance(user_groups_raw, list):
|
||||
user_groups = [str(g) for g in user_groups_raw]
|
||||
elif isinstance(user_groups_raw, str):
|
||||
user_groups = [g.strip() for g in user_groups_raw.split(",") if g.strip()]
|
||||
user_groups = [
|
||||
g.strip() for g in user_groups_raw.split(",") if g.strip()
|
||||
]
|
||||
elif user_groups_raw is not None:
|
||||
user_groups = [str(user_groups_raw)]
|
||||
|
||||
|
|
@ -250,8 +262,12 @@ def process_sso_jwt_access_token(
|
|||
|
||||
# Fallback: try GENERIC_USER_ROLE_ATTRIBUTE on the access token payload
|
||||
if user_role is None:
|
||||
generic_user_role_attribute_name = os.getenv("GENERIC_USER_ROLE_ATTRIBUTE", "role")
|
||||
user_role_from_token = get_nested_value(access_token_payload, generic_user_role_attribute_name)
|
||||
generic_user_role_attribute_name = os.getenv(
|
||||
"GENERIC_USER_ROLE_ATTRIBUTE", "role"
|
||||
)
|
||||
user_role_from_token = get_nested_value(
|
||||
access_token_payload, generic_user_role_attribute_name
|
||||
)
|
||||
if user_role_from_token is not None:
|
||||
user_role = get_litellm_user_role(user_role_from_token)
|
||||
verbose_proxy_logger.debug(
|
||||
|
|
@ -309,7 +325,7 @@ async def google_login(
|
|||
total_users = await prisma_client.db.litellm_usertable.count()
|
||||
if total_users and total_users > 5:
|
||||
raise ProxyException(
|
||||
message="You must be a LiteLLM Enterprise user to use SSO for more than 5 users. If you have a license please set `LITELLM_LICENSE` in your env. If you want to obtain a license meet with us here: https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat You are seeing this error message because You set one of `MICROSOFT_CLIENT_ID`, `GOOGLE_CLIENT_ID`, or `GENERIC_CLIENT_ID` in your env. Please unset this",
|
||||
message="You must be a LiteLLM Enterprise user to use SSO for more than 5 users. If you have a license please set `LITELLM_LICENSE` in your env. If you want to obtain a license meet with us here: https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions You are seeing this error message because You set one of `MICROSOFT_CLIENT_ID`, `GOOGLE_CLIENT_ID`, or `GENERIC_CLIENT_ID` in your env. Please unset this",
|
||||
type=ProxyErrorTypes.auth_error,
|
||||
param="premium_user",
|
||||
code=status.HTTP_403_FORBIDDEN,
|
||||
|
|
@ -662,13 +678,11 @@ async def _setup_role_mappings() -> Optional["RoleMappings"]:
|
|||
import ast
|
||||
|
||||
try:
|
||||
generic_user_role_mappings_data: Dict[
|
||||
LitellmUserRoles, List[str]
|
||||
] = ast.literal_eval(generic_role_mappings)
|
||||
generic_user_role_mappings_data: Dict[LitellmUserRoles, List[str]] = (
|
||||
ast.literal_eval(generic_role_mappings)
|
||||
)
|
||||
if isinstance(generic_user_role_mappings_data, dict):
|
||||
from litellm.types.proxy.management_endpoints.ui_sso import (
|
||||
RoleMappings,
|
||||
)
|
||||
from litellm.types.proxy.management_endpoints.ui_sso import RoleMappings
|
||||
|
||||
role_mappings_data = {
|
||||
"provider": "generic",
|
||||
|
|
@ -770,7 +784,9 @@ async def get_generic_sso_response(
|
|||
)
|
||||
|
||||
access_token_str: Optional[str] = generic_sso.access_token
|
||||
process_sso_jwt_access_token(access_token_str, sso_jwt_handler, result, role_mappings=role_mappings)
|
||||
process_sso_jwt_access_token(
|
||||
access_token_str, sso_jwt_handler, result, role_mappings=role_mappings
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.exception(
|
||||
|
|
@ -1000,9 +1016,9 @@ def apply_user_info_values_to_sso_user_defined_values(
|
|||
else:
|
||||
# SSO didn't provide a valid role, fall back to DB role or default
|
||||
if user_info is None or user_info.user_role is None:
|
||||
user_defined_values[
|
||||
"user_role"
|
||||
] = LitellmUserRoles.INTERNAL_USER_VIEW_ONLY.value
|
||||
user_defined_values["user_role"] = (
|
||||
LitellmUserRoles.INTERNAL_USER_VIEW_ONLY.value
|
||||
)
|
||||
verbose_proxy_logger.debug(
|
||||
"No SSO or DB role found, using default: INTERNAL_USER_VIEW_ONLY"
|
||||
)
|
||||
|
|
@ -1430,9 +1446,9 @@ async def insert_sso_user(
|
|||
if user_defined_values.get("max_budget") is None:
|
||||
user_defined_values["max_budget"] = litellm.max_internal_user_budget
|
||||
if user_defined_values.get("budget_duration") is None:
|
||||
user_defined_values[
|
||||
"budget_duration"
|
||||
] = litellm.internal_user_budget_duration
|
||||
user_defined_values["budget_duration"] = (
|
||||
litellm.internal_user_budget_duration
|
||||
)
|
||||
|
||||
if user_defined_values["user_role"] is None:
|
||||
user_defined_values["user_role"] = LitellmUserRoles.INTERNAL_USER_VIEW_ONLY
|
||||
|
|
@ -2533,9 +2549,9 @@ class MicrosoftSSOHandler:
|
|||
|
||||
# if user is trying to get the raw sso response for debugging, return the raw sso response
|
||||
if return_raw_sso_response:
|
||||
original_msft_result[
|
||||
MicrosoftSSOHandler.GRAPH_API_RESPONSE_KEY
|
||||
] = user_team_ids
|
||||
original_msft_result[MicrosoftSSOHandler.GRAPH_API_RESPONSE_KEY] = (
|
||||
user_team_ids
|
||||
)
|
||||
original_msft_result["app_roles"] = app_roles
|
||||
return original_msft_result or {}
|
||||
|
||||
|
|
@ -2654,9 +2670,9 @@ class MicrosoftSSOHandler:
|
|||
|
||||
# Fetch user membership from Microsoft Graph API
|
||||
all_group_ids = []
|
||||
next_link: Optional[
|
||||
str
|
||||
] = MicrosoftSSOHandler.graph_api_user_groups_endpoint
|
||||
next_link: Optional[str] = (
|
||||
MicrosoftSSOHandler.graph_api_user_groups_endpoint
|
||||
)
|
||||
auth_headers = {"Authorization": f"Bearer {access_token}"}
|
||||
page_count = 0
|
||||
|
||||
|
|
@ -2885,7 +2901,7 @@ async def debug_sso_login(request: Request):
|
|||
):
|
||||
if premium_user is not True:
|
||||
raise ProxyException(
|
||||
message="You must be a LiteLLM Enterprise user to use SSO. If you have a license please set `LITELLM_LICENSE` in your env. If you want to obtain a license meet with us here: https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat You are seeing this error message because You set one of `MICROSOFT_CLIENT_ID`, `GOOGLE_CLIENT_ID`, or `GENERIC_CLIENT_ID` in your env. Please unset this",
|
||||
message="You must be a LiteLLM Enterprise user to use SSO. If you have a license please set `LITELLM_LICENSE` in your env. If you want to obtain a license meet with us here: https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions You are seeing this error message because You set one of `MICROSOFT_CLIENT_ID`, `GOOGLE_CLIENT_ID`, or `GENERIC_CLIENT_ID` in your env. Please unset this",
|
||||
type=ProxyErrorTypes.auth_error,
|
||||
param="premium_user",
|
||||
code=status.HTTP_403_FORBIDDEN,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue