diff --git a/.env.example b/.env.example
index 82b09ca25e..54986a97cd 100644
--- a/.env.example
+++ b/.env.example
@@ -20,6 +20,8 @@ REPLICATE_API_TOKEN = ""
ANTHROPIC_API_KEY = ""
# Infisical
INFISICAL_TOKEN = ""
+# INFINITY
+INFINITY_API_KEY = ""
# Development Configs
LITELLM_MASTER_KEY = "sk-1234"
diff --git a/.gitignore b/.gitignore
index e599411328..e8c18bed4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,6 +73,7 @@ tests/local_testing/log.txt
.codegpt
litellm/proxy/_new_new_secret_config.yaml
litellm/proxy/custom_guardrail.py
+.mypy_cache/*
litellm/proxy/_experimental/out/404.html
litellm/proxy/_experimental/out/404.html
litellm/proxy/_experimental/out/model_hub.html
@@ -85,3 +86,5 @@ litellm/proxy/db/migrations/0_init/migration.sql
litellm/proxy/db/migrations/*
litellm/proxy/migrations/*config.yaml
litellm/proxy/migrations/*
+config.yaml
+tests/litellm/litellm_core_utils/llm_cost_calc/log.txt
diff --git a/docs/my-website/docs/observability/agentops_integration.md b/docs/my-website/docs/observability/agentops_integration.md
new file mode 100644
index 0000000000..e0599fab70
--- /dev/null
+++ b/docs/my-website/docs/observability/agentops_integration.md
@@ -0,0 +1,83 @@
+# 🖇️ AgentOps - LLM Observability Platform
+
+:::tip
+
+This is community maintained. Please make an issue if you run into a bug:
+https://github.com/BerriAI/litellm
+
+:::
+
+[AgentOps](https://docs.agentops.ai) is an observability platform that enables tracing and monitoring of LLM calls, providing detailed insights into your AI operations.
+
+## Using AgentOps with LiteLLM
+
+LiteLLM provides `success_callbacks` and `failure_callbacks`, allowing you to easily integrate AgentOps for comprehensive tracing and monitoring of your LLM operations.
+
+### Integration
+
+Use just a few lines of code to instantly trace your responses **across all providers** with AgentOps:
+Get your AgentOps API Keys from https://app.agentops.ai/
+```python
+import litellm
+
+# Configure LiteLLM to use AgentOps
+litellm.success_callback = ["agentops"]
+
+# Make your LLM calls as usual
+response = litellm.completion(
+ model="gpt-3.5-turbo",
+ messages=[{"role": "user", "content": "Hello, how are you?"}],
+)
+```
+
+Complete Code:
+
+```python
+import os
+from litellm import completion
+
+# Set env variables
+os.environ["OPENAI_API_KEY"] = "your-openai-key"
+os.environ["AGENTOPS_API_KEY"] = "your-agentops-api-key"
+
+# Configure LiteLLM to use AgentOps
+litellm.success_callback = ["agentops"]
+
+# OpenAI call
+response = completion(
+ model="gpt-4",
+ messages=[{"role": "user", "content": "Hi 👋 - I'm OpenAI"}],
+)
+
+print(response)
+```
+
+### Configuration Options
+
+The AgentOps integration can be configured through environment variables:
+
+- `AGENTOPS_API_KEY` (str, optional): Your AgentOps API key
+- `AGENTOPS_ENVIRONMENT` (str, optional): Deployment environment (defaults to "production")
+- `AGENTOPS_SERVICE_NAME` (str, optional): Service name for tracing (defaults to "agentops")
+
+### Advanced Usage
+
+You can configure additional settings through environment variables:
+
+```python
+import os
+
+# Configure AgentOps settings
+os.environ["AGENTOPS_API_KEY"] = "your-agentops-api-key"
+os.environ["AGENTOPS_ENVIRONMENT"] = "staging"
+os.environ["AGENTOPS_SERVICE_NAME"] = "my-service"
+
+# Enable AgentOps tracing
+litellm.success_callback = ["agentops"]
+```
+
+### Support
+
+For issues or questions, please refer to:
+- [AgentOps Documentation](https://docs.agentops.ai)
+- [LiteLLM Documentation](https://docs.litellm.ai)
\ No newline at end of file
diff --git a/docs/my-website/docs/pass_through/cohere.md b/docs/my-website/docs/pass_through/cohere.md
index 87eabd462c..227ff5777a 100644
--- a/docs/my-website/docs/pass_through/cohere.md
+++ b/docs/my-website/docs/pass_through/cohere.md
@@ -4,7 +4,7 @@ Pass-through endpoints for Cohere - call provider-specific endpoint, in native f
| Feature | Supported | Notes |
|-------|-------|-------|
-| Cost Tracking | ❌ | [Tell us if you need this](https://github.com/BerriAI/litellm/issues/new) |
+| Cost Tracking | ✅ | Supported for `/v1/chat`, and `/v2/chat` |
| Logging | ✅ | works across all integrations |
| End-user Tracking | ❌ | [Tell us if you need this](https://github.com/BerriAI/litellm/issues/new) |
| Streaming | ✅ | |
diff --git a/docs/my-website/docs/pass_through/mistral.md b/docs/my-website/docs/pass_through/mistral.md
new file mode 100644
index 0000000000..ee7ca800c4
--- /dev/null
+++ b/docs/my-website/docs/pass_through/mistral.md
@@ -0,0 +1,217 @@
+# Mistral
+
+Pass-through endpoints for Mistral - call provider-specific endpoint, in native format (no translation).
+
+| Feature | Supported | Notes |
+|-------|-------|-------|
+| Cost Tracking | ❌ | Not supported |
+| Logging | ✅ | works across all integrations |
+| End-user Tracking | ❌ | [Tell us if you need this](https://github.com/BerriAI/litellm/issues/new) |
+| Streaming | ✅ | |
+
+Just replace `https://api.mistral.ai/v1` with `LITELLM_PROXY_BASE_URL/mistral` 🚀
+
+#### **Example Usage**
+
+```bash
+curl -L -X POST 'http://0.0.0.0:4000/mistral/v1/ocr' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer sk-1234' \
+-d '{
+ "model": "mistral-ocr-latest",
+ "document": {
+ "type": "image_url",
+ "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"
+ }
+
+}'
+```
+
+Supports **ALL** Mistral Endpoints (including streaming).
+
+## Quick Start
+
+Let's call the Mistral [`/chat/completions` endpoint](https://docs.mistral.ai/api/#tag/chat/operation/chat_completion_v1_chat_completions_post)
+
+1. Add MISTRAL_API_KEY to your environment
+
+```bash
+export MISTRAL_API_KEY="sk-1234"
+```
+
+2. Start LiteLLM Proxy
+
+```bash
+litellm
+
+# RUNNING on http://0.0.0.0:4000
+```
+
+3. Test it!
+
+Let's call the Mistral `/ocr` endpoint
+
+```bash
+curl -L -X POST 'http://0.0.0.0:4000/mistral/v1/ocr' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer sk-1234' \
+-d '{
+ "model": "mistral-ocr-latest",
+ "document": {
+ "type": "image_url",
+ "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"
+ }
+
+}'
+```
+
+
+## Examples
+
+Anything after `http://0.0.0.0:4000/mistral` is treated as a provider-specific route, and handled accordingly.
+
+Key Changes:
+
+| **Original Endpoint** | **Replace With** |
+|------------------------------------------------------|-----------------------------------|
+| `https://api.mistral.ai/v1` | `http://0.0.0.0:4000/mistral` (LITELLM_PROXY_BASE_URL="http://0.0.0.0:4000") |
+| `bearer $MISTRAL_API_KEY` | `bearer anything` (use `bearer LITELLM_VIRTUAL_KEY` if Virtual Keys are setup on proxy) |
+
+
+### **Example 1: OCR endpoint**
+
+#### LiteLLM Proxy Call
+
+```bash
+curl -L -X POST 'http://0.0.0.0:4000/mistral/v1/ocr' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer $LITELLM_API_KEY' \
+-d '{
+ "model": "mistral-ocr-latest",
+ "document": {
+ "type": "image_url",
+ "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"
+ }
+}'
+```
+
+
+#### Direct Mistral API Call
+
+```bash
+curl https://api.mistral.ai/v1/ocr \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer ${MISTRAL_API_KEY}" \
+ -d '{
+ "model": "mistral-ocr-latest",
+ "document": {
+ "type": "document_url",
+ "document_url": "https://arxiv.org/pdf/2201.04234"
+ },
+ "include_image_base64": true
+ }'
+```
+
+### **Example 2: Chat API**
+
+#### LiteLLM Proxy Call
+
+```bash
+curl -L -X POST 'http://0.0.0.0:4000/mistral/v1/chat/completions' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer $LITELLM_VIRTUAL_KEY' \
+-d '{
+ "messages": [
+ {
+ "role": "user",
+ "content": "I am going to Paris, what should I see?"
+ }
+ ],
+ "max_tokens": 2048,
+ "temperature": 0.8,
+ "top_p": 0.1,
+ "model": "mistral-large-latest",
+}'
+```
+
+#### Direct Mistral API Call
+
+```bash
+curl -L -X POST 'https://api.mistral.ai/v1/chat/completions' \
+-H 'Content-Type: application/json' \
+-d '{
+ "messages": [
+ {
+ "role": "user",
+ "content": "I am going to Paris, what should I see?"
+ }
+ ],
+ "max_tokens": 2048,
+ "temperature": 0.8,
+ "top_p": 0.1,
+ "model": "mistral-large-latest",
+}'
+```
+
+
+## Advanced - Use with Virtual Keys
+
+Pre-requisites
+- [Setup proxy with DB](../proxy/virtual_keys.md#setup)
+
+Use this, to avoid giving developers the raw Mistral API key, but still letting them use Mistral endpoints.
+
+### Usage
+
+1. Setup environment
+
+```bash
+export DATABASE_URL=""
+export LITELLM_MASTER_KEY=""
+export MISTRAL_API_BASE=""
+```
+
+```bash
+litellm
+
+# RUNNING on http://0.0.0.0:4000
+```
+
+2. Generate virtual key
+
+```bash
+curl -X POST 'http://0.0.0.0:4000/key/generate' \
+-H 'Authorization: Bearer sk-1234' \
+-H 'Content-Type: application/json' \
+-d '{}'
+```
+
+Expected Response
+
+```bash
+{
+ ...
+ "key": "sk-1234ewknldferwedojwojw"
+}
+```
+
+3. Test it!
+
+
+```bash
+curl -L -X POST 'http://0.0.0.0:4000/mistral/v1/chat/completions' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer sk-1234ewknldferwedojwojw' \
+ --data '{
+ "messages": [
+ {
+ "role": "user",
+ "content": "I am going to Paris, what should I see?"
+ }
+ ],
+ "max_tokens": 2048,
+ "temperature": 0.8,
+ "top_p": 0.1,
+ "model": "qwen2.5-7b-instruct",
+}'
+```
\ No newline at end of file
diff --git a/docs/my-website/docs/pass_through/vertex_ai.md b/docs/my-website/docs/pass_through/vertex_ai.md
index 4918d889ed..f40dfa70eb 100644
--- a/docs/my-website/docs/pass_through/vertex_ai.md
+++ b/docs/my-website/docs/pass_through/vertex_ai.md
@@ -13,6 +13,15 @@ Pass-through endpoints for Vertex AI - call provider-specific endpoint, in nativ
| End-user Tracking | ❌ | [Tell us if you need this](https://github.com/BerriAI/litellm/issues/new) |
| Streaming | ✅ | |
+## Supported Endpoints
+
+LiteLLM supports 2 vertex ai passthrough routes:
+
+1. `/vertex_ai` → routes to `https://{vertex_location}-aiplatform.googleapis.com/`
+2. `/vertex_ai/discovery` → routes to [`https://discoveryengine.googleapis.com`](https://discoveryengine.googleapis.com/)
+
+## How to use
+
Just replace `https://REGION-aiplatform.googleapis.com` with `LITELLM_PROXY_BASE_URL/vertex_ai`
LiteLLM supports 3 flows for calling Vertex AI endpoints via pass-through:
diff --git a/docs/my-website/docs/pass_through/vllm.md b/docs/my-website/docs/pass_through/vllm.md
new file mode 100644
index 0000000000..b267622948
--- /dev/null
+++ b/docs/my-website/docs/pass_through/vllm.md
@@ -0,0 +1,185 @@
+# VLLM
+
+Pass-through endpoints for VLLM - call provider-specific endpoint, in native format (no translation).
+
+| Feature | Supported | Notes |
+|-------|-------|-------|
+| Cost Tracking | ❌ | Not supported |
+| Logging | ✅ | works across all integrations |
+| End-user Tracking | ❌ | [Tell us if you need this](https://github.com/BerriAI/litellm/issues/new) |
+| Streaming | ✅ | |
+
+Just replace `https://my-vllm-server.com` with `LITELLM_PROXY_BASE_URL/vllm` 🚀
+
+#### **Example Usage**
+
+```bash
+curl -L -X GET 'http://0.0.0.0:4000/vllm/metrics' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer sk-1234' \
+```
+
+Supports **ALL** VLLM Endpoints (including streaming).
+
+## Quick Start
+
+Let's call the VLLM [`/metrics` endpoint](https://vllm.readthedocs.io/en/latest/api_reference/api_reference.html)
+
+1. Add HOSTED VLLM API BASE to your environment
+
+```bash
+export HOSTED_VLLM_API_BASE="https://my-vllm-server.com"
+```
+
+2. Start LiteLLM Proxy
+
+```bash
+litellm
+
+# RUNNING on http://0.0.0.0:4000
+```
+
+3. Test it!
+
+Let's call the VLLM `/metrics` endpoint
+
+```bash
+curl -L -X GET 'http://0.0.0.0:4000/vllm/metrics' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer sk-1234' \
+```
+
+
+## Examples
+
+Anything after `http://0.0.0.0:4000/vllm` is treated as a provider-specific route, and handled accordingly.
+
+Key Changes:
+
+| **Original Endpoint** | **Replace With** |
+|------------------------------------------------------|-----------------------------------|
+| `https://my-vllm-server.com` | `http://0.0.0.0:4000/vllm` (LITELLM_PROXY_BASE_URL="http://0.0.0.0:4000") |
+| `bearer $VLLM_API_KEY` | `bearer anything` (use `bearer LITELLM_VIRTUAL_KEY` if Virtual Keys are setup on proxy) |
+
+
+### **Example 1: Metrics endpoint**
+
+#### LiteLLM Proxy Call
+
+```bash
+curl -L -X GET 'http://0.0.0.0:4000/vllm/metrics' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer $LITELLM_VIRTUAL_KEY' \
+```
+
+
+#### Direct VLLM API Call
+
+```bash
+curl -L -X GET 'https://my-vllm-server.com/metrics' \
+-H 'Content-Type: application/json' \
+```
+
+### **Example 2: Chat API**
+
+#### LiteLLM Proxy Call
+
+```bash
+curl -L -X POST 'http://0.0.0.0:4000/vllm/chat/completions' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer $LITELLM_VIRTUAL_KEY' \
+-d '{
+ "messages": [
+ {
+ "role": "user",
+ "content": "I am going to Paris, what should I see?"
+ }
+ ],
+ "max_tokens": 2048,
+ "temperature": 0.8,
+ "top_p": 0.1,
+ "model": "qwen2.5-7b-instruct",
+}'
+```
+
+#### Direct VLLM API Call
+
+```bash
+curl -L -X POST 'https://my-vllm-server.com/chat/completions' \
+-H 'Content-Type: application/json' \
+-d '{
+ "messages": [
+ {
+ "role": "user",
+ "content": "I am going to Paris, what should I see?"
+ }
+ ],
+ "max_tokens": 2048,
+ "temperature": 0.8,
+ "top_p": 0.1,
+ "model": "qwen2.5-7b-instruct",
+}'
+```
+
+
+## Advanced - Use with Virtual Keys
+
+Pre-requisites
+- [Setup proxy with DB](../proxy/virtual_keys.md#setup)
+
+Use this, to avoid giving developers the raw Cohere API key, but still letting them use Cohere endpoints.
+
+### Usage
+
+1. Setup environment
+
+```bash
+export DATABASE_URL=""
+export LITELLM_MASTER_KEY=""
+export HOSTED_VLLM_API_BASE=""
+```
+
+```bash
+litellm
+
+# RUNNING on http://0.0.0.0:4000
+```
+
+2. Generate virtual key
+
+```bash
+curl -X POST 'http://0.0.0.0:4000/key/generate' \
+-H 'Authorization: Bearer sk-1234' \
+-H 'Content-Type: application/json' \
+-d '{}'
+```
+
+Expected Response
+
+```bash
+{
+ ...
+ "key": "sk-1234ewknldferwedojwojw"
+}
+```
+
+3. Test it!
+
+
+```bash
+curl -L -X POST 'http://0.0.0.0:4000/vllm/chat/completions' \
+-H 'Content-Type: application/json' \
+-H 'Authorization: Bearer sk-1234ewknldferwedojwojw' \
+ --data '{
+ "messages": [
+ {
+ "role": "user",
+ "content": "I am going to Paris, what should I see?"
+ }
+ ],
+ "max_tokens": 2048,
+ "temperature": 0.8,
+ "top_p": 0.1,
+ "model": "qwen2.5-7b-instruct",
+}'
+```
\ No newline at end of file
diff --git a/docs/my-website/docs/providers/azure.md b/docs/my-website/docs/providers/azure.md
index 30bf3be1e4..e58d8a7b5d 100644
--- a/docs/my-website/docs/providers/azure.md
+++ b/docs/my-website/docs/providers/azure.md
@@ -1002,8 +1002,125 @@ Expected Response:
```
+## **Azure Responses API**
+| Property | Details |
+|-------|-------|
+| Description | Azure OpenAI Responses API |
+| `custom_llm_provider` on LiteLLM | `azure/` |
+| Supported Operations | `/v1/responses`|
+| Azure OpenAI Responses API | [Azure OpenAI Responses API ↗](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/responses?tabs=python-secure) |
+| Cost Tracking, Logging Support | ✅ LiteLLM will log, track cost for Responses API Requests |
+| Supported OpenAI Params | ✅ All OpenAI params are supported, [See here](https://github.com/BerriAI/litellm/blob/0717369ae6969882d149933da48eeb8ab0e691bd/litellm/llms/openai/responses/transformation.py#L23) |
+## Usage
+
+## Create a model response
+
+
+
+
+#### Non-streaming
+
+```python showLineNumbers title="Azure Responses API"
+import litellm
+
+# Non-streaming response
+response = litellm.responses(
+ model="azure/o1-pro",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ max_output_tokens=100,
+ api_key=os.getenv("AZURE_RESPONSES_OPENAI_API_KEY"),
+ api_base="https://litellm8397336933.openai.azure.com/",
+ api_version="2023-03-15-preview",
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="Azure Responses API"
+import litellm
+
+# Streaming response
+response = litellm.responses(
+ model="azure/o1-pro",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True,
+ api_key=os.getenv("AZURE_RESPONSES_OPENAI_API_KEY"),
+ api_base="https://litellm8397336933.openai.azure.com/",
+ api_version="2023-03-15-preview",
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+First, add this to your litellm proxy config.yaml:
+```yaml showLineNumbers title="Azure Responses API"
+model_list:
+ - model_name: o1-pro
+ litellm_params:
+ model: azure/o1-pro
+ api_key: os.environ/AZURE_RESPONSES_OPENAI_API_KEY
+ api_base: https://litellm8397336933.openai.azure.com/
+ api_version: 2023-03-15-preview
+```
+
+Start your LiteLLM proxy:
+```bash
+litellm --config /path/to/config.yaml
+
+# RUNNING on http://0.0.0.0:4000
+```
+
+Then use the OpenAI SDK pointed to your proxy:
+
+#### Non-streaming
+```python showLineNumbers
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Non-streaming response
+response = client.responses.create(
+ model="o1-pro",
+ input="Tell me a three sentence bedtime story about a unicorn."
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Streaming response
+response = client.responses.create(
+ model="o1-pro",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
diff --git a/docs/my-website/docs/providers/gemini.md b/docs/my-website/docs/providers/gemini.md
index db63d33d8d..434df6a7c9 100644
--- a/docs/my-website/docs/providers/gemini.md
+++ b/docs/my-website/docs/providers/gemini.md
@@ -39,14 +39,164 @@ response = completion(
- temperature
- top_p
- max_tokens
+- max_completion_tokens
- stream
- tools
- tool_choice
+- functions
- response_format
- n
- stop
+- logprobs
+- frequency_penalty
+- modalities
+- reasoning_content
+
+**Anthropic Params**
+- thinking (used to set max budget tokens across anthropic/gemini models)
+
+[**See Updated List**](https://github.com/BerriAI/litellm/blob/main/litellm/llms/gemini/chat/transformation.py#L70)
+
+
+
+## Usage - Thinking / `reasoning_content`
+
+LiteLLM translates OpenAI's `reasoning_effort` to Gemini's `thinking` parameter. [Code](https://github.com/BerriAI/litellm/blob/620664921902d7a9bfb29897a7b27c1a7ef4ddfb/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py#L362)
+
+**Mapping**
+
+| reasoning_effort | thinking |
+| ---------------- | -------- |
+| "low" | "budget_tokens": 1024 |
+| "medium" | "budget_tokens": 2048 |
+| "high" | "budget_tokens": 4096 |
+
+
+
+
+```python
+from litellm import completion
+
+resp = completion(
+ model="gemini/gemini-2.5-flash-preview-04-17",
+ messages=[{"role": "user", "content": "What is the capital of France?"}],
+ reasoning_effort="low",
+)
+
+```
+
+
+
+
+
+1. Setup config.yaml
+
+```yaml
+- model_name: gemini-2.5-flash
+ litellm_params:
+ model: gemini/gemini-2.5-flash-preview-04-17
+ api_key: os.environ/GEMINI_API_KEY
+```
+
+2. Start proxy
+
+```bash
+litellm --config /path/to/config.yaml
+```
+
+3. Test it!
+
+```bash
+curl http://0.0.0.0:4000/v1/chat/completions \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer " \
+ -d '{
+ "model": "gemini-2.5-flash",
+ "messages": [{"role": "user", "content": "What is the capital of France?"}],
+ "reasoning_effort": "low"
+ }'
+```
+
+
+
+
+
+**Expected Response**
+
+```python
+ModelResponse(
+ id='chatcmpl-c542d76d-f675-4e87-8e5f-05855f5d0f5e',
+ created=1740470510,
+ model='claude-3-7-sonnet-20250219',
+ object='chat.completion',
+ system_fingerprint=None,
+ choices=[
+ Choices(
+ finish_reason='stop',
+ index=0,
+ message=Message(
+ content="The capital of France is Paris.",
+ role='assistant',
+ tool_calls=None,
+ function_call=None,
+ reasoning_content='The capital of France is Paris. This is a very straightforward factual question.'
+ ),
+ )
+ ],
+ usage=Usage(
+ completion_tokens=68,
+ prompt_tokens=42,
+ total_tokens=110,
+ completion_tokens_details=None,
+ prompt_tokens_details=PromptTokensDetailsWrapper(
+ audio_tokens=None,
+ cached_tokens=0,
+ text_tokens=None,
+ image_tokens=None
+ ),
+ cache_creation_input_tokens=0,
+ cache_read_input_tokens=0
+ )
+)
+```
+
+### Pass `thinking` to Gemini models
+
+You can also pass the `thinking` parameter to Gemini models.
+
+This is translated to Gemini's [`thinkingConfig` parameter](https://ai.google.dev/gemini-api/docs/thinking#set-budget).
+
+
+
+
+```python
+response = litellm.completion(
+ model="gemini/gemini-2.5-flash-preview-04-17",
+ messages=[{"role": "user", "content": "What is the capital of France?"}],
+ thinking={"type": "enabled", "budget_tokens": 1024},
+)
+```
+
+
+
+
+```bash
+curl http://0.0.0.0:4000/v1/chat/completions \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer $LITELLM_KEY" \
+ -d '{
+ "model": "gemini/gemini-2.5-flash-preview-04-17",
+ "messages": [{"role": "user", "content": "What is the capital of France?"}],
+ "thinking": {"type": "enabled", "budget_tokens": 1024}
+ }'
+```
+
+
+
+
+
+
-[**See Updated List**](https://github.com/BerriAI/litellm/blob/1c747f3ad372399c5b95cc5696b06a5fbe53186b/litellm/llms/vertex_httpx.py#L122)
## Passing Gemini Specific Params
### Response schema
diff --git a/docs/my-website/docs/providers/infinity.md b/docs/my-website/docs/providers/infinity.md
index 091503bf18..7900d5adb4 100644
--- a/docs/my-website/docs/providers/infinity.md
+++ b/docs/my-website/docs/providers/infinity.md
@@ -3,18 +3,17 @@ import TabItem from '@theme/TabItem';
# Infinity
-| Property | Details |
-|-------|-------|
-| Description | Infinity is a high-throughput, low-latency REST API for serving text-embeddings, reranking models and clip|
-| Provider Route on LiteLLM | `infinity/` |
-| Supported Operations | `/rerank` |
-| Link to Provider Doc | [Infinity ↗](https://github.com/michaelfeil/infinity) |
-
+| Property | Details |
+| ------------------------- | ---------------------------------------------------------------------------------------------------------- |
+| Description | Infinity is a high-throughput, low-latency REST API for serving text-embeddings, reranking models and clip |
+| Provider Route on LiteLLM | `infinity/` |
+| Supported Operations | `/rerank`, `/embeddings` |
+| Link to Provider Doc | [Infinity ↗](https://github.com/michaelfeil/infinity) |
## **Usage - LiteLLM Python SDK**
```python
-from litellm import rerank
+from litellm import rerank, embedding
import os
os.environ["INFINITY_API_BASE"] = "http://localhost:8080"
@@ -39,8 +38,8 @@ model_list:
- model_name: custom-infinity-rerank
litellm_params:
model: infinity/rerank
- api_key: os.environ/INFINITY_API_KEY
api_base: https://localhost:8080
+ api_key: os.environ/INFINITY_API_KEY
```
Start litellm
@@ -51,7 +50,9 @@ litellm --config /path/to/config.yaml
# RUNNING on http://0.0.0.0:4000
```
-Test request
+## Test request:
+
+### Rerank
```bash
curl http://0.0.0.0:4000/rerank \
@@ -70,15 +71,14 @@ curl http://0.0.0.0:4000/rerank \
}'
```
+#### Supported Cohere Rerank API Params
-## Supported Cohere Rerank API Params
-
-| Param | Type | Description |
-|-------|-------|-------|
-| `query` | `str` | The query to rerank the documents against |
-| `documents` | `list[str]` | The documents to rerank |
-| `top_n` | `int` | The number of documents to return |
-| `return_documents` | `bool` | Whether to return the documents in the response |
+| Param | Type | Description |
+| ------------------ | ----------- | ----------------------------------------------- |
+| `query` | `str` | The query to rerank the documents against |
+| `documents` | `list[str]` | The documents to rerank |
+| `top_n` | `int` | The number of documents to return |
+| `return_documents` | `bool` | Whether to return the documents in the response |
### Usage - Return Documents
@@ -138,6 +138,7 @@ response = rerank(
raw_scores=True, # 👈 PROVIDER-SPECIFIC PARAM
)
```
+
@@ -161,7 +162,7 @@ litellm --config /path/to/config.yaml
# RUNNING on http://0.0.0.0:4000
```
-3. Test it!
+3. Test it!
```bash
curl http://0.0.0.0:4000/rerank \
@@ -179,6 +180,121 @@ curl http://0.0.0.0:4000/rerank \
"raw_scores": True # 👈 PROVIDER-SPECIFIC PARAM
}'
```
+
+
+## Embeddings
+
+LiteLLM provides an OpenAI api compatible `/embeddings` endpoint for embedding calls.
+
+**Setup**
+
+Add this to your litellm proxy config.yaml
+
+```yaml
+model_list:
+ - model_name: custom-infinity-embedding
+ litellm_params:
+ model: infinity/provider/custom-embedding-v1
+ api_base: http://localhost:8080
+ api_key: os.environ/INFINITY_API_KEY
+```
+
+### Test request:
+
+```bash
+curl http://0.0.0.0:4000/embeddings \
+ -H "Authorization: Bearer sk-1234" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "custom-infinity-embedding",
+ "input": ["hello"]
+ }'
+```
+
+#### Supported Embedding API Params
+
+| Param | Type | Description |
+| ----------------- | ----------- | ----------------------------------------------------------- |
+| `model` | `str` | The embedding model to use |
+| `input` | `list[str]` | The text inputs to generate embeddings for |
+| `encoding_format` | `str` | The format to return embeddings in (e.g. "float", "base64") |
+| `modality` | `str` | The type of input (e.g. "text", "image", "audio") |
+
+### Usage - Basic Examples
+
+
+
+
+```python
+from litellm import embedding
+import os
+
+os.environ["INFINITY_API_BASE"] = "http://localhost:8080"
+
+response = embedding(
+ model="infinity/bge-small",
+ input=["good morning from litellm"]
+)
+
+print(response.data[0]['embedding'])
+```
+
+
+
+
+
+```bash
+curl http://0.0.0.0:4000/embeddings \
+ -H "Authorization: Bearer sk-1234" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "custom-infinity-embedding",
+ "input": ["hello"]
+ }'
+```
+
+
+
+
+### Usage - OpenAI Client
+
+
+
+
+```python
+from openai import OpenAI
+
+client = OpenAI(
+ api_key="",
+ base_url=""
+)
+
+response = client.embeddings.create(
+ model="bge-small",
+ input=["The food was delicious and the waiter..."],
+ encoding_format="float"
+)
+
+print(response.data[0].embedding)
+```
+
+
+
+
+
+```bash
+curl http://0.0.0.0:4000/embeddings \
+ -H "Authorization: Bearer sk-1234" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "bge-small",
+ "input": ["The food was delicious and the waiter..."],
+ "encoding_format": "float"
+ }'
+```
+
+
+
diff --git a/docs/my-website/docs/providers/openai.md b/docs/my-website/docs/providers/openai.md
index 9ab9061aaa..a4aee5dbf7 100644
--- a/docs/my-website/docs/providers/openai.md
+++ b/docs/my-website/docs/providers/openai.md
@@ -163,6 +163,12 @@ os.environ["OPENAI_API_BASE"] = "openaiai-api-base" # OPTIONAL
| Model Name | Function Call |
|-----------------------|-----------------------------------------------------------------|
+| gpt-4.1 | `response = completion(model="gpt-4.1", messages=messages)` |
+| gpt-4.1-mini | `response = completion(model="gpt-4.1-mini", messages=messages)` |
+| gpt-4.1-nano | `response = completion(model="gpt-4.1-nano", messages=messages)` |
+| o4-mini | `response = completion(model="o4-mini", messages=messages)` |
+| o3-mini | `response = completion(model="o3-mini", messages=messages)` |
+| o3 | `response = completion(model="o3", messages=messages)` |
| o1-mini | `response = completion(model="o1-mini", messages=messages)` |
| o1-preview | `response = completion(model="o1-preview", messages=messages)` |
| gpt-4o-mini | `response = completion(model="gpt-4o-mini", messages=messages)` |
diff --git a/docs/my-website/docs/providers/vertex.md b/docs/my-website/docs/providers/vertex.md
index 476cc8a453..762bd5f332 100644
--- a/docs/my-website/docs/providers/vertex.md
+++ b/docs/my-website/docs/providers/vertex.md
@@ -542,6 +542,154 @@ print(resp)
```
+### **Thinking / `reasoning_content`**
+
+LiteLLM translates OpenAI's `reasoning_effort` to Gemini's `thinking` parameter. [Code](https://github.com/BerriAI/litellm/blob/620664921902d7a9bfb29897a7b27c1a7ef4ddfb/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py#L362)
+
+**Mapping**
+
+| reasoning_effort | thinking |
+| ---------------- | -------- |
+| "low" | "budget_tokens": 1024 |
+| "medium" | "budget_tokens": 2048 |
+| "high" | "budget_tokens": 4096 |
+
+
+
+
+```python
+from litellm import completion
+
+# !gcloud auth application-default login - run this to add vertex credentials to your env
+
+resp = completion(
+ model="vertex_ai/gemini-2.5-flash-preview-04-17",
+ messages=[{"role": "user", "content": "What is the capital of France?"}],
+ reasoning_effort="low",
+ vertex_project="project-id",
+ vertex_location="us-central1"
+)
+
+```
+
+
+
+
+
+1. Setup config.yaml
+
+```yaml
+- model_name: gemini-2.5-flash
+ litellm_params:
+ model: vertex_ai/gemini-2.5-flash-preview-04-17
+ vertex_credentials: {"project_id": "project-id", "location": "us-central1", "project_key": "project-key"}
+ vertex_project: "project-id"
+ vertex_location: "us-central1"
+```
+
+2. Start proxy
+
+```bash
+litellm --config /path/to/config.yaml
+```
+
+3. Test it!
+
+```bash
+curl http://0.0.0.0:4000/v1/chat/completions \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer " \
+ -d '{
+ "model": "gemini-2.5-flash",
+ "messages": [{"role": "user", "content": "What is the capital of France?"}],
+ "reasoning_effort": "low"
+ }'
+```
+
+
+
+
+
+**Expected Response**
+
+```python
+ModelResponse(
+ id='chatcmpl-c542d76d-f675-4e87-8e5f-05855f5d0f5e',
+ created=1740470510,
+ model='claude-3-7-sonnet-20250219',
+ object='chat.completion',
+ system_fingerprint=None,
+ choices=[
+ Choices(
+ finish_reason='stop',
+ index=0,
+ message=Message(
+ content="The capital of France is Paris.",
+ role='assistant',
+ tool_calls=None,
+ function_call=None,
+ reasoning_content='The capital of France is Paris. This is a very straightforward factual question.'
+ ),
+ )
+ ],
+ usage=Usage(
+ completion_tokens=68,
+ prompt_tokens=42,
+ total_tokens=110,
+ completion_tokens_details=None,
+ prompt_tokens_details=PromptTokensDetailsWrapper(
+ audio_tokens=None,
+ cached_tokens=0,
+ text_tokens=None,
+ image_tokens=None
+ ),
+ cache_creation_input_tokens=0,
+ cache_read_input_tokens=0
+ )
+)
+```
+
+#### Pass `thinking` to Gemini models
+
+You can also pass the `thinking` parameter to Gemini models.
+
+This is translated to Gemini's [`thinkingConfig` parameter](https://ai.google.dev/gemini-api/docs/thinking#set-budget).
+
+
+
+
+```python
+from litellm import completion
+
+# !gcloud auth application-default login - run this to add vertex credentials to your env
+
+response = litellm.completion(
+ model="vertex_ai/gemini-2.5-flash-preview-04-17",
+ messages=[{"role": "user", "content": "What is the capital of France?"}],
+ thinking={"type": "enabled", "budget_tokens": 1024},
+ vertex_project="project-id",
+ vertex_location="us-central1"
+)
+```
+
+
+
+
+```bash
+curl http://0.0.0.0:4000/v1/chat/completions \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer $LITELLM_KEY" \
+ -d '{
+ "model": "vertex_ai/gemini-2.5-flash-preview-04-17",
+ "messages": [{"role": "user", "content": "What is the capital of France?"}],
+ "thinking": {"type": "enabled", "budget_tokens": 1024}
+ }'
+```
+
+
+
+
+
### **Context Caching**
Use Vertex AI context caching is supported by calling provider api directly. (Unified Endpoint support comin soon.).
diff --git a/docs/my-website/docs/providers/vllm.md b/docs/my-website/docs/providers/vllm.md
index b5987167ec..5c8233b056 100644
--- a/docs/my-website/docs/providers/vllm.md
+++ b/docs/my-website/docs/providers/vllm.md
@@ -161,6 +161,120 @@ curl -L -X POST 'http://0.0.0.0:4000/embeddings' \
Example Implementation from VLLM [here](https://github.com/vllm-project/vllm/pull/10020)
+
+
+
+Use this to send a video url to VLLM + Gemini in the same format, using OpenAI's `files` message type.
+
+There are two ways to send a video url to VLLM:
+
+1. Pass the video url directly
+
+```
+{"type": "file", "file": {"file_id": video_url}},
+```
+
+2. Pass the video data as base64
+
+```
+{"type": "file", "file": {"file_data": f"data:video/mp4;base64,{video_data_base64}"}}
+```
+
+
+
+
+```python
+from litellm import completion
+
+messages=[
+ {
+ "role": "user",
+ "content": [
+ {
+ "type": "text",
+ "text": "Summarize the following video"
+ },
+ {
+ "type": "file",
+ "file": {
+ "file_id": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
+ }
+ }
+ ]
+ }
+]
+
+# call vllm
+os.environ["HOSTED_VLLM_API_BASE"] = "https://hosted-vllm-api.co"
+os.environ["HOSTED_VLLM_API_KEY"] = "" # [optional], if your VLLM server requires an API key
+response = completion(
+ model="hosted_vllm/qwen", # pass the vllm model name
+ messages=messages,
+)
+
+# call gemini
+os.environ["GEMINI_API_KEY"] = "your-gemini-api-key"
+response = completion(
+ model="gemini/gemini-1.5-flash", # pass the gemini model name
+ messages=messages,
+)
+
+print(response)
+```
+
+
+
+
+1. Setup config.yaml
+
+```yaml
+model_list:
+ - model_name: my-model
+ litellm_params:
+ model: hosted_vllm/qwen # add hosted_vllm/ prefix to route as OpenAI provider
+ api_base: https://hosted-vllm-api.co # add api base for OpenAI compatible provider
+ - model_name: my-gemini-model
+ litellm_params:
+ model: gemini/gemini-1.5-flash # add gemini/ prefix to route as Google AI Studio provider
+ api_key: os.environ/GEMINI_API_KEY
+```
+
+2. Start the proxy
+
+```bash
+$ litellm --config /path/to/config.yaml
+
+# RUNNING on http://0.0.0.0:4000
+```
+
+3. Test it!
+
+```bash
+curl -X POST http://0.0.0.0:4000/chat/completions \
+-H "Authorization: Bearer sk-1234" \
+-H "Content-Type: application/json" \
+-d '{
+ "model": "my-model",
+ "messages": [
+ {"role": "user", "content":
+ [
+ {"type": "text", "text": "Summarize the following video"},
+ {"type": "file", "file": {"file_id": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}}
+ ]
+ }
+ ]
+}'
+```
+
+
+
+
+
+
+
+
+Use this to send a video url to VLLM in it's native message format (`video_url`).
+
There are two ways to send a video url to VLLM:
1. Pass the video url directly
@@ -249,6 +363,10 @@ curl -X POST http://0.0.0.0:4000/chat/completions \
+
+
+
+
## (Deprecated) for `vllm pip package`
### Using - `litellm.completion`
diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md
index 863349a8fe..1e3c800b03 100644
--- a/docs/my-website/docs/proxy/config_settings.md
+++ b/docs/my-website/docs/proxy/config_settings.md
@@ -299,6 +299,9 @@ router_settings:
|------|-------------|
| ACTIONS_ID_TOKEN_REQUEST_TOKEN | Token for requesting ID in GitHub Actions
| ACTIONS_ID_TOKEN_REQUEST_URL | URL for requesting ID token in GitHub Actions
+| AGENTOPS_ENVIRONMENT | Environment for AgentOps logging integration
+| AGENTOPS_API_KEY | API Key for AgentOps logging integration
+| AGENTOPS_SERVICE_NAME | Service Name for AgentOps logging integration
| AISPEND_ACCOUNT_ID | Account ID for AI Spend
| AISPEND_API_KEY | API Key for AI Spend
| ALLOWED_EMAIL_DOMAINS | List of email domains allowed for access
@@ -323,6 +326,9 @@ router_settings:
| AZURE_AUTHORITY_HOST | Azure authority host URL
| AZURE_CLIENT_ID | Client ID for Azure services
| AZURE_CLIENT_SECRET | Client secret for Azure services
+| AZURE_TENANT_ID | Tenant ID for Azure Active Directory
+| AZURE_USERNAME | Username for Azure services, use in conjunction with AZURE_PASSWORD for azure ad token with basic username/password workflow
+| AZURE_PASSWORD | Password for Azure services, use in conjunction with AZURE_USERNAME for azure ad token with basic username/password workflow
| AZURE_FEDERATED_TOKEN_FILE | File path to Azure federated token
| AZURE_KEY_VAULT_URI | URI for Azure Key Vault
| AZURE_STORAGE_ACCOUNT_KEY | The Azure Storage Account Key to use for Authentication to Azure Blob Storage logging
@@ -331,7 +337,6 @@ router_settings:
| AZURE_STORAGE_TENANT_ID | The Application Tenant ID to use for Authentication to Azure Blob Storage logging
| AZURE_STORAGE_CLIENT_ID | The Application Client ID to use for Authentication to Azure Blob Storage logging
| AZURE_STORAGE_CLIENT_SECRET | The Application Client Secret to use for Authentication to Azure Blob Storage logging
-| AZURE_TENANT_ID | Tenant ID for Azure Active Directory
| BERRISPEND_ACCOUNT_ID | Account ID for BerriSpend service
| BRAINTRUST_API_KEY | API key for Braintrust integration
| CIRCLE_OIDC_TOKEN | OpenID Connect token for CircleCI
@@ -433,6 +438,7 @@ router_settings:
| LITERAL_BATCH_SIZE | Batch size for Literal operations
| LITELLM_DONT_SHOW_FEEDBACK_BOX | Flag to hide feedback box in LiteLLM UI
| LITELLM_DROP_PARAMS | Parameters to drop in LiteLLM requests
+| LITELLM_MODIFY_PARAMS | Parameters to modify in LiteLLM requests
| LITELLM_EMAIL | Email associated with LiteLLM account
| LITELLM_GLOBAL_MAX_PARALLEL_REQUEST_RETRIES | Maximum retries for parallel requests in LiteLLM
| LITELLM_GLOBAL_MAX_PARALLEL_REQUEST_RETRY_TIMEOUT | Timeout for retries of parallel requests in LiteLLM
@@ -446,6 +452,8 @@ router_settings:
| LITELLM_TOKEN | Access token for LiteLLM integration
| LITELLM_PRINT_STANDARD_LOGGING_PAYLOAD | If true, prints the standard logging payload to the console - useful for debugging
| LOGFIRE_TOKEN | Token for Logfire logging service
+| MISTRAL_API_BASE | Base URL for Mistral API
+| MISTRAL_API_KEY | API key for Mistral API
| MICROSOFT_CLIENT_ID | Client ID for Microsoft services
| MICROSOFT_CLIENT_SECRET | Client secret for Microsoft services
| MICROSOFT_TENANT | Tenant ID for Microsoft Azure
diff --git a/docs/my-website/docs/proxy/logging.md b/docs/my-website/docs/proxy/logging.md
index e13a403634..c8731dd270 100644
--- a/docs/my-website/docs/proxy/logging.md
+++ b/docs/my-website/docs/proxy/logging.md
@@ -862,7 +862,7 @@ Add the following to your env
```shell
OTEL_EXPORTER="otlp_http"
-OTEL_ENDPOINT="http:/0.0.0.0:4317"
+OTEL_ENDPOINT="http://0.0.0.0:4317"
OTEL_HEADERS="x-honeycomb-team=" # Optional
```
@@ -2501,4 +2501,4 @@ litellm_settings:
:::info
`thresholds` are not required by default, but you can tune the values to your needs.
Default values is `4` for all categories
-::: -->
\ No newline at end of file
+::: -->
diff --git a/docs/my-website/docs/proxy/model_discovery.md b/docs/my-website/docs/proxy/model_discovery.md
new file mode 100644
index 0000000000..5790dfc520
--- /dev/null
+++ b/docs/my-website/docs/proxy/model_discovery.md
@@ -0,0 +1,108 @@
+# Model Discovery
+
+Use this to give users an accurate list of models available behind provider endpoint, when calling `/v1/models` for wildcard models.
+
+## Supported Models
+
+- Fireworks AI
+- OpenAI
+- Gemini
+- LiteLLM Proxy
+- Topaz
+- Anthropic
+- XAI
+- VLLM
+- Vertex AI
+
+### Usage
+
+**1. Setup config.yaml**
+
+```yaml
+model_list:
+ - model_name: xai/*
+ litellm_params:
+ model: xai/*
+ api_key: os.environ/XAI_API_KEY
+
+litellm_settings:
+ check_provider_endpoint: true # 👈 Enable checking provider endpoint for wildcard models
+```
+
+**2. Start proxy**
+
+```bash
+litellm --config /path/to/config.yaml
+
+# RUNNING on http://0.0.0.0:4000
+```
+
+**3. Call `/v1/models`**
+
+```bash
+curl -X GET "http://localhost:4000/v1/models" -H "Authorization: Bearer $LITELLM_KEY"
+```
+
+Expected response
+
+```json
+{
+ "data": [
+ {
+ "id": "xai/grok-2-1212",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ },
+ {
+ "id": "xai/grok-2-vision-1212",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ },
+ {
+ "id": "xai/grok-3-beta",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ },
+ {
+ "id": "xai/grok-3-fast-beta",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ },
+ {
+ "id": "xai/grok-3-mini-beta",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ },
+ {
+ "id": "xai/grok-3-mini-fast-beta",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ },
+ {
+ "id": "xai/grok-beta",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ },
+ {
+ "id": "xai/grok-vision-beta",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ },
+ {
+ "id": "xai/grok-2-image-1212",
+ "object": "model",
+ "created": 1677610602,
+ "owned_by": "openai"
+ }
+ ],
+ "object": "list"
+}
+```
\ No newline at end of file
diff --git a/docs/my-website/docs/reasoning_content.md b/docs/my-website/docs/reasoning_content.md
index 86ef58bd68..12a0f17ba0 100644
--- a/docs/my-website/docs/reasoning_content.md
+++ b/docs/my-website/docs/reasoning_content.md
@@ -16,6 +16,8 @@ Supported Providers:
- Vertex AI (Anthropic) (`vertexai/`)
- OpenRouter (`openrouter/`)
- XAI (`xai/`)
+- Google AI Studio (`google/`)
+- Vertex AI (`vertex_ai/`)
LiteLLM will standardize the `reasoning_content` in the response and `thinking_blocks` in the assistant message.
@@ -23,7 +25,7 @@ LiteLLM will standardize the `reasoning_content` in the response and `thinking_b
"message": {
...
"reasoning_content": "The capital of France is Paris.",
- "thinking_blocks": [
+ "thinking_blocks": [ # only returned for Anthropic models
{
"type": "thinking",
"thinking": "The capital of France is Paris.",
diff --git a/docs/my-website/docs/response_api.md b/docs/my-website/docs/response_api.md
index 1ab9865504..532f20bc05 100644
--- a/docs/my-website/docs/response_api.md
+++ b/docs/my-website/docs/response_api.md
@@ -14,22 +14,22 @@ LiteLLM provides a BETA endpoint in the spec of [OpenAI's `/responses` API](http
| Fallbacks | ✅ | Works between supported models |
| Loadbalancing | ✅ | Works between supported models |
| Supported LiteLLM Versions | 1.63.8+ | |
-| Supported LLM providers | `openai` | |
+| Supported LLM providers | **All LiteLLM supported providers** | `openai`, `anthropic`, `bedrock`, `vertex_ai`, `gemini`, `azure`, `azure_ai` etc. |
## Usage
-## Create a model response
+### LiteLLM Python SDK
-
+
#### Non-streaming
-```python
+```python showLineNumbers title="OpenAI Non-streaming Response"
import litellm
# Non-streaming response
response = litellm.responses(
- model="o1-pro",
+ model="openai/o1-pro",
input="Tell me a three sentence bedtime story about a unicorn.",
max_output_tokens=100
)
@@ -38,12 +38,12 @@ print(response)
```
#### Streaming
-```python
+```python showLineNumbers title="OpenAI Streaming Response"
import litellm
# Streaming response
response = litellm.responses(
- model="o1-pro",
+ model="openai/o1-pro",
input="Tell me a three sentence bedtime story about a unicorn.",
stream=True
)
@@ -53,58 +53,169 @@ for event in response:
```
-
-First, add this to your litellm proxy config.yaml:
-```yaml
-model_list:
- - model_name: o1-pro
- litellm_params:
- model: openai/o1-pro
- api_key: os.environ/OPENAI_API_KEY
-```
-
-Start your LiteLLM proxy:
-```bash
-litellm --config /path/to/config.yaml
-
-# RUNNING on http://0.0.0.0:4000
-```
-
-Then use the OpenAI SDK pointed to your proxy:
+
#### Non-streaming
-```python
-from openai import OpenAI
+```python showLineNumbers title="Anthropic Non-streaming Response"
+import litellm
+import os
-# Initialize client with your proxy URL
-client = OpenAI(
- base_url="http://localhost:4000", # Your proxy URL
- api_key="your-api-key" # Your proxy API key
-)
+# Set API key
+os.environ["ANTHROPIC_API_KEY"] = "your-anthropic-api-key"
# Non-streaming response
-response = client.responses.create(
- model="o1-pro",
- input="Tell me a three sentence bedtime story about a unicorn."
+response = litellm.responses(
+ model="anthropic/claude-3-5-sonnet-20240620",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ max_output_tokens=100
)
print(response)
```
#### Streaming
-```python
-from openai import OpenAI
+```python showLineNumbers title="Anthropic Streaming Response"
+import litellm
+import os
-# Initialize client with your proxy URL
-client = OpenAI(
- base_url="http://localhost:4000", # Your proxy URL
- api_key="your-api-key" # Your proxy API key
-)
+# Set API key
+os.environ["ANTHROPIC_API_KEY"] = "your-anthropic-api-key"
# Streaming response
-response = client.responses.create(
- model="o1-pro",
+response = litellm.responses(
+ model="anthropic/claude-3-5-sonnet-20240620",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+
+#### Non-streaming
+```python showLineNumbers title="Vertex AI Non-streaming Response"
+import litellm
+import os
+
+# Set credentials - Vertex AI uses application default credentials
+# Run 'gcloud auth application-default login' to authenticate
+os.environ["VERTEXAI_PROJECT"] = "your-gcp-project-id"
+os.environ["VERTEXAI_LOCATION"] = "us-central1"
+
+# Non-streaming response
+response = litellm.responses(
+ model="vertex_ai/gemini-1.5-pro",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ max_output_tokens=100
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="Vertex AI Streaming Response"
+import litellm
+import os
+
+# Set credentials - Vertex AI uses application default credentials
+# Run 'gcloud auth application-default login' to authenticate
+os.environ["VERTEXAI_PROJECT"] = "your-gcp-project-id"
+os.environ["VERTEXAI_LOCATION"] = "us-central1"
+
+# Streaming response
+response = litellm.responses(
+ model="vertex_ai/gemini-1.5-pro",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+
+#### Non-streaming
+```python showLineNumbers title="AWS Bedrock Non-streaming Response"
+import litellm
+import os
+
+# Set AWS credentials
+os.environ["AWS_ACCESS_KEY_ID"] = "your-access-key-id"
+os.environ["AWS_SECRET_ACCESS_KEY"] = "your-secret-access-key"
+os.environ["AWS_REGION_NAME"] = "us-west-2" # or your AWS region
+
+# Non-streaming response
+response = litellm.responses(
+ model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ max_output_tokens=100
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="AWS Bedrock Streaming Response"
+import litellm
+import os
+
+# Set AWS credentials
+os.environ["AWS_ACCESS_KEY_ID"] = "your-access-key-id"
+os.environ["AWS_SECRET_ACCESS_KEY"] = "your-secret-access-key"
+os.environ["AWS_REGION_NAME"] = "us-west-2" # or your AWS region
+
+# Streaming response
+response = litellm.responses(
+ model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+
+#### Non-streaming
+```python showLineNumbers title="Google AI Studio Non-streaming Response"
+import litellm
+import os
+
+# Set API key for Google AI Studio
+os.environ["GEMINI_API_KEY"] = "your-gemini-api-key"
+
+# Non-streaming response
+response = litellm.responses(
+ model="gemini/gemini-1.5-flash",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ max_output_tokens=100
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="Google AI Studio Streaming Response"
+import litellm
+import os
+
+# Set API key for Google AI Studio
+os.environ["GEMINI_API_KEY"] = "your-gemini-api-key"
+
+# Streaming response
+response = litellm.responses(
+ model="gemini/gemini-1.5-flash",
input="Tell me a three sentence bedtime story about a unicorn.",
stream=True
)
@@ -115,3 +226,408 @@ for event in response:
+
+### LiteLLM Proxy with OpenAI SDK
+
+First, set up and start your LiteLLM proxy server.
+
+```bash title="Start LiteLLM Proxy Server"
+litellm --config /path/to/config.yaml
+
+# RUNNING on http://0.0.0.0:4000
+```
+
+
+
+
+First, add this to your litellm proxy config.yaml:
+```yaml showLineNumbers title="OpenAI Proxy Configuration"
+model_list:
+ - model_name: openai/o1-pro
+ litellm_params:
+ model: openai/o1-pro
+ api_key: os.environ/OPENAI_API_KEY
+```
+
+#### Non-streaming
+```python showLineNumbers title="OpenAI Proxy Non-streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Non-streaming response
+response = client.responses.create(
+ model="openai/o1-pro",
+ input="Tell me a three sentence bedtime story about a unicorn."
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="OpenAI Proxy Streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Streaming response
+response = client.responses.create(
+ model="openai/o1-pro",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+
+First, add this to your litellm proxy config.yaml:
+```yaml showLineNumbers title="Anthropic Proxy Configuration"
+model_list:
+ - model_name: anthropic/claude-3-5-sonnet-20240620
+ litellm_params:
+ model: anthropic/claude-3-5-sonnet-20240620
+ api_key: os.environ/ANTHROPIC_API_KEY
+```
+
+#### Non-streaming
+```python showLineNumbers title="Anthropic Proxy Non-streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Non-streaming response
+response = client.responses.create(
+ model="anthropic/claude-3-5-sonnet-20240620",
+ input="Tell me a three sentence bedtime story about a unicorn."
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="Anthropic Proxy Streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Streaming response
+response = client.responses.create(
+ model="anthropic/claude-3-5-sonnet-20240620",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+
+First, add this to your litellm proxy config.yaml:
+```yaml showLineNumbers title="Vertex AI Proxy Configuration"
+model_list:
+ - model_name: vertex_ai/gemini-1.5-pro
+ litellm_params:
+ model: vertex_ai/gemini-1.5-pro
+ vertex_project: your-gcp-project-id
+ vertex_location: us-central1
+```
+
+#### Non-streaming
+```python showLineNumbers title="Vertex AI Proxy Non-streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Non-streaming response
+response = client.responses.create(
+ model="vertex_ai/gemini-1.5-pro",
+ input="Tell me a three sentence bedtime story about a unicorn."
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="Vertex AI Proxy Streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Streaming response
+response = client.responses.create(
+ model="vertex_ai/gemini-1.5-pro",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+
+First, add this to your litellm proxy config.yaml:
+```yaml showLineNumbers title="AWS Bedrock Proxy Configuration"
+model_list:
+ - model_name: bedrock/anthropic.claude-3-sonnet-20240229-v1:0
+ litellm_params:
+ model: bedrock/anthropic.claude-3-sonnet-20240229-v1:0
+ aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID
+ aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY
+ aws_region_name: us-west-2
+```
+
+#### Non-streaming
+```python showLineNumbers title="AWS Bedrock Proxy Non-streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Non-streaming response
+response = client.responses.create(
+ model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0",
+ input="Tell me a three sentence bedtime story about a unicorn."
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="AWS Bedrock Proxy Streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Streaming response
+response = client.responses.create(
+ model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+
+First, add this to your litellm proxy config.yaml:
+```yaml showLineNumbers title="Google AI Studio Proxy Configuration"
+model_list:
+ - model_name: gemini/gemini-1.5-flash
+ litellm_params:
+ model: gemini/gemini-1.5-flash
+ api_key: os.environ/GEMINI_API_KEY
+```
+
+#### Non-streaming
+```python showLineNumbers title="Google AI Studio Proxy Non-streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Non-streaming response
+response = client.responses.create(
+ model="gemini/gemini-1.5-flash",
+ input="Tell me a three sentence bedtime story about a unicorn."
+)
+
+print(response)
+```
+
+#### Streaming
+```python showLineNumbers title="Google AI Studio Proxy Streaming Response"
+from openai import OpenAI
+
+# Initialize client with your proxy URL
+client = OpenAI(
+ base_url="http://localhost:4000", # Your proxy URL
+ api_key="your-api-key" # Your proxy API key
+)
+
+# Streaming response
+response = client.responses.create(
+ model="gemini/gemini-1.5-flash",
+ input="Tell me a three sentence bedtime story about a unicorn.",
+ stream=True
+)
+
+for event in response:
+ print(event)
+```
+
+
+
+
+## Supported Responses API Parameters
+
+| Provider | Supported Parameters |
+|----------|---------------------|
+| `openai` | [All Responses API parameters are supported](https://github.com/BerriAI/litellm/blob/7c3df984da8e4dff9201e4c5353fdc7a2b441831/litellm/llms/openai/responses/transformation.py#L23) |
+| `azure` | [All Responses API parameters are supported](https://github.com/BerriAI/litellm/blob/7c3df984da8e4dff9201e4c5353fdc7a2b441831/litellm/llms/openai/responses/transformation.py#L23) |
+| `anthropic` | [See supported parameters here](https://github.com/BerriAI/litellm/blob/f39d9178868662746f159d5ef642c7f34f9bfe5f/litellm/responses/litellm_completion_transformation/transformation.py#L57) |
+| `bedrock` | [See supported parameters here](https://github.com/BerriAI/litellm/blob/f39d9178868662746f159d5ef642c7f34f9bfe5f/litellm/responses/litellm_completion_transformation/transformation.py#L57) |
+| `gemini` | [See supported parameters here](https://github.com/BerriAI/litellm/blob/f39d9178868662746f159d5ef642c7f34f9bfe5f/litellm/responses/litellm_completion_transformation/transformation.py#L57) |
+| `vertex_ai` | [See supported parameters here](https://github.com/BerriAI/litellm/blob/f39d9178868662746f159d5ef642c7f34f9bfe5f/litellm/responses/litellm_completion_transformation/transformation.py#L57) |
+| `azure_ai` | [See supported parameters here](https://github.com/BerriAI/litellm/blob/f39d9178868662746f159d5ef642c7f34f9bfe5f/litellm/responses/litellm_completion_transformation/transformation.py#L57) |
+| All other llm api providers | [See supported parameters here](https://github.com/BerriAI/litellm/blob/f39d9178868662746f159d5ef642c7f34f9bfe5f/litellm/responses/litellm_completion_transformation/transformation.py#L57) |
+
+## Load Balancing with Routing Affinity
+
+When using the Responses API with multiple deployments of the same model (e.g., multiple Azure OpenAI endpoints), LiteLLM provides routing affinity for conversations. This ensures that follow-up requests using a `previous_response_id` are routed to the same deployment that generated the original response.
+
+
+#### Example Usage
+
+
+
+
+```python showLineNumbers title="Python SDK with Routing Affinity"
+import litellm
+
+# Set up router with multiple deployments of the same model
+router = litellm.Router(
+ model_list=[
+ {
+ "model_name": "azure-gpt4-turbo",
+ "litellm_params": {
+ "model": "azure/gpt-4-turbo",
+ "api_key": "your-api-key-1",
+ "api_version": "2024-06-01",
+ "api_base": "https://endpoint1.openai.azure.com",
+ },
+ },
+ {
+ "model_name": "azure-gpt4-turbo",
+ "litellm_params": {
+ "model": "azure/gpt-4-turbo",
+ "api_key": "your-api-key-2",
+ "api_version": "2024-06-01",
+ "api_base": "https://endpoint2.openai.azure.com",
+ },
+ },
+ ],
+ optional_pre_call_checks=["responses_api_deployment_check"],
+)
+
+# Initial request
+response = await router.aresponses(
+ model="azure-gpt4-turbo",
+ input="Hello, who are you?",
+ truncation="auto",
+)
+
+# Store the response ID
+response_id = response.id
+
+# Follow-up request - will be automatically routed to the same deployment
+follow_up = await router.aresponses(
+ model="azure-gpt4-turbo",
+ input="Tell me more about yourself",
+ truncation="auto",
+ previous_response_id=response_id # This ensures routing to the same deployment
+)
+```
+
+
+
+
+#### 1. Setup routing affinity on proxy config.yaml
+
+To enable routing affinity for Responses API in your LiteLLM proxy, set `optional_pre_call_checks: ["responses_api_deployment_check"]` in your proxy config.yaml.
+
+```yaml showLineNumbers title="config.yaml with Responses API Routing Affinity"
+model_list:
+ - model_name: azure-gpt4-turbo
+ litellm_params:
+ model: azure/gpt-4-turbo
+ api_key: your-api-key-1
+ api_version: 2024-06-01
+ api_base: https://endpoint1.openai.azure.com
+ - model_name: azure-gpt4-turbo
+ litellm_params:
+ model: azure/gpt-4-turbo
+ api_key: your-api-key-2
+ api_version: 2024-06-01
+ api_base: https://endpoint2.openai.azure.com
+
+router_settings:
+ optional_pre_call_checks: ["responses_api_deployment_check"]
+```
+
+#### 2. Use the OpenAI Python SDK to make requests to LiteLLM Proxy
+
+```python showLineNumbers title="OpenAI Client with Proxy Server"
+from openai import OpenAI
+
+client = OpenAI(
+ base_url="http://localhost:4000",
+ api_key="your-api-key"
+)
+
+# Initial request
+response = client.responses.create(
+ model="azure-gpt4-turbo",
+ input="Hello, who are you?"
+)
+
+response_id = response.id
+
+# Follow-up request - will be automatically routed to the same deployment
+follow_up = client.responses.create(
+ model="azure-gpt4-turbo",
+ input="Tell me more about yourself",
+ previous_response_id=response_id # This ensures routing to the same deployment
+)
+```
+
+
+
diff --git a/docs/my-website/docs/tutorials/openai_codex.md b/docs/my-website/docs/tutorials/openai_codex.md
new file mode 100644
index 0000000000..bb5af956b0
--- /dev/null
+++ b/docs/my-website/docs/tutorials/openai_codex.md
@@ -0,0 +1,146 @@
+import Image from '@theme/IdealImage';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# Using LiteLLM with OpenAI Codex
+
+This guide walks you through connecting OpenAI Codex to LiteLLM. Using LiteLLM with Codex allows teams to:
+- Access 100+ LLMs through the Codex interface
+- Use powerful models like Gemini through a familiar interface
+- Track spend and usage with LiteLLM's built-in analytics
+- Control model access with virtual keys
+
+
+
+## Quickstart
+
+:::info
+
+Requires LiteLLM v1.66.3.dev5 and higher
+
+:::
+
+
+Make sure to set up LiteLLM with the [LiteLLM Getting Started Guide](../proxy/docker_quick_start.md).
+
+## 1. Install OpenAI Codex
+
+Install the OpenAI Codex CLI tool globally using npm:
+
+
+
+
+```bash showLineNumbers
+npm i -g @openai/codex
+```
+
+
+
+
+```bash showLineNumbers
+yarn global add @openai/codex
+```
+
+
+
+
+## 2. Start LiteLLM Proxy
+
+
+
+
+```bash showLineNumbers
+docker run \
+ -v $(pwd)/litellm_config.yaml:/app/config.yaml \
+ -p 4000:4000 \
+ ghcr.io/berriai/litellm:main-latest \
+ --config /app/config.yaml
+```
+
+
+
+
+```bash showLineNumbers
+litellm --config /path/to/config.yaml
+```
+
+
+
+
+LiteLLM should now be running on [http://localhost:4000](http://localhost:4000)
+
+## 3. Configure LiteLLM for Model Routing
+
+Ensure your LiteLLM Proxy is properly configured to route to your desired models. Create a `litellm_config.yaml` file with the following content:
+
+```yaml showLineNumbers
+model_list:
+ - model_name: o3-mini
+ litellm_params:
+ model: openai/o3-mini
+ api_key: os.environ/OPENAI_API_KEY
+ - model_name: claude-3-7-sonnet-latest
+ litellm_params:
+ model: anthropic/claude-3-7-sonnet-latest
+ api_key: os.environ/ANTHROPIC_API_KEY
+ - model_name: gemini-2.0-flash
+ litellm_params:
+ model: gemini/gemini-2.0-flash
+ api_key: os.environ/GEMINI_API_KEY
+
+litellm_settings:
+ drop_params: true
+```
+
+This configuration enables routing to specific OpenAI, Anthropic, and Gemini models with explicit names.
+
+## 4. Configure Codex to Use LiteLLM Proxy
+
+Set the required environment variables to point Codex to your LiteLLM Proxy:
+
+```bash
+# Point to your LiteLLM Proxy server
+export OPENAI_BASE_URL=http://0.0.0.0:4000
+
+# Use your LiteLLM API key (if you've set up authentication)
+export OPENAI_API_KEY="sk-1234"
+```
+
+## 5. Run Codex with Gemini
+
+With everything configured, you can now run Codex with Gemini:
+
+```bash showLineNumbers
+codex --model gemini-2.0-flash --full-auto
+```
+
+
+
+The `--full-auto` flag allows Codex to automatically generate code without additional prompting.
+
+## 6. Advanced Options
+
+### Using Different Models
+
+You can use any model configured in your LiteLLM proxy:
+
+```bash
+# Use Claude models
+codex --model claude-3-7-sonnet-latest
+
+# Use Google AI Studio Gemini models
+codex --model gemini/gemini-2.0-flash
+```
+
+## Troubleshooting
+
+- If you encounter connection issues, ensure your LiteLLM Proxy is running and accessible at the specified URL
+- Verify your LiteLLM API key is valid if you're using authentication
+- Check that your model routing configuration is correct
+- For model-specific errors, ensure the model is properly configured in your LiteLLM setup
+
+## Additional Resources
+
+- [LiteLLM Docker Quick Start Guide](../proxy/docker_quick_start.md)
+- [OpenAI Codex GitHub Repository](https://github.com/openai/codex)
+- [LiteLLM Virtual Keys and Authentication](../proxy/virtual_keys.md)
diff --git a/docs/my-website/docs/tutorials/prompt_caching.md b/docs/my-website/docs/tutorials/prompt_caching.md
new file mode 100644
index 0000000000..bf3d5a8dda
--- /dev/null
+++ b/docs/my-website/docs/tutorials/prompt_caching.md
@@ -0,0 +1,128 @@
+import Image from '@theme/IdealImage';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# Auto-Inject Prompt Caching Checkpoints
+
+Reduce costs by up to 90% by using LiteLLM to auto-inject prompt caching checkpoints.
+
+
+
+
+## How it works
+
+LiteLLM can automatically inject prompt caching checkpoints into your requests to LLM providers. This allows:
+
+- **Cost Reduction**: Long, static parts of your prompts can be cached to avoid repeated processing
+- **No need to modify your application code**: You can configure the auto-caching behavior in the LiteLLM UI or in the `litellm config.yaml` file.
+
+## Configuration
+
+You need to specify `cache_control_injection_points` in your model configuration. This tells LiteLLM:
+1. Where to add the caching directive (`location`)
+2. Which message to target (`role`)
+
+LiteLLM will then automatically add a `cache_control` directive to the specified messages in your requests:
+
+```json
+"cache_control": {
+ "type": "ephemeral"
+}
+```
+
+## Usage Example
+
+In this example, we'll configure caching for system messages by adding the directive to all messages with `role: system`.
+
+
+
+
+```yaml showLineNumbers title="litellm config.yaml"
+model_list:
+ - model_name: anthropic-auto-inject-cache-system-message
+ litellm_params:
+ model: anthropic/claude-3-5-sonnet-20240620
+ api_key: os.environ/ANTHROPIC_API_KEY
+ cache_control_injection_points:
+ - location: message
+ role: system
+```
+
+
+
+
+On the LiteLLM UI, you can specify the `cache_control_injection_points` in the `Advanced Settings` tab when adding a model.
+
+
+
+
+
+
+## Detailed Example
+
+### 1. Original Request to LiteLLM
+
+In this example, we have a very long, static system message and a varying user message. It's efficient to cache the system message since it rarely changes.
+
+```json
+{
+ "messages": [
+ {
+ "role": "system",
+ "content": [
+ {
+ "type": "text",
+ "text": "You are a helpful assistant. This is a set of very long instructions that you will follow. Here is a legal document that you will use to answer the user's question."
+ }
+ ]
+ },
+ {
+ "role": "user",
+ "content": [
+ {
+ "type": "text",
+ "text": "What is the main topic of this legal document?"
+ }
+ ]
+ }
+ ]
+}
+```
+
+### 2. LiteLLM's Modified Request
+
+LiteLLM auto-injects the caching directive into the system message based on our configuration:
+
+```json
+{
+ "messages": [
+ {
+ "role": "system",
+ "content": [
+ {
+ "type": "text",
+ "text": "You are a helpful assistant. This is a set of very long instructions that you will follow. Here is a legal document that you will use to answer the user's question.",
+ "cache_control": {"type": "ephemeral"}
+ }
+ ]
+ },
+ {
+ "role": "user",
+ "content": [
+ {
+ "type": "text",
+ "text": "What is the main topic of this legal document?"
+ }
+ ]
+ }
+ ]
+}
+```
+
+When the model provider processes this request, it will recognize the caching directive and only process the system message once, caching it for subsequent requests.
+
+
+
+
+
+
diff --git a/docs/my-website/docs/tutorials/scim_litellm.md b/docs/my-website/docs/tutorials/scim_litellm.md
new file mode 100644
index 0000000000..c744abe4b4
--- /dev/null
+++ b/docs/my-website/docs/tutorials/scim_litellm.md
@@ -0,0 +1,74 @@
+
+import Image from '@theme/IdealImage';
+
+# SCIM with LiteLLM
+
+Enables identity providers (Okta, Azure AD, OneLogin, etc.) to automate user and team (group) provisioning, updates, and deprovisioning on LiteLLM.
+
+
+This tutorial will walk you through the steps to connect your IDP to LiteLLM SCIM Endpoints.
+
+### Supported SSO Providers for SCIM
+Below is a list of supported SSO providers for connecting to LiteLLM SCIM Endpoints.
+- Microsoft Entra ID (Azure AD)
+- Okta
+- Google Workspace
+- OneLogin
+- Keycloak
+- Auth0
+
+
+## 1. Get your SCIM Tenant URL and Bearer Token
+
+On LiteLLM, navigate to the Settings > Admin Settings > SCIM. On this page you will create a SCIM Token, this allows your IDP to authenticate to litellm `/scim` endpoints.
+
+
+
+## 2. Connect your IDP to LiteLLM SCIM Endpoints
+
+On your IDP provider, navigate to your SSO application and select `Provisioning` > `New provisioning configuration`.
+
+On this page, paste in your litellm scim tenant url and bearer token.
+
+Once this is pasted in, click on `Test Connection` to ensure your IDP can authenticate to the LiteLLM SCIM endpoints.
+
+
+
+
+## 3. Test SCIM Connection
+
+### 3.1 Assign the group to your LiteLLM Enterprise App
+
+On your IDP Portal, navigate to `Enterprise Applications` > Select your litellm app
+
+
+
+
+
+
+Once you've selected your litellm app, click on `Users and Groups` > `Add user/group`
+
+
+
+
+
+Now select the group you created in step 1.1. And add it to the LiteLLM Enterprise App. At this point we have added `Production LLM Evals Group` to the LiteLLM Enterprise App. The next step is having LiteLLM automatically create the `Production LLM Evals Group` on the LiteLLM DB when a new user signs in.
+
+
+
+
+### 3.2 Sign in to LiteLLM UI via SSO
+
+Sign into the LiteLLM UI via SSO. You should be redirected to the Entra ID SSO page. This SSO sign in flow will trigger LiteLLM to fetch the latest Groups and Members from Azure Entra ID.
+
+
+
+### 3.3 Check the new team on LiteLLM UI
+
+On the LiteLLM UI, Navigate to `Teams`, You should see the new team `Production LLM Evals Group` auto-created on LiteLLM.
+
+
+
+
+
+
diff --git a/docs/my-website/img/auto_prompt_caching.png b/docs/my-website/img/auto_prompt_caching.png
new file mode 100644
index 0000000000..6cd3785512
Binary files /dev/null and b/docs/my-website/img/auto_prompt_caching.png differ
diff --git a/docs/my-website/img/litellm_codex.gif b/docs/my-website/img/litellm_codex.gif
new file mode 100644
index 0000000000..04332b5053
Binary files /dev/null and b/docs/my-website/img/litellm_codex.gif differ
diff --git a/docs/my-website/img/release_notes/new_tag_usage.png b/docs/my-website/img/release_notes/new_tag_usage.png
new file mode 100644
index 0000000000..4188cbc245
Binary files /dev/null and b/docs/my-website/img/release_notes/new_tag_usage.png differ
diff --git a/docs/my-website/img/release_notes/new_team_usage.png b/docs/my-website/img/release_notes/new_team_usage.png
new file mode 100644
index 0000000000..5fea2506d9
Binary files /dev/null and b/docs/my-website/img/release_notes/new_team_usage.png differ
diff --git a/docs/my-website/img/release_notes/new_team_usage_highlight.jpg b/docs/my-website/img/release_notes/new_team_usage_highlight.jpg
new file mode 100644
index 0000000000..05dbf4b918
Binary files /dev/null and b/docs/my-website/img/release_notes/new_team_usage_highlight.jpg differ
diff --git a/docs/my-website/img/release_notes/unified_responses_api_rn.png b/docs/my-website/img/release_notes/unified_responses_api_rn.png
new file mode 100644
index 0000000000..60ede0e211
Binary files /dev/null and b/docs/my-website/img/release_notes/unified_responses_api_rn.png differ
diff --git a/docs/my-website/img/scim_0.png b/docs/my-website/img/scim_0.png
new file mode 100644
index 0000000000..265271b78c
Binary files /dev/null and b/docs/my-website/img/scim_0.png differ
diff --git a/docs/my-website/img/scim_1.png b/docs/my-website/img/scim_1.png
new file mode 100644
index 0000000000..c6d64b5d11
Binary files /dev/null and b/docs/my-website/img/scim_1.png differ
diff --git a/docs/my-website/img/scim_2.png b/docs/my-website/img/scim_2.png
new file mode 100644
index 0000000000..c96cf9f0b5
Binary files /dev/null and b/docs/my-website/img/scim_2.png differ
diff --git a/docs/my-website/img/scim_3.png b/docs/my-website/img/scim_3.png
new file mode 100644
index 0000000000..5ecd3906bd
Binary files /dev/null and b/docs/my-website/img/scim_3.png differ
diff --git a/docs/my-website/img/scim_4.png b/docs/my-website/img/scim_4.png
new file mode 100644
index 0000000000..b4b484418c
Binary files /dev/null and b/docs/my-website/img/scim_4.png differ
diff --git a/docs/my-website/img/scim_integration.png b/docs/my-website/img/scim_integration.png
new file mode 100644
index 0000000000..2cfeb872bf
Binary files /dev/null and b/docs/my-website/img/scim_integration.png differ
diff --git a/docs/my-website/img/ui_auto_prompt_caching.png b/docs/my-website/img/ui_auto_prompt_caching.png
new file mode 100644
index 0000000000..e6f48e48d0
Binary files /dev/null and b/docs/my-website/img/ui_auto_prompt_caching.png differ
diff --git a/docs/my-website/package-lock.json b/docs/my-website/package-lock.json
index c84c7b394c..e6f20d567b 100644
--- a/docs/my-website/package-lock.json
+++ b/docs/my-website/package-lock.json
@@ -12455,9 +12455,10 @@
}
},
"node_modules/http-proxy-middleware": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz",
- "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==",
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz",
+ "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==",
+ "license": "MIT",
"dependencies": {
"@types/http-proxy": "^1.17.8",
"http-proxy": "^1.18.1",
diff --git a/docs/my-website/release_notes/v1.57.8-stable/index.md b/docs/my-website/release_notes/v1.57.8-stable/index.md
index ea712f0f77..78fe13f2ed 100644
--- a/docs/my-website/release_notes/v1.57.8-stable/index.md
+++ b/docs/my-website/release_notes/v1.57.8-stable/index.md
@@ -38,7 +38,7 @@ hide_table_of_contents: false
2. OpenAI Moderations - `omni-moderation-latest` support. [Start Here](https://docs.litellm.ai/docs/moderation)
3. Azure O1 - fake streaming support. This ensures if a `stream=true` is passed, the response is streamed. [Start Here](https://docs.litellm.ai/docs/providers/azure)
4. Anthropic - non-whitespace char stop sequence handling - [PR](https://github.com/BerriAI/litellm/pull/7484)
-5. Azure OpenAI - support Entra id username + password based auth. [Start Here](https://docs.litellm.ai/docs/providers/azure#entrata-id---use-tenant_id-client_id-client_secret)
+5. Azure OpenAI - support Entra ID username + password based auth. [Start Here](https://docs.litellm.ai/docs/providers/azure#entra-id---use-tenant_id-client_id-client_secret)
6. LM Studio - embedding route support. [Start Here](https://docs.litellm.ai/docs/providers/lm-studio)
7. WatsonX - ZenAPIKeyAuth support. [Start Here](https://docs.litellm.ai/docs/providers/watsonx)
diff --git a/docs/my-website/release_notes/v1.67.0-stable/index.md b/docs/my-website/release_notes/v1.67.0-stable/index.md
new file mode 100644
index 0000000000..cb7938fce5
--- /dev/null
+++ b/docs/my-website/release_notes/v1.67.0-stable/index.md
@@ -0,0 +1,153 @@
+---
+title: v1.67.0-stable - SCIM Integration
+slug: v1.67.0-stable
+date: 2025-04-19T10:00:00
+authors:
+ - name: Krrish Dholakia
+ title: CEO, LiteLLM
+ url: https://www.linkedin.com/in/krish-d/
+ image_url: https://media.licdn.com/dms/image/v2/D4D03AQGrlsJ3aqpHmQ/profile-displayphoto-shrink_400_400/B4DZSAzgP7HYAg-/0/1737327772964?e=1749686400&v=beta&t=Hkl3U8Ps0VtvNxX0BNNq24b4dtX5wQaPFp6oiKCIHD8
+ - name: Ishaan Jaffer
+ title: CTO, LiteLLM
+ url: https://www.linkedin.com/in/reffajnaahsi/
+ image_url: https://pbs.twimg.com/profile_images/1613813310264340481/lz54oEiB_400x400.jpg
+
+tags: ["sso", "unified_file_id", "cost_tracking", "security"]
+hide_table_of_contents: false
+---
+import Image from '@theme/IdealImage';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+## Key Highlights
+
+- **SCIM Integration**: Enables identity providers (Okta, Azure AD, OneLogin, etc.) to automate user and team (group) provisioning, updates, and deprovisioning
+- **Team and Tag based usage tracking**: You can now see usage and spend by team and tag at 1M+ spend logs.
+- **Unified Responses API**: Support for calling Anthropic, Gemini, Groq, etc. via OpenAI's new Responses API.
+
+Let's dive in.
+
+## SCIM Integration
+
+
+
+This release adds SCIM support to LiteLLM. This allows your SSO provider (Okta, Azure AD, etc) to automatically create/delete users, teams, and memberships on LiteLLM. This means that when you remove a team on your SSO provider, your SSO provider will automatically delete the corresponding team on LiteLLM.
+
+[Read more](../../docs/tutorials/scim_litellm)
+## Team and Tag based usage tracking
+
+
+
+
+This release improves team and tag based usage tracking at 1m+ spend logs, making it easy to monitor your LLM API Spend in production. This covers:
+
+- View **daily spend** by teams + tags
+- View **usage / spend by key**, within teams
+- View **spend by multiple tags**
+- Allow **internal users** to view spend of teams they're a member of
+
+[Read more](#management-endpoints--ui)
+
+## Unified Responses API
+
+This release allows you to call Azure OpenAI, Anthropic, AWS Bedrock, and Google Vertex AI models via the POST /v1/responses endpoint on LiteLLM. This means you can now use popular tools like [OpenAI Codex](https://docs.litellm.ai/docs/tutorials/openai_codex) with your own models.
+
+
+
+
+[Read more](https://docs.litellm.ai/docs/response_api)
+
+
+## New Models / Updated Models
+
+- **OpenAI**
+ 1. gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o3, o3-mini, o4-mini pricing - [Get Started](../../docs/providers/openai#usage), [PR](https://github.com/BerriAI/litellm/pull/9990)
+ 2. o4 - correctly map o4 to openai o_series model
+- **Azure AI**
+ 1. Phi-4 output cost per token fix - [PR](https://github.com/BerriAI/litellm/pull/9880)
+ 2. Responses API support [Get Started](../../docs/providers/azure#azure-responses-api),[PR](https://github.com/BerriAI/litellm/pull/10116)
+- **Anthropic**
+ 1. redacted message thinking support - [Get Started](../../docs/providers/anthropic#usage---thinking--reasoning_content),[PR](https://github.com/BerriAI/litellm/pull/10129)
+- **Cohere**
+ 1. `/v2/chat` Passthrough endpoint support w/ cost tracking - [Get Started](../../docs/pass_through/cohere), [PR](https://github.com/BerriAI/litellm/pull/9997)
+- **Azure**
+ 1. Support azure tenant_id/client_id env vars - [Get Started](../../docs/providers/azure#entra-id---use-tenant_id-client_id-client_secret), [PR](https://github.com/BerriAI/litellm/pull/9993)
+ 2. Fix response_format check for 2025+ api versions - [PR](https://github.com/BerriAI/litellm/pull/9993)
+ 3. Add gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o3, o3-mini, o4-mini pricing
+- **VLLM**
+ 1. Files - Support 'file' message type for VLLM video url's - [Get Started](../../docs/providers/vllm#send-video-url-to-vllm), [PR](https://github.com/BerriAI/litellm/pull/10129)
+ 2. Passthrough - new `/vllm/` passthrough endpoint support [Get Started](../../docs/pass_through/vllm), [PR](https://github.com/BerriAI/litellm/pull/10002)
+- **Mistral**
+ 1. new `/mistral` passthrough endpoint support [Get Started](../../docs/pass_through/mistral), [PR](https://github.com/BerriAI/litellm/pull/10002)
+- **AWS**
+ 1. New mapped bedrock regions - [PR](https://github.com/BerriAI/litellm/pull/9430)
+- **VertexAI / Google AI Studio**
+ 1. Gemini - Response format - Retain schema field ordering for google gemini and vertex by specifying propertyOrdering - [Get Started](../../docs/providers/vertex#json-schema), [PR](https://github.com/BerriAI/litellm/pull/9828)
+ 2. Gemini-2.5-flash - return reasoning content [Google AI Studio](../../docs/providers/gemini#usage---thinking--reasoning_content), [Vertex AI](../../docs/providers/vertex#thinking--reasoning_content)
+ 3. Gemini-2.5-flash - pricing + model information [PR](https://github.com/BerriAI/litellm/pull/10125)
+ 4. Passthrough - new `/vertex_ai/discovery` route - enables calling AgentBuilder API routes [Get Started](../../docs/pass_through/vertex_ai#supported-api-endpoints), [PR](https://github.com/BerriAI/litellm/pull/10084)
+- **Fireworks AI**
+ 1. return tool calling responses in `tool_calls` field (fireworks incorrectly returns this as a json str in content) [PR](https://github.com/BerriAI/litellm/pull/10130)
+- **Triton**
+ 1. Remove fixed remove bad_words / stop words from `/generate` call - [Get Started](../../docs/providers/triton-inference-server#triton-generate---chat-completion), [PR](https://github.com/BerriAI/litellm/pull/10163)
+- **Other**
+ 1. Support for all litellm providers on Responses API (works with Codex) - [Get Started](../../docs/tutorials/openai_codex), [PR](https://github.com/BerriAI/litellm/pull/10132)
+ 2. Fix combining multiple tool calls in streaming response - [Get Started](../../docs/completion/stream#helper-function), [PR](https://github.com/BerriAI/litellm/pull/10040)
+
+
+## Spend Tracking Improvements
+
+- **Cost Control** - inject cache control points in prompt for cost reduction [Get Started](../../docs/tutorials/prompt_caching), [PR](https://github.com/BerriAI/litellm/pull/10000)
+- **Spend Tags** - spend tags in headers - support x-litellm-tags even if tag based routing not enabled [Get Started](../../docs/proxy/request_headers#litellm-headers), [PR](https://github.com/BerriAI/litellm/pull/10000)
+- **Gemini-2.5-flash** - support cost calculation for reasoning tokens [PR](https://github.com/BerriAI/litellm/pull/10141)
+
+## Management Endpoints / UI
+- **Users**
+ 1. Show created_at and updated_at on users page - [PR](https://github.com/BerriAI/litellm/pull/10033)
+- **Virtual Keys**
+ 1. Filter by key alias - https://github.com/BerriAI/litellm/pull/10085
+- **Usage Tab**
+
+ 1. Team based usage
+
+ - New `LiteLLM_DailyTeamSpend` Table for aggregate team based usage logging - [PR](https://github.com/BerriAI/litellm/pull/10039)
+
+ - New Team based usage dashboard + new `/team/daily/activity` API - [PR](https://github.com/BerriAI/litellm/pull/10081)
+ - Return team alias on /team/daily/activity API - [PR](https://github.com/BerriAI/litellm/pull/10157)
+ - allow internal user view spend for teams they belong to - [PR](https://github.com/BerriAI/litellm/pull/10157)
+ - allow viewing top keys by team - [PR](https://github.com/BerriAI/litellm/pull/10157)
+
+
+
+ 2. Tag Based Usage
+ - New `LiteLLM_DailyTagSpend` Table for aggregate tag based usage logging - [PR](https://github.com/BerriAI/litellm/pull/10071)
+ - Restrict to only Proxy Admins - [PR](https://github.com/BerriAI/litellm/pull/10157)
+ - allow viewing top keys by tag
+ - Return tags passed in request (i.e. dynamic tags) on `/tag/list` API - [PR](https://github.com/BerriAI/litellm/pull/10157)
+
+ 3. Track prompt caching metrics in daily user, team, tag tables - [PR](https://github.com/BerriAI/litellm/pull/10029)
+ 4. Show usage by key (on all up, team, and tag usage dashboards) - [PR](https://github.com/BerriAI/litellm/pull/10157)
+ 5. swap old usage with new usage tab
+- **Models**
+ 1. Make columns resizable/hideable - [PR](https://github.com/BerriAI/litellm/pull/10119)
+- **API Playground**
+ 1. Allow internal user to call api playground - [PR](https://github.com/BerriAI/litellm/pull/10157)
+- **SCIM**
+ 1. Add LiteLLM SCIM Integration for Team and User management - [Get Started](../../docs/tutorials/scim_litellm), [PR](https://github.com/BerriAI/litellm/pull/10072)
+
+
+## Logging / Guardrail Integrations
+- **GCS**
+ 1. Fix gcs pub sub logging with env var GCS_PROJECT_ID - [Get Started](../../docs/observability/gcs_bucket_integration#usage), [PR](https://github.com/BerriAI/litellm/pull/10042)
+- **AIM**
+ 1. Add litellm call id passing to Aim guardrails on pre and post-hooks calls - [Get Started](../../docs/proxy/guardrails/aim_security), [PR](https://github.com/BerriAI/litellm/pull/10021)
+- **Azure blob storage**
+ 1. Ensure logging works in high throughput scenarios - [Get Started](../../docs/proxy/logging#azure-blob-storage), [PR](https://github.com/BerriAI/litellm/pull/9962)
+
+## General Proxy Improvements
+
+- **Support setting `litellm.modify_params` via env var** [PR](https://github.com/BerriAI/litellm/pull/9964)
+- **Model Discovery** - Check provider’s `/models` endpoints when calling proxy’s `/v1/models` endpoint - [Get Started](../../docs/proxy/model_discovery), [PR](https://github.com/BerriAI/litellm/pull/9958)
+- **`/utils/token_counter`** - fix retrieving custom tokenizer for db models - [Get Started](../../docs/proxy/configs#set-custom-tokenizer), [PR](https://github.com/BerriAI/litellm/pull/10047)
+- **Prisma migrate** - handle existing columns in db table - [PR](https://github.com/BerriAI/litellm/pull/10138)
+
diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js
index 3d4e09fda3..60030a59bb 100644
--- a/docs/my-website/sidebars.js
+++ b/docs/my-website/sidebars.js
@@ -69,6 +69,7 @@ const sidebars = {
"proxy/clientside_auth",
"proxy/request_headers",
"proxy/response_headers",
+ "proxy/model_discovery",
],
},
{
@@ -101,6 +102,7 @@ const sidebars = {
"proxy/admin_ui_sso",
"proxy/self_serve",
"proxy/public_teams",
+ "tutorials/scim_litellm",
"proxy/custom_sso",
"proxy/ui_credentials",
"proxy/ui_logs"
@@ -188,7 +190,7 @@ const sidebars = {
"providers/azure_ai",
"providers/aiml",
"providers/vertex",
-
+
{
type: "category",
label: "Google AI Studio",
@@ -330,6 +332,8 @@ const sidebars = {
"pass_through/vertex_ai",
"pass_through/google_ai_studio",
"pass_through/cohere",
+ "pass_through/vllm",
+ "pass_through/mistral",
"pass_through/openai_passthrough",
"pass_through/anthropic_completion",
"pass_through/bedrock",
@@ -340,7 +344,7 @@ const sidebars = {
},
"rerank",
"assistants",
-
+
{
type: "category",
label: "/files",
@@ -407,9 +411,10 @@ const sidebars = {
type: "category",
label: "Logging & Observability",
items: [
+ "observability/agentops_integration",
+ "observability/langfuse_integration",
"observability/lunary_integration",
"observability/mlflow",
- "observability/langfuse_integration",
"observability/gcs_bucket_integration",
"observability/langsmith_integration",
"observability/literalai_integration",
@@ -443,7 +448,9 @@ const sidebars = {
label: "Tutorials",
items: [
"tutorials/openweb_ui",
+ "tutorials/openai_codex",
"tutorials/msft_sso",
+ "tutorials/prompt_caching",
"tutorials/tag_management",
'tutorials/litellm_proxy_aporia',
{
diff --git a/litellm-proxy-extras/dist/litellm_proxy_extras-0.1.8-py3-none-any.whl b/litellm-proxy-extras/dist/litellm_proxy_extras-0.1.8-py3-none-any.whl
new file mode 100644
index 0000000000..b4a2ca73d2
Binary files /dev/null and b/litellm-proxy-extras/dist/litellm_proxy_extras-0.1.8-py3-none-any.whl differ
diff --git a/litellm-proxy-extras/dist/litellm_proxy_extras-0.1.8.tar.gz b/litellm-proxy-extras/dist/litellm_proxy_extras-0.1.8.tar.gz
new file mode 100644
index 0000000000..a254112d2b
Binary files /dev/null and b/litellm-proxy-extras/dist/litellm_proxy_extras-0.1.8.tar.gz differ
diff --git a/litellm-proxy-extras/litellm_proxy_extras/migrations/20250415151647_add_cache_read_write_tokens_daily_spend_transactions/migration.sql b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250415151647_add_cache_read_write_tokens_daily_spend_transactions/migration.sql
new file mode 100644
index 0000000000..f47e1c2e91
--- /dev/null
+++ b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250415151647_add_cache_read_write_tokens_daily_spend_transactions/migration.sql
@@ -0,0 +1,4 @@
+-- AlterTable
+ALTER TABLE "LiteLLM_DailyUserSpend" ADD COLUMN "cache_creation_input_tokens" INTEGER NOT NULL DEFAULT 0,
+ADD COLUMN "cache_read_input_tokens" INTEGER NOT NULL DEFAULT 0;
+
diff --git a/litellm-proxy-extras/litellm_proxy_extras/migrations/20250415191926_add_daily_team_table/migration.sql b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250415191926_add_daily_team_table/migration.sql
new file mode 100644
index 0000000000..a6eb461bc2
--- /dev/null
+++ b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250415191926_add_daily_team_table/migration.sql
@@ -0,0 +1,36 @@
+-- CreateTable
+CREATE TABLE "LiteLLM_DailyTeamSpend" (
+ "id" TEXT NOT NULL,
+ "team_id" TEXT NOT NULL,
+ "date" TEXT NOT NULL,
+ "api_key" TEXT NOT NULL,
+ "model" TEXT NOT NULL,
+ "model_group" TEXT,
+ "custom_llm_provider" TEXT,
+ "prompt_tokens" INTEGER NOT NULL DEFAULT 0,
+ "completion_tokens" INTEGER NOT NULL DEFAULT 0,
+ "spend" DOUBLE PRECISION NOT NULL DEFAULT 0.0,
+ "api_requests" INTEGER NOT NULL DEFAULT 0,
+ "successful_requests" INTEGER NOT NULL DEFAULT 0,
+ "failed_requests" INTEGER NOT NULL DEFAULT 0,
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "LiteLLM_DailyTeamSpend_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateIndex
+CREATE INDEX "LiteLLM_DailyTeamSpend_date_idx" ON "LiteLLM_DailyTeamSpend"("date");
+
+-- CreateIndex
+CREATE INDEX "LiteLLM_DailyTeamSpend_team_id_idx" ON "LiteLLM_DailyTeamSpend"("team_id");
+
+-- CreateIndex
+CREATE INDEX "LiteLLM_DailyTeamSpend_api_key_idx" ON "LiteLLM_DailyTeamSpend"("api_key");
+
+-- CreateIndex
+CREATE INDEX "LiteLLM_DailyTeamSpend_model_idx" ON "LiteLLM_DailyTeamSpend"("model");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "LiteLLM_DailyTeamSpend_team_id_date_api_key_model_custom_ll_key" ON "LiteLLM_DailyTeamSpend"("team_id", "date", "api_key", "model", "custom_llm_provider");
+
diff --git a/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416115320_add_tag_table_to_db/migration.sql b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416115320_add_tag_table_to_db/migration.sql
new file mode 100644
index 0000000000..8c3cea7093
--- /dev/null
+++ b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416115320_add_tag_table_to_db/migration.sql
@@ -0,0 +1,45 @@
+-- AlterTable
+ALTER TABLE "LiteLLM_DailyTeamSpend" ADD COLUMN "cache_creation_input_tokens" INTEGER NOT NULL DEFAULT 0,
+ADD COLUMN "cache_read_input_tokens" INTEGER NOT NULL DEFAULT 0;
+
+-- CreateTable
+CREATE TABLE "LiteLLM_DailyTagSpend" (
+ "id" TEXT NOT NULL,
+ "tag" TEXT NOT NULL,
+ "date" TEXT NOT NULL,
+ "api_key" TEXT NOT NULL,
+ "model" TEXT NOT NULL,
+ "model_group" TEXT,
+ "custom_llm_provider" TEXT,
+ "prompt_tokens" INTEGER NOT NULL DEFAULT 0,
+ "completion_tokens" INTEGER NOT NULL DEFAULT 0,
+ "cache_read_input_tokens" INTEGER NOT NULL DEFAULT 0,
+ "cache_creation_input_tokens" INTEGER NOT NULL DEFAULT 0,
+ "spend" DOUBLE PRECISION NOT NULL DEFAULT 0.0,
+ "api_requests" INTEGER NOT NULL DEFAULT 0,
+ "successful_requests" INTEGER NOT NULL DEFAULT 0,
+ "failed_requests" INTEGER NOT NULL DEFAULT 0,
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "LiteLLM_DailyTagSpend_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "LiteLLM_DailyTagSpend_tag_key" ON "LiteLLM_DailyTagSpend"("tag");
+
+-- CreateIndex
+CREATE INDEX "LiteLLM_DailyTagSpend_date_idx" ON "LiteLLM_DailyTagSpend"("date");
+
+-- CreateIndex
+CREATE INDEX "LiteLLM_DailyTagSpend_tag_idx" ON "LiteLLM_DailyTagSpend"("tag");
+
+-- CreateIndex
+CREATE INDEX "LiteLLM_DailyTagSpend_api_key_idx" ON "LiteLLM_DailyTagSpend"("api_key");
+
+-- CreateIndex
+CREATE INDEX "LiteLLM_DailyTagSpend_model_idx" ON "LiteLLM_DailyTagSpend"("model");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "LiteLLM_DailyTagSpend_tag_date_api_key_model_custom_llm_pro_key" ON "LiteLLM_DailyTagSpend"("tag", "date", "api_key", "model", "custom_llm_provider");
+
diff --git a/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416151339_drop_tag_uniqueness_requirement/migration.sql b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416151339_drop_tag_uniqueness_requirement/migration.sql
new file mode 100644
index 0000000000..5c27b84efb
--- /dev/null
+++ b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416151339_drop_tag_uniqueness_requirement/migration.sql
@@ -0,0 +1,3 @@
+-- DropIndex
+DROP INDEX "LiteLLM_DailyTagSpend_tag_key";
+
diff --git a/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416185146_add_allowed_routes_litellm_verification_token/migration.sql b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416185146_add_allowed_routes_litellm_verification_token/migration.sql
new file mode 100644
index 0000000000..2ee7838dcf
--- /dev/null
+++ b/litellm-proxy-extras/litellm_proxy_extras/migrations/20250416185146_add_allowed_routes_litellm_verification_token/migration.sql
@@ -0,0 +1,3 @@
+-- AlterTable
+ALTER TABLE "LiteLLM_VerificationToken" ADD COLUMN "allowed_routes" TEXT[] DEFAULT ARRAY[]::TEXT[];
+
diff --git a/litellm-proxy-extras/litellm_proxy_extras/schema.prisma b/litellm-proxy-extras/litellm_proxy_extras/schema.prisma
index b2a6b362cf..68e9382d75 100644
--- a/litellm-proxy-extras/litellm_proxy_extras/schema.prisma
+++ b/litellm-proxy-extras/litellm_proxy_extras/schema.prisma
@@ -169,6 +169,7 @@ model LiteLLM_VerificationToken {
budget_duration String?
budget_reset_at DateTime?
allowed_cache_controls String[] @default([])
+ allowed_routes String[] @default([])
model_spend Json @default("{}")
model_max_budget Json @default("{}")
budget_id String?
@@ -326,6 +327,8 @@ model LiteLLM_DailyUserSpend {
custom_llm_provider String?
prompt_tokens Int @default(0)
completion_tokens Int @default(0)
+ cache_read_input_tokens Int @default(0)
+ cache_creation_input_tokens Int @default(0)
spend Float @default(0.0)
api_requests Int @default(0)
successful_requests Int @default(0)
@@ -340,6 +343,60 @@ model LiteLLM_DailyUserSpend {
@@index([model])
}
+// Track daily team spend metrics per model and key
+model LiteLLM_DailyTeamSpend {
+ id String @id @default(uuid())
+ team_id String
+ date String
+ api_key String
+ model String
+ model_group String?
+ custom_llm_provider String?
+ prompt_tokens Int @default(0)
+ completion_tokens Int @default(0)
+ cache_read_input_tokens Int @default(0)
+ cache_creation_input_tokens Int @default(0)
+ spend Float @default(0.0)
+ api_requests Int @default(0)
+ successful_requests Int @default(0)
+ failed_requests Int @default(0)
+ created_at DateTime @default(now())
+ updated_at DateTime @updatedAt
+
+ @@unique([team_id, date, api_key, model, custom_llm_provider])
+ @@index([date])
+ @@index([team_id])
+ @@index([api_key])
+ @@index([model])
+}
+
+// Track daily team spend metrics per model and key
+model LiteLLM_DailyTagSpend {
+ id String @id @default(uuid())
+ tag String
+ date String
+ api_key String
+ model String
+ model_group String?
+ custom_llm_provider String?
+ prompt_tokens Int @default(0)
+ completion_tokens Int @default(0)
+ cache_read_input_tokens Int @default(0)
+ cache_creation_input_tokens Int @default(0)
+ spend Float @default(0.0)
+ api_requests Int @default(0)
+ successful_requests Int @default(0)
+ failed_requests Int @default(0)
+ created_at DateTime @default(now())
+ updated_at DateTime @updatedAt
+
+ @@unique([tag, date, api_key, model, custom_llm_provider])
+ @@index([date])
+ @@index([tag])
+ @@index([api_key])
+ @@index([model])
+}
+
// Track the status of cron jobs running. Only allow one pod to run the job at a time
model LiteLLM_CronJob {
diff --git a/litellm-proxy-extras/litellm_proxy_extras/utils.py b/litellm-proxy-extras/litellm_proxy_extras/utils.py
index 2dab9421cb..e771e48e45 100644
--- a/litellm-proxy-extras/litellm_proxy_extras/utils.py
+++ b/litellm-proxy-extras/litellm_proxy_extras/utils.py
@@ -1,6 +1,7 @@
import glob
import os
import random
+import re
import subprocess
import time
from pathlib import Path
@@ -82,6 +83,26 @@ class ProxyExtrasDBManager:
logger.info(f"Found {len(migration_paths)} migrations at {migrations_dir}")
return [Path(p).parent.name for p in migration_paths]
+ @staticmethod
+ def _roll_back_migration(migration_name: str):
+ """Mark a specific migration as rolled back"""
+ subprocess.run(
+ ["prisma", "migrate", "resolve", "--rolled-back", migration_name],
+ timeout=60,
+ check=True,
+ capture_output=True,
+ )
+
+ @staticmethod
+ def _resolve_specific_migration(migration_name: str):
+ """Mark a specific migration as applied"""
+ subprocess.run(
+ ["prisma", "migrate", "resolve", "--applied", migration_name],
+ timeout=60,
+ check=True,
+ capture_output=True,
+ )
+
@staticmethod
def _resolve_all_migrations(migrations_dir: str):
"""Mark all existing migrations as applied"""
@@ -141,7 +162,34 @@ class ProxyExtrasDBManager:
return True
except subprocess.CalledProcessError as e:
logger.info(f"prisma db error: {e.stderr}, e: {e.stdout}")
- if (
+ if "P3009" in e.stderr:
+ # Extract the failed migration name from the error message
+ migration_match = re.search(
+ r"`(\d+_.*)` migration", e.stderr
+ )
+ if migration_match:
+ failed_migration = migration_match.group(1)
+ logger.info(
+ f"Found failed migration: {failed_migration}, marking as rolled back"
+ )
+ # Mark the failed migration as rolled back
+ subprocess.run(
+ [
+ "prisma",
+ "migrate",
+ "resolve",
+ "--rolled-back",
+ failed_migration,
+ ],
+ timeout=60,
+ check=True,
+ capture_output=True,
+ text=True,
+ )
+ logger.info(
+ f"✅ Migration {failed_migration} marked as rolled back... retrying"
+ )
+ elif (
"P3005" in e.stderr
and "database schema is not empty" in e.stderr
):
@@ -155,6 +203,29 @@ class ProxyExtrasDBManager:
ProxyExtrasDBManager._resolve_all_migrations(migrations_dir)
logger.info("✅ All migrations resolved.")
return True
+ elif (
+ "P3018" in e.stderr
+ ): # PostgreSQL error code for duplicate column
+ logger.info(
+ "Migration already exists, resolving specific migration"
+ )
+ # Extract the migration name from the error message
+ migration_match = re.search(
+ r"Migration name: (\d+_.*)", e.stderr
+ )
+ if migration_match:
+ migration_name = migration_match.group(1)
+ logger.info(f"Rolling back migration {migration_name}")
+ ProxyExtrasDBManager._roll_back_migration(
+ migration_name
+ )
+ logger.info(
+ f"Resolving migration {migration_name} that failed due to existing columns"
+ )
+ ProxyExtrasDBManager._resolve_specific_migration(
+ migration_name
+ )
+ logger.info("✅ Migration resolved.")
else:
# Use prisma db push with increased timeout
subprocess.run(
diff --git a/litellm-proxy-extras/poetry.lock b/litellm-proxy-extras/poetry.lock
index f526fec8da..bb436a168c 100644
--- a/litellm-proxy-extras/poetry.lock
+++ b/litellm-proxy-extras/poetry.lock
@@ -1,7 +1,7 @@
-# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
package = []
[metadata]
-lock-version = "2.0"
+lock-version = "2.1"
python-versions = ">=3.8.1,<4.0, !=3.9.7"
content-hash = "2cf39473e67ff0615f0a61c9d2ac9f02b38cc08cbb1bdb893d89bee002646623"
diff --git a/litellm-proxy-extras/pyproject.toml b/litellm-proxy-extras/pyproject.toml
index 8fd40a78ab..75e2ef9a5c 100644
--- a/litellm-proxy-extras/pyproject.toml
+++ b/litellm-proxy-extras/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "litellm-proxy-extras"
-version = "0.1.7"
+version = "0.1.11"
description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package."
authors = ["BerriAI"]
readme = "README.md"
@@ -22,7 +22,7 @@ requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.commitizen]
-version = "0.1.7"
+version = "0.1.11"
version_files = [
"pyproject.toml:version",
"../requirements.txt:litellm-proxy-extras==",
diff --git a/litellm/__init__.py b/litellm/__init__.py
index f27fa98029..59c8c78eb9 100644
--- a/litellm/__init__.py
+++ b/litellm/__init__.py
@@ -113,6 +113,8 @@ _custom_logger_compatible_callbacks_literal = Literal[
"pagerduty",
"humanloop",
"gcs_pubsub",
+ "agentops",
+ "anthropic_cache_control_hook",
]
logged_real_time_event_types: Optional[Union[List[str], Literal["*"]]] = None
_known_custom_logger_compatible_callbacks: List = list(
@@ -162,7 +164,7 @@ token: Optional[str] = (
telemetry = True
max_tokens: int = DEFAULT_MAX_TOKENS # OpenAI Defaults
drop_params = bool(os.getenv("LITELLM_DROP_PARAMS", False))
-modify_params = False
+modify_params = bool(os.getenv("LITELLM_MODIFY_PARAMS", False))
retry = True
### AUTH ###
api_key: Optional[str] = None
@@ -324,6 +326,7 @@ from litellm.litellm_core_utils.get_model_cost_map import get_model_cost_map
model_cost = get_model_cost_map(url=model_cost_map_url)
custom_prompt_dict: Dict[str, dict] = {}
+check_provider_endpoint = False
####### THREAD-SPECIFIC DATA ####################
@@ -413,6 +416,7 @@ deepseek_models: List = []
azure_ai_models: List = []
jina_ai_models: List = []
voyage_models: List = []
+infinity_models: List = []
databricks_models: List = []
cloudflare_models: List = []
codestral_models: List = []
@@ -554,6 +558,8 @@ def add_known_models():
azure_ai_models.append(key)
elif value.get("litellm_provider") == "voyage":
voyage_models.append(key)
+ elif value.get("litellm_provider") == "infinity":
+ infinity_models.append(key)
elif value.get("litellm_provider") == "databricks":
databricks_models.append(key)
elif value.get("litellm_provider") == "cloudflare":
@@ -642,6 +648,7 @@ model_list = (
+ deepseek_models
+ azure_ai_models
+ voyage_models
+ + infinity_models
+ databricks_models
+ cloudflare_models
+ codestral_models
@@ -697,6 +704,7 @@ models_by_provider: dict = {
"mistral": mistral_chat_models,
"azure_ai": azure_ai_models,
"voyage": voyage_models,
+ "infinity": infinity_models,
"databricks": databricks_models,
"cloudflare": cloudflare_models,
"codestral": codestral_models,
@@ -944,9 +952,11 @@ from .llms.topaz.image_variations.transformation import TopazImageVariationConfi
from litellm.llms.openai.completion.transformation import OpenAITextCompletionConfig
from .llms.groq.chat.transformation import GroqChatConfig
from .llms.voyage.embedding.transformation import VoyageEmbeddingConfig
+from .llms.infinity.embedding.transformation import InfinityEmbeddingConfig
from .llms.azure_ai.chat.transformation import AzureAIStudioConfig
from .llms.mistral.mistral_chat_transformation import MistralConfig
from .llms.openai.responses.transformation import OpenAIResponsesAPIConfig
+from .llms.azure.responses.transformation import AzureOpenAIResponsesAPIConfig
from .llms.openai.chat.o_series_transformation import (
OpenAIOSeriesConfig as OpenAIO1Config, # maintain backwards compatibility
OpenAIOSeriesConfig,
diff --git a/litellm/assistants/main.py b/litellm/assistants/main.py
index 28f4518f15..928b6e8ac2 100644
--- a/litellm/assistants/main.py
+++ b/litellm/assistants/main.py
@@ -304,6 +304,11 @@ def create_assistants(
"response_format": response_format,
}
+ # only send params that are not None
+ create_assistant_data = {
+ k: v for k, v in create_assistant_data.items() if v is not None
+ }
+
response: Optional[Union[Coroutine[Any, Any, Assistant], Assistant]] = None
if custom_llm_provider == "openai":
api_base = (
diff --git a/litellm/constants.py b/litellm/constants.py
index 12bfd17815..f48ce97afe 100644
--- a/litellm/constants.py
+++ b/litellm/constants.py
@@ -21,9 +21,18 @@ DEFAULT_MAX_TOKENS = 256 # used when providers need a default
MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB = 1024 # 1MB = 1024KB
SINGLE_DEPLOYMENT_TRAFFIC_FAILURE_THRESHOLD = 1000 # Minimum number of requests to consider "reasonable traffic". Used for single-deployment cooldown logic.
+DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET = 1024
+DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET = 2048
+DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET = 4096
+
+########## Networking constants ##############################################################
+_DEFAULT_TTL_FOR_HTTPX_CLIENTS = 3600 # 1 hour, re-use the same httpx client for 1 hour
+
########### v2 Architecture constants for managing writing updates to the database ###########
REDIS_UPDATE_BUFFER_KEY = "litellm_spend_update_buffer"
REDIS_DAILY_SPEND_UPDATE_BUFFER_KEY = "litellm_daily_spend_update_buffer"
+REDIS_DAILY_TEAM_SPEND_UPDATE_BUFFER_KEY = "litellm_daily_team_spend_update_buffer"
+REDIS_DAILY_TAG_SPEND_UPDATE_BUFFER_KEY = "litellm_daily_tag_spend_update_buffer"
MAX_REDIS_BUFFER_DEQUEUE_COUNT = 100
MAX_SIZE_IN_MEMORY_QUEUE = 10000
MAX_IN_MEMORY_QUEUE_FLUSH_COUNT = 1000
diff --git a/litellm/integrations/agentops/__init__.py b/litellm/integrations/agentops/__init__.py
new file mode 100644
index 0000000000..6ad02ce0ba
--- /dev/null
+++ b/litellm/integrations/agentops/__init__.py
@@ -0,0 +1,3 @@
+from .agentops import AgentOps
+
+__all__ = ["AgentOps"]
\ No newline at end of file
diff --git a/litellm/integrations/agentops/agentops.py b/litellm/integrations/agentops/agentops.py
new file mode 100644
index 0000000000..11e76841e9
--- /dev/null
+++ b/litellm/integrations/agentops/agentops.py
@@ -0,0 +1,118 @@
+"""
+AgentOps integration for LiteLLM - Provides OpenTelemetry tracing for LLM calls
+"""
+import os
+from dataclasses import dataclass
+from typing import Optional, Dict, Any
+from litellm.integrations.opentelemetry import OpenTelemetry, OpenTelemetryConfig
+from litellm.llms.custom_httpx.http_handler import _get_httpx_client
+
+@dataclass
+class AgentOpsConfig:
+ endpoint: str = "https://otlp.agentops.cloud/v1/traces"
+ api_key: Optional[str] = None
+ service_name: Optional[str] = None
+ deployment_environment: Optional[str] = None
+ auth_endpoint: str = "https://api.agentops.ai/v3/auth/token"
+
+ @classmethod
+ def from_env(cls):
+ return cls(
+ endpoint="https://otlp.agentops.cloud/v1/traces",
+ api_key=os.getenv("AGENTOPS_API_KEY"),
+ service_name=os.getenv("AGENTOPS_SERVICE_NAME", "agentops"),
+ deployment_environment=os.getenv("AGENTOPS_ENVIRONMENT", "production"),
+ auth_endpoint="https://api.agentops.ai/v3/auth/token"
+ )
+
+class AgentOps(OpenTelemetry):
+ """
+ AgentOps integration - built on top of OpenTelemetry
+
+ Example usage:
+ ```python
+ import litellm
+
+ litellm.success_callback = ["agentops"]
+
+ response = litellm.completion(
+ model="gpt-3.5-turbo",
+ messages=[{"role": "user", "content": "Hello, how are you?"}],
+ )
+ ```
+ """
+ def __init__(
+ self,
+ config: Optional[AgentOpsConfig] = None,
+ ):
+ if config is None:
+ config = AgentOpsConfig.from_env()
+
+ # Prefetch JWT token for authentication
+ jwt_token = None
+ project_id = None
+ if config.api_key:
+ try:
+ response = self._fetch_auth_token(config.api_key, config.auth_endpoint)
+ jwt_token = response.get("token")
+ project_id = response.get("project_id")
+ except Exception:
+ pass
+
+ headers = f"Authorization=Bearer {jwt_token}" if jwt_token else None
+
+ otel_config = OpenTelemetryConfig(
+ exporter="otlp_http",
+ endpoint=config.endpoint,
+ headers=headers
+ )
+
+ # Initialize OpenTelemetry with our config
+ super().__init__(
+ config=otel_config,
+ callback_name="agentops"
+ )
+
+ # Set AgentOps-specific resource attributes
+ resource_attrs = {
+ "service.name": config.service_name or "litellm",
+ "deployment.environment": config.deployment_environment or "production",
+ "telemetry.sdk.name": "agentops",
+ }
+
+ if project_id:
+ resource_attrs["project.id"] = project_id
+
+ self.resource_attributes = resource_attrs
+
+ def _fetch_auth_token(self, api_key: str, auth_endpoint: str) -> Dict[str, Any]:
+ """
+ Fetch JWT authentication token from AgentOps API
+
+ Args:
+ api_key: AgentOps API key
+ auth_endpoint: Authentication endpoint
+
+ Returns:
+ Dict containing JWT token and project ID
+ """
+ headers = {
+ "Content-Type": "application/json",
+ "Connection": "keep-alive",
+ }
+
+ client = _get_httpx_client()
+ try:
+ response = client.post(
+ url=auth_endpoint,
+ headers=headers,
+ json={"api_key": api_key},
+ timeout=10
+ )
+
+ if response.status_code != 200:
+ raise Exception(f"Failed to fetch auth token: {response.text}")
+
+ return response.json()
+ finally:
+ client.close()
\ No newline at end of file
diff --git a/litellm/integrations/anthropic_cache_control_hook.py b/litellm/integrations/anthropic_cache_control_hook.py
new file mode 100644
index 0000000000..c138b3cc25
--- /dev/null
+++ b/litellm/integrations/anthropic_cache_control_hook.py
@@ -0,0 +1,150 @@
+"""
+This hook is used to inject cache control directives into the messages of a chat completion.
+
+Users can define
+- `cache_control_injection_points` in the completion params and litellm will inject the cache control directives into the messages at the specified injection points.
+
+"""
+
+import copy
+from typing import Dict, List, Optional, Tuple, Union, cast
+
+from litellm.integrations.custom_logger import CustomLogger
+from litellm.integrations.custom_prompt_management import CustomPromptManagement
+from litellm.types.integrations.anthropic_cache_control_hook import (
+ CacheControlInjectionPoint,
+ CacheControlMessageInjectionPoint,
+)
+from litellm.types.llms.openai import AllMessageValues, ChatCompletionCachedContent
+from litellm.types.utils import StandardCallbackDynamicParams
+
+
+class AnthropicCacheControlHook(CustomPromptManagement):
+ def get_chat_completion_prompt(
+ self,
+ model: str,
+ messages: List[AllMessageValues],
+ non_default_params: dict,
+ prompt_id: Optional[str],
+ prompt_variables: Optional[dict],
+ dynamic_callback_params: StandardCallbackDynamicParams,
+ ) -> Tuple[str, List[AllMessageValues], dict]:
+ """
+ Apply cache control directives based on specified injection points.
+
+ Returns:
+ - model: str - the model to use
+ - messages: List[AllMessageValues] - messages with applied cache controls
+ - non_default_params: dict - params with any global cache controls
+ """
+ # Extract cache control injection points
+ injection_points: List[CacheControlInjectionPoint] = non_default_params.pop(
+ "cache_control_injection_points", []
+ )
+ if not injection_points:
+ return model, messages, non_default_params
+
+ # Create a deep copy of messages to avoid modifying the original list
+ processed_messages = copy.deepcopy(messages)
+
+ # Process message-level cache controls
+ for point in injection_points:
+ if point.get("location") == "message":
+ point = cast(CacheControlMessageInjectionPoint, point)
+ processed_messages = self._process_message_injection(
+ point=point, messages=processed_messages
+ )
+
+ return model, processed_messages, non_default_params
+
+ @staticmethod
+ def _process_message_injection(
+ point: CacheControlMessageInjectionPoint, messages: List[AllMessageValues]
+ ) -> List[AllMessageValues]:
+ """Process message-level cache control injection."""
+ control: ChatCompletionCachedContent = point.get(
+ "control", None
+ ) or ChatCompletionCachedContent(type="ephemeral")
+
+ _targetted_index: Optional[Union[int, str]] = point.get("index", None)
+ targetted_index: Optional[int] = None
+ if isinstance(_targetted_index, str):
+ if _targetted_index.isdigit():
+ targetted_index = int(_targetted_index)
+ else:
+ targetted_index = _targetted_index
+
+ targetted_role = point.get("role", None)
+
+ # Case 1: Target by specific index
+ if targetted_index is not None:
+ if 0 <= targetted_index < len(messages):
+ messages[targetted_index] = (
+ AnthropicCacheControlHook._safe_insert_cache_control_in_message(
+ messages[targetted_index], control
+ )
+ )
+ # Case 2: Target by role
+ elif targetted_role is not None:
+ for msg in messages:
+ if msg.get("role") == targetted_role:
+ msg = (
+ AnthropicCacheControlHook._safe_insert_cache_control_in_message(
+ message=msg, control=control
+ )
+ )
+ return messages
+
+ @staticmethod
+ def _safe_insert_cache_control_in_message(
+ message: AllMessageValues, control: ChatCompletionCachedContent
+ ) -> AllMessageValues:
+ """
+ Safe way to insert cache control in a message
+
+ OpenAI Message content can be either:
+ - string
+ - list of objects
+
+ This method handles inserting cache control in both cases.
+ """
+ message_content = message.get("content", None)
+
+ # 1. if string, insert cache control in the message
+ if isinstance(message_content, str):
+ message["cache_control"] = control # type: ignore
+ # 2. list of objects
+ elif isinstance(message_content, list):
+ for content_item in message_content:
+ if isinstance(content_item, dict):
+ content_item["cache_control"] = control # type: ignore
+ return message
+
+ @property
+ def integration_name(self) -> str:
+ """Return the integration name for this hook."""
+ return "anthropic_cache_control_hook"
+
+ @staticmethod
+ def should_use_anthropic_cache_control_hook(non_default_params: Dict) -> bool:
+ if non_default_params.get("cache_control_injection_points", None):
+ return True
+ return False
+
+ @staticmethod
+ def get_custom_logger_for_anthropic_cache_control_hook(
+ non_default_params: Dict,
+ ) -> Optional[CustomLogger]:
+ from litellm.litellm_core_utils.litellm_logging import (
+ _init_custom_logger_compatible_class,
+ )
+
+ if AnthropicCacheControlHook.should_use_anthropic_cache_control_hook(
+ non_default_params
+ ):
+ return _init_custom_logger_compatible_class(
+ logging_integration="anthropic_cache_control_hook",
+ internal_usage_cache=None,
+ llm_router=None,
+ )
+ return None
diff --git a/litellm/integrations/azure_storage/azure_storage.py b/litellm/integrations/azure_storage/azure_storage.py
index 27f5e0e112..6ffb1e542f 100644
--- a/litellm/integrations/azure_storage/azure_storage.py
+++ b/litellm/integrations/azure_storage/azure_storage.py
@@ -1,14 +1,15 @@
import asyncio
import json
import os
+import time
import uuid
from datetime import datetime, timedelta
from typing import List, Optional
from litellm._logging import verbose_logger
-from litellm.constants import AZURE_STORAGE_MSFT_VERSION
+from litellm.constants import _DEFAULT_TTL_FOR_HTTPX_CLIENTS, AZURE_STORAGE_MSFT_VERSION
from litellm.integrations.custom_batch_logger import CustomBatchLogger
-from litellm.llms.azure.common_utils import get_azure_ad_token_from_entrata_id
+from litellm.llms.azure.common_utils import get_azure_ad_token_from_entra_id
from litellm.llms.custom_httpx.http_handler import (
AsyncHTTPHandler,
get_async_httpx_client,
@@ -48,14 +49,17 @@ class AzureBlobStorageLogger(CustomBatchLogger):
"Missing required environment variable: AZURE_STORAGE_FILE_SYSTEM"
)
self.azure_storage_file_system: str = _azure_storage_file_system
+ self._service_client = None
+ # Time that the azure service client expires, in order to reset the connection pool and keep it fresh
+ self._service_client_timeout: Optional[float] = None
# Internal variables used for Token based authentication
- self.azure_auth_token: Optional[
- str
- ] = None # the Azure AD token to use for Azure Storage API requests
- self.token_expiry: Optional[
- datetime
- ] = None # the expiry time of the currentAzure AD token
+ self.azure_auth_token: Optional[str] = (
+ None # the Azure AD token to use for Azure Storage API requests
+ )
+ self.token_expiry: Optional[datetime] = (
+ None # the expiry time of the currentAzure AD token
+ )
asyncio.create_task(self.periodic_flush())
self.flush_lock = asyncio.Lock()
@@ -291,7 +295,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
"Missing required environment variable: AZURE_STORAGE_CLIENT_SECRET"
)
- token_provider = get_azure_ad_token_from_entrata_id(
+ token_provider = get_azure_ad_token_from_entra_id(
tenant_id=tenant_id,
client_id=client_id,
client_secret=client_secret,
@@ -324,6 +328,25 @@ class AzureBlobStorageLogger(CustomBatchLogger):
f"AzureBlobStorageLogger is only available for premium users. {CommonProxyErrors.not_premium_user}"
)
+ async def get_service_client(self):
+ from azure.storage.filedatalake.aio import DataLakeServiceClient
+
+ # expire old clients to recover from connection issues
+ if (
+ self._service_client_timeout
+ and self._service_client
+ and self._service_client_timeout > time.time()
+ ):
+ await self._service_client.close()
+ self._service_client = None
+ if not self._service_client:
+ self._service_client = DataLakeServiceClient(
+ account_url=f"https://{self.azure_storage_account_name}.dfs.core.windows.net",
+ credential=self.azure_storage_account_key,
+ )
+ self._service_client_timeout = time.time() + _DEFAULT_TTL_FOR_HTTPX_CLIENTS
+ return self._service_client
+
async def upload_to_azure_data_lake_with_azure_account_key(
self, payload: StandardLoggingPayload
):
@@ -332,13 +355,10 @@ class AzureBlobStorageLogger(CustomBatchLogger):
This is used when Azure Storage Account Key is set - Azure Storage Account Key does not work directly with Azure Rest API
"""
- from azure.storage.filedatalake.aio import DataLakeServiceClient
# Create an async service client
- service_client = DataLakeServiceClient(
- account_url=f"https://{self.azure_storage_account_name}.dfs.core.windows.net",
- credential=self.azure_storage_account_key,
- )
+
+ service_client = await self.get_service_client()
# Get file system client
file_system_client = service_client.get_file_system_client(
file_system=self.azure_storage_file_system
diff --git a/litellm/integrations/custom_logger.py b/litellm/integrations/custom_logger.py
index a7471f32f4..18cb8e8d7f 100644
--- a/litellm/integrations/custom_logger.py
+++ b/litellm/integrations/custom_logger.py
@@ -94,7 +94,7 @@ class CustomLogger: # https://docs.litellm.ai/docs/observability/custom_callbac
model: str,
messages: List[AllMessageValues],
non_default_params: dict,
- prompt_id: str,
+ prompt_id: Optional[str],
prompt_variables: Optional[dict],
dynamic_callback_params: StandardCallbackDynamicParams,
) -> Tuple[str, List[AllMessageValues], dict]:
diff --git a/litellm/integrations/custom_prompt_management.py b/litellm/integrations/custom_prompt_management.py
index 5b34ef0c34..9d05e7b242 100644
--- a/litellm/integrations/custom_prompt_management.py
+++ b/litellm/integrations/custom_prompt_management.py
@@ -15,7 +15,7 @@ class CustomPromptManagement(CustomLogger, PromptManagementBase):
model: str,
messages: List[AllMessageValues],
non_default_params: dict,
- prompt_id: str,
+ prompt_id: Optional[str],
prompt_variables: Optional[dict],
dynamic_callback_params: StandardCallbackDynamicParams,
) -> Tuple[str, List[AllMessageValues], dict]:
diff --git a/litellm/integrations/gcs_pubsub/pub_sub.py b/litellm/integrations/gcs_pubsub/pub_sub.py
index bdaedcd908..db7f9bb4d0 100644
--- a/litellm/integrations/gcs_pubsub/pub_sub.py
+++ b/litellm/integrations/gcs_pubsub/pub_sub.py
@@ -75,7 +75,7 @@ class GcsPubSubLogger(CustomBatchLogger):
vertex_project,
) = await vertex_chat_completion._ensure_access_token_async(
credentials=self.path_service_account_json,
- project_id=None,
+ project_id=self.project_id,
custom_llm_provider="vertex_ai",
)
diff --git a/litellm/integrations/humanloop.py b/litellm/integrations/humanloop.py
index 4651238af4..853fbe148c 100644
--- a/litellm/integrations/humanloop.py
+++ b/litellm/integrations/humanloop.py
@@ -152,14 +152,21 @@ class HumanloopLogger(CustomLogger):
model: str,
messages: List[AllMessageValues],
non_default_params: dict,
- prompt_id: str,
+ prompt_id: Optional[str],
prompt_variables: Optional[dict],
dynamic_callback_params: StandardCallbackDynamicParams,
- ) -> Tuple[str, List[AllMessageValues], dict,]:
+ ) -> Tuple[
+ str,
+ List[AllMessageValues],
+ dict,
+ ]:
humanloop_api_key = dynamic_callback_params.get(
"humanloop_api_key"
) or get_secret_str("HUMANLOOP_API_KEY")
+ if prompt_id is None:
+ raise ValueError("prompt_id is required for Humanloop integration")
+
if humanloop_api_key is None:
return super().get_chat_completion_prompt(
model=model,
diff --git a/litellm/integrations/langfuse/langfuse_prompt_management.py b/litellm/integrations/langfuse/langfuse_prompt_management.py
index 30f991ebd6..dcd3d9933a 100644
--- a/litellm/integrations/langfuse/langfuse_prompt_management.py
+++ b/litellm/integrations/langfuse/langfuse_prompt_management.py
@@ -169,10 +169,14 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge
model: str,
messages: List[AllMessageValues],
non_default_params: dict,
- prompt_id: str,
+ prompt_id: Optional[str],
prompt_variables: Optional[dict],
dynamic_callback_params: StandardCallbackDynamicParams,
- ) -> Tuple[str, List[AllMessageValues], dict,]:
+ ) -> Tuple[
+ str,
+ List[AllMessageValues],
+ dict,
+ ]:
return self.get_chat_completion_prompt(
model,
messages,
diff --git a/litellm/integrations/prompt_management_base.py b/litellm/integrations/prompt_management_base.py
index 07b6720ffe..270c34be8a 100644
--- a/litellm/integrations/prompt_management_base.py
+++ b/litellm/integrations/prompt_management_base.py
@@ -79,10 +79,12 @@ class PromptManagementBase(ABC):
model: str,
messages: List[AllMessageValues],
non_default_params: dict,
- prompt_id: str,
+ prompt_id: Optional[str],
prompt_variables: Optional[dict],
dynamic_callback_params: StandardCallbackDynamicParams,
- ) -> Tuple[str, List[AllMessageValues], dict,]:
+ ) -> Tuple[str, List[AllMessageValues], dict]:
+ if prompt_id is None:
+ raise ValueError("prompt_id is required for Prompt Management Base class")
if not self.should_run_prompt_management(
prompt_id=prompt_id, dynamic_callback_params=dynamic_callback_params
):
diff --git a/litellm/litellm_core_utils/get_supported_openai_params.py b/litellm/litellm_core_utils/get_supported_openai_params.py
index bcf9fdb961..c0f638ddc2 100644
--- a/litellm/litellm_core_utils/get_supported_openai_params.py
+++ b/litellm/litellm_core_utils/get_supported_openai_params.py
@@ -221,6 +221,8 @@ def get_supported_openai_params( # noqa: PLR0915
return litellm.PredibaseConfig().get_supported_openai_params(model=model)
elif custom_llm_provider == "voyage":
return litellm.VoyageEmbeddingConfig().get_supported_openai_params(model=model)
+ elif custom_llm_provider == "infinity":
+ return litellm.InfinityEmbeddingConfig().get_supported_openai_params(model=model)
elif custom_llm_provider == "triton":
if request_type == "embeddings":
return litellm.TritonEmbeddingConfig().get_supported_openai_params(
diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py
index af59901b33..77d4fd7d5d 100644
--- a/litellm/litellm_core_utils/litellm_logging.py
+++ b/litellm/litellm_core_utils/litellm_logging.py
@@ -28,6 +28,7 @@ from litellm._logging import _is_debugging_on, verbose_logger
from litellm.batches.batch_utils import _handle_completed_batch
from litellm.caching.caching import DualCache, InMemoryCache
from litellm.caching.caching_handler import LLMCachingHandler
+
from litellm.constants import (
DEFAULT_MOCK_RESPONSE_COMPLETION_TOKEN_COUNT,
DEFAULT_MOCK_RESPONSE_PROMPT_TOKEN_COUNT,
@@ -36,6 +37,8 @@ from litellm.cost_calculator import (
RealtimeAPITokenUsageProcessor,
_select_model_name_for_cost_calc,
)
+from litellm.integrations.agentops import AgentOps
+from litellm.integrations.anthropic_cache_control_hook import AnthropicCacheControlHook
from litellm.integrations.arize.arize import ArizeLogger
from litellm.integrations.custom_guardrail import CustomGuardrail
from litellm.integrations.custom_logger import CustomLogger
@@ -249,9 +252,9 @@ class Logging(LiteLLMLoggingBaseClass):
self.litellm_trace_id = litellm_trace_id
self.function_id = function_id
self.streaming_chunks: List[Any] = [] # for generating complete stream response
- self.sync_streaming_chunks: List[
- Any
- ] = [] # for generating complete stream response
+ self.sync_streaming_chunks: List[Any] = (
+ []
+ ) # for generating complete stream response
self.log_raw_request_response = log_raw_request_response
# Initialize dynamic callbacks
@@ -455,19 +458,38 @@ class Logging(LiteLLMLoggingBaseClass):
if "custom_llm_provider" in self.model_call_details:
self.custom_llm_provider = self.model_call_details["custom_llm_provider"]
+ def should_run_prompt_management_hooks(
+ self,
+ non_default_params: Dict,
+ prompt_id: Optional[str] = None,
+ ) -> bool:
+ """
+ Return True if prompt management hooks should be run
+ """
+ if prompt_id:
+ return True
+ if AnthropicCacheControlHook.should_use_anthropic_cache_control_hook(
+ non_default_params
+ ):
+ return True
+ return False
+
def get_chat_completion_prompt(
self,
model: str,
messages: List[AllMessageValues],
- non_default_params: dict,
- prompt_id: str,
+ non_default_params: Dict,
+ prompt_id: Optional[str],
prompt_variables: Optional[dict],
prompt_management_logger: Optional[CustomLogger] = None,
) -> Tuple[str, List[AllMessageValues], dict]:
custom_logger = (
prompt_management_logger
- or self.get_custom_logger_for_prompt_management(model)
+ or self.get_custom_logger_for_prompt_management(
+ model=model, non_default_params=non_default_params
+ )
)
+
if custom_logger:
(
model,
@@ -476,7 +498,7 @@ class Logging(LiteLLMLoggingBaseClass):
) = custom_logger.get_chat_completion_prompt(
model=model,
messages=messages,
- non_default_params=non_default_params,
+ non_default_params=non_default_params or {},
prompt_id=prompt_id,
prompt_variables=prompt_variables,
dynamic_callback_params=self.standard_callback_dynamic_params,
@@ -485,7 +507,7 @@ class Logging(LiteLLMLoggingBaseClass):
return model, messages, non_default_params
def get_custom_logger_for_prompt_management(
- self, model: str
+ self, model: str, non_default_params: Dict
) -> Optional[CustomLogger]:
"""
Get a custom logger for prompt management based on model name or available callbacks.
@@ -520,6 +542,26 @@ class Logging(LiteLLMLoggingBaseClass):
self.model_call_details["prompt_integration"] = logger.__class__.__name__
return logger
+ if anthropic_cache_control_logger := AnthropicCacheControlHook.get_custom_logger_for_anthropic_cache_control_hook(
+ non_default_params
+ ):
+ self.model_call_details["prompt_integration"] = (
+ anthropic_cache_control_logger.__class__.__name__
+ )
+ return anthropic_cache_control_logger
+
+ return None
+
+ def get_custom_logger_for_anthropic_cache_control_hook(
+ self, non_default_params: Dict
+ ) -> Optional[CustomLogger]:
+ if non_default_params.get("cache_control_injection_points", None):
+ custom_logger = _init_custom_logger_compatible_class(
+ logging_integration="anthropic_cache_control_hook",
+ internal_usage_cache=None,
+ llm_router=None,
+ )
+ return custom_logger
return None
def _get_raw_request_body(self, data: Optional[Union[dict, str]]) -> dict:
@@ -557,9 +599,9 @@ class Logging(LiteLLMLoggingBaseClass):
model
): # if model name was changes pre-call, overwrite the initial model call name with the new one
self.model_call_details["model"] = model
- self.model_call_details["litellm_params"][
- "api_base"
- ] = self._get_masked_api_base(additional_args.get("api_base", ""))
+ self.model_call_details["litellm_params"]["api_base"] = (
+ self._get_masked_api_base(additional_args.get("api_base", ""))
+ )
def pre_call(self, input, api_key, model=None, additional_args={}): # noqa: PLR0915
# Log the exact input to the LLM API
@@ -588,10 +630,10 @@ class Logging(LiteLLMLoggingBaseClass):
try:
# [Non-blocking Extra Debug Information in metadata]
if turn_off_message_logging is True:
- _metadata[
- "raw_request"
- ] = "redacted by litellm. \
+ _metadata["raw_request"] = (
+ "redacted by litellm. \
'litellm.turn_off_message_logging=True'"
+ )
else:
curl_command = self._get_request_curl_command(
api_base=additional_args.get("api_base", ""),
@@ -602,32 +644,32 @@ class Logging(LiteLLMLoggingBaseClass):
_metadata["raw_request"] = str(curl_command)
# split up, so it's easier to parse in the UI
- self.model_call_details[
- "raw_request_typed_dict"
- ] = RawRequestTypedDict(
- raw_request_api_base=str(
- additional_args.get("api_base") or ""
- ),
- raw_request_body=self._get_raw_request_body(
- additional_args.get("complete_input_dict", {})
- ),
- raw_request_headers=self._get_masked_headers(
- additional_args.get("headers", {}) or {},
- ignore_sensitive_headers=True,
- ),
- error=None,
+ self.model_call_details["raw_request_typed_dict"] = (
+ RawRequestTypedDict(
+ raw_request_api_base=str(
+ additional_args.get("api_base") or ""
+ ),
+ raw_request_body=self._get_raw_request_body(
+ additional_args.get("complete_input_dict", {})
+ ),
+ raw_request_headers=self._get_masked_headers(
+ additional_args.get("headers", {}) or {},
+ ignore_sensitive_headers=True,
+ ),
+ error=None,
+ )
)
except Exception as e:
- self.model_call_details[
- "raw_request_typed_dict"
- ] = RawRequestTypedDict(
- error=str(e),
+ self.model_call_details["raw_request_typed_dict"] = (
+ RawRequestTypedDict(
+ error=str(e),
+ )
)
- _metadata[
- "raw_request"
- ] = "Unable to Log \
+ _metadata["raw_request"] = (
+ "Unable to Log \
raw request: {}".format(
- str(e)
+ str(e)
+ )
)
if self.logger_fn and callable(self.logger_fn):
try:
@@ -957,9 +999,9 @@ class Logging(LiteLLMLoggingBaseClass):
verbose_logger.debug(
f"response_cost_failure_debug_information: {debug_info}"
)
- self.model_call_details[
- "response_cost_failure_debug_information"
- ] = debug_info
+ self.model_call_details["response_cost_failure_debug_information"] = (
+ debug_info
+ )
return None
try:
@@ -984,9 +1026,9 @@ class Logging(LiteLLMLoggingBaseClass):
verbose_logger.debug(
f"response_cost_failure_debug_information: {debug_info}"
)
- self.model_call_details[
- "response_cost_failure_debug_information"
- ] = debug_info
+ self.model_call_details["response_cost_failure_debug_information"] = (
+ debug_info
+ )
return None
@@ -1046,9 +1088,9 @@ class Logging(LiteLLMLoggingBaseClass):
end_time = datetime.datetime.now()
if self.completion_start_time is None:
self.completion_start_time = end_time
- self.model_call_details[
- "completion_start_time"
- ] = self.completion_start_time
+ self.model_call_details["completion_start_time"] = (
+ self.completion_start_time
+ )
self.model_call_details["log_event_type"] = "successful_api_call"
self.model_call_details["end_time"] = end_time
self.model_call_details["cache_hit"] = cache_hit
@@ -1127,39 +1169,39 @@ class Logging(LiteLLMLoggingBaseClass):
"response_cost"
]
else:
- self.model_call_details[
- "response_cost"
- ] = self._response_cost_calculator(result=logging_result)
+ self.model_call_details["response_cost"] = (
+ self._response_cost_calculator(result=logging_result)
+ )
## STANDARDIZED LOGGING PAYLOAD
- self.model_call_details[
- "standard_logging_object"
- ] = get_standard_logging_object_payload(
- kwargs=self.model_call_details,
- init_response_obj=logging_result,
- start_time=start_time,
- end_time=end_time,
- logging_obj=self,
- status="success",
- standard_built_in_tools_params=self.standard_built_in_tools_params,
+ self.model_call_details["standard_logging_object"] = (
+ get_standard_logging_object_payload(
+ kwargs=self.model_call_details,
+ init_response_obj=logging_result,
+ start_time=start_time,
+ end_time=end_time,
+ logging_obj=self,
+ status="success",
+ standard_built_in_tools_params=self.standard_built_in_tools_params,
+ )
)
elif isinstance(result, dict) or isinstance(result, list):
## STANDARDIZED LOGGING PAYLOAD
- self.model_call_details[
- "standard_logging_object"
- ] = get_standard_logging_object_payload(
- kwargs=self.model_call_details,
- init_response_obj=result,
- start_time=start_time,
- end_time=end_time,
- logging_obj=self,
- status="success",
- standard_built_in_tools_params=self.standard_built_in_tools_params,
+ self.model_call_details["standard_logging_object"] = (
+ get_standard_logging_object_payload(
+ kwargs=self.model_call_details,
+ init_response_obj=result,
+ start_time=start_time,
+ end_time=end_time,
+ logging_obj=self,
+ status="success",
+ standard_built_in_tools_params=self.standard_built_in_tools_params,
+ )
)
elif standard_logging_object is not None:
- self.model_call_details[
- "standard_logging_object"
- ] = standard_logging_object
+ self.model_call_details["standard_logging_object"] = (
+ standard_logging_object
+ )
else: # streaming chunks + image gen.
self.model_call_details["response_cost"] = None
@@ -1215,23 +1257,23 @@ class Logging(LiteLLMLoggingBaseClass):
verbose_logger.debug(
"Logging Details LiteLLM-Success Call streaming complete"
)
- self.model_call_details[
- "complete_streaming_response"
- ] = complete_streaming_response
- self.model_call_details[
- "response_cost"
- ] = self._response_cost_calculator(result=complete_streaming_response)
+ self.model_call_details["complete_streaming_response"] = (
+ complete_streaming_response
+ )
+ self.model_call_details["response_cost"] = (
+ self._response_cost_calculator(result=complete_streaming_response)
+ )
## STANDARDIZED LOGGING PAYLOAD
- self.model_call_details[
- "standard_logging_object"
- ] = get_standard_logging_object_payload(
- kwargs=self.model_call_details,
- init_response_obj=complete_streaming_response,
- start_time=start_time,
- end_time=end_time,
- logging_obj=self,
- status="success",
- standard_built_in_tools_params=self.standard_built_in_tools_params,
+ self.model_call_details["standard_logging_object"] = (
+ get_standard_logging_object_payload(
+ kwargs=self.model_call_details,
+ init_response_obj=complete_streaming_response,
+ start_time=start_time,
+ end_time=end_time,
+ logging_obj=self,
+ status="success",
+ standard_built_in_tools_params=self.standard_built_in_tools_params,
+ )
)
callbacks = self.get_combined_callback_list(
dynamic_success_callbacks=self.dynamic_success_callbacks,
@@ -1580,10 +1622,10 @@ class Logging(LiteLLMLoggingBaseClass):
)
else:
if self.stream and complete_streaming_response:
- self.model_call_details[
- "complete_response"
- ] = self.model_call_details.get(
- "complete_streaming_response", {}
+ self.model_call_details["complete_response"] = (
+ self.model_call_details.get(
+ "complete_streaming_response", {}
+ )
)
result = self.model_call_details["complete_response"]
openMeterLogger.log_success_event(
@@ -1623,10 +1665,10 @@ class Logging(LiteLLMLoggingBaseClass):
)
else:
if self.stream and complete_streaming_response:
- self.model_call_details[
- "complete_response"
- ] = self.model_call_details.get(
- "complete_streaming_response", {}
+ self.model_call_details["complete_response"] = (
+ self.model_call_details.get(
+ "complete_streaming_response", {}
+ )
)
result = self.model_call_details["complete_response"]
@@ -1733,9 +1775,9 @@ class Logging(LiteLLMLoggingBaseClass):
if complete_streaming_response is not None:
print_verbose("Async success callbacks: Got a complete streaming response")
- self.model_call_details[
- "async_complete_streaming_response"
- ] = complete_streaming_response
+ self.model_call_details["async_complete_streaming_response"] = (
+ complete_streaming_response
+ )
try:
if self.model_call_details.get("cache_hit", False) is True:
self.model_call_details["response_cost"] = 0.0
@@ -1745,10 +1787,10 @@ class Logging(LiteLLMLoggingBaseClass):
model_call_details=self.model_call_details
)
# base_model defaults to None if not set on model_info
- self.model_call_details[
- "response_cost"
- ] = self._response_cost_calculator(
- result=complete_streaming_response
+ self.model_call_details["response_cost"] = (
+ self._response_cost_calculator(
+ result=complete_streaming_response
+ )
)
verbose_logger.debug(
@@ -1761,16 +1803,16 @@ class Logging(LiteLLMLoggingBaseClass):
self.model_call_details["response_cost"] = None
## STANDARDIZED LOGGING PAYLOAD
- self.model_call_details[
- "standard_logging_object"
- ] = get_standard_logging_object_payload(
- kwargs=self.model_call_details,
- init_response_obj=complete_streaming_response,
- start_time=start_time,
- end_time=end_time,
- logging_obj=self,
- status="success",
- standard_built_in_tools_params=self.standard_built_in_tools_params,
+ self.model_call_details["standard_logging_object"] = (
+ get_standard_logging_object_payload(
+ kwargs=self.model_call_details,
+ init_response_obj=complete_streaming_response,
+ start_time=start_time,
+ end_time=end_time,
+ logging_obj=self,
+ status="success",
+ standard_built_in_tools_params=self.standard_built_in_tools_params,
+ )
)
callbacks = self.get_combined_callback_list(
dynamic_success_callbacks=self.dynamic_async_success_callbacks,
@@ -1976,18 +2018,18 @@ class Logging(LiteLLMLoggingBaseClass):
## STANDARDIZED LOGGING PAYLOAD
- self.model_call_details[
- "standard_logging_object"
- ] = get_standard_logging_object_payload(
- kwargs=self.model_call_details,
- init_response_obj={},
- start_time=start_time,
- end_time=end_time,
- logging_obj=self,
- status="failure",
- error_str=str(exception),
- original_exception=exception,
- standard_built_in_tools_params=self.standard_built_in_tools_params,
+ self.model_call_details["standard_logging_object"] = (
+ get_standard_logging_object_payload(
+ kwargs=self.model_call_details,
+ init_response_obj={},
+ start_time=start_time,
+ end_time=end_time,
+ logging_obj=self,
+ status="failure",
+ error_str=str(exception),
+ original_exception=exception,
+ standard_built_in_tools_params=self.standard_built_in_tools_params,
+ )
)
return start_time, end_time
@@ -2645,7 +2687,15 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915
"""
try:
custom_logger_init_args = custom_logger_init_args or {}
- if logging_integration == "lago":
+ if logging_integration == "agentops": # Add AgentOps initialization
+ for callback in _in_memory_loggers:
+ if isinstance(callback, AgentOps):
+ return callback # type: ignore
+
+ agentops_logger = AgentOps()
+ _in_memory_loggers.append(agentops_logger)
+ return agentops_logger # type: ignore
+ elif logging_integration == "lago":
for callback in _in_memory_loggers:
if isinstance(callback, LagoLogger):
return callback # type: ignore
@@ -2753,9 +2803,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915
endpoint=arize_config.endpoint,
)
- os.environ[
- "OTEL_EXPORTER_OTLP_TRACES_HEADERS"
- ] = f"space_key={arize_config.space_key},api_key={arize_config.api_key}"
+ os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = (
+ f"space_key={arize_config.space_key},api_key={arize_config.api_key}"
+ )
for callback in _in_memory_loggers:
if (
isinstance(callback, ArizeLogger)
@@ -2779,9 +2829,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915
# auth can be disabled on local deployments of arize phoenix
if arize_phoenix_config.otlp_auth_headers is not None:
- os.environ[
- "OTEL_EXPORTER_OTLP_TRACES_HEADERS"
- ] = arize_phoenix_config.otlp_auth_headers
+ os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = (
+ arize_phoenix_config.otlp_auth_headers
+ )
for callback in _in_memory_loggers:
if (
@@ -2872,9 +2922,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915
exporter="otlp_http",
endpoint="https://langtrace.ai/api/trace",
)
- os.environ[
- "OTEL_EXPORTER_OTLP_TRACES_HEADERS"
- ] = f"api_key={os.getenv('LANGTRACE_API_KEY')}"
+ os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = (
+ f"api_key={os.getenv('LANGTRACE_API_KEY')}"
+ )
for callback in _in_memory_loggers:
if (
isinstance(callback, OpenTelemetry)
@@ -2908,6 +2958,13 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915
pagerduty_logger = PagerDutyAlerting(**custom_logger_init_args)
_in_memory_loggers.append(pagerduty_logger)
return pagerduty_logger # type: ignore
+ elif logging_integration == "anthropic_cache_control_hook":
+ for callback in _in_memory_loggers:
+ if isinstance(callback, AnthropicCacheControlHook):
+ return callback
+ anthropic_cache_control_hook = AnthropicCacheControlHook()
+ _in_memory_loggers.append(anthropic_cache_control_hook)
+ return anthropic_cache_control_hook # type: ignore
elif logging_integration == "gcs_pubsub":
for callback in _in_memory_loggers:
if isinstance(callback, GcsPubSubLogger):
@@ -3046,6 +3103,10 @@ def get_custom_logger_compatible_class( # noqa: PLR0915
for callback in _in_memory_loggers:
if isinstance(callback, PagerDutyAlerting):
return callback
+ elif logging_integration == "anthropic_cache_control_hook":
+ for callback in _in_memory_loggers:
+ if isinstance(callback, AnthropicCacheControlHook):
+ return callback
elif logging_integration == "gcs_pubsub":
for callback in _in_memory_loggers:
if isinstance(callback, GcsPubSubLogger):
@@ -3369,10 +3430,10 @@ class StandardLoggingPayloadSetup:
for key in StandardLoggingHiddenParams.__annotations__.keys():
if key in hidden_params:
if key == "additional_headers":
- clean_hidden_params[
- "additional_headers"
- ] = StandardLoggingPayloadSetup.get_additional_headers(
- hidden_params[key]
+ clean_hidden_params["additional_headers"] = (
+ StandardLoggingPayloadSetup.get_additional_headers(
+ hidden_params[key]
+ )
)
else:
clean_hidden_params[key] = hidden_params[key] # type: ignore
@@ -3651,7 +3712,7 @@ def emit_standard_logging_payload(payload: StandardLoggingPayload):
def get_standard_logging_metadata(
- metadata: Optional[Dict[str, Any]]
+ metadata: Optional[Dict[str, Any]],
) -> StandardLoggingMetadata:
"""
Clean and filter the metadata dictionary to include only the specified keys in StandardLoggingMetadata.
@@ -3715,9 +3776,9 @@ def scrub_sensitive_keys_in_metadata(litellm_params: Optional[dict]):
):
for k, v in metadata["user_api_key_metadata"].items():
if k == "logging": # prevent logging user logging keys
- cleaned_user_api_key_metadata[
- k
- ] = "scrubbed_by_litellm_for_sensitive_keys"
+ cleaned_user_api_key_metadata[k] = (
+ "scrubbed_by_litellm_for_sensitive_keys"
+ )
else:
cleaned_user_api_key_metadata[k] = v
diff --git a/litellm/litellm_core_utils/llm_cost_calc/utils.py b/litellm/litellm_core_utils/llm_cost_calc/utils.py
index ae5eb286e4..48809fe856 100644
--- a/litellm/litellm_core_utils/llm_cost_calc/utils.py
+++ b/litellm/litellm_core_utils/llm_cost_calc/utils.py
@@ -265,8 +265,10 @@ def generic_cost_per_token(
)
## CALCULATE OUTPUT COST
- text_tokens = usage.completion_tokens
+ text_tokens = 0
audio_tokens = 0
+ reasoning_tokens = 0
+ is_text_tokens_total = False
if usage.completion_tokens_details is not None:
audio_tokens = (
cast(
@@ -280,9 +282,20 @@ def generic_cost_per_token(
Optional[int],
getattr(usage.completion_tokens_details, "text_tokens", None),
)
- or usage.completion_tokens # default to completion tokens, if this field is not set
+ or 0 # default to completion tokens, if this field is not set
+ )
+ reasoning_tokens = (
+ cast(
+ Optional[int],
+ getattr(usage.completion_tokens_details, "reasoning_tokens", 0),
+ )
+ or 0
)
+ if text_tokens == 0:
+ text_tokens = usage.completion_tokens
+ if text_tokens == usage.completion_tokens:
+ is_text_tokens_total = True
## TEXT COST
completion_cost = float(text_tokens) * completion_base_cost
@@ -290,12 +303,26 @@ def generic_cost_per_token(
"output_cost_per_audio_token"
)
+ _output_cost_per_reasoning_token: Optional[float] = model_info.get(
+ "output_cost_per_reasoning_token"
+ )
+
## AUDIO COST
- if (
- _output_cost_per_audio_token is not None
- and audio_tokens is not None
- and audio_tokens > 0
- ):
+ if not is_text_tokens_total and audio_tokens is not None and audio_tokens > 0:
+ _output_cost_per_audio_token = (
+ _output_cost_per_audio_token
+ if _output_cost_per_audio_token is not None
+ else completion_base_cost
+ )
completion_cost += float(audio_tokens) * _output_cost_per_audio_token
+ ## REASONING COST
+ if not is_text_tokens_total and reasoning_tokens and reasoning_tokens > 0:
+ _output_cost_per_reasoning_token = (
+ _output_cost_per_reasoning_token
+ if _output_cost_per_reasoning_token is not None
+ else completion_base_cost
+ )
+ completion_cost += float(reasoning_tokens) * _output_cost_per_reasoning_token
+
return prompt_cost, completion_cost
diff --git a/litellm/litellm_core_utils/llm_response_utils/convert_dict_to_response.py b/litellm/litellm_core_utils/llm_response_utils/convert_dict_to_response.py
index a0a99f580b..5a8319a747 100644
--- a/litellm/litellm_core_utils/llm_response_utils/convert_dict_to_response.py
+++ b/litellm/litellm_core_utils/llm_response_utils/convert_dict_to_response.py
@@ -14,6 +14,7 @@ from litellm.types.llms.openai import ChatCompletionThinkingBlock
from litellm.types.utils import (
ChatCompletionDeltaToolCall,
ChatCompletionMessageToolCall,
+ ChatCompletionRedactedThinkingBlock,
Choices,
Delta,
EmbeddingResponse,
@@ -486,7 +487,14 @@ def convert_to_model_response_object( # noqa: PLR0915
)
# Handle thinking models that display `thinking_blocks` within `content`
- thinking_blocks: Optional[List[ChatCompletionThinkingBlock]] = None
+ thinking_blocks: Optional[
+ List[
+ Union[
+ ChatCompletionThinkingBlock,
+ ChatCompletionRedactedThinkingBlock,
+ ]
+ ]
+ ] = None
if "thinking_blocks" in choice["message"]:
thinking_blocks = choice["message"]["thinking_blocks"]
provider_specific_fields["thinking_blocks"] = thinking_blocks
diff --git a/litellm/litellm_core_utils/model_param_helper.py b/litellm/litellm_core_utils/model_param_helper.py
index c96b4a3f5b..91f2f1341c 100644
--- a/litellm/litellm_core_utils/model_param_helper.py
+++ b/litellm/litellm_core_utils/model_param_helper.py
@@ -75,6 +75,10 @@ class ModelParamHelper:
combined_kwargs = combined_kwargs.difference(exclude_kwargs)
return combined_kwargs
+ @staticmethod
+ def get_litellm_provider_specific_params_for_chat_params() -> Set[str]:
+ return set(["thinking"])
+
@staticmethod
def _get_litellm_supported_chat_completion_kwargs() -> Set[str]:
"""
@@ -82,11 +86,18 @@ class ModelParamHelper:
This follows the OpenAI API Spec
"""
- all_chat_completion_kwargs = set(
+ non_streaming_params: Set[str] = set(
getattr(CompletionCreateParamsNonStreaming, "__annotations__", {}).keys()
- ).union(
- set(getattr(CompletionCreateParamsStreaming, "__annotations__", {}).keys())
)
+ streaming_params: Set[str] = set(
+ getattr(CompletionCreateParamsStreaming, "__annotations__", {}).keys()
+ )
+ litellm_provider_specific_params: Set[str] = (
+ ModelParamHelper.get_litellm_provider_specific_params_for_chat_params()
+ )
+ all_chat_completion_kwargs: Set[str] = non_streaming_params.union(
+ streaming_params
+ ).union(litellm_provider_specific_params)
return all_chat_completion_kwargs
@staticmethod
diff --git a/litellm/litellm_core_utils/prompt_templates/common_utils.py b/litellm/litellm_core_utils/prompt_templates/common_utils.py
index 2fe99fb27b..40cd4e286b 100644
--- a/litellm/litellm_core_utils/prompt_templates/common_utils.py
+++ b/litellm/litellm_core_utils/prompt_templates/common_utils.py
@@ -471,3 +471,59 @@ def unpack_defs(schema, defs):
unpack_defs(ref, defs)
value["items"] = ref
continue
+
+
+def _get_image_mime_type_from_url(url: str) -> Optional[str]:
+ """
+ Get mime type for common image URLs
+ See gemini mime types: https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/image-understanding#image-requirements
+
+ Supported by Gemini:
+ application/pdf
+ audio/mpeg
+ audio/mp3
+ audio/wav
+ image/png
+ image/jpeg
+ image/webp
+ text/plain
+ video/mov
+ video/mpeg
+ video/mp4
+ video/mpg
+ video/avi
+ video/wmv
+ video/mpegps
+ video/flv
+ """
+ url = url.lower()
+
+ # Map file extensions to mime types
+ mime_types = {
+ # Images
+ (".jpg", ".jpeg"): "image/jpeg",
+ (".png",): "image/png",
+ (".webp",): "image/webp",
+ # Videos
+ (".mp4",): "video/mp4",
+ (".mov",): "video/mov",
+ (".mpeg", ".mpg"): "video/mpeg",
+ (".avi",): "video/avi",
+ (".wmv",): "video/wmv",
+ (".mpegps",): "video/mpegps",
+ (".flv",): "video/flv",
+ # Audio
+ (".mp3",): "audio/mp3",
+ (".wav",): "audio/wav",
+ (".mpeg",): "audio/mpeg",
+ # Documents
+ (".pdf",): "application/pdf",
+ (".txt",): "text/plain",
+ }
+
+ # Check each extension group against the URL
+ for extensions, mime_type in mime_types.items():
+ if any(url.endswith(ext) for ext in extensions):
+ return mime_type
+
+ return None
diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py
index aa5dc0d49a..5b11b224bb 100644
--- a/litellm/litellm_core_utils/prompt_templates/factory.py
+++ b/litellm/litellm_core_utils/prompt_templates/factory.py
@@ -2258,6 +2258,14 @@ def _parse_content_type(content_type: str) -> str:
return m.get_content_type()
+def _parse_mime_type(base64_data: str) -> Optional[str]:
+ mime_type_match = re.match(r"data:(.*?);base64", base64_data)
+ if mime_type_match:
+ return mime_type_match.group(1)
+ else:
+ return None
+
+
class BedrockImageProcessor:
"""Handles both sync and async image processing for Bedrock conversations."""
diff --git a/litellm/litellm_core_utils/streaming_chunk_builder_utils.py b/litellm/litellm_core_utils/streaming_chunk_builder_utils.py
index abe5966d31..198b71cad3 100644
--- a/litellm/litellm_core_utils/streaming_chunk_builder_utils.py
+++ b/litellm/litellm_core_utils/streaming_chunk_builder_utils.py
@@ -106,74 +106,63 @@ class ChunkProcessor:
def get_combined_tool_content(
self, tool_call_chunks: List[Dict[str, Any]]
) -> List[ChatCompletionMessageToolCall]:
- argument_list: List[str] = []
- delta = tool_call_chunks[0]["choices"][0]["delta"]
- id = None
- name = None
- type = None
tool_calls_list: List[ChatCompletionMessageToolCall] = []
- prev_index = None
- prev_name = None
- prev_id = None
- curr_id = None
- curr_index = 0
+ tool_call_map: Dict[
+ int, Dict[str, Any]
+ ] = {} # Map to store tool calls by index
+
for chunk in tool_call_chunks:
choices = chunk["choices"]
for choice in choices:
delta = choice.get("delta", {})
- tool_calls = delta.get("tool_calls", "")
- # Check if a tool call is present
- if tool_calls and tool_calls[0].function is not None:
- if tool_calls[0].id:
- id = tool_calls[0].id
- curr_id = id
- if prev_id is None:
- prev_id = curr_id
- if tool_calls[0].index:
- curr_index = tool_calls[0].index
- if tool_calls[0].function.arguments:
- # Now, tool_calls is expected to be a dictionary
- arguments = tool_calls[0].function.arguments
- argument_list.append(arguments)
- if tool_calls[0].function.name:
- name = tool_calls[0].function.name
- if tool_calls[0].type:
- type = tool_calls[0].type
- if prev_index is None:
- prev_index = curr_index
- if prev_name is None:
- prev_name = name
- if curr_index != prev_index: # new tool call
- combined_arguments = "".join(argument_list)
+ tool_calls = delta.get("tool_calls", [])
+
+ for tool_call in tool_calls:
+ if not tool_call or not hasattr(tool_call, "function"):
+ continue
+
+ index = getattr(tool_call, "index", 0)
+ if index not in tool_call_map:
+ tool_call_map[index] = {
+ "id": None,
+ "name": None,
+ "type": None,
+ "arguments": [],
+ }
+
+ if hasattr(tool_call, "id") and tool_call.id:
+ tool_call_map[index]["id"] = tool_call.id
+ if hasattr(tool_call, "type") and tool_call.type:
+ tool_call_map[index]["type"] = tool_call.type
+ if hasattr(tool_call, "function"):
+ if (
+ hasattr(tool_call.function, "name")
+ and tool_call.function.name
+ ):
+ tool_call_map[index]["name"] = tool_call.function.name
+ if (
+ hasattr(tool_call.function, "arguments")
+ and tool_call.function.arguments
+ ):
+ tool_call_map[index]["arguments"].append(
+ tool_call.function.arguments
+ )
+
+ # Convert the map to a list of tool calls
+ for index in sorted(tool_call_map.keys()):
+ tool_call_data = tool_call_map[index]
+ if tool_call_data["id"] and tool_call_data["name"]:
+ combined_arguments = "".join(tool_call_data["arguments"]) or "{}"
tool_calls_list.append(
ChatCompletionMessageToolCall(
- id=prev_id,
+ id=tool_call_data["id"],
function=Function(
arguments=combined_arguments,
- name=prev_name,
+ name=tool_call_data["name"],
),
- type=type,
+ type=tool_call_data["type"] or "function",
)
)
- argument_list = [] # reset
- prev_index = curr_index
- prev_id = curr_id
- prev_name = name
-
- combined_arguments = (
- "".join(argument_list) or "{}"
- ) # base case, return empty dict
-
- tool_calls_list.append(
- ChatCompletionMessageToolCall(
- id=id,
- type="function",
- function=Function(
- arguments=combined_arguments,
- name=name,
- ),
- )
- )
return tool_calls_list
diff --git a/litellm/llms/anthropic/chat/handler.py b/litellm/llms/anthropic/chat/handler.py
index ebb8650044..397aa1e047 100644
--- a/litellm/llms/anthropic/chat/handler.py
+++ b/litellm/llms/anthropic/chat/handler.py
@@ -29,6 +29,7 @@ from litellm.types.llms.anthropic import (
UsageDelta,
)
from litellm.types.llms.openai import (
+ ChatCompletionRedactedThinkingBlock,
ChatCompletionThinkingBlock,
ChatCompletionToolCallChunk,
)
@@ -501,18 +502,19 @@ class ModelResponseIterator:
) -> Tuple[
str,
Optional[ChatCompletionToolCallChunk],
- List[ChatCompletionThinkingBlock],
+ List[Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]],
Dict[str, Any],
]:
"""
Helper function to handle the content block delta
"""
-
text = ""
tool_use: Optional[ChatCompletionToolCallChunk] = None
provider_specific_fields = {}
content_block = ContentBlockDelta(**chunk) # type: ignore
- thinking_blocks: List[ChatCompletionThinkingBlock] = []
+ thinking_blocks: List[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ] = []
self.content_blocks.append(content_block)
if "text" in content_block["delta"]:
@@ -541,20 +543,25 @@ class ModelResponseIterator:
)
]
provider_specific_fields["thinking_blocks"] = thinking_blocks
+
return text, tool_use, thinking_blocks, provider_specific_fields
def _handle_reasoning_content(
- self, thinking_blocks: List[ChatCompletionThinkingBlock]
+ self,
+ thinking_blocks: List[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ],
) -> Optional[str]:
"""
Handle the reasoning content
"""
reasoning_content = None
for block in thinking_blocks:
+ thinking_content = cast(Optional[str], block.get("thinking"))
if reasoning_content is None:
reasoning_content = ""
- if "thinking" in block:
- reasoning_content += block["thinking"]
+ if thinking_content is not None:
+ reasoning_content += thinking_content
return reasoning_content
def chunk_parser(self, chunk: dict) -> ModelResponseStream:
@@ -567,7 +574,13 @@ class ModelResponseIterator:
usage: Optional[Usage] = None
provider_specific_fields: Dict[str, Any] = {}
reasoning_content: Optional[str] = None
- thinking_blocks: Optional[List[ChatCompletionThinkingBlock]] = None
+ thinking_blocks: Optional[
+ List[
+ Union[
+ ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock
+ ]
+ ]
+ ] = None
index = int(chunk.get("index", 0))
if type_chunk == "content_block_delta":
@@ -605,6 +618,15 @@ class ModelResponseIterator:
},
"index": self.tool_index,
}
+ elif (
+ content_block_start["content_block"]["type"] == "redacted_thinking"
+ ):
+ thinking_blocks = [
+ ChatCompletionRedactedThinkingBlock(
+ type="redacted_thinking",
+ data=content_block_start["content_block"]["data"],
+ )
+ ]
elif type_chunk == "content_block_stop":
ContentBlockStop(**chunk) # type: ignore
# check if tool call content block
diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py
index 96da34a855..06e0553f8d 100644
--- a/litellm/llms/anthropic/chat/transformation.py
+++ b/litellm/llms/anthropic/chat/transformation.py
@@ -7,6 +7,9 @@ import httpx
import litellm
from litellm.constants import (
DEFAULT_ANTHROPIC_CHAT_MAX_TOKENS,
+ DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
+ DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
+ DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
RESPONSE_FORMAT_TOOL_NAME,
)
from litellm.litellm_core_utils.core_helpers import map_finish_reason
@@ -27,6 +30,7 @@ from litellm.types.llms.openai import (
REASONING_EFFORT,
AllMessageValues,
ChatCompletionCachedContent,
+ ChatCompletionRedactedThinkingBlock,
ChatCompletionSystemMessage,
ChatCompletionThinkingBlock,
ChatCompletionToolCallChunk,
@@ -44,7 +48,7 @@ from litellm.utils import (
token_counter,
)
-from ..common_utils import AnthropicError, process_anthropic_headers
+from ..common_utils import AnthropicError, AnthropicModelInfo, process_anthropic_headers
if TYPE_CHECKING:
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
@@ -54,7 +58,7 @@ else:
LoggingClass = Any
-class AnthropicConfig(BaseConfig):
+class AnthropicConfig(AnthropicModelInfo, BaseConfig):
"""
Reference: https://docs.anthropic.com/claude/reference/messages_post
@@ -127,41 +131,6 @@ class AnthropicConfig(BaseConfig):
"anthropic-beta": "prompt-caching-2024-07-31",
}
- def get_anthropic_headers(
- self,
- api_key: str,
- anthropic_version: Optional[str] = None,
- computer_tool_used: bool = False,
- prompt_caching_set: bool = False,
- pdf_used: bool = False,
- is_vertex_request: bool = False,
- user_anthropic_beta_headers: Optional[List[str]] = None,
- ) -> dict:
- betas = set()
- if prompt_caching_set:
- betas.add("prompt-caching-2024-07-31")
- if computer_tool_used:
- betas.add("computer-use-2024-10-22")
- if pdf_used:
- betas.add("pdfs-2024-09-25")
- headers = {
- "anthropic-version": anthropic_version or "2023-06-01",
- "x-api-key": api_key,
- "accept": "application/json",
- "content-type": "application/json",
- }
-
- if user_anthropic_beta_headers is not None:
- betas.update(user_anthropic_beta_headers)
-
- # Don't send any beta headers to Vertex, Vertex has failed requests when they are sent
- if is_vertex_request is True:
- pass
- elif len(betas) > 0:
- headers["anthropic-beta"] = ",".join(betas)
-
- return headers
-
def _map_tool_choice(
self, tool_choice: Optional[str], parallel_tool_use: Optional[bool]
) -> Optional[AnthropicMessagesToolChoice]:
@@ -311,11 +280,20 @@ class AnthropicConfig(BaseConfig):
if reasoning_effort is None:
return None
elif reasoning_effort == "low":
- return AnthropicThinkingParam(type="enabled", budget_tokens=1024)
+ return AnthropicThinkingParam(
+ type="enabled",
+ budget_tokens=DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
+ )
elif reasoning_effort == "medium":
- return AnthropicThinkingParam(type="enabled", budget_tokens=2048)
+ return AnthropicThinkingParam(
+ type="enabled",
+ budget_tokens=DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
+ )
elif reasoning_effort == "high":
- return AnthropicThinkingParam(type="enabled", budget_tokens=4096)
+ return AnthropicThinkingParam(
+ type="enabled",
+ budget_tokens=DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
+ )
else:
raise ValueError(f"Unmapped reasoning effort: {reasoning_effort}")
@@ -446,49 +424,6 @@ class AnthropicConfig(BaseConfig):
)
return _tool
- def is_cache_control_set(self, messages: List[AllMessageValues]) -> bool:
- """
- Return if {"cache_control": ..} in message content block
-
- Used to check if anthropic prompt caching headers need to be set.
- """
- for message in messages:
- if message.get("cache_control", None) is not None:
- return True
- _message_content = message.get("content")
- if _message_content is not None and isinstance(_message_content, list):
- for content in _message_content:
- if "cache_control" in content:
- return True
-
- return False
-
- def is_computer_tool_used(
- self, tools: Optional[List[AllAnthropicToolsValues]]
- ) -> bool:
- if tools is None:
- return False
- for tool in tools:
- if "type" in tool and tool["type"].startswith("computer_"):
- return True
- return False
-
- def is_pdf_used(self, messages: List[AllMessageValues]) -> bool:
- """
- Set to true if media passed into messages.
-
- """
- for message in messages:
- if (
- "content" in message
- and message["content"] is not None
- and isinstance(message["content"], list)
- ):
- for content in message["content"]:
- if "type" in content and content["type"] != "text":
- return True
- return False
-
def translate_system_message(
self, messages: List[AllMessageValues]
) -> List[AnthropicSystemMessageContent]:
@@ -641,13 +576,21 @@ class AnthropicConfig(BaseConfig):
) -> Tuple[
str,
Optional[List[Any]],
- Optional[List[ChatCompletionThinkingBlock]],
+ Optional[
+ List[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ]
+ ],
Optional[str],
List[ChatCompletionToolCallChunk],
]:
text_content = ""
citations: Optional[List[Any]] = None
- thinking_blocks: Optional[List[ChatCompletionThinkingBlock]] = None
+ thinking_blocks: Optional[
+ List[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ]
+ ] = None
reasoning_content: Optional[str] = None
tool_calls: List[ChatCompletionToolCallChunk] = []
for idx, content in enumerate(completion_response["content"]):
@@ -666,20 +609,30 @@ class AnthropicConfig(BaseConfig):
index=idx,
)
)
- ## CITATIONS
- if content.get("citations", None) is not None:
- if citations is None:
- citations = []
- citations.append(content["citations"])
- if content.get("thinking", None) is not None:
+
+ elif content.get("thinking", None) is not None:
if thinking_blocks is None:
thinking_blocks = []
thinking_blocks.append(cast(ChatCompletionThinkingBlock, content))
+ elif content["type"] == "redacted_thinking":
+ if thinking_blocks is None:
+ thinking_blocks = []
+ thinking_blocks.append(
+ cast(ChatCompletionRedactedThinkingBlock, content)
+ )
+
+ ## CITATIONS
+ if content.get("citations") is not None:
+ if citations is None:
+ citations = []
+ citations.append(content["citations"])
if thinking_blocks is not None:
reasoning_content = ""
for block in thinking_blocks:
- if "thinking" in block:
- reasoning_content += block["thinking"]
+ thinking_content = cast(Optional[str], block.get("thinking"))
+ if thinking_content is not None:
+ reasoning_content += thinking_content
+
return text_content, citations, thinking_blocks, reasoning_content, tool_calls
def calculate_usage(
@@ -769,7 +722,13 @@ class AnthropicConfig(BaseConfig):
else:
text_content = ""
citations: Optional[List[Any]] = None
- thinking_blocks: Optional[List[ChatCompletionThinkingBlock]] = None
+ thinking_blocks: Optional[
+ List[
+ Union[
+ ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock
+ ]
+ ]
+ ] = None
reasoning_content: Optional[str] = None
tool_calls: List[ChatCompletionToolCallChunk] = []
@@ -862,47 +821,3 @@ class AnthropicConfig(BaseConfig):
message=error_message,
headers=cast(httpx.Headers, headers),
)
-
- def _get_user_anthropic_beta_headers(
- self, anthropic_beta_header: Optional[str]
- ) -> Optional[List[str]]:
- if anthropic_beta_header is None:
- return None
- return anthropic_beta_header.split(",")
-
- def validate_environment(
- self,
- headers: dict,
- model: str,
- messages: List[AllMessageValues],
- optional_params: dict,
- litellm_params: dict,
- api_key: Optional[str] = None,
- api_base: Optional[str] = None,
- ) -> Dict:
- if api_key is None:
- raise litellm.AuthenticationError(
- message="Missing Anthropic API Key - A call is being made to anthropic but no key is set either in the environment variables or via params. Please set `ANTHROPIC_API_KEY` in your environment vars",
- llm_provider="anthropic",
- model=model,
- )
-
- tools = optional_params.get("tools")
- prompt_caching_set = self.is_cache_control_set(messages=messages)
- computer_tool_used = self.is_computer_tool_used(tools=tools)
- pdf_used = self.is_pdf_used(messages=messages)
- user_anthropic_beta_headers = self._get_user_anthropic_beta_headers(
- anthropic_beta_header=headers.get("anthropic-beta")
- )
- anthropic_headers = self.get_anthropic_headers(
- computer_tool_used=computer_tool_used,
- prompt_caching_set=prompt_caching_set,
- pdf_used=pdf_used,
- api_key=api_key,
- is_vertex_request=optional_params.get("is_vertex_request", False),
- user_anthropic_beta_headers=user_anthropic_beta_headers,
- )
-
- headers = {**headers, **anthropic_headers}
-
- return headers
diff --git a/litellm/llms/anthropic/common_utils.py b/litellm/llms/anthropic/common_utils.py
index 9eae6734ff..bacd2a54d0 100644
--- a/litellm/llms/anthropic/common_utils.py
+++ b/litellm/llms/anthropic/common_utils.py
@@ -2,7 +2,7 @@
This file contains common utils for anthropic calls.
"""
-from typing import List, Optional, Union
+from typing import Dict, List, Optional, Union
import httpx
@@ -10,6 +10,8 @@ import litellm
from litellm.llms.base_llm.base_utils import BaseLLMModelInfo
from litellm.llms.base_llm.chat.transformation import BaseLLMException
from litellm.secret_managers.main import get_secret_str
+from litellm.types.llms.anthropic import AllAnthropicToolsValues
+from litellm.types.llms.openai import AllMessageValues
class AnthropicError(BaseLLMException):
@@ -23,6 +25,128 @@ class AnthropicError(BaseLLMException):
class AnthropicModelInfo(BaseLLMModelInfo):
+ def is_cache_control_set(self, messages: List[AllMessageValues]) -> bool:
+ """
+ Return if {"cache_control": ..} in message content block
+
+ Used to check if anthropic prompt caching headers need to be set.
+ """
+ for message in messages:
+ if message.get("cache_control", None) is not None:
+ return True
+ _message_content = message.get("content")
+ if _message_content is not None and isinstance(_message_content, list):
+ for content in _message_content:
+ if "cache_control" in content:
+ return True
+
+ return False
+
+ def is_computer_tool_used(
+ self, tools: Optional[List[AllAnthropicToolsValues]]
+ ) -> bool:
+ if tools is None:
+ return False
+ for tool in tools:
+ if "type" in tool and tool["type"].startswith("computer_"):
+ return True
+ return False
+
+ def is_pdf_used(self, messages: List[AllMessageValues]) -> bool:
+ """
+ Set to true if media passed into messages.
+
+ """
+ for message in messages:
+ if (
+ "content" in message
+ and message["content"] is not None
+ and isinstance(message["content"], list)
+ ):
+ for content in message["content"]:
+ if "type" in content and content["type"] != "text":
+ return True
+ return False
+
+ def _get_user_anthropic_beta_headers(
+ self, anthropic_beta_header: Optional[str]
+ ) -> Optional[List[str]]:
+ if anthropic_beta_header is None:
+ return None
+ return anthropic_beta_header.split(",")
+
+ def get_anthropic_headers(
+ self,
+ api_key: str,
+ anthropic_version: Optional[str] = None,
+ computer_tool_used: bool = False,
+ prompt_caching_set: bool = False,
+ pdf_used: bool = False,
+ is_vertex_request: bool = False,
+ user_anthropic_beta_headers: Optional[List[str]] = None,
+ ) -> dict:
+ betas = set()
+ if prompt_caching_set:
+ betas.add("prompt-caching-2024-07-31")
+ if computer_tool_used:
+ betas.add("computer-use-2024-10-22")
+ if pdf_used:
+ betas.add("pdfs-2024-09-25")
+ headers = {
+ "anthropic-version": anthropic_version or "2023-06-01",
+ "x-api-key": api_key,
+ "accept": "application/json",
+ "content-type": "application/json",
+ }
+
+ if user_anthropic_beta_headers is not None:
+ betas.update(user_anthropic_beta_headers)
+
+ # Don't send any beta headers to Vertex, Vertex has failed requests when they are sent
+ if is_vertex_request is True:
+ pass
+ elif len(betas) > 0:
+ headers["anthropic-beta"] = ",".join(betas)
+
+ return headers
+
+ def validate_environment(
+ self,
+ headers: dict,
+ model: str,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ api_key: Optional[str] = None,
+ api_base: Optional[str] = None,
+ ) -> Dict:
+ if api_key is None:
+ raise litellm.AuthenticationError(
+ message="Missing Anthropic API Key - A call is being made to anthropic but no key is set either in the environment variables or via params. Please set `ANTHROPIC_API_KEY` in your environment vars",
+ llm_provider="anthropic",
+ model=model,
+ )
+
+ tools = optional_params.get("tools")
+ prompt_caching_set = self.is_cache_control_set(messages=messages)
+ computer_tool_used = self.is_computer_tool_used(tools=tools)
+ pdf_used = self.is_pdf_used(messages=messages)
+ user_anthropic_beta_headers = self._get_user_anthropic_beta_headers(
+ anthropic_beta_header=headers.get("anthropic-beta")
+ )
+ anthropic_headers = self.get_anthropic_headers(
+ computer_tool_used=computer_tool_used,
+ prompt_caching_set=prompt_caching_set,
+ pdf_used=pdf_used,
+ api_key=api_key,
+ is_vertex_request=optional_params.get("is_vertex_request", False),
+ user_anthropic_beta_headers=user_anthropic_beta_headers,
+ )
+
+ headers = {**headers, **anthropic_headers}
+
+ return headers
+
@staticmethod
def get_api_base(api_base: Optional[str] = None) -> Optional[str]:
return (
diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py
index a37d816770..ab335ca7c1 100644
--- a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py
+++ b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py
@@ -1,6 +1,6 @@
"""
- call /messages on Anthropic API
-- Make streaming + non-streaming request - just pass it through direct to Anthropic. No need to do anything special here
+- Make streaming + non-streaming request - just pass it through direct to Anthropic. No need to do anything special here
- Ensure requests are logged in the DB - stream + non-stream
"""
@@ -43,7 +43,9 @@ class AnthropicMessagesHandler:
from litellm.proxy.pass_through_endpoints.success_handler import (
PassThroughEndpointLogging,
)
- from litellm.proxy.pass_through_endpoints.types import EndpointType
+ from litellm.types.passthrough_endpoints.pass_through_endpoints import (
+ EndpointType,
+ )
# Create success handler object
passthrough_success_handler_obj = PassThroughEndpointLogging()
@@ -98,11 +100,11 @@ async def anthropic_messages(
api_base=optional_params.api_base,
api_key=optional_params.api_key,
)
- anthropic_messages_provider_config: Optional[
- BaseAnthropicMessagesConfig
- ] = ProviderConfigManager.get_provider_anthropic_messages_config(
- model=model,
- provider=litellm.LlmProviders(_custom_llm_provider),
+ anthropic_messages_provider_config: Optional[BaseAnthropicMessagesConfig] = (
+ ProviderConfigManager.get_provider_anthropic_messages_config(
+ model=model,
+ provider=litellm.LlmProviders(_custom_llm_provider),
+ )
)
if anthropic_messages_provider_config is None:
raise ValueError(
diff --git a/litellm/llms/azure/assistants.py b/litellm/llms/azure/assistants.py
index 2e8c78b259..271cd698e7 100644
--- a/litellm/llms/azure/assistants.py
+++ b/litellm/llms/azure/assistants.py
@@ -288,6 +288,7 @@ class AzureAssistantsAPI(BaseAzureLLM):
timeout=timeout,
max_retries=max_retries,
client=client,
+ litellm_params=litellm_params,
)
thread_message: OpenAIMessage = openai_client.beta.threads.messages.create( # type: ignore
diff --git a/litellm/llms/azure/chat/gpt_transformation.py b/litellm/llms/azure/chat/gpt_transformation.py
index ea61ef2c9a..238566faf7 100644
--- a/litellm/llms/azure/chat/gpt_transformation.py
+++ b/litellm/llms/azure/chat/gpt_transformation.py
@@ -125,14 +125,22 @@ class AzureOpenAIConfig(BaseConfig):
) -> bool:
"""
- check if api_version is supported for response_format
+ - returns True if the API version is equal to or newer than the supported version
"""
+ api_year = int(api_version_year)
+ api_month = int(api_version_month)
+ supported_year = int(API_VERSION_YEAR_SUPPORTED_RESPONSE_FORMAT)
+ supported_month = int(API_VERSION_MONTH_SUPPORTED_RESPONSE_FORMAT)
- is_supported = (
- int(api_version_year) <= API_VERSION_YEAR_SUPPORTED_RESPONSE_FORMAT
- and int(api_version_month) >= API_VERSION_MONTH_SUPPORTED_RESPONSE_FORMAT
- )
-
- return is_supported
+ # If the year is greater than supported year, it's definitely supported
+ if api_year > supported_year:
+ return True
+ # If the year is less than supported year, it's not supported
+ elif api_year < supported_year:
+ return False
+ # If same year, check if month is >= supported month
+ else:
+ return api_month >= supported_month
def map_openai_params(
self,
@@ -202,6 +210,7 @@ class AzureOpenAIConfig(BaseConfig):
is_response_format_supported_api_version
and _is_response_format_supported_model
)
+
optional_params = self._add_response_format_to_tools(
optional_params=optional_params,
value=value,
diff --git a/litellm/llms/azure/chat/o_series_transformation.py b/litellm/llms/azure/chat/o_series_transformation.py
index 21aafce7fb..69fb941ca5 100644
--- a/litellm/llms/azure/chat/o_series_transformation.py
+++ b/litellm/llms/azure/chat/o_series_transformation.py
@@ -79,7 +79,7 @@ class AzureOpenAIO1Config(OpenAIOSeriesConfig):
return True
def is_o_series_model(self, model: str) -> bool:
- return "o1" in model or "o3" in model or "o_series/" in model
+ return "o1" in model or "o3" in model or "o4" in model or "o_series/" in model
def transform_request(
self,
diff --git a/litellm/llms/azure/common_utils.py b/litellm/llms/azure/common_utils.py
index 5d61557c21..012f47c851 100644
--- a/litellm/llms/azure/common_utils.py
+++ b/litellm/llms/azure/common_utils.py
@@ -61,7 +61,7 @@ def process_azure_headers(headers: Union[httpx.Headers, dict]) -> dict:
return {**llm_response_headers, **openai_headers}
-def get_azure_ad_token_from_entrata_id(
+def get_azure_ad_token_from_entra_id(
tenant_id: str,
client_id: str,
client_secret: str,
@@ -81,7 +81,7 @@ def get_azure_ad_token_from_entrata_id(
"""
from azure.identity import ClientSecretCredential, get_bearer_token_provider
- verbose_logger.debug("Getting Azure AD Token from Entrata ID")
+ verbose_logger.debug("Getting Azure AD Token from Entra ID")
if tenant_id.startswith("os.environ/"):
_tenant_id = get_secret_str(tenant_id)
@@ -309,21 +309,30 @@ class BaseAzureLLM(BaseOpenAILLM):
azure_ad_token_provider: Optional[Callable[[], str]] = None
# If we have api_key, then we have higher priority
azure_ad_token = litellm_params.get("azure_ad_token")
- tenant_id = litellm_params.get("tenant_id")
- client_id = litellm_params.get("client_id")
- client_secret = litellm_params.get("client_secret")
- azure_username = litellm_params.get("azure_username")
- azure_password = litellm_params.get("azure_password")
+ tenant_id = litellm_params.get("tenant_id", os.getenv("AZURE_TENANT_ID"))
+ client_id = litellm_params.get("client_id", os.getenv("AZURE_CLIENT_ID"))
+ client_secret = litellm_params.get(
+ "client_secret", os.getenv("AZURE_CLIENT_SECRET")
+ )
+ azure_username = litellm_params.get(
+ "azure_username", os.getenv("AZURE_USERNAME")
+ )
+ azure_password = litellm_params.get(
+ "azure_password", os.getenv("AZURE_PASSWORD")
+ )
max_retries = litellm_params.get("max_retries")
timeout = litellm_params.get("timeout")
if not api_key and tenant_id and client_id and client_secret:
- verbose_logger.debug("Using Azure AD Token Provider for Azure Auth")
- azure_ad_token_provider = get_azure_ad_token_from_entrata_id(
+ verbose_logger.debug(
+ "Using Azure AD Token Provider from Entra ID for Azure Auth"
+ )
+ azure_ad_token_provider = get_azure_ad_token_from_entra_id(
tenant_id=tenant_id,
client_id=client_id,
client_secret=client_secret,
)
if azure_username and azure_password and client_id:
+ verbose_logger.debug("Using Azure Username and Password for Azure Auth")
azure_ad_token_provider = get_azure_ad_token_from_username_password(
azure_username=azure_username,
azure_password=azure_password,
@@ -331,12 +340,16 @@ class BaseAzureLLM(BaseOpenAILLM):
)
if azure_ad_token is not None and azure_ad_token.startswith("oidc/"):
+ verbose_logger.debug("Using Azure OIDC Token for Azure Auth")
azure_ad_token = get_azure_ad_token_from_oidc(azure_ad_token)
elif (
not api_key
and azure_ad_token_provider is None
and litellm.enable_azure_ad_token_refresh is True
):
+ verbose_logger.debug(
+ "Using Azure AD token provider based on Service Principal with Secret workflow for Azure Auth"
+ )
try:
azure_ad_token_provider = get_azure_ad_token_provider()
except ValueError:
diff --git a/litellm/llms/azure/responses/transformation.py b/litellm/llms/azure/responses/transformation.py
new file mode 100644
index 0000000000..499d21cb0e
--- /dev/null
+++ b/litellm/llms/azure/responses/transformation.py
@@ -0,0 +1,138 @@
+from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, cast
+
+import httpx
+
+import litellm
+from litellm._logging import verbose_logger
+from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig
+from litellm.secret_managers.main import get_secret_str
+from litellm.types.llms.openai import *
+from litellm.types.responses.main import *
+from litellm.types.router import GenericLiteLLMParams
+from litellm.utils import _add_path_to_api_base
+
+if TYPE_CHECKING:
+ from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj
+
+ LiteLLMLoggingObj = _LiteLLMLoggingObj
+else:
+ LiteLLMLoggingObj = Any
+
+
+class AzureOpenAIResponsesAPIConfig(OpenAIResponsesAPIConfig):
+ def validate_environment(
+ self,
+ headers: dict,
+ model: str,
+ api_key: Optional[str] = None,
+ ) -> dict:
+ api_key = (
+ api_key
+ or litellm.api_key
+ or litellm.azure_key
+ or get_secret_str("AZURE_OPENAI_API_KEY")
+ or get_secret_str("AZURE_API_KEY")
+ )
+
+ headers.update(
+ {
+ "Authorization": f"Bearer {api_key}",
+ }
+ )
+ return headers
+
+ def get_complete_url(
+ self,
+ api_base: Optional[str],
+ litellm_params: dict,
+ ) -> str:
+ """
+ Constructs a complete URL for the API request.
+
+ Args:
+ - api_base: Base URL, e.g.,
+ "https://litellm8397336933.openai.azure.com"
+ OR
+ "https://litellm8397336933.openai.azure.com/openai/responses?api-version=2024-05-01-preview"
+ - model: Model name.
+ - optional_params: Additional query parameters, including "api_version".
+ - stream: If streaming is required (optional).
+
+ Returns:
+ - A complete URL string, e.g.,
+ "https://litellm8397336933.openai.azure.com/openai/responses?api-version=2024-05-01-preview"
+ """
+ api_base = api_base or litellm.api_base or get_secret_str("AZURE_API_BASE")
+ if api_base is None:
+ raise ValueError(
+ f"api_base is required for Azure AI Studio. Please set the api_base parameter. Passed `api_base={api_base}`"
+ )
+ original_url = httpx.URL(api_base)
+
+ # Extract api_version or use default
+ api_version = cast(Optional[str], litellm_params.get("api_version"))
+
+ # Create a new dictionary with existing params
+ query_params = dict(original_url.params)
+
+ # Add api_version if needed
+ if "api-version" not in query_params and api_version:
+ query_params["api-version"] = api_version
+
+ # Add the path to the base URL
+ if "/openai/responses" not in api_base:
+ new_url = _add_path_to_api_base(
+ api_base=api_base, ending_path="/openai/responses"
+ )
+ else:
+ new_url = api_base
+
+ # Use the new query_params dictionary
+ final_url = httpx.URL(new_url).copy_with(params=query_params)
+
+ return str(final_url)
+
+ #########################################################
+ ########## DELETE RESPONSE API TRANSFORMATION ##############
+ #########################################################
+ def transform_delete_response_api_request(
+ self,
+ response_id: str,
+ api_base: str,
+ litellm_params: GenericLiteLLMParams,
+ headers: dict,
+ ) -> Tuple[str, Dict]:
+ """
+ Transform the delete response API request into a URL and data
+
+ Azure OpenAI API expects the following request:
+ - DELETE /openai/responses/{response_id}?api-version=xxx
+
+ This function handles URLs with query parameters by inserting the response_id
+ at the correct location (before any query parameters).
+ """
+ from urllib.parse import urlparse, urlunparse
+
+ # Parse the URL to separate its components
+ parsed_url = urlparse(api_base)
+
+ # Insert the response_id at the end of the path component
+ # Remove trailing slash if present to avoid double slashes
+ path = parsed_url.path.rstrip("/")
+ new_path = f"{path}/{response_id}"
+
+ # Reconstruct the URL with all original components but with the modified path
+ delete_url = urlunparse(
+ (
+ parsed_url.scheme, # http, https
+ parsed_url.netloc, # domain name, port
+ new_path, # path with response_id added
+ parsed_url.params, # parameters
+ parsed_url.query, # query string
+ parsed_url.fragment, # fragment
+ )
+ )
+
+ data: Dict = {}
+ verbose_logger.debug(f"delete response url={delete_url}")
+ return delete_url, data
diff --git a/litellm/llms/azure_ai/chat/transformation.py b/litellm/llms/azure_ai/chat/transformation.py
index 839f875f75..1adc56804f 100644
--- a/litellm/llms/azure_ai/chat/transformation.py
+++ b/litellm/llms/azure_ai/chat/transformation.py
@@ -1,3 +1,4 @@
+import enum
from typing import Any, List, Optional, Tuple, cast
from urllib.parse import urlparse
@@ -19,6 +20,10 @@ from litellm.types.utils import ModelResponse, ProviderField
from litellm.utils import _add_path_to_api_base, supports_tool_choice
+class AzureFoundryErrorStrings(str, enum.Enum):
+ SET_EXTRA_PARAMETERS_TO_PASS_THROUGH = "Set extra-parameters to 'pass-through'"
+
+
class AzureAIStudioConfig(OpenAIConfig):
def get_supported_openai_params(self, model: str) -> List:
model_supports_tool_choice = True # azure ai supports this by default
@@ -240,12 +245,18 @@ class AzureAIStudioConfig(OpenAIConfig):
) -> bool:
should_drop_params = litellm_params.get("drop_params") or litellm.drop_params
error_text = e.response.text
+
if should_drop_params and "Extra inputs are not permitted" in error_text:
return True
elif (
"unknown field: parameter index is not a valid field" in error_text
): # remove index from tool calls
return True
+ elif (
+ AzureFoundryErrorStrings.SET_EXTRA_PARAMETERS_TO_PASS_THROUGH.value
+ in error_text
+ ): # remove extra-parameters from tool calls
+ return True
return super().should_retry_llm_api_inside_llm_translation_on_http_error(
e=e, litellm_params=litellm_params
)
@@ -265,5 +276,46 @@ class AzureAIStudioConfig(OpenAIConfig):
litellm.remove_index_from_tool_calls(
messages=_messages,
)
+ elif (
+ AzureFoundryErrorStrings.SET_EXTRA_PARAMETERS_TO_PASS_THROUGH.value
+ in e.response.text
+ ):
+ request_data = self._drop_extra_params_from_request_data(
+ request_data, e.response.text
+ )
data = drop_params_from_unprocessable_entity_error(e=e, data=request_data)
return data
+
+ def _drop_extra_params_from_request_data(
+ self, request_data: dict, error_text: str
+ ) -> dict:
+ params_to_drop = self._extract_params_to_drop_from_error_text(error_text)
+ if params_to_drop:
+ for param in params_to_drop:
+ if param in request_data:
+ request_data.pop(param, None)
+ return request_data
+
+ def _extract_params_to_drop_from_error_text(
+ self, error_text: str
+ ) -> Optional[List[str]]:
+ """
+ Error text looks like this"
+ "Extra parameters ['stream_options', 'extra-parameters'] are not allowed when extra-parameters is not set or set to be 'error'.
+ """
+ import re
+
+ # Extract parameters within square brackets
+ match = re.search(r"\[(.*?)\]", error_text)
+ if not match:
+ return []
+
+ # Parse the extracted string into a list of parameter names
+ params_str = match.group(1)
+ params = []
+ for param in params_str.split(","):
+ # Clean up the parameter name (remove quotes, spaces)
+ clean_param = param.strip().strip("'").strip('"')
+ if clean_param:
+ params.append(clean_param)
+ return params
diff --git a/litellm/llms/base_llm/base_model_iterator.py b/litellm/llms/base_llm/base_model_iterator.py
index 90dcc52fef..4cf757d6cd 100644
--- a/litellm/llms/base_llm/base_model_iterator.py
+++ b/litellm/llms/base_llm/base_model_iterator.py
@@ -1,9 +1,16 @@
import json
from abc import abstractmethod
-from typing import Optional, Union
+from typing import List, Optional, Union, cast
import litellm
-from litellm.types.utils import GenericStreamingChunk, ModelResponseStream
+from litellm.types.utils import (
+ Choices,
+ Delta,
+ GenericStreamingChunk,
+ ModelResponse,
+ ModelResponseStream,
+ StreamingChoices,
+)
class BaseModelResponseIterator:
@@ -121,6 +128,59 @@ class BaseModelResponseIterator:
raise RuntimeError(f"Error parsing chunk: {e},\nReceived chunk: {chunk}")
+class MockResponseIterator: # for returning ai21 streaming responses
+ def __init__(
+ self, model_response: ModelResponse, json_mode: Optional[bool] = False
+ ):
+ self.model_response = model_response
+ self.json_mode = json_mode
+ self.is_done = False
+
+ # Sync iterator
+ def __iter__(self):
+ return self
+
+ def _chunk_parser(self, chunk_data: ModelResponse) -> ModelResponseStream:
+ try:
+ streaming_choices: List[StreamingChoices] = []
+ for choice in chunk_data.choices:
+ streaming_choices.append(
+ StreamingChoices(
+ index=choice.index,
+ delta=Delta(
+ **cast(Choices, choice).message.model_dump(),
+ ),
+ finish_reason=choice.finish_reason,
+ )
+ )
+ processed_chunk = ModelResponseStream(
+ id=chunk_data.id,
+ object="chat.completion",
+ created=chunk_data.created,
+ model=chunk_data.model,
+ choices=streaming_choices,
+ )
+ return processed_chunk
+ except Exception as e:
+ raise ValueError(f"Failed to decode chunk: {chunk_data}. Error: {e}")
+
+ def __next__(self):
+ if self.is_done:
+ raise StopIteration
+ self.is_done = True
+ return self._chunk_parser(self.model_response)
+
+ # Async iterator
+ def __aiter__(self):
+ return self
+
+ async def __anext__(self):
+ if self.is_done:
+ raise StopAsyncIteration
+ self.is_done = True
+ return self._chunk_parser(self.model_response)
+
+
class FakeStreamResponseIterator:
def __init__(self, model_response, json_mode: Optional[bool] = False):
self.model_response = model_response
diff --git a/litellm/llms/base_llm/base_utils.py b/litellm/llms/base_llm/base_utils.py
index 5b175f4756..712f5de8cc 100644
--- a/litellm/llms/base_llm/base_utils.py
+++ b/litellm/llms/base_llm/base_utils.py
@@ -44,6 +44,19 @@ class BaseLLMModelInfo(ABC):
def get_api_base(api_base: Optional[str] = None) -> Optional[str]:
pass
+ @abstractmethod
+ def validate_environment(
+ self,
+ headers: dict,
+ model: str,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ api_key: Optional[str] = None,
+ api_base: Optional[str] = None,
+ ) -> dict:
+ pass
+
@staticmethod
@abstractmethod
def get_base_model(model: str) -> Optional[str]:
diff --git a/litellm/llms/base_llm/responses/transformation.py b/litellm/llms/base_llm/responses/transformation.py
index e98a579845..15ce8cba3f 100644
--- a/litellm/llms/base_llm/responses/transformation.py
+++ b/litellm/llms/base_llm/responses/transformation.py
@@ -1,6 +1,6 @@
import types
from abc import ABC, abstractmethod
-from typing import TYPE_CHECKING, Any, Dict, Optional, Union
+from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
import httpx
@@ -10,6 +10,7 @@ from litellm.types.llms.openai import (
ResponsesAPIResponse,
ResponsesAPIStreamingResponse,
)
+from litellm.types.responses.main import *
from litellm.types.router import GenericLiteLLMParams
if TYPE_CHECKING:
@@ -73,8 +74,7 @@ class BaseResponsesAPIConfig(ABC):
def get_complete_url(
self,
api_base: Optional[str],
- model: str,
- stream: Optional[bool] = None,
+ litellm_params: dict,
) -> str:
"""
OPTIONAL
@@ -119,6 +119,31 @@ class BaseResponsesAPIConfig(ABC):
"""
pass
+ #########################################################
+ ########## DELETE RESPONSE API TRANSFORMATION ##############
+ #########################################################
+ @abstractmethod
+ def transform_delete_response_api_request(
+ self,
+ response_id: str,
+ api_base: str,
+ litellm_params: GenericLiteLLMParams,
+ headers: dict,
+ ) -> Tuple[str, Dict]:
+ pass
+
+ @abstractmethod
+ def transform_delete_response_api_response(
+ self,
+ raw_response: httpx.Response,
+ logging_obj: LiteLLMLoggingObj,
+ ) -> DeleteResponseResult:
+ pass
+
+ #########################################################
+ ########## END DELETE RESPONSE API TRANSFORMATION ##########
+ #########################################################
+
def get_error_class(
self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers]
) -> BaseLLMException:
diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py
index 76ea51f435..31d7542cb4 100644
--- a/litellm/llms/bedrock/chat/converse_transformation.py
+++ b/litellm/llms/bedrock/chat/converse_transformation.py
@@ -22,6 +22,7 @@ from litellm.llms.base_llm.chat.transformation import BaseConfig, BaseLLMExcepti
from litellm.types.llms.bedrock import *
from litellm.types.llms.openai import (
AllMessageValues,
+ ChatCompletionRedactedThinkingBlock,
ChatCompletionResponseMessage,
ChatCompletionSystemMessage,
ChatCompletionThinkingBlock,
@@ -375,25 +376,27 @@ class AmazonConverseConfig(BaseConfig):
system_content_blocks: List[SystemContentBlock] = []
for idx, message in enumerate(messages):
if message["role"] == "system":
- _system_content_block: Optional[SystemContentBlock] = None
- _cache_point_block: Optional[SystemContentBlock] = None
- if isinstance(message["content"], str) and len(message["content"]) > 0:
- _system_content_block = SystemContentBlock(text=message["content"])
- _cache_point_block = self._get_cache_point_block(
+ system_prompt_indices.append(idx)
+ if isinstance(message["content"], str) and message["content"]:
+ system_content_blocks.append(
+ SystemContentBlock(text=message["content"])
+ )
+ cache_block = self._get_cache_point_block(
message, block_type="system"
)
+ if cache_block:
+ system_content_blocks.append(cache_block)
elif isinstance(message["content"], list):
for m in message["content"]:
- if m.get("type", "") == "text" and len(m["text"]) > 0:
- _system_content_block = SystemContentBlock(text=m["text"])
- _cache_point_block = self._get_cache_point_block(
+ if m.get("type") == "text" and m.get("text"):
+ system_content_blocks.append(
+ SystemContentBlock(text=m["text"])
+ )
+ cache_block = self._get_cache_point_block(
m, block_type="system"
)
- if _system_content_block is not None:
- system_content_blocks.append(_system_content_block)
- if _cache_point_block is not None:
- system_content_blocks.append(_cache_point_block)
- system_prompt_indices.append(idx)
+ if cache_block:
+ system_content_blocks.append(cache_block)
if len(system_prompt_indices) > 0:
for idx in reversed(system_prompt_indices):
messages.pop(idx)
@@ -627,9 +630,11 @@ class AmazonConverseConfig(BaseConfig):
def _transform_thinking_blocks(
self, thinking_blocks: List[BedrockConverseReasoningContentBlock]
- ) -> List[ChatCompletionThinkingBlock]:
+ ) -> List[Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]]:
"""Return a consistent format for thinking blocks between Anthropic and Bedrock."""
- thinking_blocks_list: List[ChatCompletionThinkingBlock] = []
+ thinking_blocks_list: List[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ] = []
for block in thinking_blocks:
if "reasoningText" in block:
_thinking_block = ChatCompletionThinkingBlock(type="thinking")
@@ -640,6 +645,11 @@ class AmazonConverseConfig(BaseConfig):
if _signature is not None:
_thinking_block["signature"] = _signature
thinking_blocks_list.append(_thinking_block)
+ elif "redactedContent" in block:
+ _redacted_block = ChatCompletionRedactedThinkingBlock(
+ type="redacted_thinking", data=block["redactedContent"]
+ )
+ thinking_blocks_list.append(_redacted_block)
return thinking_blocks_list
def _transform_usage(self, usage: ConverseTokenUsageBlock) -> Usage:
diff --git a/litellm/llms/bedrock/chat/invoke_handler.py b/litellm/llms/bedrock/chat/invoke_handler.py
index 09bdd63572..dfd1658543 100644
--- a/litellm/llms/bedrock/chat/invoke_handler.py
+++ b/litellm/llms/bedrock/chat/invoke_handler.py
@@ -50,6 +50,7 @@ from litellm.llms.custom_httpx.http_handler import (
)
from litellm.types.llms.bedrock import *
from litellm.types.llms.openai import (
+ ChatCompletionRedactedThinkingBlock,
ChatCompletionThinkingBlock,
ChatCompletionToolCallChunk,
ChatCompletionToolCallFunctionChunk,
@@ -1255,19 +1256,33 @@ class AWSEventStreamDecoder:
def translate_thinking_blocks(
self, thinking_block: BedrockConverseReasoningContentBlockDelta
- ) -> Optional[List[ChatCompletionThinkingBlock]]:
+ ) -> Optional[
+ List[Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]]
+ ]:
"""
Translate the thinking blocks to a string
"""
- thinking_blocks_list: List[ChatCompletionThinkingBlock] = []
- _thinking_block = ChatCompletionThinkingBlock(type="thinking")
+ thinking_blocks_list: List[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ] = []
+ _thinking_block: Optional[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ] = None
+
if "text" in thinking_block:
+ _thinking_block = ChatCompletionThinkingBlock(type="thinking")
_thinking_block["thinking"] = thinking_block["text"]
elif "signature" in thinking_block:
+ _thinking_block = ChatCompletionThinkingBlock(type="thinking")
_thinking_block["signature"] = thinking_block["signature"]
_thinking_block["thinking"] = "" # consistent with anthropic response
- thinking_blocks_list.append(_thinking_block)
+ elif "redactedContent" in thinking_block:
+ _thinking_block = ChatCompletionRedactedThinkingBlock(
+ type="redacted_thinking", data=thinking_block["redactedContent"]
+ )
+ if _thinking_block is not None:
+ thinking_blocks_list.append(_thinking_block)
return thinking_blocks_list
def converse_chunk_parser(self, chunk_data: dict) -> ModelResponseStream:
@@ -1279,31 +1294,44 @@ class AWSEventStreamDecoder:
usage: Optional[Usage] = None
provider_specific_fields: dict = {}
reasoning_content: Optional[str] = None
- thinking_blocks: Optional[List[ChatCompletionThinkingBlock]] = None
+ thinking_blocks: Optional[
+ List[
+ Union[
+ ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock
+ ]
+ ]
+ ] = None
index = int(chunk_data.get("contentBlockIndex", 0))
if "start" in chunk_data:
start_obj = ContentBlockStartEvent(**chunk_data["start"])
self.content_blocks = [] # reset
- if (
- start_obj is not None
- and "toolUse" in start_obj
- and start_obj["toolUse"] is not None
- ):
- ## check tool name was formatted by litellm
- _response_tool_name = start_obj["toolUse"]["name"]
- response_tool_name = get_bedrock_tool_name(
- response_tool_name=_response_tool_name
- )
- tool_use = {
- "id": start_obj["toolUse"]["toolUseId"],
- "type": "function",
- "function": {
- "name": response_tool_name,
- "arguments": "",
- },
- "index": index,
- }
+ if start_obj is not None:
+ if "toolUse" in start_obj and start_obj["toolUse"] is not None:
+ ## check tool name was formatted by litellm
+ _response_tool_name = start_obj["toolUse"]["name"]
+ response_tool_name = get_bedrock_tool_name(
+ response_tool_name=_response_tool_name
+ )
+ tool_use = {
+ "id": start_obj["toolUse"]["toolUseId"],
+ "type": "function",
+ "function": {
+ "name": response_tool_name,
+ "arguments": "",
+ },
+ "index": index,
+ }
+ elif (
+ "reasoningContent" in start_obj
+ and start_obj["reasoningContent"] is not None
+ ): # redacted thinking can be in start object
+ thinking_blocks = self.translate_thinking_blocks(
+ start_obj["reasoningContent"]
+ )
+ provider_specific_fields = {
+ "reasoningContent": start_obj["reasoningContent"],
+ }
elif "delta" in chunk_data:
delta_obj = ContentBlockDeltaEvent(**chunk_data["delta"])
self.content_blocks.append(delta_obj)
diff --git a/litellm/llms/bedrock/common_utils.py b/litellm/llms/bedrock/common_utils.py
index f4a1170660..69a249b842 100644
--- a/litellm/llms/bedrock/common_utils.py
+++ b/litellm/llms/bedrock/common_utils.py
@@ -44,7 +44,18 @@ class AmazonBedrockGlobalConfig:
)
def get_ap_regions(self) -> List[str]:
- return ["ap-northeast-1", "ap-northeast-2", "ap-northeast-3", "ap-south-1"]
+ """
+ Source: https://www.aws-services.info/bedrock.html
+ """
+ return [
+ "ap-northeast-1", # Asia Pacific (Tokyo)
+ "ap-northeast-2", # Asia Pacific (Seoul)
+ "ap-northeast-3", # Asia Pacific (Osaka)
+ "ap-south-1", # Asia Pacific (Mumbai)
+ "ap-south-2", # Asia Pacific (Hyderabad)
+ "ap-southeast-1", # Asia Pacific (Singapore)
+ "ap-southeast-2", # Asia Pacific (Sydney)
+ ]
def get_sa_regions(self) -> List[str]:
return ["sa-east-1"]
@@ -54,10 +65,14 @@ class AmazonBedrockGlobalConfig:
Source: https://www.aws-services.info/bedrock.html
"""
return [
- "eu-west-1",
- "eu-west-2",
- "eu-west-3",
- "eu-central-1",
+ "eu-west-1", # Europe (Ireland)
+ "eu-west-2", # Europe (London)
+ "eu-west-3", # Europe (Paris)
+ "eu-central-1", # Europe (Frankfurt)
+ "eu-central-2", # Europe (Zurich)
+ "eu-south-1", # Europe (Milan)
+ "eu-south-2", # Europe (Spain)
+ "eu-north-1", # Europe (Stockholm)
]
def get_ca_regions(self) -> List[str]:
@@ -68,11 +83,12 @@ class AmazonBedrockGlobalConfig:
Source: https://www.aws-services.info/bedrock.html
"""
return [
- "us-east-2",
- "us-east-1",
- "us-west-1",
- "us-west-2",
- "us-gov-west-1",
+ "us-east-1", # US East (N. Virginia)
+ "us-east-2", # US East (Ohio)
+ "us-west-1", # US West (N. California)
+ "us-west-2", # US West (Oregon)
+ "us-gov-east-1", # AWS GovCloud (US-East)
+ "us-gov-west-1", # AWS GovCloud (US-West)
]
diff --git a/litellm/llms/cohere/chat/v2_transformation.py b/litellm/llms/cohere/chat/v2_transformation.py
new file mode 100644
index 0000000000..76948e7f8b
--- /dev/null
+++ b/litellm/llms/cohere/chat/v2_transformation.py
@@ -0,0 +1,356 @@
+import time
+from typing import TYPE_CHECKING, Any, AsyncIterator, Iterator, List, Optional, Union
+
+import httpx
+
+import litellm
+from litellm.litellm_core_utils.prompt_templates.factory import cohere_messages_pt_v2
+from litellm.llms.base_llm.chat.transformation import BaseConfig, BaseLLMException
+from litellm.types.llms.cohere import CohereV2ChatResponse
+from litellm.types.llms.openai import AllMessageValues, ChatCompletionToolCallChunk
+from litellm.types.utils import ModelResponse, Usage
+
+from ..common_utils import CohereError
+from ..common_utils import ModelResponseIterator as CohereModelResponseIterator
+from ..common_utils import validate_environment as cohere_validate_environment
+
+if TYPE_CHECKING:
+ from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj
+
+ LiteLLMLoggingObj = _LiteLLMLoggingObj
+else:
+ LiteLLMLoggingObj = Any
+
+
+class CohereV2ChatConfig(BaseConfig):
+ """
+ Configuration class for Cohere's API interface.
+
+ Args:
+ preamble (str, optional): When specified, the default Cohere preamble will be replaced with the provided one.
+ chat_history (List[Dict[str, str]], optional): A list of previous messages between the user and the model.
+ generation_id (str, optional): Unique identifier for the generated reply.
+ response_id (str, optional): Unique identifier for the response.
+ conversation_id (str, optional): An alternative to chat_history, creates or resumes a persisted conversation.
+ prompt_truncation (str, optional): Dictates how the prompt will be constructed. Options: 'AUTO', 'AUTO_PRESERVE_ORDER', 'OFF'.
+ connectors (List[Dict[str, str]], optional): List of connectors (e.g., web-search) to enrich the model's reply.
+ search_queries_only (bool, optional): When true, the response will only contain a list of generated search queries.
+ documents (List[Dict[str, str]], optional): A list of relevant documents that the model can cite.
+ temperature (float, optional): A non-negative float that tunes the degree of randomness in generation.
+ max_tokens (int, optional): The maximum number of tokens the model will generate as part of the response.
+ k (int, optional): Ensures only the top k most likely tokens are considered for generation at each step.
+ p (float, optional): Ensures that only the most likely tokens, with total probability mass of p, are considered for generation.
+ frequency_penalty (float, optional): Used to reduce repetitiveness of generated tokens.
+ presence_penalty (float, optional): Used to reduce repetitiveness of generated tokens.
+ tools (List[Dict[str, str]], optional): A list of available tools (functions) that the model may suggest invoking.
+ tool_results (List[Dict[str, Any]], optional): A list of results from invoking tools.
+ seed (int, optional): A seed to assist reproducibility of the model's response.
+ """
+
+ preamble: Optional[str] = None
+ chat_history: Optional[list] = None
+ generation_id: Optional[str] = None
+ response_id: Optional[str] = None
+ conversation_id: Optional[str] = None
+ prompt_truncation: Optional[str] = None
+ connectors: Optional[list] = None
+ search_queries_only: Optional[bool] = None
+ documents: Optional[list] = None
+ temperature: Optional[int] = None
+ max_tokens: Optional[int] = None
+ k: Optional[int] = None
+ p: Optional[int] = None
+ frequency_penalty: Optional[int] = None
+ presence_penalty: Optional[int] = None
+ tools: Optional[list] = None
+ tool_results: Optional[list] = None
+ seed: Optional[int] = None
+
+ def __init__(
+ self,
+ preamble: Optional[str] = None,
+ chat_history: Optional[list] = None,
+ generation_id: Optional[str] = None,
+ response_id: Optional[str] = None,
+ conversation_id: Optional[str] = None,
+ prompt_truncation: Optional[str] = None,
+ connectors: Optional[list] = None,
+ search_queries_only: Optional[bool] = None,
+ documents: Optional[list] = None,
+ temperature: Optional[int] = None,
+ max_tokens: Optional[int] = None,
+ k: Optional[int] = None,
+ p: Optional[int] = None,
+ frequency_penalty: Optional[int] = None,
+ presence_penalty: Optional[int] = None,
+ tools: Optional[list] = None,
+ tool_results: Optional[list] = None,
+ seed: Optional[int] = None,
+ ) -> None:
+ locals_ = locals()
+ for key, value in locals_.items():
+ if key != "self" and value is not None:
+ setattr(self.__class__, key, value)
+
+ def validate_environment(
+ self,
+ headers: dict,
+ model: str,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ api_key: Optional[str] = None,
+ api_base: Optional[str] = None,
+ ) -> dict:
+ return cohere_validate_environment(
+ headers=headers,
+ model=model,
+ messages=messages,
+ optional_params=optional_params,
+ api_key=api_key,
+ )
+
+ def get_supported_openai_params(self, model: str) -> List[str]:
+ return [
+ "stream",
+ "temperature",
+ "max_tokens",
+ "top_p",
+ "frequency_penalty",
+ "presence_penalty",
+ "stop",
+ "n",
+ "tools",
+ "tool_choice",
+ "seed",
+ "extra_headers",
+ ]
+
+ def map_openai_params(
+ self,
+ non_default_params: dict,
+ optional_params: dict,
+ model: str,
+ drop_params: bool,
+ ) -> dict:
+ for param, value in non_default_params.items():
+ if param == "stream":
+ optional_params["stream"] = value
+ if param == "temperature":
+ optional_params["temperature"] = value
+ if param == "max_tokens":
+ optional_params["max_tokens"] = value
+ if param == "n":
+ optional_params["num_generations"] = value
+ if param == "top_p":
+ optional_params["p"] = value
+ if param == "frequency_penalty":
+ optional_params["frequency_penalty"] = value
+ if param == "presence_penalty":
+ optional_params["presence_penalty"] = value
+ if param == "stop":
+ optional_params["stop_sequences"] = value
+ if param == "tools":
+ optional_params["tools"] = value
+ if param == "seed":
+ optional_params["seed"] = value
+ return optional_params
+
+ def transform_request(
+ self,
+ model: str,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ headers: dict,
+ ) -> dict:
+ ## Load Config
+ for k, v in litellm.CohereChatConfig.get_config().items():
+ if (
+ k not in optional_params
+ ): # completion(top_k=3) > cohere_config(top_k=3) <- allows for dynamic variables to be passed in
+ optional_params[k] = v
+
+ most_recent_message, chat_history = cohere_messages_pt_v2(
+ messages=messages, model=model, llm_provider="cohere_chat"
+ )
+
+ ## Handle Tool Calling
+ if "tools" in optional_params:
+ _is_function_call = True
+ cohere_tools = self._construct_cohere_tool(tools=optional_params["tools"])
+ optional_params["tools"] = cohere_tools
+ if isinstance(most_recent_message, dict):
+ optional_params["tool_results"] = [most_recent_message]
+ elif isinstance(most_recent_message, str):
+ optional_params["message"] = most_recent_message
+
+ ## check if chat history message is 'user' and 'tool_results' is given -> force_single_step=True, else cohere api fails
+ if len(chat_history) > 0 and chat_history[-1]["role"] == "USER":
+ optional_params["force_single_step"] = True
+
+ return optional_params
+
+ def transform_response(
+ self,
+ model: str,
+ raw_response: httpx.Response,
+ model_response: ModelResponse,
+ logging_obj: LiteLLMLoggingObj,
+ request_data: dict,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ encoding: Any,
+ api_key: Optional[str] = None,
+ json_mode: Optional[bool] = None,
+ ) -> ModelResponse:
+ try:
+ raw_response_json = raw_response.json()
+ except Exception:
+ raise CohereError(
+ message=raw_response.text, status_code=raw_response.status_code
+ )
+
+ try:
+ cohere_v2_chat_response = CohereV2ChatResponse(**raw_response_json) # type: ignore
+ except Exception:
+ raise CohereError(message=raw_response.text, status_code=422)
+
+ cohere_content = cohere_v2_chat_response["message"].get("content", None)
+ if cohere_content is not None:
+ model_response.choices[0].message.content = "".join( # type: ignore
+ [
+ content.get("text", "")
+ for content in cohere_content
+ if content is not None
+ ]
+ )
+
+ ## ADD CITATIONS
+ if "citations" in cohere_v2_chat_response:
+ setattr(model_response, "citations", cohere_v2_chat_response["citations"])
+
+ ## Tool calling response
+ cohere_tools_response = cohere_v2_chat_response["message"].get("tool_calls", [])
+ if cohere_tools_response is not None and cohere_tools_response != []:
+ # convert cohere_tools_response to OpenAI response format
+ tool_calls: List[ChatCompletionToolCallChunk] = []
+ for index, tool in enumerate(cohere_tools_response):
+ tool_call: ChatCompletionToolCallChunk = {
+ **tool, # type: ignore
+ "index": index,
+ }
+ tool_calls.append(tool_call)
+ _message = litellm.Message(
+ tool_calls=tool_calls,
+ content=None,
+ )
+ model_response.choices[0].message = _message # type: ignore
+
+ ## CALCULATING USAGE - use cohere `billed_units` for returning usage
+ token_usage = cohere_v2_chat_response["usage"].get("tokens", {})
+ prompt_tokens = token_usage.get("input_tokens", 0)
+ completion_tokens = token_usage.get("output_tokens", 0)
+
+ model_response.created = int(time.time())
+ model_response.model = model
+ usage = Usage(
+ prompt_tokens=prompt_tokens,
+ completion_tokens=completion_tokens,
+ total_tokens=prompt_tokens + completion_tokens,
+ )
+ setattr(model_response, "usage", usage)
+ return model_response
+
+ def _construct_cohere_tool(
+ self,
+ tools: Optional[list] = None,
+ ):
+ if tools is None:
+ tools = []
+ cohere_tools = []
+ for tool in tools:
+ cohere_tool = self._translate_openai_tool_to_cohere(tool)
+ cohere_tools.append(cohere_tool)
+ return cohere_tools
+
+ def _translate_openai_tool_to_cohere(
+ self,
+ openai_tool: dict,
+ ):
+ # cohere tools look like this
+ """
+ {
+ "name": "query_daily_sales_report",
+ "description": "Connects to a database to retrieve overall sales volumes and sales information for a given day.",
+ "parameter_definitions": {
+ "day": {
+ "description": "Retrieves sales data for this day, formatted as YYYY-MM-DD.",
+ "type": "str",
+ "required": True
+ }
+ }
+ }
+ """
+
+ # OpenAI tools look like this
+ """
+ {
+ "type": "function",
+ "function": {
+ "name": "get_current_weather",
+ "description": "Get the current weather in a given location",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "type": "string",
+ "description": "The city and state, e.g. San Francisco, CA",
+ },
+ "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
+ },
+ "required": ["location"],
+ },
+ },
+ }
+ """
+ cohere_tool = {
+ "name": openai_tool["function"]["name"],
+ "description": openai_tool["function"]["description"],
+ "parameter_definitions": {},
+ }
+
+ for param_name, param_def in openai_tool["function"]["parameters"][
+ "properties"
+ ].items():
+ required_params = (
+ openai_tool.get("function", {})
+ .get("parameters", {})
+ .get("required", [])
+ )
+ cohere_param_def = {
+ "description": param_def.get("description", ""),
+ "type": param_def.get("type", ""),
+ "required": param_name in required_params,
+ }
+ cohere_tool["parameter_definitions"][param_name] = cohere_param_def
+
+ return cohere_tool
+
+ def get_model_response_iterator(
+ self,
+ streaming_response: Union[Iterator[str], AsyncIterator[str], ModelResponse],
+ sync_stream: bool,
+ json_mode: Optional[bool] = False,
+ ):
+ return CohereModelResponseIterator(
+ streaming_response=streaming_response,
+ sync_stream=sync_stream,
+ json_mode=json_mode,
+ )
+
+ def get_error_class(
+ self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers]
+ ) -> BaseLLMException:
+ return CohereError(status_code=status_code, message=error_message)
diff --git a/litellm/llms/cohere/common_utils.py b/litellm/llms/cohere/common_utils.py
index 11ff73efc2..6dbe52d575 100644
--- a/litellm/llms/cohere/common_utils.py
+++ b/litellm/llms/cohere/common_utils.py
@@ -104,19 +104,28 @@ class ModelResponseIterator:
raise RuntimeError(f"Error receiving chunk from stream: {e}")
try:
- str_line = chunk
- if isinstance(chunk, bytes): # Handle binary data
- str_line = chunk.decode("utf-8") # Convert bytes to string
- index = str_line.find("data:")
- if index != -1:
- str_line = str_line[index:]
- data_json = json.loads(str_line)
- return self.chunk_parser(chunk=data_json)
+ return self.convert_str_chunk_to_generic_chunk(chunk=chunk)
except StopIteration:
raise StopIteration
except ValueError as e:
raise RuntimeError(f"Error parsing chunk: {e},\nReceived chunk: {chunk}")
+ def convert_str_chunk_to_generic_chunk(self, chunk: str) -> GenericStreamingChunk:
+ """
+ Convert a string chunk to a GenericStreamingChunk
+
+ Note: This is used for Cohere pass through streaming logging
+ """
+ str_line = chunk
+ if isinstance(chunk, bytes): # Handle binary data
+ str_line = chunk.decode("utf-8") # Convert bytes to string
+ index = str_line.find("data:")
+ if index != -1:
+ str_line = str_line[index:]
+
+ data_json = json.loads(str_line)
+ return self.chunk_parser(chunk=data_json)
+
# Async iterator
def __aiter__(self):
self.async_response_iterator = self.streaming_response.__aiter__()
@@ -131,15 +140,7 @@ class ModelResponseIterator:
raise RuntimeError(f"Error receiving chunk from stream: {e}")
try:
- str_line = chunk
- if isinstance(chunk, bytes): # Handle binary data
- str_line = chunk.decode("utf-8") # Convert bytes to string
- index = str_line.find("data:")
- if index != -1:
- str_line = str_line[index:]
-
- data_json = json.loads(str_line)
- return self.chunk_parser(chunk=data_json)
+ return self.convert_str_chunk_to_generic_chunk(chunk=chunk)
except StopAsyncIteration:
raise StopAsyncIteration
except ValueError as e:
diff --git a/litellm/llms/custom_httpx/http_handler.py b/litellm/llms/custom_httpx/http_handler.py
index f1aa5627dc..f99e04ab9d 100644
--- a/litellm/llms/custom_httpx/http_handler.py
+++ b/litellm/llms/custom_httpx/http_handler.py
@@ -8,6 +8,7 @@ import httpx
from httpx import USE_CLIENT_DEFAULT, AsyncHTTPTransport, HTTPTransport
import litellm
+from litellm.constants import _DEFAULT_TTL_FOR_HTTPX_CLIENTS
from litellm.litellm_core_utils.logging_utils import track_llm_api_timing
from litellm.types.llms.custom_http import *
@@ -31,7 +32,6 @@ headers = {
# https://www.python-httpx.org/advanced/timeouts
_DEFAULT_TIMEOUT = httpx.Timeout(timeout=5.0, connect=5.0)
-_DEFAULT_TTL_FOR_HTTPX_CLIENTS = 3600 # 1 hour, re-use the same httpx client for 1 hour
def mask_sensitive_info(error_message):
@@ -650,6 +650,49 @@ class HTTPHandler:
except Exception as e:
raise e
+ def delete(
+ self,
+ url: str,
+ data: Optional[Union[dict, str]] = None, # type: ignore
+ json: Optional[dict] = None,
+ params: Optional[dict] = None,
+ headers: Optional[dict] = None,
+ timeout: Optional[Union[float, httpx.Timeout]] = None,
+ stream: bool = False,
+ ):
+ try:
+ if timeout is not None:
+ req = self.client.build_request(
+ "DELETE", url, data=data, json=json, params=params, headers=headers, timeout=timeout # type: ignore
+ )
+ else:
+ req = self.client.build_request(
+ "DELETE", url, data=data, json=json, params=params, headers=headers # type: ignore
+ )
+ response = self.client.send(req, stream=stream)
+ response.raise_for_status()
+ return response
+ except httpx.TimeoutException:
+ raise litellm.Timeout(
+ message=f"Connection timed out after {timeout} seconds.",
+ model="default-model-name",
+ llm_provider="litellm-httpx-handler",
+ )
+ except httpx.HTTPStatusError as e:
+ if stream is True:
+ setattr(e, "message", mask_sensitive_info(e.response.read()))
+ setattr(e, "text", mask_sensitive_info(e.response.read()))
+ else:
+ error_text = mask_sensitive_info(e.response.text)
+ setattr(e, "message", error_text)
+ setattr(e, "text", error_text)
+
+ setattr(e, "status_code", e.response.status_code)
+
+ raise e
+ except Exception as e:
+ raise e
+
def __del__(self) -> None:
try:
self.close()
diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py
index b7c72e89ef..1958ef0b60 100644
--- a/litellm/llms/custom_httpx/llm_http_handler.py
+++ b/litellm/llms/custom_httpx/llm_http_handler.py
@@ -11,6 +11,7 @@ from litellm._logging import verbose_logger
from litellm.llms.base_llm.audio_transcription.transformation import (
BaseAudioTranscriptionConfig,
)
+from litellm.llms.base_llm.base_model_iterator import MockResponseIterator
from litellm.llms.base_llm.chat.transformation import BaseConfig
from litellm.llms.base_llm.embedding.transformation import BaseEmbeddingConfig
from litellm.llms.base_llm.files.transformation import BaseFilesConfig
@@ -35,6 +36,7 @@ from litellm.types.llms.openai import (
ResponsesAPIResponse,
)
from litellm.types.rerank import OptionalRerankParams, RerankResponse
+from litellm.types.responses.main import DeleteResponseResult
from litellm.types.router import GenericLiteLLMParams
from litellm.types.utils import EmbeddingResponse, FileTypes, TranscriptionResponse
from litellm.utils import CustomStreamWrapper, ModelResponse, ProviderConfigManager
@@ -228,11 +230,17 @@ class BaseLLMHTTPHandler:
api_key: Optional[str] = None,
headers: Optional[dict] = {},
client: Optional[Union[HTTPHandler, AsyncHTTPHandler]] = None,
+ provider_config: Optional[BaseConfig] = None,
):
json_mode: bool = optional_params.pop("json_mode", False)
+ extra_body: Optional[dict] = optional_params.pop("extra_body", None)
+ fake_stream = fake_stream or optional_params.pop("fake_stream", False)
- provider_config = ProviderConfigManager.get_provider_chat_config(
- model=model, provider=litellm.LlmProviders(custom_llm_provider)
+ provider_config = (
+ provider_config
+ or ProviderConfigManager.get_provider_chat_config(
+ model=model, provider=litellm.LlmProviders(custom_llm_provider)
+ )
)
if provider_config is None:
raise ValueError(
@@ -267,6 +275,9 @@ class BaseLLMHTTPHandler:
headers=headers,
)
+ if extra_body is not None:
+ data = {**data, **extra_body}
+
headers = provider_config.sign_request(
headers=headers,
optional_params=optional_params,
@@ -313,6 +324,7 @@ class BaseLLMHTTPHandler:
),
litellm_params=litellm_params,
json_mode=json_mode,
+ optional_params=optional_params,
)
else:
@@ -374,6 +386,7 @@ class BaseLLMHTTPHandler:
),
litellm_params=litellm_params,
json_mode=json_mode,
+ optional_params=optional_params,
)
return CustomStreamWrapper(
completion_stream=completion_stream,
@@ -422,6 +435,7 @@ class BaseLLMHTTPHandler:
model: str,
messages: list,
logging_obj,
+ optional_params: dict,
litellm_params: dict,
timeout: Union[float, httpx.Timeout],
fake_stream: bool = False,
@@ -453,11 +467,22 @@ class BaseLLMHTTPHandler:
)
if fake_stream is True:
- completion_stream = provider_config.get_model_response_iterator(
- streaming_response=response.json(),
- sync_stream=True,
+ model_response: ModelResponse = provider_config.transform_response(
+ model=model,
+ raw_response=response,
+ model_response=litellm.ModelResponse(),
+ logging_obj=logging_obj,
+ request_data=data,
+ messages=messages,
+ optional_params=optional_params,
+ litellm_params=litellm_params,
+ encoding=None,
json_mode=json_mode,
)
+
+ completion_stream: Any = MockResponseIterator(
+ model_response=model_response, json_mode=json_mode
+ )
else:
completion_stream = provider_config.get_model_response_iterator(
streaming_response=response.iter_lines(),
@@ -487,6 +512,7 @@ class BaseLLMHTTPHandler:
logging_obj: LiteLLMLoggingObj,
data: dict,
litellm_params: dict,
+ optional_params: dict,
fake_stream: bool = False,
client: Optional[AsyncHTTPHandler] = None,
json_mode: Optional[bool] = None,
@@ -505,6 +531,7 @@ class BaseLLMHTTPHandler:
)
completion_stream, _response_headers = await self.make_async_call_stream_helper(
+ model=model,
custom_llm_provider=custom_llm_provider,
provider_config=provider_config,
api_base=api_base,
@@ -516,6 +543,8 @@ class BaseLLMHTTPHandler:
fake_stream=fake_stream,
client=client,
litellm_params=litellm_params,
+ optional_params=optional_params,
+ json_mode=json_mode,
)
streamwrapper = CustomStreamWrapper(
completion_stream=completion_stream,
@@ -527,6 +556,7 @@ class BaseLLMHTTPHandler:
async def make_async_call_stream_helper(
self,
+ model: str,
custom_llm_provider: str,
provider_config: BaseConfig,
api_base: str,
@@ -536,8 +566,10 @@ class BaseLLMHTTPHandler:
logging_obj: LiteLLMLoggingObj,
timeout: Union[float, httpx.Timeout],
litellm_params: dict,
+ optional_params: dict,
fake_stream: bool = False,
client: Optional[AsyncHTTPHandler] = None,
+ json_mode: Optional[bool] = None,
) -> Tuple[Any, httpx.Headers]:
"""
Helper function for making an async call with stream.
@@ -568,8 +600,21 @@ class BaseLLMHTTPHandler:
)
if fake_stream is True:
- completion_stream = provider_config.get_model_response_iterator(
- streaming_response=response.json(), sync_stream=False
+ model_response: ModelResponse = provider_config.transform_response(
+ model=model,
+ raw_response=response,
+ model_response=litellm.ModelResponse(),
+ logging_obj=logging_obj,
+ request_data=data,
+ messages=messages,
+ optional_params=optional_params,
+ litellm_params=litellm_params,
+ encoding=None,
+ json_mode=json_mode,
+ )
+
+ completion_stream: Any = MockResponseIterator(
+ model_response=model_response, json_mode=json_mode
)
else:
completion_stream = provider_config.get_model_response_iterator(
@@ -594,8 +639,12 @@ class BaseLLMHTTPHandler:
"""
Some providers like Bedrock invoke do not support the stream parameter in the request body, we only pass `stream` in the request body the provider supports it.
"""
+
if fake_stream is True:
- return data
+ # remove 'stream' from data
+ new_data = data.copy()
+ new_data.pop("stream", None)
+ return new_data
if provider_config.supports_stream_param_in_request_body is True:
data["stream"] = True
return data
@@ -967,6 +1016,7 @@ class BaseLLMHTTPHandler:
client: Optional[Union[HTTPHandler, AsyncHTTPHandler]] = None,
_is_async: bool = False,
fake_stream: bool = False,
+ litellm_metadata: Optional[Dict[str, Any]] = None,
) -> Union[
ResponsesAPIResponse,
BaseResponsesAPIStreamingIterator,
@@ -993,6 +1043,7 @@ class BaseLLMHTTPHandler:
timeout=timeout,
client=client if isinstance(client, AsyncHTTPHandler) else None,
fake_stream=fake_stream,
+ litellm_metadata=litellm_metadata,
)
if client is None or not isinstance(client, HTTPHandler):
@@ -1011,9 +1062,12 @@ class BaseLLMHTTPHandler:
if extra_headers:
headers.update(extra_headers)
+ # Check if streaming is requested
+ stream = response_api_optional_request_params.get("stream", False)
+
api_base = responses_api_provider_config.get_complete_url(
api_base=litellm_params.api_base,
- model=model,
+ litellm_params=dict(litellm_params),
)
data = responses_api_provider_config.transform_responses_api_request(
@@ -1035,9 +1089,6 @@ class BaseLLMHTTPHandler:
},
)
- # Check if streaming is requested
- stream = response_api_optional_request_params.get("stream", False)
-
try:
if stream:
# For streaming, use stream=True in the request
@@ -1061,6 +1112,8 @@ class BaseLLMHTTPHandler:
model=model,
logging_obj=logging_obj,
responses_api_provider_config=responses_api_provider_config,
+ litellm_metadata=litellm_metadata,
+ custom_llm_provider=custom_llm_provider,
)
return SyncResponsesAPIStreamingIterator(
@@ -1068,6 +1121,8 @@ class BaseLLMHTTPHandler:
model=model,
logging_obj=logging_obj,
responses_api_provider_config=responses_api_provider_config,
+ litellm_metadata=litellm_metadata,
+ custom_llm_provider=custom_llm_provider,
)
else:
# For non-streaming requests
@@ -1104,6 +1159,7 @@ class BaseLLMHTTPHandler:
timeout: Optional[Union[float, httpx.Timeout]] = None,
client: Optional[Union[HTTPHandler, AsyncHTTPHandler]] = None,
fake_stream: bool = False,
+ litellm_metadata: Optional[Dict[str, Any]] = None,
) -> Union[ResponsesAPIResponse, BaseResponsesAPIStreamingIterator]:
"""
Async version of the responses API handler.
@@ -1126,9 +1182,12 @@ class BaseLLMHTTPHandler:
if extra_headers:
headers.update(extra_headers)
+ # Check if streaming is requested
+ stream = response_api_optional_request_params.get("stream", False)
+
api_base = responses_api_provider_config.get_complete_url(
api_base=litellm_params.api_base,
- model=model,
+ litellm_params=dict(litellm_params),
)
data = responses_api_provider_config.transform_responses_api_request(
@@ -1149,8 +1208,6 @@ class BaseLLMHTTPHandler:
"headers": headers,
},
)
- # Check if streaming is requested
- stream = response_api_optional_request_params.get("stream", False)
try:
if stream:
@@ -1177,6 +1234,8 @@ class BaseLLMHTTPHandler:
model=model,
logging_obj=logging_obj,
responses_api_provider_config=responses_api_provider_config,
+ litellm_metadata=litellm_metadata,
+ custom_llm_provider=custom_llm_provider,
)
# Return the streaming iterator
@@ -1185,6 +1244,8 @@ class BaseLLMHTTPHandler:
model=model,
logging_obj=logging_obj,
responses_api_provider_config=responses_api_provider_config,
+ litellm_metadata=litellm_metadata,
+ custom_llm_provider=custom_llm_provider,
)
else:
# For non-streaming, proceed as before
@@ -1208,6 +1269,163 @@ class BaseLLMHTTPHandler:
logging_obj=logging_obj,
)
+ async def async_delete_response_api_handler(
+ self,
+ response_id: str,
+ responses_api_provider_config: BaseResponsesAPIConfig,
+ litellm_params: GenericLiteLLMParams,
+ logging_obj: LiteLLMLoggingObj,
+ custom_llm_provider: Optional[str],
+ extra_headers: Optional[Dict[str, Any]] = None,
+ extra_body: Optional[Dict[str, Any]] = None,
+ timeout: Optional[Union[float, httpx.Timeout]] = None,
+ client: Optional[Union[HTTPHandler, AsyncHTTPHandler]] = None,
+ _is_async: bool = False,
+ ) -> DeleteResponseResult:
+ """
+ Async version of the delete response API handler.
+ Uses async HTTP client to make requests.
+ """
+ if client is None or not isinstance(client, AsyncHTTPHandler):
+ async_httpx_client = get_async_httpx_client(
+ llm_provider=litellm.LlmProviders(custom_llm_provider),
+ params={"ssl_verify": litellm_params.get("ssl_verify", None)},
+ )
+ else:
+ async_httpx_client = client
+
+ headers = responses_api_provider_config.validate_environment(
+ api_key=litellm_params.api_key,
+ headers=extra_headers or {},
+ model="None",
+ )
+
+ if extra_headers:
+ headers.update(extra_headers)
+
+ api_base = responses_api_provider_config.get_complete_url(
+ api_base=litellm_params.api_base,
+ litellm_params=dict(litellm_params),
+ )
+
+ url, data = responses_api_provider_config.transform_delete_response_api_request(
+ response_id=response_id,
+ api_base=api_base,
+ litellm_params=litellm_params,
+ headers=headers,
+ )
+
+ ## LOGGING
+ logging_obj.pre_call(
+ input=input,
+ api_key="",
+ additional_args={
+ "complete_input_dict": data,
+ "api_base": api_base,
+ "headers": headers,
+ },
+ )
+
+ try:
+ response = await async_httpx_client.delete(
+ url=url, headers=headers, data=json.dumps(data), timeout=timeout
+ )
+
+ except Exception as e:
+ raise self._handle_error(
+ e=e,
+ provider_config=responses_api_provider_config,
+ )
+
+ return responses_api_provider_config.transform_delete_response_api_response(
+ raw_response=response,
+ logging_obj=logging_obj,
+ )
+
+ def delete_response_api_handler(
+ self,
+ response_id: str,
+ responses_api_provider_config: BaseResponsesAPIConfig,
+ litellm_params: GenericLiteLLMParams,
+ logging_obj: LiteLLMLoggingObj,
+ custom_llm_provider: Optional[str],
+ extra_headers: Optional[Dict[str, Any]] = None,
+ extra_body: Optional[Dict[str, Any]] = None,
+ timeout: Optional[Union[float, httpx.Timeout]] = None,
+ client: Optional[Union[HTTPHandler, AsyncHTTPHandler]] = None,
+ _is_async: bool = False,
+ ) -> Union[DeleteResponseResult, Coroutine[Any, Any, DeleteResponseResult]]:
+ """
+ Async version of the responses API handler.
+ Uses async HTTP client to make requests.
+ """
+ if _is_async:
+ return self.async_delete_response_api_handler(
+ response_id=response_id,
+ responses_api_provider_config=responses_api_provider_config,
+ litellm_params=litellm_params,
+ logging_obj=logging_obj,
+ custom_llm_provider=custom_llm_provider,
+ extra_headers=extra_headers,
+ extra_body=extra_body,
+ timeout=timeout,
+ client=client,
+ )
+ if client is None or not isinstance(client, HTTPHandler):
+ sync_httpx_client = _get_httpx_client(
+ params={"ssl_verify": litellm_params.get("ssl_verify", None)}
+ )
+ else:
+ sync_httpx_client = client
+
+ headers = responses_api_provider_config.validate_environment(
+ api_key=litellm_params.api_key,
+ headers=extra_headers or {},
+ model="None",
+ )
+
+ if extra_headers:
+ headers.update(extra_headers)
+
+ api_base = responses_api_provider_config.get_complete_url(
+ api_base=litellm_params.api_base,
+ litellm_params=dict(litellm_params),
+ )
+
+ url, data = responses_api_provider_config.transform_delete_response_api_request(
+ response_id=response_id,
+ api_base=api_base,
+ litellm_params=litellm_params,
+ headers=headers,
+ )
+
+ ## LOGGING
+ logging_obj.pre_call(
+ input=input,
+ api_key="",
+ additional_args={
+ "complete_input_dict": data,
+ "api_base": api_base,
+ "headers": headers,
+ },
+ )
+
+ try:
+ response = sync_httpx_client.delete(
+ url=url, headers=headers, data=json.dumps(data), timeout=timeout
+ )
+
+ except Exception as e:
+ raise self._handle_error(
+ e=e,
+ provider_config=responses_api_provider_config,
+ )
+
+ return responses_api_provider_config.transform_delete_response_api_response(
+ raw_response=response,
+ logging_obj=logging_obj,
+ )
+
def create_file(
self,
create_file_data: CreateFileRequest,
diff --git a/litellm/llms/databricks/chat/transformation.py b/litellm/llms/databricks/chat/transformation.py
index 6f5738fb4b..7eb3d82963 100644
--- a/litellm/llms/databricks/chat/transformation.py
+++ b/litellm/llms/databricks/chat/transformation.py
@@ -37,6 +37,7 @@ from litellm.types.llms.databricks import (
)
from litellm.types.llms.openai import (
AllMessageValues,
+ ChatCompletionRedactedThinkingBlock,
ChatCompletionThinkingBlock,
ChatCompletionToolChoiceFunctionParam,
ChatCompletionToolChoiceObjectParam,
@@ -314,13 +315,24 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig):
@staticmethod
def extract_reasoning_content(
content: Optional[AllDatabricksContentValues],
- ) -> Tuple[Optional[str], Optional[List[ChatCompletionThinkingBlock]]]:
+ ) -> Tuple[
+ Optional[str],
+ Optional[
+ List[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ]
+ ],
+ ]:
"""
Extract and return the reasoning content and thinking blocks
"""
if content is None:
return None, None
- thinking_blocks: Optional[List[ChatCompletionThinkingBlock]] = None
+ thinking_blocks: Optional[
+ List[
+ Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]
+ ]
+ ] = None
reasoning_content: Optional[str] = None
if isinstance(content, list):
for item in content:
diff --git a/litellm/llms/fireworks_ai/chat/transformation.py b/litellm/llms/fireworks_ai/chat/transformation.py
index dc78c5bc5d..2a795bdf2f 100644
--- a/litellm/llms/fireworks_ai/chat/transformation.py
+++ b/litellm/llms/fireworks_ai/chat/transformation.py
@@ -1,15 +1,33 @@
-from typing import List, Literal, Optional, Tuple, Union, cast
+import json
+import uuid
+from typing import Any, List, Literal, Optional, Tuple, Union, cast
+
+import httpx
import litellm
+from litellm.constants import RESPONSE_FORMAT_TOOL_NAME
+from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
+from litellm.litellm_core_utils.llm_response_utils.get_headers import (
+ get_response_headers,
+)
from litellm.secret_managers.main import get_secret_str
from litellm.types.llms.openai import (
AllMessageValues,
ChatCompletionImageObject,
+ ChatCompletionToolParam,
OpenAIChatCompletionToolParam,
)
-from litellm.types.utils import ProviderSpecificModelInfo
+from litellm.types.utils import (
+ ChatCompletionMessageToolCall,
+ Choices,
+ Function,
+ Message,
+ ModelResponse,
+ ProviderSpecificModelInfo,
+)
from ...openai.chat.gpt_transformation import OpenAIGPTConfig
+from ..common_utils import FireworksAIException
class FireworksAIConfig(OpenAIGPTConfig):
@@ -219,6 +237,94 @@ class FireworksAIConfig(OpenAIGPTConfig):
headers=headers,
)
+ def _handle_message_content_with_tool_calls(
+ self,
+ message: Message,
+ tool_calls: Optional[List[ChatCompletionToolParam]],
+ ) -> Message:
+ """
+ Fireworks AI sends tool calls in the content field instead of tool_calls
+
+ Relevant Issue: https://github.com/BerriAI/litellm/issues/7209#issuecomment-2813208780
+ """
+ if (
+ tool_calls is not None
+ and message.content is not None
+ and message.tool_calls is None
+ ):
+ try:
+ function = Function(**json.loads(message.content))
+ if function.name != RESPONSE_FORMAT_TOOL_NAME and function.name in [
+ tool["function"]["name"] for tool in tool_calls
+ ]:
+ tool_call = ChatCompletionMessageToolCall(
+ function=function, id=str(uuid.uuid4()), type="function"
+ )
+ message.tool_calls = [tool_call]
+
+ message.content = None
+ except Exception:
+ pass
+
+ return message
+
+ def transform_response(
+ self,
+ model: str,
+ raw_response: httpx.Response,
+ model_response: ModelResponse,
+ logging_obj: LiteLLMLoggingObj,
+ request_data: dict,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ encoding: Any,
+ api_key: Optional[str] = None,
+ json_mode: Optional[bool] = None,
+ ) -> ModelResponse:
+ ## LOGGING
+ logging_obj.post_call(
+ input=messages,
+ api_key=api_key,
+ original_response=raw_response.text,
+ additional_args={"complete_input_dict": request_data},
+ )
+
+ ## RESPONSE OBJECT
+ try:
+ completion_response = raw_response.json()
+ except Exception as e:
+ response_headers = getattr(raw_response, "headers", None)
+ raise FireworksAIException(
+ message="Unable to get json response - {}, Original Response: {}".format(
+ str(e), raw_response.text
+ ),
+ status_code=raw_response.status_code,
+ headers=response_headers,
+ )
+
+ raw_response_headers = dict(raw_response.headers)
+
+ additional_headers = get_response_headers(raw_response_headers)
+
+ response = ModelResponse(**completion_response)
+
+ if response.model is not None:
+ response.model = "fireworks_ai/" + response.model
+
+ ## FIREWORKS AI sends tool calls in the content field instead of tool_calls
+ for choice in response.choices:
+ cast(
+ Choices, choice
+ ).message = self._handle_message_content_with_tool_calls(
+ message=cast(Choices, choice).message,
+ tool_calls=optional_params.get("tools", None),
+ )
+
+ response._hidden_params = {"additional_headers": additional_headers}
+
+ return response
+
def _get_openai_compatible_provider_info(
self, api_base: Optional[str], api_key: Optional[str]
) -> Tuple[Optional[str], Optional[str]]:
diff --git a/litellm/llms/gemini/chat/transformation.py b/litellm/llms/gemini/chat/transformation.py
index 795333d598..dc65c46455 100644
--- a/litellm/llms/gemini/chat/transformation.py
+++ b/litellm/llms/gemini/chat/transformation.py
@@ -7,6 +7,7 @@ from litellm.litellm_core_utils.prompt_templates.factory import (
)
from litellm.types.llms.openai import AllMessageValues
from litellm.types.llms.vertex_ai import ContentType, PartType
+from litellm.utils import supports_reasoning
from ...vertex_ai.gemini.transformation import _gemini_convert_messages_with_history
from ...vertex_ai.gemini.vertex_and_google_ai_studio_gemini import VertexGeminiConfig
@@ -67,7 +68,7 @@ class GoogleAIStudioGeminiConfig(VertexGeminiConfig):
return super().get_config()
def get_supported_openai_params(self, model: str) -> List[str]:
- return [
+ supported_params = [
"temperature",
"top_p",
"max_tokens",
@@ -83,6 +84,10 @@ class GoogleAIStudioGeminiConfig(VertexGeminiConfig):
"frequency_penalty",
"modalities",
]
+ if supports_reasoning(model):
+ supported_params.append("reasoning_effort")
+ supported_params.append("thinking")
+ return supported_params
def map_openai_params(
self,
diff --git a/litellm/llms/groq/chat/transformation.py b/litellm/llms/groq/chat/transformation.py
index b0ee69bed2..4befdc504e 100644
--- a/litellm/llms/groq/chat/transformation.py
+++ b/litellm/llms/groq/chat/transformation.py
@@ -14,10 +14,10 @@ from litellm.types.llms.openai import (
ChatCompletionToolParamFunctionChunk,
)
-from ...openai.chat.gpt_transformation import OpenAIGPTConfig
+from ...openai_like.chat.transformation import OpenAILikeChatConfig
-class GroqChatConfig(OpenAIGPTConfig):
+class GroqChatConfig(OpenAILikeChatConfig):
frequency_penalty: Optional[int] = None
function_call: Optional[Union[str, dict]] = None
functions: Optional[list] = None
@@ -57,6 +57,14 @@ class GroqChatConfig(OpenAIGPTConfig):
def get_config(cls):
return super().get_config()
+ def get_supported_openai_params(self, model: str) -> list:
+ base_params = super().get_supported_openai_params(model)
+ try:
+ base_params.remove("max_retries")
+ except ValueError:
+ pass
+ return base_params
+
def _transform_messages(self, messages: List[AllMessageValues], model: str) -> List:
for idx, message in enumerate(messages):
"""
@@ -124,8 +132,11 @@ class GroqChatConfig(OpenAIGPTConfig):
optional_params: dict,
model: str,
drop_params: bool = False,
+ replace_max_completion_tokens_with_max_tokens: bool = False, # groq supports max_completion_tokens
) -> dict:
_response_format = non_default_params.get("response_format")
+ if self._should_fake_stream(non_default_params):
+ optional_params["fake_stream"] = True
if _response_format is not None and isinstance(_response_format, dict):
json_schema: Optional[dict] = None
if "response_schema" in _response_format:
@@ -152,6 +163,8 @@ class GroqChatConfig(OpenAIGPTConfig):
non_default_params.pop(
"response_format", None
) # only remove if it's a json_schema - handled via using groq's tool calling params.
- return super().map_openai_params(
+ optional_params = super().map_openai_params(
non_default_params, optional_params, model, drop_params
)
+
+ return optional_params
diff --git a/litellm/llms/hosted_vllm/chat/transformation.py b/litellm/llms/hosted_vllm/chat/transformation.py
index 9332e98789..e328bf2881 100644
--- a/litellm/llms/hosted_vllm/chat/transformation.py
+++ b/litellm/llms/hosted_vllm/chat/transformation.py
@@ -2,9 +2,19 @@
Translate from OpenAI's `/v1/chat/completions` to VLLM's `/v1/chat/completions`
"""
-from typing import Optional, Tuple
+from typing import List, Optional, Tuple, cast
+from litellm.litellm_core_utils.prompt_templates.common_utils import (
+ _get_image_mime_type_from_url,
+)
+from litellm.litellm_core_utils.prompt_templates.factory import _parse_mime_type
from litellm.secret_managers.main import get_secret_str
+from litellm.types.llms.openai import (
+ AllMessageValues,
+ ChatCompletionFileObject,
+ ChatCompletionVideoObject,
+ ChatCompletionVideoUrlObject,
+)
from ....utils import _remove_additional_properties, _remove_strict_from_schema
from ...openai.chat.gpt_transformation import OpenAIGPTConfig
@@ -38,3 +48,71 @@ class HostedVLLMChatConfig(OpenAIGPTConfig):
api_key or get_secret_str("HOSTED_VLLM_API_KEY") or "fake-api-key"
) # vllm does not require an api key
return api_base, dynamic_api_key
+
+ def _is_video_file(self, content_item: ChatCompletionFileObject) -> bool:
+ """
+ Check if the file is a video
+
+ - format: video/
+ - file_data: base64 encoded video data
+ - file_id: infer mp4 from extension
+ """
+ file = content_item.get("file", {})
+ format = file.get("format")
+ file_data = file.get("file_data")
+ file_id = file.get("file_id")
+ if content_item.get("type") != "file":
+ return False
+ if format and format.startswith("video/"):
+ return True
+ elif file_data:
+ mime_type = _parse_mime_type(file_data)
+ if mime_type and mime_type.startswith("video/"):
+ return True
+ elif file_id:
+ mime_type = _get_image_mime_type_from_url(file_id)
+ if mime_type and mime_type.startswith("video/"):
+ return True
+ return False
+
+ def _convert_file_to_video_url(
+ self, content_item: ChatCompletionFileObject
+ ) -> ChatCompletionVideoObject:
+ file = content_item.get("file", {})
+ file_id = file.get("file_id")
+ file_data = file.get("file_data")
+
+ if file_id:
+ return ChatCompletionVideoObject(
+ type="video_url", video_url=ChatCompletionVideoUrlObject(url=file_id)
+ )
+ elif file_data:
+ return ChatCompletionVideoObject(
+ type="video_url", video_url=ChatCompletionVideoUrlObject(url=file_data)
+ )
+ raise ValueError("file_id or file_data is required")
+
+ def _transform_messages(
+ self, messages: List[AllMessageValues], model: str
+ ) -> List[AllMessageValues]:
+ """
+ Support translating video files from file_id or file_data to video_url
+ """
+ for message in messages:
+ if message["role"] == "user":
+ message_content = message.get("content")
+ if message_content and isinstance(message_content, list):
+ replaced_content_items: List[
+ Tuple[int, ChatCompletionFileObject]
+ ] = []
+ for idx, content_item in enumerate(message_content):
+ if content_item.get("type") == "file":
+ content_item = cast(ChatCompletionFileObject, content_item)
+ if self._is_video_file(content_item):
+ replaced_content_items.append((idx, content_item))
+ for idx, content_item in replaced_content_items:
+ message_content[idx] = self._convert_file_to_video_url(
+ content_item
+ )
+ transformed_messages = super()._transform_messages(messages, model)
+ return transformed_messages
diff --git a/litellm/llms/infinity/rerank/common_utils.py b/litellm/llms/infinity/common_utils.py
similarity index 76%
rename from litellm/llms/infinity/rerank/common_utils.py
rename to litellm/llms/infinity/common_utils.py
index 99477d1a33..089818c829 100644
--- a/litellm/llms/infinity/rerank/common_utils.py
+++ b/litellm/llms/infinity/common_utils.py
@@ -1,10 +1,16 @@
+from typing import Union
import httpx
from litellm.llms.base_llm.chat.transformation import BaseLLMException
class InfinityError(BaseLLMException):
- def __init__(self, status_code, message):
+ def __init__(
+ self,
+ status_code: int,
+ message: str,
+ headers: Union[dict, httpx.Headers] = {}
+ ):
self.status_code = status_code
self.message = message
self.request = httpx.Request(
@@ -16,4 +22,5 @@ class InfinityError(BaseLLMException):
message=message,
request=self.request,
response=self.response,
+ headers=headers,
) # Call the base class constructor with the parameters it needs
diff --git a/litellm/llms/infinity/embedding/handler.py b/litellm/llms/infinity/embedding/handler.py
new file mode 100644
index 0000000000..cdcb99c433
--- /dev/null
+++ b/litellm/llms/infinity/embedding/handler.py
@@ -0,0 +1,5 @@
+"""
+Infinity Embedding - uses `llm_http_handler.py` to make httpx requests
+
+Request/Response transformation is handled in `transformation.py`
+"""
diff --git a/litellm/llms/infinity/embedding/transformation.py b/litellm/llms/infinity/embedding/transformation.py
new file mode 100644
index 0000000000..824dcd38da
--- /dev/null
+++ b/litellm/llms/infinity/embedding/transformation.py
@@ -0,0 +1,141 @@
+from typing import List, Optional, Union
+
+import httpx
+
+from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
+from litellm.llms.base_llm.chat.transformation import BaseLLMException
+from litellm.llms.base_llm.embedding.transformation import BaseEmbeddingConfig
+from litellm.secret_managers.main import get_secret_str
+from litellm.types.llms.openai import AllEmbeddingInputValues, AllMessageValues
+from litellm.types.utils import EmbeddingResponse, Usage
+
+from ..common_utils import InfinityError
+
+
+class InfinityEmbeddingConfig(BaseEmbeddingConfig):
+ """
+ Reference: https://infinity.modal.michaelfeil.eu/docs
+ """
+
+ def __init__(self) -> None:
+ pass
+
+ def get_complete_url(
+ self,
+ api_base: Optional[str],
+ api_key: Optional[str],
+ model: str,
+ optional_params: dict,
+ litellm_params: dict,
+ stream: Optional[bool] = None,
+ ) -> str:
+ if api_base is None:
+ raise ValueError("api_base is required for Infinity embeddings")
+ # Remove trailing slashes and ensure clean base URL
+ api_base = api_base.rstrip("/")
+ if not api_base.endswith("/embeddings"):
+ api_base = f"{api_base}/embeddings"
+ return api_base
+
+ def validate_environment(
+ self,
+ headers: dict,
+ model: str,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ api_key: Optional[str] = None,
+ api_base: Optional[str] = None,
+ ) -> dict:
+ if api_key is None:
+ api_key = get_secret_str("INFINITY_API_KEY")
+
+ default_headers = {
+ "Authorization": f"Bearer {api_key}",
+ "accept": "application/json",
+ "Content-Type": "application/json",
+ }
+
+ # If 'Authorization' is provided in headers, it overrides the default.
+ if "Authorization" in headers:
+ default_headers["Authorization"] = headers["Authorization"]
+
+ # Merge other headers, overriding any default ones except Authorization
+ return {**default_headers, **headers}
+
+ def get_supported_openai_params(self, model: str) -> list:
+ return [
+ "encoding_format",
+ "modality",
+ "dimensions",
+ ]
+
+ def map_openai_params(
+ self,
+ non_default_params: dict,
+ optional_params: dict,
+ model: str,
+ drop_params: bool,
+ ) -> dict:
+ """
+ Map OpenAI params to Infinity params
+
+ Reference: https://infinity.modal.michaelfeil.eu/docs
+ """
+ if "encoding_format" in non_default_params:
+ optional_params["encoding_format"] = non_default_params["encoding_format"]
+ if "modality" in non_default_params:
+ optional_params["modality"] = non_default_params["modality"]
+ if "dimensions" in non_default_params:
+ optional_params["output_dimension"] = non_default_params["dimensions"]
+ return optional_params
+
+ def transform_embedding_request(
+ self,
+ model: str,
+ input: AllEmbeddingInputValues,
+ optional_params: dict,
+ headers: dict,
+ ) -> dict:
+ return {
+ "input": input,
+ "model": model,
+ **optional_params,
+ }
+
+ def transform_embedding_response(
+ self,
+ model: str,
+ raw_response: httpx.Response,
+ model_response: EmbeddingResponse,
+ logging_obj: LiteLLMLoggingObj,
+ api_key: Optional[str] = None,
+ request_data: dict = {},
+ optional_params: dict = {},
+ litellm_params: dict = {},
+ ) -> EmbeddingResponse:
+ try:
+ raw_response_json = raw_response.json()
+ except Exception:
+ raise InfinityError(
+ message=raw_response.text, status_code=raw_response.status_code
+ )
+
+ # model_response.usage
+ model_response.model = raw_response_json.get("model")
+ model_response.data = raw_response_json.get("data")
+ model_response.object = raw_response_json.get("object")
+
+ usage = Usage(
+ prompt_tokens=raw_response_json.get("usage", {}).get("prompt_tokens", 0),
+ total_tokens=raw_response_json.get("usage", {}).get("total_tokens", 0),
+ )
+ model_response.usage = usage
+ return model_response
+
+ def get_error_class(
+ self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers]
+ ) -> BaseLLMException:
+ return InfinityError(
+ message=error_message, status_code=status_code, headers=headers
+ )
diff --git a/litellm/llms/infinity/rerank/transformation.py b/litellm/llms/infinity/rerank/transformation.py
index 1e7234ab17..4b75fa121b 100644
--- a/litellm/llms/infinity/rerank/transformation.py
+++ b/litellm/llms/infinity/rerank/transformation.py
@@ -22,7 +22,7 @@ from litellm.types.rerank import (
RerankTokens,
)
-from .common_utils import InfinityError
+from ..common_utils import InfinityError
class InfinityRerankConfig(CohereRerankConfig):
diff --git a/litellm/llms/litellm_proxy/chat/transformation.py b/litellm/llms/litellm_proxy/chat/transformation.py
index 6699ef70d4..22013198ba 100644
--- a/litellm/llms/litellm_proxy/chat/transformation.py
+++ b/litellm/llms/litellm_proxy/chat/transformation.py
@@ -13,6 +13,7 @@ class LiteLLMProxyChatConfig(OpenAIGPTConfig):
def get_supported_openai_params(self, model: str) -> List:
list = super().get_supported_openai_params(model)
list.append("thinking")
+ list.append("reasoning_effort")
return list
def _map_openai_params(
diff --git a/litellm/llms/openai/chat/gpt_transformation.py b/litellm/llms/openai/chat/gpt_transformation.py
index 03257e50f0..e8f60357a6 100644
--- a/litellm/llms/openai/chat/gpt_transformation.py
+++ b/litellm/llms/openai/chat/gpt_transformation.py
@@ -389,7 +389,7 @@ class OpenAIGPTConfig(BaseLLMModelInfo, BaseConfig):
)
@staticmethod
- def get_base_model(model: str) -> str:
+ def get_base_model(model: Optional[str] = None) -> Optional[str]:
return model
def get_model_response_iterator(
diff --git a/litellm/llms/openai/chat/o_series_transformation.py b/litellm/llms/openai/chat/o_series_transformation.py
index b2ffda6e7d..c9a700face 100644
--- a/litellm/llms/openai/chat/o_series_transformation.py
+++ b/litellm/llms/openai/chat/o_series_transformation.py
@@ -131,7 +131,10 @@ class OpenAIOSeriesConfig(OpenAIGPTConfig):
def is_model_o_series_model(self, model: str) -> bool:
if model in litellm.open_ai_chat_completion_models and (
- "o1" in model or "o3" in model
+ "o1" in model
+ or "o3" in model
+ or "o4"
+ in model # [TODO] make this a more generic check (e.g. using `openai-o-series` as provider like gemini)
):
return True
return False
diff --git a/litellm/llms/openai/responses/transformation.py b/litellm/llms/openai/responses/transformation.py
index e062c0c9fa..d4a443aedb 100644
--- a/litellm/llms/openai/responses/transformation.py
+++ b/litellm/llms/openai/responses/transformation.py
@@ -7,6 +7,7 @@ from litellm._logging import verbose_logger
from litellm.llms.base_llm.responses.transformation import BaseResponsesAPIConfig
from litellm.secret_managers.main import get_secret_str
from litellm.types.llms.openai import *
+from litellm.types.responses.main import *
from litellm.types.router import GenericLiteLLMParams
from ..common_utils import OpenAIError
@@ -110,8 +111,7 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig):
def get_complete_url(
self,
api_base: Optional[str],
- model: str,
- stream: Optional[bool] = None,
+ litellm_params: dict,
) -> str:
"""
Get the endpoint for OpenAI responses API
@@ -214,3 +214,39 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig):
f"Error getting model info in OpenAIResponsesAPIConfig: {e}"
)
return False
+
+ #########################################################
+ ########## DELETE RESPONSE API TRANSFORMATION ##############
+ #########################################################
+ def transform_delete_response_api_request(
+ self,
+ response_id: str,
+ api_base: str,
+ litellm_params: GenericLiteLLMParams,
+ headers: dict,
+ ) -> Tuple[str, Dict]:
+ """
+ Transform the delete response API request into a URL and data
+
+ OpenAI API expects the following request
+ - DELETE /v1/responses/{response_id}
+ """
+ url = f"{api_base}/{response_id}"
+ data: Dict = {}
+ return url, data
+
+ def transform_delete_response_api_response(
+ self,
+ raw_response: httpx.Response,
+ logging_obj: LiteLLMLoggingObj,
+ ) -> DeleteResponseResult:
+ """
+ Transform the delete response API response into a DeleteResponseResult
+ """
+ try:
+ raw_response_json = raw_response.json()
+ except Exception:
+ raise OpenAIError(
+ message=raw_response.text, status_code=raw_response.status_code
+ )
+ return DeleteResponseResult(**raw_response_json)
diff --git a/litellm/llms/openai_like/chat/transformation.py b/litellm/llms/openai_like/chat/transformation.py
index ea9757a855..068d3d8dfd 100644
--- a/litellm/llms/openai_like/chat/transformation.py
+++ b/litellm/llms/openai_like/chat/transformation.py
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Union
import httpx
from litellm.secret_managers.main import get_secret_str
-from litellm.types.llms.openai import ChatCompletionAssistantMessage
+from litellm.types.llms.openai import AllMessageValues, ChatCompletionAssistantMessage
from litellm.types.utils import ModelResponse
from ...openai.chat.gpt_transformation import OpenAIGPTConfig
@@ -25,7 +25,6 @@ class OpenAILikeChatConfig(OpenAIGPTConfig):
self,
api_base: Optional[str],
api_key: Optional[str],
- model: Optional[str] = None,
) -> Tuple[Optional[str], Optional[str]]:
api_base = api_base or get_secret_str("OPENAI_LIKE_API_BASE") # type: ignore
dynamic_api_key = (
@@ -74,8 +73,8 @@ class OpenAILikeChatConfig(OpenAIGPTConfig):
messages: List,
print_verbose,
encoding,
- json_mode: bool,
- custom_llm_provider: str,
+ json_mode: Optional[bool],
+ custom_llm_provider: Optional[str],
base_model: Optional[str],
) -> ModelResponse:
response_json = response.json()
@@ -97,14 +96,46 @@ class OpenAILikeChatConfig(OpenAIGPTConfig):
returned_response = ModelResponse(**response_json)
- returned_response.model = (
- custom_llm_provider + "/" + (returned_response.model or "")
- )
+ if custom_llm_provider is not None:
+ returned_response.model = (
+ custom_llm_provider + "/" + (returned_response.model or "")
+ )
if base_model is not None:
returned_response._hidden_params["model"] = base_model
return returned_response
+ def transform_response(
+ self,
+ model: str,
+ raw_response: httpx.Response,
+ model_response: ModelResponse,
+ logging_obj: LiteLLMLoggingObj,
+ request_data: dict,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ encoding: Any,
+ api_key: Optional[str] = None,
+ json_mode: Optional[bool] = None,
+ ) -> ModelResponse:
+ return OpenAILikeChatConfig._transform_response(
+ model=model,
+ response=raw_response,
+ model_response=model_response,
+ stream=optional_params.get("stream", False),
+ logging_obj=logging_obj,
+ optional_params=optional_params,
+ api_key=api_key,
+ data=request_data,
+ messages=messages,
+ print_verbose=None,
+ encoding=None,
+ json_mode=json_mode,
+ custom_llm_provider=None,
+ base_model=None,
+ )
+
def map_openai_params(
self,
non_default_params: dict,
diff --git a/litellm/llms/topaz/common_utils.py b/litellm/llms/topaz/common_utils.py
index 0252585922..95fe291493 100644
--- a/litellm/llms/topaz/common_utils.py
+++ b/litellm/llms/topaz/common_utils.py
@@ -1,6 +1,7 @@
from typing import List, Optional
from litellm.secret_managers.main import get_secret_str
+from litellm.types.llms.openai import AllMessageValues
from ..base_llm.base_utils import BaseLLMModelInfo
from ..base_llm.chat.transformation import BaseLLMException
@@ -11,6 +12,26 @@ class TopazException(BaseLLMException):
class TopazModelInfo(BaseLLMModelInfo):
+ def validate_environment(
+ self,
+ headers: dict,
+ model: str,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ api_key: Optional[str] = None,
+ api_base: Optional[str] = None,
+ ) -> dict:
+ if api_key is None:
+ raise ValueError(
+ "API key is required for Topaz image variations. Set via `TOPAZ_API_KEY` or `api_key=..`"
+ )
+ return {
+ # "Content-Type": "multipart/form-data",
+ "Accept": "image/jpeg",
+ "X-API-Key": api_key,
+ }
+
def get_models(
self, api_key: Optional[str] = None, api_base: Optional[str] = None
) -> List[str]:
diff --git a/litellm/llms/topaz/image_variations/transformation.py b/litellm/llms/topaz/image_variations/transformation.py
index afbd89b9bc..41b51a558c 100644
--- a/litellm/llms/topaz/image_variations/transformation.py
+++ b/litellm/llms/topaz/image_variations/transformation.py
@@ -10,10 +10,7 @@ from litellm.llms.base_llm.chat.transformation import (
BaseLLMException,
LiteLLMLoggingObj,
)
-from litellm.types.llms.openai import (
- AllMessageValues,
- OpenAIImageVariationOptionalParams,
-)
+from litellm.types.llms.openai import OpenAIImageVariationOptionalParams
from litellm.types.utils import (
FileTypes,
HttpHandlerRequestFields,
@@ -22,35 +19,15 @@ from litellm.types.utils import (
)
from ...base_llm.image_variations.transformation import BaseImageVariationConfig
-from ..common_utils import TopazException
+from ..common_utils import TopazException, TopazModelInfo
-class TopazImageVariationConfig(BaseImageVariationConfig):
+class TopazImageVariationConfig(TopazModelInfo, BaseImageVariationConfig):
def get_supported_openai_params(
self, model: str
) -> List[OpenAIImageVariationOptionalParams]:
return ["response_format", "size"]
- def validate_environment(
- self,
- headers: dict,
- model: str,
- messages: List[AllMessageValues],
- optional_params: dict,
- litellm_params: dict,
- api_key: Optional[str] = None,
- api_base: Optional[str] = None,
- ) -> dict:
- if api_key is None:
- raise ValueError(
- "API key is required for Topaz image variations. Set via `TOPAZ_API_KEY` or `api_key=..`"
- )
- return {
- # "Content-Type": "multipart/form-data",
- "Accept": "image/jpeg",
- "X-API-Key": api_key,
- }
-
def get_complete_url(
self,
api_base: Optional[str],
diff --git a/litellm/llms/triton/completion/transformation.py b/litellm/llms/triton/completion/transformation.py
index 21fcf2eefb..0db83b2d3d 100644
--- a/litellm/llms/triton/completion/transformation.py
+++ b/litellm/llms/triton/completion/transformation.py
@@ -201,8 +201,6 @@ class TritonGenerateConfig(TritonConfig):
"max_tokens": int(
optional_params.get("max_tokens", DEFAULT_MAX_TOKENS_FOR_TRITON)
),
- "bad_words": [""],
- "stop_words": [""],
},
"stream": bool(stream),
}
diff --git a/litellm/llms/vertex_ai/common_utils.py b/litellm/llms/vertex_ai/common_utils.py
index be8e4749dd..314fb81901 100644
--- a/litellm/llms/vertex_ai/common_utils.py
+++ b/litellm/llms/vertex_ai/common_utils.py
@@ -1,5 +1,5 @@
-from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union, get_type_hints
import re
+from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union, get_type_hints
import httpx
@@ -165,9 +165,18 @@ def _check_text_in_content(parts: List[PartType]) -> bool:
return has_text_param
-def _build_vertex_schema(parameters: dict):
+def _build_vertex_schema(parameters: dict, add_property_ordering: bool = False):
"""
This is a modified version of https://github.com/google-gemini/generative-ai-python/blob/8f77cc6ac99937cd3a81299ecf79608b91b06bbb/google/generativeai/types/content_types.py#L419
+
+ Updates the input parameters, removing extraneous fields, adjusting types, unwinding $defs, and adding propertyOrdering if specified, returning the updated parameters.
+
+ Parameters:
+ parameters: dict - the json schema to build from
+ add_property_ordering: bool - whether to add propertyOrdering to the schema. This is only applicable to schemas for structured outputs. See
+ set_schema_property_ordering for more details.
+ Returns:
+ parameters: dict - the input parameters, modified in place
"""
# Get valid fields from Schema TypedDict
valid_schema_fields = set(get_type_hints(Schema).keys())
@@ -186,8 +195,40 @@ def _build_vertex_schema(parameters: dict):
add_object_type(parameters)
# Postprocessing
# Filter out fields that don't exist in Schema
- filtered_parameters = filter_schema_fields(parameters, valid_schema_fields)
- return filtered_parameters
+ parameters = filter_schema_fields(parameters, valid_schema_fields)
+
+ if add_property_ordering:
+ set_schema_property_ordering(parameters)
+ return parameters
+
+
+def set_schema_property_ordering(
+ schema: Dict[str, Any], depth: int = 0
+) -> Dict[str, Any]:
+ """
+ vertex ai and generativeai apis order output of fields alphabetically, unless you specify the order.
+ python dicts retain order, so we just use that. Note that this field only applies to structured outputs, and not tools.
+ Function tools are not afflicted by the same alphabetical ordering issue, (the order of keys returned seems to be arbitrary, up to the model)
+ https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.cachedContents#Schema.FIELDS.property_ordering
+
+ Args:
+ schema: The schema dictionary to process
+ depth: Current recursion depth to prevent infinite loops
+ """
+ if depth > DEFAULT_MAX_RECURSE_DEPTH:
+ raise ValueError(
+ f"Max depth of {DEFAULT_MAX_RECURSE_DEPTH} exceeded while processing schema. Please check the schema for excessive nesting."
+ )
+
+ if "properties" in schema and isinstance(schema["properties"], dict):
+ # retain propertyOrdering as an escape hatch if user already specifies it
+ if "propertyOrdering" not in schema:
+ schema["propertyOrdering"] = [k for k, v in schema["properties"].items()]
+ for k, v in schema["properties"].items():
+ set_schema_property_ordering(v, depth + 1)
+ if "items" in schema:
+ set_schema_property_ordering(schema["items"], depth + 1)
+ return schema
def filter_schema_fields(
@@ -360,6 +401,7 @@ def construct_target_url(
Constructed Url:
POST https://LOCATION-aiplatform.googleapis.com/{version}/projects/PROJECT_ID/locations/LOCATION/cachedContents
"""
+
new_base_url = httpx.URL(base_url)
if "locations" in requested_route: # contains the target project id + location
if vertex_project and vertex_location:
diff --git a/litellm/llms/vertex_ai/gemini/transformation.py b/litellm/llms/vertex_ai/gemini/transformation.py
index 0afad13feb..e50954b8f9 100644
--- a/litellm/llms/vertex_ai/gemini/transformation.py
+++ b/litellm/llms/vertex_ai/gemini/transformation.py
@@ -12,6 +12,9 @@ from pydantic import BaseModel
import litellm
from litellm._logging import verbose_logger
+from litellm.litellm_core_utils.prompt_templates.common_utils import (
+ _get_image_mime_type_from_url,
+)
from litellm.litellm_core_utils.prompt_templates.factory import (
convert_to_anthropic_image_obj,
convert_to_gemini_tool_call_invoke,
@@ -99,62 +102,6 @@ def _process_gemini_image(image_url: str, format: Optional[str] = None) -> PartT
raise e
-def _get_image_mime_type_from_url(url: str) -> Optional[str]:
- """
- Get mime type for common image URLs
- See gemini mime types: https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/image-understanding#image-requirements
-
- Supported by Gemini:
- application/pdf
- audio/mpeg
- audio/mp3
- audio/wav
- image/png
- image/jpeg
- image/webp
- text/plain
- video/mov
- video/mpeg
- video/mp4
- video/mpg
- video/avi
- video/wmv
- video/mpegps
- video/flv
- """
- url = url.lower()
-
- # Map file extensions to mime types
- mime_types = {
- # Images
- (".jpg", ".jpeg"): "image/jpeg",
- (".png",): "image/png",
- (".webp",): "image/webp",
- # Videos
- (".mp4",): "video/mp4",
- (".mov",): "video/mov",
- (".mpeg", ".mpg"): "video/mpeg",
- (".avi",): "video/avi",
- (".wmv",): "video/wmv",
- (".mpegps",): "video/mpegps",
- (".flv",): "video/flv",
- # Audio
- (".mp3",): "audio/mp3",
- (".wav",): "audio/wav",
- (".mpeg",): "audio/mpeg",
- # Documents
- (".pdf",): "application/pdf",
- (".txt",): "text/plain",
- }
-
- # Check each extension group against the URL
- for extensions, mime_type in mime_types.items():
- if any(url.endswith(ext) for ext in extensions):
- return mime_type
-
- return None
-
-
def _gemini_convert_messages_with_history( # noqa: PLR0915
messages: List[AllMessageValues],
) -> List[ContentType]:
@@ -269,6 +216,11 @@ def _gemini_convert_messages_with_history( # noqa: PLR0915
msg_dict = messages[msg_i] # type: ignore
assistant_msg = ChatCompletionAssistantMessage(**msg_dict) # type: ignore
_message_content = assistant_msg.get("content", None)
+ reasoning_content = assistant_msg.get("reasoning_content", None)
+ if reasoning_content is not None:
+ assistant_content.append(
+ PartType(thought=True, text=reasoning_content)
+ )
if _message_content is not None and isinstance(_message_content, list):
_parts = []
for element in _message_content:
@@ -276,6 +228,7 @@ def _gemini_convert_messages_with_history( # noqa: PLR0915
if element["type"] == "text":
_part = PartType(text=element["text"])
_parts.append(_part)
+
assistant_content.extend(_parts)
elif (
_message_content is not None
diff --git a/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py b/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py
index c57090093b..9ea1c2ee12 100644
--- a/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py
+++ b/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py
@@ -24,6 +24,11 @@ import litellm
import litellm.litellm_core_utils
import litellm.litellm_core_utils.litellm_logging
from litellm import verbose_logger
+from litellm.constants import (
+ DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
+ DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
+ DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
+)
from litellm.litellm_core_utils.core_helpers import map_finish_reason
from litellm.llms.base_llm.chat.transformation import BaseConfig, BaseLLMException
from litellm.llms.custom_httpx.http_handler import (
@@ -31,6 +36,7 @@ from litellm.llms.custom_httpx.http_handler import (
HTTPHandler,
get_async_httpx_client,
)
+from litellm.types.llms.anthropic import AnthropicThinkingParam
from litellm.types.llms.openai import (
AllMessageValues,
ChatCompletionResponseMessage,
@@ -45,11 +51,13 @@ from litellm.types.llms.vertex_ai import (
ContentType,
FunctionCallingConfig,
FunctionDeclaration,
+ GeminiThinkingConfig,
GenerateContentResponseBody,
HttpxPartType,
LogprobsResult,
ToolConfig,
Tools,
+ UsageMetadata,
)
from litellm.types.utils import (
ChatCompletionTokenLogprob,
@@ -59,7 +67,7 @@ from litellm.types.utils import (
TopLogprob,
Usage,
)
-from litellm.utils import CustomStreamWrapper, ModelResponse
+from litellm.utils import CustomStreamWrapper, ModelResponse, supports_reasoning
from ....utils import _remove_additional_properties, _remove_strict_from_schema
from ..common_utils import VertexAIError, _build_vertex_schema
@@ -190,7 +198,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
return super().get_config()
def get_supported_openai_params(self, model: str) -> List[str]:
- return [
+ supported_params = [
"temperature",
"top_p",
"max_tokens",
@@ -207,9 +215,13 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
"extra_headers",
"seed",
"logprobs",
- "top_logprobs", # Added this to list of supported openAI params
+ "top_logprobs",
"modalities",
]
+ if supports_reasoning(model):
+ supported_params.append("reasoning_effort")
+ supported_params.append("thinking")
+ return supported_params
def map_tool_choice_values(
self, model: str, tool_choice: Union[str, dict]
@@ -313,9 +325,14 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
if isinstance(old_schema, list):
for item in old_schema:
if isinstance(item, dict):
- item = _build_vertex_schema(parameters=item)
+ item = _build_vertex_schema(
+ parameters=item, add_property_ordering=True
+ )
+
elif isinstance(old_schema, dict):
- old_schema = _build_vertex_schema(parameters=old_schema)
+ old_schema = _build_vertex_schema(
+ parameters=old_schema, add_property_ordering=True
+ )
return old_schema
def apply_response_schema_transformation(self, value: dict, optional_params: dict):
@@ -342,6 +359,43 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
value=optional_params["response_schema"]
)
+ @staticmethod
+ def _map_reasoning_effort_to_thinking_budget(
+ reasoning_effort: str,
+ ) -> GeminiThinkingConfig:
+ if reasoning_effort == "low":
+ return {
+ "thinkingBudget": DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
+ "includeThoughts": True,
+ }
+ elif reasoning_effort == "medium":
+ return {
+ "thinkingBudget": DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
+ "includeThoughts": True,
+ }
+ elif reasoning_effort == "high":
+ return {
+ "thinkingBudget": DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
+ "includeThoughts": True,
+ }
+ else:
+ raise ValueError(f"Invalid reasoning effort: {reasoning_effort}")
+
+ @staticmethod
+ def _map_thinking_param(
+ thinking_param: AnthropicThinkingParam,
+ ) -> GeminiThinkingConfig:
+ thinking_enabled = thinking_param.get("type") == "enabled"
+ thinking_budget = thinking_param.get("budget_tokens")
+
+ params: GeminiThinkingConfig = {}
+ if thinking_enabled:
+ params["includeThoughts"] = True
+ if thinking_budget is not None and isinstance(thinking_budget, int):
+ params["thinkingBudget"] = thinking_budget
+
+ return params
+
def map_openai_params(
self,
non_default_params: Dict,
@@ -398,6 +452,16 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
optional_params["tool_choice"] = _tool_choice_value
elif param == "seed":
optional_params["seed"] = value
+ elif param == "reasoning_effort" and isinstance(value, str):
+ optional_params[
+ "thinkingConfig"
+ ] = VertexGeminiConfig._map_reasoning_effort_to_thinking_budget(value)
+ elif param == "thinking":
+ optional_params[
+ "thinkingConfig"
+ ] = VertexGeminiConfig._map_thinking_param(
+ cast(AnthropicThinkingParam, value)
+ )
elif param == "modalities" and isinstance(value, list):
response_modalities = []
for modality in value:
@@ -513,19 +577,28 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
def get_assistant_content_message(
self, parts: List[HttpxPartType]
- ) -> Optional[str]:
- _content_str = ""
+ ) -> Tuple[Optional[str], Optional[str]]:
+ content_str: Optional[str] = None
+ reasoning_content_str: Optional[str] = None
for part in parts:
+ _content_str = ""
if "text" in part:
_content_str += part["text"]
elif "inlineData" in part: # base64 encoded image
_content_str += "data:{};base64,{}".format(
part["inlineData"]["mimeType"], part["inlineData"]["data"]
)
+ if len(_content_str) > 0:
+ if part.get("thought") is True:
+ if reasoning_content_str is None:
+ reasoning_content_str = ""
+ reasoning_content_str += _content_str
+ else:
+ if content_str is None:
+ content_str = ""
+ content_str += _content_str
- if _content_str:
- return _content_str
- return None
+ return content_str, reasoning_content_str
def _transform_parts(
self,
@@ -668,6 +741,23 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
return model_response
+ def is_candidate_token_count_inclusive(self, usage_metadata: UsageMetadata) -> bool:
+ """
+ Check if the candidate token count is inclusive of the thinking token count
+
+ if prompttokencount + candidatesTokenCount == totalTokenCount, then the candidate token count is inclusive of the thinking token count
+
+ else the candidate token count is exclusive of the thinking token count
+
+ Addresses - https://github.com/BerriAI/litellm/pull/10141#discussion_r2052272035
+ """
+ if usage_metadata.get("promptTokenCount", 0) + usage_metadata.get(
+ "candidatesTokenCount", 0
+ ) == usage_metadata.get("totalTokenCount", 0):
+ return True
+ else:
+ return False
+
def _calculate_usage(
self,
completion_response: GenerateContentResponseBody,
@@ -676,6 +766,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
audio_tokens: Optional[int] = None
text_tokens: Optional[int] = None
prompt_tokens_details: Optional[PromptTokensDetailsWrapper] = None
+ reasoning_tokens: Optional[int] = None
if "cachedContentTokenCount" in completion_response["usageMetadata"]:
cached_tokens = completion_response["usageMetadata"][
"cachedContentTokenCount"
@@ -686,22 +777,35 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
audio_tokens = detail["tokenCount"]
elif detail["modality"] == "TEXT":
text_tokens = detail["tokenCount"]
-
+ if "thoughtsTokenCount" in completion_response["usageMetadata"]:
+ reasoning_tokens = completion_response["usageMetadata"][
+ "thoughtsTokenCount"
+ ]
prompt_tokens_details = PromptTokensDetailsWrapper(
cached_tokens=cached_tokens,
audio_tokens=audio_tokens,
text_tokens=text_tokens,
)
+
+ completion_tokens = completion_response["usageMetadata"].get(
+ "candidatesTokenCount", 0
+ )
+ if (
+ not self.is_candidate_token_count_inclusive(
+ completion_response["usageMetadata"]
+ )
+ and reasoning_tokens
+ ):
+ completion_tokens = reasoning_tokens + completion_tokens
## GET USAGE ##
usage = Usage(
prompt_tokens=completion_response["usageMetadata"].get(
"promptTokenCount", 0
),
- completion_tokens=completion_response["usageMetadata"].get(
- "candidatesTokenCount", 0
- ),
+ completion_tokens=completion_tokens,
total_tokens=completion_response["usageMetadata"].get("totalTokenCount", 0),
prompt_tokens_details=prompt_tokens_details,
+ reasoning_tokens=reasoning_tokens,
)
return usage
@@ -730,11 +834,16 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
citation_metadata.append(candidate["citationMetadata"])
if "parts" in candidate["content"]:
- chat_completion_message[
- "content"
- ] = VertexGeminiConfig().get_assistant_content_message(
+ (
+ content,
+ reasoning_content,
+ ) = VertexGeminiConfig().get_assistant_content_message(
parts=candidate["content"]["parts"]
)
+ if content is not None:
+ chat_completion_message["content"] = content
+ if reasoning_content is not None:
+ chat_completion_message["reasoning_content"] = reasoning_content
functions, tools = self._transform_parts(
parts=candidate["content"]["parts"],
diff --git a/litellm/llms/vllm/common_utils.py b/litellm/llms/vllm/common_utils.py
new file mode 100644
index 0000000000..8dca3e1de2
--- /dev/null
+++ b/litellm/llms/vllm/common_utils.py
@@ -0,0 +1,75 @@
+from typing import List, Optional, Union
+
+import httpx
+
+import litellm
+from litellm.llms.base_llm.base_utils import BaseLLMModelInfo
+from litellm.llms.base_llm.chat.transformation import BaseLLMException
+from litellm.secret_managers.main import get_secret_str
+from litellm.types.llms.openai import AllMessageValues
+from litellm.utils import _add_path_to_api_base
+
+
+class VLLMError(BaseLLMException):
+ pass
+
+
+class VLLMModelInfo(BaseLLMModelInfo):
+ def validate_environment(
+ self,
+ headers: dict,
+ model: str,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ api_key: Optional[str] = None,
+ api_base: Optional[str] = None,
+ ) -> dict:
+ """Google AI Studio sends api key in query params"""
+ return headers
+
+ @staticmethod
+ def get_api_base(api_base: Optional[str] = None) -> Optional[str]:
+ api_base = api_base or get_secret_str("VLLM_API_BASE")
+ if api_base is None:
+ raise ValueError(
+ "VLLM_API_BASE is not set. Please set the environment variable, to use VLLM's pass-through - `{LITELLM_API_BASE}/vllm/{endpoint}`."
+ )
+ return api_base
+
+ @staticmethod
+ def get_api_key(api_key: Optional[str] = None) -> Optional[str]:
+ return None
+
+ @staticmethod
+ def get_base_model(model: str) -> Optional[str]:
+ return model
+
+ def get_models(
+ self, api_key: Optional[str] = None, api_base: Optional[str] = None
+ ) -> List[str]:
+ api_base = VLLMModelInfo.get_api_base(api_base)
+ api_key = VLLMModelInfo.get_api_key(api_key)
+ endpoint = "/v1/models"
+ if api_base is None or api_key is None:
+ raise ValueError(
+ "GEMINI_API_BASE or GEMINI_API_KEY is not set. Please set the environment variable, to query Gemini's `/models` endpoint."
+ )
+
+ url = _add_path_to_api_base(api_base, endpoint)
+ response = litellm.module_level_client.get(
+ url=url,
+ )
+
+ response.raise_for_status()
+
+ models = response.json()["data"]
+
+ return [model["id"] for model in models]
+
+ def get_error_class(
+ self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers]
+ ) -> BaseLLMException:
+ return VLLMError(
+ status_code=status_code, message=error_message, headers=headers
+ )
diff --git a/litellm/llms/watsonx/common_utils.py b/litellm/llms/watsonx/common_utils.py
index e13e015add..d6f296c608 100644
--- a/litellm/llms/watsonx/common_utils.py
+++ b/litellm/llms/watsonx/common_utils.py
@@ -38,7 +38,7 @@ def generate_iam_token(api_key=None, **params) -> str:
headers = {}
headers["Content-Type"] = "application/x-www-form-urlencoded"
if api_key is None:
- api_key = get_secret_str("WX_API_KEY") or get_secret_str("WATSONX_API_KEY")
+ api_key = get_secret_str("WX_API_KEY") or get_secret_str("WATSONX_API_KEY") or get_secret_str("WATSONX_APIKEY")
if api_key is None:
raise ValueError("API key is required")
headers["Accept"] = "application/json"
diff --git a/litellm/llms/xai/common_utils.py b/litellm/llms/xai/common_utils.py
index d7ceeadd95..a26dc1e043 100644
--- a/litellm/llms/xai/common_utils.py
+++ b/litellm/llms/xai/common_utils.py
@@ -5,9 +5,29 @@ import httpx
import litellm
from litellm.llms.base_llm.base_utils import BaseLLMModelInfo
from litellm.secret_managers.main import get_secret_str
+from litellm.types.llms.openai import AllMessageValues
class XAIModelInfo(BaseLLMModelInfo):
+ def validate_environment(
+ self,
+ headers: dict,
+ model: str,
+ messages: List[AllMessageValues],
+ optional_params: dict,
+ litellm_params: dict,
+ api_key: Optional[str] = None,
+ api_base: Optional[str] = None,
+ ) -> dict:
+ if api_key is not None:
+ headers["Authorization"] = f"Bearer {api_key}"
+
+ # Ensure Content-Type is set to application/json
+ if "content-type" not in headers and "Content-Type" not in headers:
+ headers["Content-Type"] = "application/json"
+
+ return headers
+
@staticmethod
def get_api_base(api_base: Optional[str] = None) -> Optional[str]:
return api_base or get_secret_str("XAI_API_BASE") or "https://api.x.ai"
diff --git a/litellm/main.py b/litellm/main.py
index 3f1d9a1e76..80486fbe02 100644
--- a/litellm/main.py
+++ b/litellm/main.py
@@ -954,7 +954,11 @@ def completion( # type: ignore # noqa: PLR0915
non_default_params = get_non_default_completion_params(kwargs=kwargs)
litellm_params = {} # used to prevent unbound var errors
## PROMPT MANAGEMENT HOOKS ##
- if isinstance(litellm_logging_obj, LiteLLMLoggingObj) and prompt_id is not None:
+ if isinstance(litellm_logging_obj, LiteLLMLoggingObj) and (
+ litellm_logging_obj.should_run_prompt_management_hooks(
+ prompt_id=prompt_id, non_default_params=non_default_params
+ )
+ ):
(
model,
messages,
@@ -1431,6 +1435,7 @@ def completion( # type: ignore # noqa: PLR0915
custom_llm_provider=custom_llm_provider,
encoding=encoding,
stream=stream,
+ provider_config=provider_config,
)
except Exception as e:
## LOGGING - log the original exception returned
@@ -1592,6 +1597,37 @@ def completion( # type: ignore # noqa: PLR0915
additional_args={"headers": headers},
)
response = _response
+ elif custom_llm_provider == "fireworks_ai":
+ ## COMPLETION CALL
+ try:
+ response = base_llm_http_handler.completion(
+ model=model,
+ messages=messages,
+ headers=headers,
+ model_response=model_response,
+ api_key=api_key,
+ api_base=api_base,
+ acompletion=acompletion,
+ logging_obj=logging,
+ optional_params=optional_params,
+ litellm_params=litellm_params,
+ timeout=timeout, # type: ignore
+ client=client,
+ custom_llm_provider=custom_llm_provider,
+ encoding=encoding,
+ stream=stream,
+ provider_config=provider_config,
+ )
+ except Exception as e:
+ ## LOGGING - log the original exception returned
+ logging.post_call(
+ input=messages,
+ api_key=api_key,
+ original_response=str(e),
+ additional_args={"headers": headers},
+ )
+ raise e
+
elif custom_llm_provider == "groq":
api_base = (
api_base # for deepinfra/perplexity/anyscale/groq/friendliai we check in get_llm_provider and pass in the api base from there
@@ -1618,24 +1654,22 @@ def completion( # type: ignore # noqa: PLR0915
): # completion(top_k=3) > openai_config(top_k=3) <- allows for dynamic variables to be passed in
optional_params[k] = v
- response = groq_chat_completions.completion(
+ response = base_llm_http_handler.completion(
model=model,
+ stream=stream,
messages=messages,
- headers=headers,
- model_response=model_response,
- print_verbose=print_verbose,
- api_key=api_key,
- api_base=api_base,
acompletion=acompletion,
- logging_obj=logging,
+ api_base=api_base,
+ model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
- logger_fn=logger_fn,
- timeout=timeout, # type: ignore
- custom_prompt_dict=custom_prompt_dict,
- client=client, # pass AsyncOpenAI, OpenAI client
custom_llm_provider=custom_llm_provider,
+ timeout=timeout,
+ headers=headers,
encoding=encoding,
+ api_key=api_key,
+ logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
+ client=client,
)
elif custom_llm_provider == "aiohttp_openai":
# NEW aiohttp provider for 10-100x higher RPS
@@ -3850,6 +3884,21 @@ def embedding( # noqa: PLR0915
aembedding=aembedding,
litellm_params={},
)
+ elif custom_llm_provider == "infinity":
+ response = base_llm_http_handler.embedding(
+ model=model,
+ input=input,
+ custom_llm_provider=custom_llm_provider,
+ api_base=api_base,
+ api_key=api_key,
+ logging_obj=logging,
+ timeout=timeout,
+ model_response=EmbeddingResponse(),
+ optional_params=optional_params,
+ client=client,
+ aembedding=aembedding,
+ litellm_params={},
+ )
elif custom_llm_provider == "watsonx":
credentials = IBMWatsonXMixin.get_watsonx_credentials(
optional_params=optional_params, api_key=api_key, api_base=api_base
diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json
index 4795c6d862..95543d09c2 100644
--- a/litellm/model_prices_and_context_window_backup.json
+++ b/litellm/model_prices_and_context_window_backup.json
@@ -5,6 +5,7 @@
"max_output_tokens": "max output tokens, if the provider specifies it. if not default to max_tokens",
"input_cost_per_token": 0.0000,
"output_cost_per_token": 0.000,
+ "output_cost_per_reasoning_token": 0.000,
"litellm_provider": "one of https://docs.litellm.ai/docs/providers",
"mode": "one of: chat, embedding, completion, image_generation, audio_transcription, audio_speech, image_generation, moderation, rerank",
"supports_function_calling": true,
@@ -64,6 +65,168 @@
"supports_system_messages": true,
"supports_tool_choice": true
},
+ "gpt-4.1": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 2e-6,
+ "output_cost_per_token": 8e-6,
+ "input_cost_per_token_batches": 1e-6,
+ "output_cost_per_token_batches": 4e-6,
+ "cache_read_input_token_cost": 0.5e-6,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_web_search": true,
+ "search_context_cost_per_query": {
+ "search_context_size_low": 30e-3,
+ "search_context_size_medium": 35e-3,
+ "search_context_size_high": 50e-3
+ }
+ },
+ "gpt-4.1-2025-04-14": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 2e-6,
+ "output_cost_per_token": 8e-6,
+ "input_cost_per_token_batches": 1e-6,
+ "output_cost_per_token_batches": 4e-6,
+ "cache_read_input_token_cost": 0.5e-6,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_web_search": true,
+ "search_context_cost_per_query": {
+ "search_context_size_low": 30e-3,
+ "search_context_size_medium": 35e-3,
+ "search_context_size_high": 50e-3
+ }
+ },
+ "gpt-4.1-mini": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 0.4e-6,
+ "output_cost_per_token": 1.6e-6,
+ "input_cost_per_token_batches": 0.2e-6,
+ "output_cost_per_token_batches": 0.8e-6,
+ "cache_read_input_token_cost": 0.1e-6,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_web_search": true,
+ "search_context_cost_per_query": {
+ "search_context_size_low": 25e-3,
+ "search_context_size_medium": 27.5e-3,
+ "search_context_size_high": 30e-3
+ }
+ },
+ "gpt-4.1-mini-2025-04-14": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 0.4e-6,
+ "output_cost_per_token": 1.6e-6,
+ "input_cost_per_token_batches": 0.2e-6,
+ "output_cost_per_token_batches": 0.8e-6,
+ "cache_read_input_token_cost": 0.1e-6,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_web_search": true,
+ "search_context_cost_per_query": {
+ "search_context_size_low": 25e-3,
+ "search_context_size_medium": 27.5e-3,
+ "search_context_size_high": 30e-3
+ }
+ },
+ "gpt-4.1-nano": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 0.1e-6,
+ "output_cost_per_token": 0.4e-6,
+ "input_cost_per_token_batches": 0.05e-6,
+ "output_cost_per_token_batches": 0.2e-6,
+ "cache_read_input_token_cost": 0.025e-6,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true
+ },
+ "gpt-4.1-nano-2025-04-14": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 0.1e-6,
+ "output_cost_per_token": 0.4e-6,
+ "input_cost_per_token_batches": 0.05e-6,
+ "output_cost_per_token_batches": 0.2e-6,
+ "cache_read_input_token_cost": 0.025e-6,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true
+ },
"gpt-4o": {
"max_tokens": 16384,
"max_input_tokens": 128000,
@@ -438,6 +601,40 @@
"supports_vision": true,
"supports_prompt_caching": true
},
+ "o3": {
+ "max_tokens": 100000,
+ "max_input_tokens": 200000,
+ "max_output_tokens": 100000,
+ "input_cost_per_token": 1e-5,
+ "output_cost_per_token": 4e-5,
+ "cache_read_input_token_cost": 2.5e-6,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": false,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_response_schema": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true
+ },
+ "o3-2025-04-16": {
+ "max_tokens": 100000,
+ "max_input_tokens": 200000,
+ "max_output_tokens": 100000,
+ "input_cost_per_token": 1e-5,
+ "output_cost_per_token": 4e-5,
+ "cache_read_input_token_cost": 2.5e-6,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": false,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_response_schema": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true
+ },
"o3-mini": {
"max_tokens": 100000,
"max_input_tokens": 200000,
@@ -472,6 +669,40 @@
"supports_reasoning": true,
"supports_tool_choice": true
},
+ "o4-mini": {
+ "max_tokens": 100000,
+ "max_input_tokens": 200000,
+ "max_output_tokens": 100000,
+ "input_cost_per_token": 1.1e-6,
+ "output_cost_per_token": 4.4e-6,
+ "cache_read_input_token_cost": 2.75e-7,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": false,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_response_schema": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true
+ },
+ "o4-mini-2025-04-16": {
+ "max_tokens": 100000,
+ "max_input_tokens": 200000,
+ "max_output_tokens": 100000,
+ "input_cost_per_token": 1.1e-6,
+ "output_cost_per_token": 4.4e-6,
+ "cache_read_input_token_cost": 2.75e-7,
+ "litellm_provider": "openai",
+ "mode": "chat",
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": false,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_response_schema": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true
+ },
"o1-mini-2024-09-12": {
"max_tokens": 65536,
"max_input_tokens": 128000,
@@ -1241,6 +1472,294 @@
"litellm_provider": "openai",
"supported_endpoints": ["/v1/audio/speech"]
},
+ "azure/computer-use-preview": {
+ "max_tokens": 1024,
+ "max_input_tokens": 8192,
+ "max_output_tokens": 1024,
+ "input_cost_per_token": 0.000003,
+ "output_cost_per_token": 0.000012,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": false,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_reasoning": true
+ },
+ "azure/gpt-4o-audio-preview-2024-12-17": {
+ "max_tokens": 16384,
+ "max_input_tokens": 128000,
+ "max_output_tokens": 16384,
+ "input_cost_per_token": 0.0000025,
+ "input_cost_per_audio_token": 0.00004,
+ "output_cost_per_token": 0.00001,
+ "output_cost_per_audio_token": 0.00008,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions"],
+ "supported_modalities": ["text", "audio"],
+ "supported_output_modalities": ["text", "audio"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": false,
+ "supports_vision": false,
+ "supports_prompt_caching": false,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_reasoning": false
+ },
+ "azure/gpt-4o-mini-audio-preview-2024-12-17": {
+ "max_tokens": 16384,
+ "max_input_tokens": 128000,
+ "max_output_tokens": 16384,
+ "input_cost_per_token": 0.0000025,
+ "input_cost_per_audio_token": 0.00004,
+ "output_cost_per_token": 0.00001,
+ "output_cost_per_audio_token": 0.00008,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions"],
+ "supported_modalities": ["text", "audio"],
+ "supported_output_modalities": ["text", "audio"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": false,
+ "supports_vision": false,
+ "supports_prompt_caching": false,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_reasoning": false
+ },
+ "azure/gpt-4.1": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 2e-6,
+ "output_cost_per_token": 8e-6,
+ "input_cost_per_token_batches": 1e-6,
+ "output_cost_per_token_batches": 4e-6,
+ "cache_read_input_token_cost": 0.5e-6,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_web_search": true,
+ "search_context_cost_per_query": {
+ "search_context_size_low": 30e-3,
+ "search_context_size_medium": 35e-3,
+ "search_context_size_high": 50e-3
+ }
+ },
+ "azure/gpt-4.1-2025-04-14": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 2e-6,
+ "output_cost_per_token": 8e-6,
+ "input_cost_per_token_batches": 1e-6,
+ "output_cost_per_token_batches": 4e-6,
+ "cache_read_input_token_cost": 0.5e-6,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_web_search": true,
+ "search_context_cost_per_query": {
+ "search_context_size_low": 30e-3,
+ "search_context_size_medium": 35e-3,
+ "search_context_size_high": 50e-3
+ }
+ },
+ "azure/gpt-4.1-mini": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 0.4e-6,
+ "output_cost_per_token": 1.6e-6,
+ "input_cost_per_token_batches": 0.2e-6,
+ "output_cost_per_token_batches": 0.8e-6,
+ "cache_read_input_token_cost": 0.1e-6,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_web_search": true,
+ "search_context_cost_per_query": {
+ "search_context_size_low": 25e-3,
+ "search_context_size_medium": 27.5e-3,
+ "search_context_size_high": 30e-3
+ }
+ },
+ "azure/gpt-4.1-mini-2025-04-14": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 0.4e-6,
+ "output_cost_per_token": 1.6e-6,
+ "input_cost_per_token_batches": 0.2e-6,
+ "output_cost_per_token_batches": 0.8e-6,
+ "cache_read_input_token_cost": 0.1e-6,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true,
+ "supports_web_search": true,
+ "search_context_cost_per_query": {
+ "search_context_size_low": 25e-3,
+ "search_context_size_medium": 27.5e-3,
+ "search_context_size_high": 30e-3
+ }
+ },
+ "azure/gpt-4.1-nano": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 0.1e-6,
+ "output_cost_per_token": 0.4e-6,
+ "input_cost_per_token_batches": 0.05e-6,
+ "output_cost_per_token_batches": 0.2e-6,
+ "cache_read_input_token_cost": 0.025e-6,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true
+ },
+ "azure/gpt-4.1-nano-2025-04-14": {
+ "max_tokens": 32768,
+ "max_input_tokens": 1047576,
+ "max_output_tokens": 32768,
+ "input_cost_per_token": 0.1e-6,
+ "output_cost_per_token": 0.4e-6,
+ "input_cost_per_token_batches": 0.05e-6,
+ "output_cost_per_token_batches": 0.2e-6,
+ "cache_read_input_token_cost": 0.025e-6,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": true,
+ "supports_response_schema": true,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_system_messages": true,
+ "supports_tool_choice": true,
+ "supports_native_streaming": true
+ },
+ "azure/o3": {
+ "max_tokens": 100000,
+ "max_input_tokens": 200000,
+ "max_output_tokens": 100000,
+ "input_cost_per_token": 1e-5,
+ "output_cost_per_token": 4e-5,
+ "cache_read_input_token_cost": 2.5e-6,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": false,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_response_schema": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true
+ },
+ "azure/o3-2025-04-16": {
+ "max_tokens": 100000,
+ "max_input_tokens": 200000,
+ "max_output_tokens": 100000,
+ "input_cost_per_token": 1e-5,
+ "output_cost_per_token": 4e-5,
+ "cache_read_input_token_cost": 2.5e-6,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": false,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_response_schema": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true
+ },
+ "azure/o4-mini": {
+ "max_tokens": 100000,
+ "max_input_tokens": 200000,
+ "max_output_tokens": 100000,
+ "input_cost_per_token": 1.1e-6,
+ "output_cost_per_token": 4.4e-6,
+ "cache_read_input_token_cost": 2.75e-7,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supported_endpoints": ["/v1/chat/completions", "/v1/batch", "/v1/responses"],
+ "supported_modalities": ["text", "image"],
+ "supported_output_modalities": ["text"],
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": false,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_response_schema": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true
+ },
"azure/gpt-4o-mini-realtime-preview-2024-12-17": {
"max_tokens": 4096,
"max_input_tokens": 128000,
@@ -1417,6 +1936,23 @@
"supports_system_messages": true,
"supports_tool_choice": true
},
+ "azure/o4-mini-2025-04-16": {
+ "max_tokens": 100000,
+ "max_input_tokens": 200000,
+ "max_output_tokens": 100000,
+ "input_cost_per_token": 1.1e-6,
+ "output_cost_per_token": 4.4e-6,
+ "cache_read_input_token_cost": 2.75e-7,
+ "litellm_provider": "azure",
+ "mode": "chat",
+ "supports_function_calling": true,
+ "supports_parallel_function_calling": false,
+ "supports_vision": true,
+ "supports_prompt_caching": true,
+ "supports_response_schema": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true
+ },
"azure/o3-mini-2025-01-31": {
"max_tokens": 100000,
"max_input_tokens": 200000,
@@ -2507,7 +3043,7 @@
"max_output_tokens": 4096,
"input_cost_per_token": 0.00000008,
"input_cost_per_audio_token": 0.000004,
- "output_cost_per_token": 0.00032,
+ "output_cost_per_token": 0.00000032,
"litellm_provider": "azure_ai",
"mode": "chat",
"supports_audio_input": true,
@@ -4863,6 +5399,64 @@
"source": "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#gemini-2.0-flash",
"supports_tool_choice": true
},
+ "gemini/gemini-2.5-flash-preview-04-17": {
+ "max_tokens": 65536,
+ "max_input_tokens": 1048576,
+ "max_output_tokens": 65536,
+ "max_images_per_prompt": 3000,
+ "max_videos_per_prompt": 10,
+ "max_video_length": 1,
+ "max_audio_length_hours": 8.4,
+ "max_audio_per_prompt": 1,
+ "max_pdf_size_mb": 30,
+ "input_cost_per_audio_token": 1e-6,
+ "input_cost_per_token": 0.15e-6,
+ "output_cost_per_token": 0.6e-6,
+ "output_cost_per_reasoning_token": 3.5e-6,
+ "litellm_provider": "gemini",
+ "mode": "chat",
+ "rpm": 10,
+ "tpm": 250000,
+ "supports_system_messages": true,
+ "supports_function_calling": true,
+ "supports_vision": true,
+ "supports_reasoning": true,
+ "supports_response_schema": true,
+ "supports_audio_output": false,
+ "supports_tool_choice": true,
+ "supported_endpoints": ["/v1/chat/completions", "/v1/completions"],
+ "supported_modalities": ["text", "image", "audio", "video"],
+ "supported_output_modalities": ["text"],
+ "source": "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview"
+ },
+ "gemini-2.5-flash-preview-04-17": {
+ "max_tokens": 65536,
+ "max_input_tokens": 1048576,
+ "max_output_tokens": 65536,
+ "max_images_per_prompt": 3000,
+ "max_videos_per_prompt": 10,
+ "max_video_length": 1,
+ "max_audio_length_hours": 8.4,
+ "max_audio_per_prompt": 1,
+ "max_pdf_size_mb": 30,
+ "input_cost_per_audio_token": 1e-6,
+ "input_cost_per_token": 0.15e-6,
+ "output_cost_per_token": 0.6e-6,
+ "output_cost_per_reasoning_token": 3.5e-6,
+ "litellm_provider": "vertex_ai-language-models",
+ "mode": "chat",
+ "supports_reasoning": true,
+ "supports_system_messages": true,
+ "supports_function_calling": true,
+ "supports_vision": true,
+ "supports_response_schema": true,
+ "supports_audio_output": false,
+ "supports_tool_choice": true,
+ "supported_endpoints": ["/v1/chat/completions", "/v1/completions", "/v1/batch"],
+ "supported_modalities": ["text", "image", "audio", "video"],
+ "supported_output_modalities": ["text"],
+ "source": "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview"
+ },
"gemini-2.0-flash": {
"max_tokens": 8192,
"max_input_tokens": 1048576,
@@ -4937,6 +5531,35 @@
"source": "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#gemini-2.0-flash",
"supports_tool_choice": true
},
+ "gemini-2.5-pro-preview-03-25": {
+ "max_tokens": 65536,
+ "max_input_tokens": 1048576,
+ "max_output_tokens": 65536,
+ "max_images_per_prompt": 3000,
+ "max_videos_per_prompt": 10,
+ "max_video_length": 1,
+ "max_audio_length_hours": 8.4,
+ "max_audio_per_prompt": 1,
+ "max_pdf_size_mb": 30,
+ "input_cost_per_audio_token": 0.00000125,
+ "input_cost_per_token": 0.00000125,
+ "input_cost_per_token_above_200k_tokens": 0.0000025,
+ "output_cost_per_token": 0.00001,
+ "output_cost_per_token_above_200k_tokens": 0.000015,
+ "litellm_provider": "vertex_ai-language-models",
+ "mode": "chat",
+ "supports_reasoning": true,
+ "supports_system_messages": true,
+ "supports_function_calling": true,
+ "supports_vision": true,
+ "supports_response_schema": true,
+ "supports_audio_output": false,
+ "supports_tool_choice": true,
+ "supported_endpoints": ["/v1/chat/completions", "/v1/completions", "/v1/batch"],
+ "supported_modalities": ["text", "image", "audio", "video"],
+ "supported_output_modalities": ["text"],
+ "source": "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview"
+ },
"gemini/gemini-2.0-pro-exp-02-05": {
"max_tokens": 8192,
"max_input_tokens": 2097152,
diff --git a/litellm/openai-responses-starter-app b/litellm/openai-responses-starter-app
new file mode 160000
index 0000000000..bf0485467c
--- /dev/null
+++ b/litellm/openai-responses-starter-app
@@ -0,0 +1 @@
+Subproject commit bf0485467c343957ba5c217db777f407b2e65453
diff --git a/litellm/proxy/_experimental/out/_next/static/eKo9wJb6ZFjAy85GaOeQ6/_buildManifest.js b/litellm/proxy/_experimental/out/_next/static/FPIQgzUY81b7nl8zNun4_/_buildManifest.js
similarity index 100%
rename from litellm/proxy/_experimental/out/_next/static/eKo9wJb6ZFjAy85GaOeQ6/_buildManifest.js
rename to litellm/proxy/_experimental/out/_next/static/FPIQgzUY81b7nl8zNun4_/_buildManifest.js
diff --git a/litellm/proxy/_experimental/out/_next/static/eKo9wJb6ZFjAy85GaOeQ6/_ssgManifest.js b/litellm/proxy/_experimental/out/_next/static/FPIQgzUY81b7nl8zNun4_/_ssgManifest.js
similarity index 100%
rename from litellm/proxy/_experimental/out/_next/static/eKo9wJb6ZFjAy85GaOeQ6/_ssgManifest.js
rename to litellm/proxy/_experimental/out/_next/static/FPIQgzUY81b7nl8zNun4_/_ssgManifest.js
diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/250-a927a558002d8fb9.js b/litellm/proxy/_experimental/out/_next/static/chunks/250-a927a558002d8fb9.js
new file mode 100644
index 0000000000..80c21540d2
--- /dev/null
+++ b/litellm/proxy/_experimental/out/_next/static/chunks/250-a927a558002d8fb9.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[250],{19250:function(e,t,o){o.d(t,{$I:function(){return K},AZ:function(){return D},Au:function(){return em},BL:function(){return eU},Br:function(){return b},E9:function(){return eZ},EB:function(){return te},EG:function(){return eX},EY:function(){return eK},Eb:function(){return C},FC:function(){return ei},Gh:function(){return eO},H1:function(){return v},H2:function(){return n},Hx:function(){return eg},I1:function(){return j},It:function(){return x},J$:function(){return ea},K8:function(){return d},K_:function(){return eY},LY:function(){return eI},Lp:function(){return eG},N3:function(){return eN},N8:function(){return ee},NL:function(){return e1},NV:function(){return f},Nc:function(){return ex},O3:function(){return eV},OD:function(){return e_},OU:function(){return eh},Of:function(){return S},Og:function(){return y},Ov:function(){return E},PT:function(){return X},Qg:function(){return eS},RQ:function(){return _},Rg:function(){return Q},Sb:function(){return eJ},So:function(){return et},TF:function(){return ta},Tj:function(){return e$},UM:function(){return e7},VA:function(){return G},Vt:function(){return eD},W_:function(){return V},X:function(){return er},XO:function(){return k},Xd:function(){return eT},Xm:function(){return F},YU:function(){return eL},Yo:function(){return J},Z9:function(){return R},Zr:function(){return m},a6:function(){return O},aC:function(){return to},ao:function(){return eq},b1:function(){return ed},cq:function(){return A},cu:function(){return eP},eH:function(){return Y},eZ:function(){return eF},fE:function(){return e8},fP:function(){return W},g:function(){return eQ},gX:function(){return eb},h3:function(){return es},hT:function(){return ej},hy:function(){return u},ix:function(){return H},j2:function(){return en},jA:function(){return eH},jE:function(){return ez},kK:function(){return p},kn:function(){return q},lP:function(){return h},lU:function(){return e2},lg:function(){return eE},mC:function(){return e6},mR:function(){return eo},mY:function(){return e5},m_:function(){return U},mp:function(){return eM},n$:function(){return ey},n9:function(){return e9},nd:function(){return e3},o6:function(){return $},oC:function(){return eC},ol:function(){return z},pf:function(){return eR},qI:function(){return g},qk:function(){return e0},qm:function(){return w},r1:function(){return tt},r6:function(){return B},rs:function(){return N},s0:function(){return L},sN:function(){return ev},t$:function(){return P},t0:function(){return ek},t3:function(){return eW},tB:function(){return e4},tN:function(){return el},u5:function(){return ec},um:function(){return eB},v9:function(){return ef},vh:function(){return eA},wX:function(){return T},wd:function(){return ew},xA:function(){return eu},xX:function(){return I},zg:function(){return ep}});var a=o(20347),r=o(41021);let n=null;console.log=function(){};let c=0,s=e=>new Promise(t=>setTimeout(t,e)),i=async e=>{let t=Date.now();t-c>6e4?(e.includes("Authentication Error - Expired Key")&&(r.ZP.info("UI Session Expired. Logging out."),c=t,await s(3e3),document.cookie="token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;",window.location.href="/"),c=t):console.log("Error suppressed to prevent spam:",e)},l="Authorization";function d(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"Authorization";console.log("setGlobalLitellmHeaderName: ".concat(e)),l=e}let h=async()=>{let e=n?"".concat(n,"/openapi.json"):"/openapi.json",t=await fetch(e);return await t.json()},w=async e=>{try{let t=n?"".concat(n,"/get/litellm_model_cost_map"):"/get/litellm_model_cost_map",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}}),a=await o.json();return console.log("received litellm model cost data: ".concat(a)),a}catch(e){throw console.error("Failed to get model cost map:",e),e}},p=async(e,t)=>{try{let o=n?"".concat(n,"/model/new"):"/model/new",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text()||"Network response was not ok";throw r.ZP.error(e),Error(e)}let c=await a.json();return console.log("API Response:",c),r.ZP.destroy(),r.ZP.success("Model ".concat(t.model_name," created successfully"),2),c}catch(e){throw console.error("Failed to create key:",e),e}},u=async e=>{try{let t=n?"".concat(n,"/model/settings"):"/model/settings",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){console.error("Failed to get model settings:",e)}},y=async(e,t)=>{console.log("model_id in model delete call: ".concat(t));try{let o=n?"".concat(n,"/model/delete"):"/model/delete",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},f=async(e,t)=>{if(console.log("budget_id in budget delete call: ".concat(t)),null!=e)try{let o=n?"".concat(n,"/budget/delete"):"/budget/delete",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},m=async(e,t)=>{try{console.log("Form Values in budgetCreateCall:",t),console.log("Form Values after check:",t);let o=n?"".concat(n,"/budget/new"):"/budget/new",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},g=async(e,t)=>{try{console.log("Form Values in budgetUpdateCall:",t),console.log("Form Values after check:",t);let o=n?"".concat(n,"/budget/update"):"/budget/update",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},k=async(e,t)=>{try{let o=n?"".concat(n,"/invitation/new"):"/invitation/new",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},_=async e=>{try{let t=n?"".concat(n,"/alerting/settings"):"/alerting/settings",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},T=async(e,t,o)=>{try{if(console.log("Form Values in keyCreateCall:",o),o.description&&(o.metadata||(o.metadata={}),o.metadata.description=o.description,delete o.description,o.metadata=JSON.stringify(o.metadata)),o.metadata){console.log("formValues.metadata:",o.metadata);try{o.metadata=JSON.parse(o.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",o);let a=n?"".concat(n,"/key/generate"):"/key/generate",r=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...o})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error(e)}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},E=async(e,t,o)=>{try{if(console.log("Form Values in keyCreateCall:",o),o.description&&(o.metadata||(o.metadata={}),o.metadata.description=o.description,delete o.description,o.metadata=JSON.stringify(o.metadata)),o.auto_create_key=!1,o.metadata){console.log("formValues.metadata:",o.metadata);try{o.metadata=JSON.parse(o.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",o);let a=n?"".concat(n,"/user/new"):"/user/new",r=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...o})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error(e)}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},j=async(e,t)=>{try{let o=n?"".concat(n,"/key/delete"):"/key/delete";console.log("in keyDeleteCall:",t);let a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let r=await a.json();return console.log(r),r}catch(e){throw console.error("Failed to create key:",e),e}},C=async(e,t)=>{try{let o=n?"".concat(n,"/user/delete"):"/user/delete";console.log("in userDeleteCall:",t);let a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_ids:t})});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let r=await a.json();return console.log(r),r}catch(e){throw console.error("Failed to delete user(s):",e),e}},N=async(e,t)=>{try{let o=n?"".concat(n,"/team/delete"):"/team/delete";console.log("in teamDeleteCall:",t);let a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_ids:[t]})});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let r=await a.json();return console.log(r),r}catch(e){throw console.error("Failed to delete key:",e),e}},S=async function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;try{let r=n?"".concat(n,"/user/list"):"/user/list";console.log("in userListCall");let c=new URLSearchParams;if(t&&t.length>0){let e=t.join(",");c.append("user_ids",e)}o&&c.append("page",o.toString()),a&&c.append("page_size",a.toString());let s=c.toString();s&&(r+="?".concat(s));let d=await fetch(r,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!d.ok){let e=await d.text();throw i(e),Error("Network response was not ok")}let h=await d.json();return console.log("/user/list API Response:",h),h}catch(e){throw console.error("Failed to create key:",e),e}},b=async function(e,t,o){let a=arguments.length>3&&void 0!==arguments[3]&&arguments[3],r=arguments.length>4?arguments[4]:void 0,c=arguments.length>5?arguments[5]:void 0;try{let s;if(a){s=n?"".concat(n,"/user/list"):"/user/list";let e=new URLSearchParams;null!=r&&e.append("page",r.toString()),null!=c&&e.append("page_size",c.toString()),s+="?".concat(e.toString())}else s=n?"".concat(n,"/user/info"):"/user/info","Admin"===o||"Admin Viewer"===o||t&&(s+="?user_id=".concat(t));console.log("Requesting user data from:",s);let d=await fetch(s,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!d.ok){let e=await d.text();throw i(e),Error("Network response was not ok")}let h=await d.json();return console.log("API Response:",h),h}catch(e){throw console.error("Failed to fetch user data:",e),e}},F=async(e,t)=>{try{let o=n?"".concat(n,"/team/info"):"/team/info";t&&(o="".concat(o,"?team_id=").concat(t)),console.log("in teamInfoCall");let a=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},x=async function(e,t){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;try{let a=n?"".concat(n,"/team/list"):"/team/list";console.log("in teamInfoCall");let r=new URLSearchParams;o&&r.append("user_id",o.toString()),t&&r.append("organization_id",t.toString());let c=r.toString();c&&(a+="?".concat(c));let s=await fetch(a,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!s.ok){let e=await s.text();throw i(e),Error("Network response was not ok")}let d=await s.json();return console.log("/team/list API Response:",d),d}catch(e){throw console.error("Failed to create key:",e),e}},O=async e=>{try{let t=n?"".concat(n,"/team/available"):"/team/available";console.log("in availableTeamListCall");let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log("/team/available_teams API Response:",a),a}catch(e){throw e}},B=async e=>{try{let t=n?"".concat(n,"/organization/list"):"/organization/list",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},P=async(e,t)=>{try{let o=n?"".concat(n,"/organization/info"):"/organization/info";t&&(o="".concat(o,"?organization_id=").concat(t)),console.log("in teamInfoCall");let a=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},v=async(e,t)=>{try{if(console.log("Form Values in organizationCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw console.error("Failed to parse metadata:",e),Error("Failed to parse metadata: "+e)}}let o=n?"".concat(n,"/organization/new"):"/organization/new",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},G=async(e,t)=>{try{console.log("Form Values in organizationUpdateCall:",t);let o=n?"".concat(n,"/organization/update"):"/organization/update",a=await fetch(o,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("Update Team Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},A=async(e,t)=>{try{let o=n?"".concat(n,"/organization/delete"):"/organization/delete",a=await fetch(o,{method:"DELETE",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({organization_ids:[t]})});if(!a.ok){let e=await a.text();throw i(e),Error("Error deleting organization: ".concat(e))}return await a.json()}catch(e){throw console.error("Failed to delete organization:",e),e}},J=async(e,t)=>{try{let o=n?"".concat(n,"/utils/transform_request"):"/utils/transform_request",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify(t)});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}return await a.json()}catch(e){throw console.error("Failed to create key:",e),e}},I=async function(e,t,o){let a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1;try{let r=n?"".concat(n,"/user/daily/activity"):"/user/daily/activity",c=new URLSearchParams;c.append("start_date",t.toISOString()),c.append("end_date",o.toISOString()),c.append("page_size","1000"),c.append("page",a.toString());let s=c.toString();s&&(r+="?".concat(s));let d=await fetch(r,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!d.ok){let e=await d.text();throw i(e),Error("Network response was not ok")}return await d.json()}catch(e){throw console.error("Failed to create key:",e),e}},R=async function(e,t,o){let a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1,r=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;try{let c=n?"".concat(n,"/tag/daily/activity"):"/tag/daily/activity",s=new URLSearchParams;s.append("start_date",t.toISOString()),s.append("end_date",o.toISOString()),s.append("page_size","1000"),s.append("page",a.toString()),r&&s.append("tags",r.join(","));let d=s.toString();d&&(c+="?".concat(d));let h=await fetch(c,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!h.ok){let e=await h.text();throw i(e),Error("Network response was not ok")}return await h.json()}catch(e){throw console.error("Failed to create key:",e),e}},z=async function(e,t,o){let a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1,r=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;try{let c=n?"".concat(n,"/team/daily/activity"):"/team/daily/activity",s=new URLSearchParams;s.append("start_date",t.toISOString()),s.append("end_date",o.toISOString()),s.append("page_size","1000"),s.append("page",a.toString()),r&&s.append("team_ids",r.join(",")),s.append("exclude_team_ids","litellm-dashboard");let d=s.toString();d&&(c+="?".concat(d));let h=await fetch(c,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!h.ok){let e=await h.text();throw i(e),Error("Network response was not ok")}return await h.json()}catch(e){throw console.error("Failed to create key:",e),e}},V=async e=>{try{let t=n?"".concat(n,"/onboarding/get_token"):"/onboarding/get_token";t+="?invite_link=".concat(e);let o=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},U=async(e,t,o,a)=>{let r=n?"".concat(n,"/onboarding/claim_token"):"/onboarding/claim_token";try{let n=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({invitation_link:t,user_id:o,password:a})});if(!n.ok){let e=await n.text();throw i(e),Error("Network response was not ok")}let c=await n.json();return console.log(c),c}catch(e){throw console.error("Failed to delete key:",e),e}},L=async(e,t,o)=>{try{let a=n?"".concat(n,"/key/").concat(t,"/regenerate"):"/key/".concat(t,"/regenerate"),r=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify(o)});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let c=await r.json();return console.log("Regenerate key Response:",c),c}catch(e){throw console.error("Failed to regenerate key:",e),e}},M=!1,Z=null,D=async(e,t,o)=>{try{console.log("modelInfoCall:",e,t,o);let c=n?"".concat(n,"/v2/model/info"):"/v2/model/info";a.ZL.includes(o)||(c+="?user_models_only=true");let s=await fetch(c,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!s.ok){let e=await s.text();throw e+="error shown=".concat(M),M||(e.includes("No model list passed")&&(e="No Models Exist. Click Add Model to get started."),r.ZP.info(e,10),M=!0,Z&&clearTimeout(Z),Z=setTimeout(()=>{M=!1},1e4)),Error("Network response was not ok")}let i=await s.json();return console.log("modelInfoCall:",i),i}catch(e){throw console.error("Failed to create key:",e),e}},H=async(e,t)=>{try{let o=n?"".concat(n,"/v1/model/info"):"/v1/model/info";o+="?litellm_model_id=".concat(t);let a=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok)throw await a.text(),Error("Network response was not ok");let r=await a.json();return console.log("modelInfoV1Call:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},q=async e=>{try{let t=n?"".concat(n,"/model_group/info"):"/model_group/info",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");let a=await o.json();return console.log("modelHubCall:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},X=async e=>{try{let t=n?"".concat(n,"/get/allowed_ips"):"/get/allowed_ips",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw Error("Network response was not ok: ".concat(e))}let a=await o.json();return console.log("getAllowedIPs:",a),a.data}catch(e){throw console.error("Failed to get allowed IPs:",e),e}},Y=async(e,t)=>{try{let o=n?"".concat(n,"/add/allowed_ip"):"/add/allowed_ip",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!a.ok){let e=await a.text();throw Error("Network response was not ok: ".concat(e))}let r=await a.json();return console.log("addAllowedIP:",r),r}catch(e){throw console.error("Failed to add allowed IP:",e),e}},K=async(e,t)=>{try{let o=n?"".concat(n,"/delete/allowed_ip"):"/delete/allowed_ip",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!a.ok){let e=await a.text();throw Error("Network response was not ok: ".concat(e))}let r=await a.json();return console.log("deleteAllowedIP:",r),r}catch(e){throw console.error("Failed to delete allowed IP:",e),e}},$=async(e,t,o,a,r,c,s,d)=>{try{let t=n?"".concat(n,"/model/metrics"):"/model/metrics";a&&(t="".concat(t,"?_selected_model_group=").concat(a,"&startTime=").concat(r,"&endTime=").concat(c,"&api_key=").concat(s,"&customer=").concat(d));let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},Q=async(e,t,o,a)=>{try{let r=n?"".concat(n,"/model/streaming_metrics"):"/model/streaming_metrics";t&&(r="".concat(r,"?_selected_model_group=").concat(t,"&startTime=").concat(o,"&endTime=").concat(a));let c=await fetch(r,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!c.ok){let e=await c.text();throw i(e),Error("Network response was not ok")}return await c.json()}catch(e){throw console.error("Failed to create key:",e),e}},W=async(e,t,o,a,r,c,s,d)=>{try{let t=n?"".concat(n,"/model/metrics/slow_responses"):"/model/metrics/slow_responses";a&&(t="".concat(t,"?_selected_model_group=").concat(a,"&startTime=").concat(r,"&endTime=").concat(c,"&api_key=").concat(s,"&customer=").concat(d));let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},ee=async(e,t,o,a,r,c,s,d)=>{try{let t=n?"".concat(n,"/model/metrics/exceptions"):"/model/metrics/exceptions";a&&(t="".concat(t,"?_selected_model_group=").concat(a,"&startTime=").concat(r,"&endTime=").concat(c,"&api_key=").concat(s,"&customer=").concat(d));let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},et=async function(e,t,o){let a=arguments.length>3&&void 0!==arguments[3]&&arguments[3],r=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;console.log("in /models calls, globalLitellmHeaderName",l);try{let t=n?"".concat(n,"/models"):"/models",o=new URLSearchParams;!0===a&&o.append("return_wildcard_routes","True"),r&&o.append("team_id",r.toString()),o.toString()&&(t+="?".concat(o.toString()));let c=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!c.ok){let e=await c.text();throw i(e),Error("Network response was not ok")}return await c.json()}catch(e){throw console.error("Failed to create key:",e),e}},eo=async e=>{try{let t=n?"".concat(n,"/global/spend/teams"):"/global/spend/teams";console.log("in teamSpendLogsCall:",t);let o=await fetch("".concat(t),{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log(a),a}catch(e){throw console.error("Failed to create key:",e),e}},ea=async(e,t,o,a)=>{try{let r=n?"".concat(n,"/global/spend/tags"):"/global/spend/tags";t&&o&&(r="".concat(r,"?start_date=").concat(t,"&end_date=").concat(o)),a&&(r+="".concat(r,"&tags=").concat(a.join(","))),console.log("in tagsSpendLogsCall:",r);let c=await fetch("".concat(r),{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!c.ok)throw await c.text(),Error("Network response was not ok");let s=await c.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}},er=async e=>{try{let t=n?"".concat(n,"/global/spend/all_tag_names"):"/global/spend/all_tag_names";console.log("in global/spend/all_tag_names call",t);let o=await fetch("".concat(t),{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");let a=await o.json();return console.log(a),a}catch(e){throw console.error("Failed to create key:",e),e}},en=async e=>{try{let t=n?"".concat(n,"/global/all_end_users"):"/global/all_end_users";console.log("in global/all_end_users call",t);let o=await fetch("".concat(t),{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");let a=await o.json();return console.log(a),a}catch(e){throw console.error("Failed to create key:",e),e}},ec=async(e,t)=>{try{let o=n?"".concat(n,"/user/filter/ui"):"/user/filter/ui";t.get("user_email")&&(o+="?user_email=".concat(t.get("user_email"))),t.get("user_id")&&(o+="?user_id=".concat(t.get("user_id")));let a=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}return await a.json()}catch(e){throw console.error("Failed to create key:",e),e}},es=async(e,t,o,a,r,c,s,d,h)=>{try{let w=n?"".concat(n,"/spend/logs/ui"):"/spend/logs/ui",p=new URLSearchParams;t&&p.append("api_key",t),o&&p.append("team_id",o),a&&p.append("request_id",a),r&&p.append("start_date",r),c&&p.append("end_date",c),s&&p.append("page",s.toString()),d&&p.append("page_size",d.toString()),h&&p.append("user_id",h);let u=p.toString();u&&(w+="?".concat(u));let y=await fetch(w,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!y.ok){let e=await y.text();throw i(e),Error("Network response was not ok")}let f=await y.json();return console.log("Spend Logs Response:",f),f}catch(e){throw console.error("Failed to fetch spend logs:",e),e}},ei=async e=>{try{let t=n?"".concat(n,"/global/spend/logs"):"/global/spend/logs",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log(a),a}catch(e){throw console.error("Failed to create key:",e),e}},el=async e=>{try{let t=n?"".concat(n,"/global/spend/keys?limit=5"):"/global/spend/keys?limit=5",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log(a),a}catch(e){throw console.error("Failed to create key:",e),e}},ed=async(e,t,o,a)=>{try{let r=n?"".concat(n,"/global/spend/end_users"):"/global/spend/end_users",c="";c=t?JSON.stringify({api_key:t,startTime:o,endTime:a}):JSON.stringify({startTime:o,endTime:a});let s={method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:c},d=await fetch(r,s);if(!d.ok){let e=await d.text();throw i(e),Error("Network response was not ok")}let h=await d.json();return console.log(h),h}catch(e){throw console.error("Failed to create key:",e),e}},eh=async(e,t,o,a)=>{try{let r=n?"".concat(n,"/global/spend/provider"):"/global/spend/provider";o&&a&&(r+="?start_date=".concat(o,"&end_date=").concat(a)),t&&(r+="&api_key=".concat(t));let c={method:"GET",headers:{[l]:"Bearer ".concat(e)}},s=await fetch(r,c);if(!s.ok){let e=await s.text();throw i(e),Error("Network response was not ok")}let d=await s.json();return console.log(d),d}catch(e){throw console.error("Failed to fetch spend data:",e),e}},ew=async(e,t,o)=>{try{let a=n?"".concat(n,"/global/activity"):"/global/activity";t&&o&&(a+="?start_date=".concat(t,"&end_date=").concat(o));let r={method:"GET",headers:{[l]:"Bearer ".concat(e)}},c=await fetch(a,r);if(!c.ok)throw await c.text(),Error("Network response was not ok");let s=await c.json();return console.log(s),s}catch(e){throw console.error("Failed to fetch spend data:",e),e}},ep=async(e,t,o)=>{try{let a=n?"".concat(n,"/global/activity/cache_hits"):"/global/activity/cache_hits";t&&o&&(a+="?start_date=".concat(t,"&end_date=").concat(o));let r={method:"GET",headers:{[l]:"Bearer ".concat(e)}},c=await fetch(a,r);if(!c.ok)throw await c.text(),Error("Network response was not ok");let s=await c.json();return console.log(s),s}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eu=async(e,t,o)=>{try{let a=n?"".concat(n,"/global/activity/model"):"/global/activity/model";t&&o&&(a+="?start_date=".concat(t,"&end_date=").concat(o));let r={method:"GET",headers:{[l]:"Bearer ".concat(e)}},c=await fetch(a,r);if(!c.ok)throw await c.text(),Error("Network response was not ok");let s=await c.json();return console.log(s),s}catch(e){throw console.error("Failed to fetch spend data:",e),e}},ey=async(e,t,o,a)=>{try{let r=n?"".concat(n,"/global/activity/exceptions"):"/global/activity/exceptions";t&&o&&(r+="?start_date=".concat(t,"&end_date=").concat(o)),a&&(r+="&model_group=".concat(a));let c={method:"GET",headers:{[l]:"Bearer ".concat(e)}},s=await fetch(r,c);if(!s.ok)throw await s.text(),Error("Network response was not ok");let i=await s.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},ef=async(e,t,o,a)=>{try{let r=n?"".concat(n,"/global/activity/exceptions/deployment"):"/global/activity/exceptions/deployment";t&&o&&(r+="?start_date=".concat(t,"&end_date=").concat(o)),a&&(r+="&model_group=".concat(a));let c={method:"GET",headers:{[l]:"Bearer ".concat(e)}},s=await fetch(r,c);if(!s.ok)throw await s.text(),Error("Network response was not ok");let i=await s.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},em=async e=>{try{let t=n?"".concat(n,"/global/spend/models?limit=5"):"/global/spend/models?limit=5",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log(a),a}catch(e){throw console.error("Failed to create key:",e),e}},eg=async(e,t,o)=>{try{console.log("Sending model connection test request:",JSON.stringify(t));let r=n?"".concat(n,"/health/test_connection"):"/health/test_connection",c=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[l]:"Bearer ".concat(e)},body:JSON.stringify({litellm_params:t,mode:o})}),s=c.headers.get("content-type");if(!s||!s.includes("application/json")){let e=await c.text();throw console.error("Received non-JSON response:",e),Error("Received non-JSON response (".concat(c.status,": ").concat(c.statusText,"). Check network tab for details."))}let i=await c.json();if(!c.ok||"error"===i.status){if("error"===i.status);else{var a;return{status:"error",message:(null===(a=i.error)||void 0===a?void 0:a.message)||"Connection test failed: ".concat(c.status," ").concat(c.statusText)}}}return i}catch(e){throw console.error("Model connection test error:",e),e}},ek=async(e,t)=>{try{console.log("entering keyInfoV1Call");let o=n?"".concat(n,"/key/info"):"/key/info";o="".concat(o,"?key=").concat(t);let a=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(console.log("response",a),!a.ok){let e=await a.text();i(e),r.ZP.error("Failed to fetch key info - "+e)}let c=await a.json();return console.log("data",c),c}catch(e){throw console.error("Failed to fetch key info:",e),e}},e_=async(e,t,o,a,r,c)=>{try{let s=n?"".concat(n,"/key/list"):"/key/list";console.log("in keyListCall");let d=new URLSearchParams;o&&d.append("team_id",o.toString()),t&&d.append("organization_id",t.toString()),a&&d.append("key_alias",a),r&&d.append("page",r.toString()),c&&d.append("size",c.toString()),d.append("return_full_object","true"),d.append("include_team_keys","true");let h=d.toString();h&&(s+="?".concat(h));let w=await fetch(s,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!w.ok){let e=await w.text();throw i(e),Error("Network response was not ok")}let p=await w.json();return console.log("/team/list API Response:",p),p}catch(e){throw console.error("Failed to create key:",e),e}},eT=async(e,t)=>{try{let o=n?"".concat(n,"/user/get_users?role=").concat(t):"/user/get_users?role=".concat(t);console.log("in userGetAllUsersCall:",o);let a=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let r=await a.json();return console.log(r),r}catch(e){throw console.error("Failed to get requested models:",e),e}},eE=async e=>{try{let t=n?"".concat(n,"/user/available_roles"):"/user/available_roles",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");let a=await o.json();return console.log("response from user/available_role",a),a}catch(e){throw e}},ej=async(e,t)=>{try{if(console.log("Form Values in teamCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let o=n?"".concat(n,"/team/new"):"/team/new",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},eC=async(e,t)=>{try{if(console.log("Form Values in credentialCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let o=n?"".concat(n,"/credentials"):"/credentials",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},eN=async e=>{try{let t=n?"".concat(n,"/credentials"):"/credentials";console.log("in credentialListCall");let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log("/credentials API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},eS=async(e,t,o)=>{try{let a=n?"".concat(n,"/credentials"):"/credentials";t?a+="/by_name/".concat(t):o&&(a+="/by_model/".concat(o)),console.log("in credentialListCall");let r=await fetch(a,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let c=await r.json();return console.log("/credentials API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},eb=async(e,t)=>{try{let o=n?"".concat(n,"/credentials/").concat(t):"/credentials/".concat(t);console.log("in credentialDeleteCall:",t);let a=await fetch(o,{method:"DELETE",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let r=await a.json();return console.log(r),r}catch(e){throw console.error("Failed to delete key:",e),e}},eF=async(e,t,o)=>{try{if(console.log("Form Values in credentialUpdateCall:",o),o.metadata){console.log("formValues.metadata:",o.metadata);try{o.metadata=JSON.parse(o.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let a=n?"".concat(n,"/credentials/").concat(t):"/credentials/".concat(t),r=await fetch(a,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...o})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},ex=async(e,t)=>{try{if(console.log("Form Values in keyUpdateCall:",t),t.model_tpm_limit){console.log("formValues.model_tpm_limit:",t.model_tpm_limit);try{t.model_tpm_limit=JSON.parse(t.model_tpm_limit)}catch(e){throw Error("Failed to parse model_tpm_limit: "+e)}}if(t.model_rpm_limit){console.log("formValues.model_rpm_limit:",t.model_rpm_limit);try{t.model_rpm_limit=JSON.parse(t.model_rpm_limit)}catch(e){throw Error("Failed to parse model_rpm_limit: "+e)}}let o=n?"".concat(n,"/key/update"):"/key/update",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("Update key Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},eO=async(e,t)=>{try{console.log("Form Values in teamUpateCall:",t);let o=n?"".concat(n,"/team/update"):"/team/update",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("Update Team Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},eB=async(e,t)=>{try{console.log("Form Values in modelUpateCall:",t);let o=n?"".concat(n,"/model/update"):"/model/update",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error update from the server:",e),Error("Network response was not ok")}let r=await a.json();return console.log("Update model Response:",r),r}catch(e){throw console.error("Failed to update model:",e),e}},eP=async(e,t,o)=>{try{console.log("Form Values in teamMemberAddCall:",o);let a=n?"".concat(n,"/team/member_add"):"/team/member_add",r=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:o})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},ev=async(e,t,o)=>{try{console.log("Form Values in teamMemberAddCall:",o);let a=n?"".concat(n,"/team/member_update"):"/team/member_update",r=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_id:t,role:o.role,user_id:o.user_id})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},eG=async(e,t,o)=>{try{console.log("Form Values in teamMemberAddCall:",o);let a=n?"".concat(n,"/team/member_delete"):"/team/member_delete",r=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_id:t,...void 0!==o.user_email&&{user_email:o.user_email},...void 0!==o.user_id&&{user_id:o.user_id}})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},eA=async(e,t,o)=>{try{console.log("Form Values in teamMemberAddCall:",o);let a=n?"".concat(n,"/organization/member_add"):"/organization/member_add",r=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,member:o})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error(e)}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create organization member:",e),e}},eJ=async(e,t,o)=>{try{console.log("Form Values in organizationMemberDeleteCall:",o);let a=n?"".concat(n,"/organization/member_delete"):"/organization/member_delete",r=await fetch(a,{method:"DELETE",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,user_id:o})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to delete organization member:",e),e}},eI=async(e,t,o)=>{try{console.log("Form Values in organizationMemberUpdateCall:",o);let a=n?"".concat(n,"/organization/member_update"):"/organization/member_update",r=await fetch(a,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,...o})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await r.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to update organization member:",e),e}},eR=async(e,t,o)=>{try{console.log("Form Values in userUpdateUserCall:",t);let a=n?"".concat(n,"/user/update"):"/user/update",r={...t};null!==o&&(r.user_role=o),r=JSON.stringify(r);let c=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:r});if(!c.ok){let e=await c.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let s=await c.json();return console.log("API Response:",s),s}catch(e){throw console.error("Failed to create key:",e),e}},ez=async(e,t)=>{try{let o=n?"".concat(n,"/health/services?service=").concat(t):"/health/services?service=".concat(t);console.log("Checking Slack Budget Alerts service health");let a=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error(e)}let c=await a.json();return r.ZP.success("Test request to ".concat(t," made - check logs/alerts on ").concat(t," to verify")),c}catch(e){throw console.error("Failed to perform health check:",e),e}},eV=async e=>{try{let t=n?"".concat(n,"/budget/list"):"/budget/list",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eU=async(e,t,o)=>{try{let t=n?"".concat(n,"/get/config/callbacks"):"/get/config/callbacks",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eL=async e=>{try{let t=n?"".concat(n,"/config/list?config_type=general_settings"):"/config/list?config_type=general_settings",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eM=async e=>{try{let t=n?"".concat(n,"/config/pass_through_endpoint"):"/config/pass_through_endpoint",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eZ=async(e,t)=>{try{let o=n?"".concat(n,"/config/field/info?field_name=").concat(t):"/config/field/info?field_name=".concat(t),a=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok)throw await a.text(),Error("Network response was not ok");return await a.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},eD=async(e,t)=>{try{let o=n?"".concat(n,"/config/pass_through_endpoint"):"/config/pass_through_endpoint",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}return await a.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},eH=async(e,t,o)=>{try{let a=n?"".concat(n,"/config/field/update"):"/config/field/update",c=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({field_name:t,field_value:o,config_type:"general_settings"})});if(!c.ok){let e=await c.text();throw i(e),Error("Network response was not ok")}let s=await c.json();return r.ZP.success("Successfully updated value!"),s}catch(e){throw console.error("Failed to set callbacks:",e),e}},eq=async(e,t)=>{try{let o=n?"".concat(n,"/config/field/delete"):"/config/field/delete",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({field_name:t,config_type:"general_settings"})});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let c=await a.json();return r.ZP.success("Field reset on proxy"),c}catch(e){throw console.error("Failed to get callbacks:",e),e}},eX=async(e,t)=>{try{let o=n?"".concat(n,"/config/pass_through_endpoint?endpoint_id=").concat(t):"/config/pass_through_endpoint".concat(t),a=await fetch(o,{method:"DELETE",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}return await a.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eY=async(e,t)=>{try{let o=n?"".concat(n,"/config/update"):"/config/update",a=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}return await a.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},eK=async e=>{try{let t=n?"".concat(n,"/health"):"/health",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to call /health:",e),e}},e$=async e=>{try{let t=n?"".concat(n,"/cache/ping"):"/cache/ping",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error(e)}return await o.json()}catch(e){throw console.error("Failed to call /cache/ping:",e),e}},eQ=async e=>{try{let t=n?"".concat(n,"/sso/get/ui_settings"):"/sso/get/ui_settings",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eW=async e=>{try{let t=n?"".concat(n,"/guardrails/list"):"/guardrails/list",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log("Guardrails list response:",a),a}catch(e){throw console.error("Failed to fetch guardrails list:",e),e}},e0=async(e,t,o)=>{try{let a=n?"".concat(n,"/spend/logs/ui/").concat(t,"?start_date=").concat(encodeURIComponent(o)):"/spend/logs/ui/".concat(t,"?start_date=").concat(encodeURIComponent(o));console.log("Fetching log details from:",a);let r=await fetch(a,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let c=await r.json();return console.log("Fetched log details:",c),c}catch(e){throw console.error("Failed to fetch log details:",e),e}},e1=async e=>{try{let t=n?"".concat(n,"/get/internal_user_settings"):"/get/internal_user_settings";console.log("Fetching SSO settings from:",t);let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log("Fetched SSO settings:",a),a}catch(e){throw console.error("Failed to fetch SSO settings:",e),e}},e3=async(e,t)=>{try{let o=n?"".concat(n,"/update/internal_user_settings"):"/update/internal_user_settings";console.log("Updating internal user settings:",t);let a=await fetch(o,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify(t)});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let c=await a.json();return console.log("Updated internal user settings:",c),r.ZP.success("Internal user settings updated successfully"),c}catch(e){throw console.error("Failed to update internal user settings:",e),e}},e2=async e=>{try{let t=n?"".concat(n,"/mcp/tools/list"):"/mcp/tools/list";console.log("Fetching MCP tools from:",t);let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log("Fetched MCP tools:",a),a}catch(e){throw console.error("Failed to fetch MCP tools:",e),e}},e4=async(e,t,o)=>{try{let a=n?"".concat(n,"/mcp/tools/call"):"/mcp/tools/call";console.log("Calling MCP tool:",t,"with arguments:",o);let r=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({name:t,arguments:o})});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let c=await r.json();return console.log("MCP tool call response:",c),c}catch(e){throw console.error("Failed to call MCP tool:",e),e}},e5=async(e,t)=>{try{let o=n?"".concat(n,"/tag/new"):"/tag/new",a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify(t)});if(!a.ok){let e=await a.text();await i(e);return}return await a.json()}catch(e){throw console.error("Error creating tag:",e),e}},e9=async(e,t)=>{try{let o=n?"".concat(n,"/tag/update"):"/tag/update",a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify(t)});if(!a.ok){let e=await a.text();await i(e);return}return await a.json()}catch(e){throw console.error("Error updating tag:",e),e}},e6=async(e,t)=>{try{let o=n?"".concat(n,"/tag/info"):"/tag/info",a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify({names:t})});if(!a.ok){let e=await a.text();return await i(e),{}}return await a.json()}catch(e){throw console.error("Error getting tag info:",e),e}},e7=async e=>{try{let t=n?"".concat(n,"/tag/list"):"/tag/list",o=await fetch(t,{method:"GET",headers:{Authorization:"Bearer ".concat(e)}});if(!o.ok){let e=await o.text();return await i(e),{}}return await o.json()}catch(e){throw console.error("Error listing tags:",e),e}},e8=async(e,t)=>{try{let o=n?"".concat(n,"/tag/delete"):"/tag/delete",a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify({name:t})});if(!a.ok){let e=await a.text();await i(e);return}return await a.json()}catch(e){throw console.error("Error deleting tag:",e),e}},te=async e=>{try{let t=n?"".concat(n,"/get/default_team_settings"):"/get/default_team_settings";console.log("Fetching default team settings from:",t);let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let a=await o.json();return console.log("Fetched default team settings:",a),a}catch(e){throw console.error("Failed to fetch default team settings:",e),e}},tt=async(e,t)=>{try{let o=n?"".concat(n,"/update/default_team_settings"):"/update/default_team_settings";console.log("Updating default team settings:",t);let a=await fetch(o,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify(t)});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let c=await a.json();return console.log("Updated default team settings:",c),r.ZP.success("Default team settings updated successfully"),c}catch(e){throw console.error("Failed to update default team settings:",e),e}},to=async(e,t)=>{try{let o=n?"".concat(n,"/team/permissions_list?team_id=").concat(t):"/team/permissions_list?team_id=".concat(t),a=await fetch(o,{method:"GET",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let r=await a.json();return console.log("Team permissions response:",r),r}catch(e){throw console.error("Failed to get team permissions:",e),e}},ta=async(e,t,o)=>{try{let a=n?"".concat(n,"/team/permissions_update"):"/team/permissions_update",r=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify({team_id:t,team_member_permissions:o})});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let c=await r.json();return console.log("Team permissions response:",c),c}catch(e){throw console.error("Failed to update team permissions:",e),e}}},20347:function(e,t,o){o.d(t,{LQ:function(){return n},ZL:function(){return a},lo:function(){return r},tY:function(){return c}});let a=["Admin","Admin Viewer","proxy_admin","proxy_admin_viewer","org_admin"],r=["Internal User","Internal Viewer"],n=["Internal User","Admin"],c=e=>a.includes(e)}}]);
\ No newline at end of file
diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/250-f21e8c1de1717077.js b/litellm/proxy/_experimental/out/_next/static/chunks/250-f21e8c1de1717077.js
deleted file mode 100644
index a09ca47f33..0000000000
--- a/litellm/proxy/_experimental/out/_next/static/chunks/250-f21e8c1de1717077.js
+++ /dev/null
@@ -1 +0,0 @@
-"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[250],{19250:function(e,t,o){o.d(t,{$I:function(){return X},AZ:function(){return M},Au:function(){return ef},BL:function(){return ez},Br:function(){return S},E9:function(){return eL},EB:function(){return e7},EG:function(){return eH},EY:function(){return eX},Eb:function(){return C},FC:function(){return ec},Gh:function(){return eF},H1:function(){return v},H2:function(){return n},Hx:function(){return ey},I1:function(){return j},It:function(){return x},J$:function(){return et},K8:function(){return d},K_:function(){return eq},LY:function(){return eG},Lp:function(){return eP},N3:function(){return ej},N8:function(){return Q},NL:function(){return eW},NV:function(){return y},Nc:function(){return eS},O3:function(){return eR},OD:function(){return eg},OU:function(){return el},Of:function(){return b},Og:function(){return f},Ov:function(){return E},PT:function(){return H},Qg:function(){return eC},RQ:function(){return _},Rg:function(){return K},Sb:function(){return eA},So:function(){return W},TF:function(){return tt},Tj:function(){return eY},UM:function(){return e9},VA:function(){return A},Vt:function(){return eM},W_:function(){return R},X:function(){return eo},XO:function(){return k},Xd:function(){return ek},Xm:function(){return F},YU:function(){return eV},Yo:function(){return J},Zr:function(){return m},a6:function(){return O},aC:function(){return te},ao:function(){return eD},b1:function(){return ei},cq:function(){return G},cu:function(){return eO},eH:function(){return q},eZ:function(){return eb},fE:function(){return e6},fP:function(){return $},g:function(){return eK},gX:function(){return eN},h3:function(){return en},hT:function(){return eT},hy:function(){return u},ix:function(){return Z},j2:function(){return er},jA:function(){return eZ},jE:function(){return eI},kK:function(){return p},kn:function(){return D},lP:function(){return h},lU:function(){return e1},lg:function(){return e_},mC:function(){return e5},mR:function(){return ee},mY:function(){return e2},m_:function(){return z},mp:function(){return eU},n$:function(){return ep},n9:function(){return e4},nd:function(){return e0},o6:function(){return Y},oC:function(){return eE},pf:function(){return eJ},qI:function(){return g},qk:function(){return eQ},qm:function(){return w},r1:function(){return e8},r6:function(){return B},rs:function(){return N},s0:function(){return V},sN:function(){return eB},t$:function(){return P},t0:function(){return em},t3:function(){return e$},tB:function(){return e3},tN:function(){return es},u5:function(){return ea},um:function(){return ex},v9:function(){return eu},vh:function(){return ev},wX:function(){return T},wd:function(){return ed},xA:function(){return ew},xX:function(){return I},zg:function(){return eh}});var r=o(20347),a=o(41021);let n=null;console.log=function(){};let c=0,s=e=>new Promise(t=>setTimeout(t,e)),i=async e=>{let t=Date.now();t-c>6e4?(e.includes("Authentication Error - Expired Key")&&(a.ZP.info("UI Session Expired. Logging out."),c=t,await s(3e3),document.cookie="token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;",window.location.href="/"),c=t):console.log("Error suppressed to prevent spam:",e)},l="Authorization";function d(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"Authorization";console.log("setGlobalLitellmHeaderName: ".concat(e)),l=e}let h=async()=>{let e=n?"".concat(n,"/openapi.json"):"/openapi.json",t=await fetch(e);return await t.json()},w=async e=>{try{let t=n?"".concat(n,"/get/litellm_model_cost_map"):"/get/litellm_model_cost_map",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}}),r=await o.json();return console.log("received litellm model cost data: ".concat(r)),r}catch(e){throw console.error("Failed to get model cost map:",e),e}},p=async(e,t)=>{try{let o=n?"".concat(n,"/model/new"):"/model/new",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text()||"Network response was not ok";throw a.ZP.error(e),Error(e)}let c=await r.json();return console.log("API Response:",c),a.ZP.destroy(),a.ZP.success("Model ".concat(t.model_name," created successfully"),2),c}catch(e){throw console.error("Failed to create key:",e),e}},u=async e=>{try{let t=n?"".concat(n,"/model/settings"):"/model/settings",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){console.error("Failed to get model settings:",e)}},f=async(e,t)=>{console.log("model_id in model delete call: ".concat(t));try{let o=n?"".concat(n,"/model/delete"):"/model/delete",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},y=async(e,t)=>{if(console.log("budget_id in budget delete call: ".concat(t)),null!=e)try{let o=n?"".concat(n,"/budget/delete"):"/budget/delete",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},m=async(e,t)=>{try{console.log("Form Values in budgetCreateCall:",t),console.log("Form Values after check:",t);let o=n?"".concat(n,"/budget/new"):"/budget/new",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},g=async(e,t)=>{try{console.log("Form Values in budgetUpdateCall:",t),console.log("Form Values after check:",t);let o=n?"".concat(n,"/budget/update"):"/budget/update",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},k=async(e,t)=>{try{let o=n?"".concat(n,"/invitation/new"):"/invitation/new",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},_=async e=>{try{let t=n?"".concat(n,"/alerting/settings"):"/alerting/settings",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},T=async(e,t,o)=>{try{if(console.log("Form Values in keyCreateCall:",o),o.description&&(o.metadata||(o.metadata={}),o.metadata.description=o.description,delete o.description,o.metadata=JSON.stringify(o.metadata)),o.metadata){console.log("formValues.metadata:",o.metadata);try{o.metadata=JSON.parse(o.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",o);let r=n?"".concat(n,"/key/generate"):"/key/generate",a=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...o})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error(e)}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},E=async(e,t,o)=>{try{if(console.log("Form Values in keyCreateCall:",o),o.description&&(o.metadata||(o.metadata={}),o.metadata.description=o.description,delete o.description,o.metadata=JSON.stringify(o.metadata)),o.auto_create_key=!1,o.metadata){console.log("formValues.metadata:",o.metadata);try{o.metadata=JSON.parse(o.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",o);let r=n?"".concat(n,"/user/new"):"/user/new",a=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...o})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error(e)}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},j=async(e,t)=>{try{let o=n?"".concat(n,"/key/delete"):"/key/delete";console.log("in keyDeleteCall:",t);let r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let a=await r.json();return console.log(a),a}catch(e){throw console.error("Failed to create key:",e),e}},C=async(e,t)=>{try{let o=n?"".concat(n,"/user/delete"):"/user/delete";console.log("in userDeleteCall:",t);let r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_ids:t})});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let a=await r.json();return console.log(a),a}catch(e){throw console.error("Failed to delete user(s):",e),e}},N=async(e,t)=>{try{let o=n?"".concat(n,"/team/delete"):"/team/delete";console.log("in teamDeleteCall:",t);let r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_ids:[t]})});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let a=await r.json();return console.log(a),a}catch(e){throw console.error("Failed to delete key:",e),e}},b=async function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;try{let a=n?"".concat(n,"/user/list"):"/user/list";console.log("in userListCall");let c=new URLSearchParams;if(t&&t.length>0){let e=t.join(",");c.append("user_ids",e)}o&&c.append("page",o.toString()),r&&c.append("page_size",r.toString());let s=c.toString();s&&(a+="?".concat(s));let d=await fetch(a,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!d.ok){let e=await d.text();throw i(e),Error("Network response was not ok")}let h=await d.json();return console.log("/user/list API Response:",h),h}catch(e){throw console.error("Failed to create key:",e),e}},S=async function(e,t,o){let r=arguments.length>3&&void 0!==arguments[3]&&arguments[3],a=arguments.length>4?arguments[4]:void 0,c=arguments.length>5?arguments[5]:void 0;try{let s;if(r){s=n?"".concat(n,"/user/list"):"/user/list";let e=new URLSearchParams;null!=a&&e.append("page",a.toString()),null!=c&&e.append("page_size",c.toString()),s+="?".concat(e.toString())}else s=n?"".concat(n,"/user/info"):"/user/info","Admin"===o||"Admin Viewer"===o||t&&(s+="?user_id=".concat(t));console.log("Requesting user data from:",s);let d=await fetch(s,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!d.ok){let e=await d.text();throw i(e),Error("Network response was not ok")}let h=await d.json();return console.log("API Response:",h),h}catch(e){throw console.error("Failed to fetch user data:",e),e}},F=async(e,t)=>{try{let o=n?"".concat(n,"/team/info"):"/team/info";t&&(o="".concat(o,"?team_id=").concat(t)),console.log("in teamInfoCall");let r=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},x=async function(e,t){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;try{let r=n?"".concat(n,"/team/list"):"/team/list";console.log("in teamInfoCall");let a=new URLSearchParams;o&&a.append("user_id",o.toString()),t&&a.append("organization_id",t.toString());let c=a.toString();c&&(r+="?".concat(c));let s=await fetch(r,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!s.ok){let e=await s.text();throw i(e),Error("Network response was not ok")}let d=await s.json();return console.log("/team/list API Response:",d),d}catch(e){throw console.error("Failed to create key:",e),e}},O=async e=>{try{let t=n?"".concat(n,"/team/available"):"/team/available";console.log("in availableTeamListCall");let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log("/team/available_teams API Response:",r),r}catch(e){throw e}},B=async e=>{try{let t=n?"".concat(n,"/organization/list"):"/organization/list",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},P=async(e,t)=>{try{let o=n?"".concat(n,"/organization/info"):"/organization/info";t&&(o="".concat(o,"?organization_id=").concat(t)),console.log("in teamInfoCall");let r=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},v=async(e,t)=>{try{if(console.log("Form Values in organizationCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw console.error("Failed to parse metadata:",e),Error("Failed to parse metadata: "+e)}}let o=n?"".concat(n,"/organization/new"):"/organization/new",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},A=async(e,t)=>{try{console.log("Form Values in organizationUpdateCall:",t);let o=n?"".concat(n,"/organization/update"):"/organization/update",r=await fetch(o,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("Update Team Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},G=async(e,t)=>{try{let o=n?"".concat(n,"/organization/delete"):"/organization/delete",r=await fetch(o,{method:"DELETE",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({organization_ids:[t]})});if(!r.ok){let e=await r.text();throw i(e),Error("Error deleting organization: ".concat(e))}return await r.json()}catch(e){throw console.error("Failed to delete organization:",e),e}},J=async(e,t)=>{try{let o=n?"".concat(n,"/utils/transform_request"):"/utils/transform_request",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify(t)});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to create key:",e),e}},I=async function(e,t,o){let r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1;try{let a=n?"".concat(n,"/user/daily/activity"):"/user/daily/activity",c=new URLSearchParams;c.append("start_date",t.toISOString()),c.append("end_date",o.toISOString()),c.append("page_size","1000"),c.append("page",r.toString());let s=c.toString();s&&(a+="?".concat(s));let d=await fetch(a,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!d.ok){let e=await d.text();throw i(e),Error("Network response was not ok")}return await d.json()}catch(e){throw console.error("Failed to create key:",e),e}},R=async e=>{try{let t=n?"".concat(n,"/onboarding/get_token"):"/onboarding/get_token";t+="?invite_link=".concat(e);let o=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},z=async(e,t,o,r)=>{let a=n?"".concat(n,"/onboarding/claim_token"):"/onboarding/claim_token";try{let n=await fetch(a,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({invitation_link:t,user_id:o,password:r})});if(!n.ok){let e=await n.text();throw i(e),Error("Network response was not ok")}let c=await n.json();return console.log(c),c}catch(e){throw console.error("Failed to delete key:",e),e}},V=async(e,t,o)=>{try{let r=n?"".concat(n,"/key/").concat(t,"/regenerate"):"/key/".concat(t,"/regenerate"),a=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify(o)});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let c=await a.json();return console.log("Regenerate key Response:",c),c}catch(e){throw console.error("Failed to regenerate key:",e),e}},U=!1,L=null,M=async(e,t,o)=>{try{console.log("modelInfoCall:",e,t,o);let c=n?"".concat(n,"/v2/model/info"):"/v2/model/info";r.ZL.includes(o)||(c+="?user_models_only=true");let s=await fetch(c,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!s.ok){let e=await s.text();throw e+="error shown=".concat(U),U||(e.includes("No model list passed")&&(e="No Models Exist. Click Add Model to get started."),a.ZP.info(e,10),U=!0,L&&clearTimeout(L),L=setTimeout(()=>{U=!1},1e4)),Error("Network response was not ok")}let i=await s.json();return console.log("modelInfoCall:",i),i}catch(e){throw console.error("Failed to create key:",e),e}},Z=async(e,t)=>{try{let o=n?"".concat(n,"/v1/model/info"):"/v1/model/info";o+="?litellm_model_id=".concat(t);let r=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok)throw await r.text(),Error("Network response was not ok");let a=await r.json();return console.log("modelInfoV1Call:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},D=async e=>{try{let t=n?"".concat(n,"/model_group/info"):"/model_group/info",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");let r=await o.json();return console.log("modelHubCall:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},H=async e=>{try{let t=n?"".concat(n,"/get/allowed_ips"):"/get/allowed_ips",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw Error("Network response was not ok: ".concat(e))}let r=await o.json();return console.log("getAllowedIPs:",r),r.data}catch(e){throw console.error("Failed to get allowed IPs:",e),e}},q=async(e,t)=>{try{let o=n?"".concat(n,"/add/allowed_ip"):"/add/allowed_ip",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!r.ok){let e=await r.text();throw Error("Network response was not ok: ".concat(e))}let a=await r.json();return console.log("addAllowedIP:",a),a}catch(e){throw console.error("Failed to add allowed IP:",e),e}},X=async(e,t)=>{try{let o=n?"".concat(n,"/delete/allowed_ip"):"/delete/allowed_ip",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!r.ok){let e=await r.text();throw Error("Network response was not ok: ".concat(e))}let a=await r.json();return console.log("deleteAllowedIP:",a),a}catch(e){throw console.error("Failed to delete allowed IP:",e),e}},Y=async(e,t,o,r,a,c,s,d)=>{try{let t=n?"".concat(n,"/model/metrics"):"/model/metrics";r&&(t="".concat(t,"?_selected_model_group=").concat(r,"&startTime=").concat(a,"&endTime=").concat(c,"&api_key=").concat(s,"&customer=").concat(d));let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},K=async(e,t,o,r)=>{try{let a=n?"".concat(n,"/model/streaming_metrics"):"/model/streaming_metrics";t&&(a="".concat(a,"?_selected_model_group=").concat(t,"&startTime=").concat(o,"&endTime=").concat(r));let c=await fetch(a,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!c.ok){let e=await c.text();throw i(e),Error("Network response was not ok")}return await c.json()}catch(e){throw console.error("Failed to create key:",e),e}},$=async(e,t,o,r,a,c,s,d)=>{try{let t=n?"".concat(n,"/model/metrics/slow_responses"):"/model/metrics/slow_responses";r&&(t="".concat(t,"?_selected_model_group=").concat(r,"&startTime=").concat(a,"&endTime=").concat(c,"&api_key=").concat(s,"&customer=").concat(d));let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},Q=async(e,t,o,r,a,c,s,d)=>{try{let t=n?"".concat(n,"/model/metrics/exceptions"):"/model/metrics/exceptions";r&&(t="".concat(t,"?_selected_model_group=").concat(r,"&startTime=").concat(a,"&endTime=").concat(c,"&api_key=").concat(s,"&customer=").concat(d));let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to create key:",e),e}},W=async function(e,t,o){let r=arguments.length>3&&void 0!==arguments[3]&&arguments[3],a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;console.log("in /models calls, globalLitellmHeaderName",l);try{let t=n?"".concat(n,"/models"):"/models",o=new URLSearchParams;!0===r&&o.append("return_wildcard_routes","True"),a&&o.append("team_id",a.toString()),o.toString()&&(t+="?".concat(o.toString()));let c=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!c.ok){let e=await c.text();throw i(e),Error("Network response was not ok")}return await c.json()}catch(e){throw console.error("Failed to create key:",e),e}},ee=async e=>{try{let t=n?"".concat(n,"/global/spend/teams"):"/global/spend/teams";console.log("in teamSpendLogsCall:",t);let o=await fetch("".concat(t),{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log(r),r}catch(e){throw console.error("Failed to create key:",e),e}},et=async(e,t,o,r)=>{try{let a=n?"".concat(n,"/global/spend/tags"):"/global/spend/tags";t&&o&&(a="".concat(a,"?start_date=").concat(t,"&end_date=").concat(o)),r&&(a+="".concat(a,"&tags=").concat(r.join(","))),console.log("in tagsSpendLogsCall:",a);let c=await fetch("".concat(a),{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!c.ok)throw await c.text(),Error("Network response was not ok");let s=await c.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}},eo=async e=>{try{let t=n?"".concat(n,"/global/spend/all_tag_names"):"/global/spend/all_tag_names";console.log("in global/spend/all_tag_names call",t);let o=await fetch("".concat(t),{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");let r=await o.json();return console.log(r),r}catch(e){throw console.error("Failed to create key:",e),e}},er=async e=>{try{let t=n?"".concat(n,"/global/all_end_users"):"/global/all_end_users";console.log("in global/all_end_users call",t);let o=await fetch("".concat(t),{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");let r=await o.json();return console.log(r),r}catch(e){throw console.error("Failed to create key:",e),e}},ea=async(e,t)=>{try{let o=n?"".concat(n,"/user/filter/ui"):"/user/filter/ui";t.get("user_email")&&(o+="?user_email=".concat(t.get("user_email"))),t.get("user_id")&&(o+="?user_id=".concat(t.get("user_id")));let r=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to create key:",e),e}},en=async(e,t,o,r,a,c,s,d,h)=>{try{let w=n?"".concat(n,"/spend/logs/ui"):"/spend/logs/ui",p=new URLSearchParams;t&&p.append("api_key",t),o&&p.append("team_id",o),r&&p.append("request_id",r),a&&p.append("start_date",a),c&&p.append("end_date",c),s&&p.append("page",s.toString()),d&&p.append("page_size",d.toString()),h&&p.append("user_id",h);let u=p.toString();u&&(w+="?".concat(u));let f=await fetch(w,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!f.ok){let e=await f.text();throw i(e),Error("Network response was not ok")}let y=await f.json();return console.log("Spend Logs Response:",y),y}catch(e){throw console.error("Failed to fetch spend logs:",e),e}},ec=async e=>{try{let t=n?"".concat(n,"/global/spend/logs"):"/global/spend/logs",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log(r),r}catch(e){throw console.error("Failed to create key:",e),e}},es=async e=>{try{let t=n?"".concat(n,"/global/spend/keys?limit=5"):"/global/spend/keys?limit=5",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log(r),r}catch(e){throw console.error("Failed to create key:",e),e}},ei=async(e,t,o,r)=>{try{let a=n?"".concat(n,"/global/spend/end_users"):"/global/spend/end_users",c="";c=t?JSON.stringify({api_key:t,startTime:o,endTime:r}):JSON.stringify({startTime:o,endTime:r});let s={method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:c},d=await fetch(a,s);if(!d.ok){let e=await d.text();throw i(e),Error("Network response was not ok")}let h=await d.json();return console.log(h),h}catch(e){throw console.error("Failed to create key:",e),e}},el=async(e,t,o,r)=>{try{let a=n?"".concat(n,"/global/spend/provider"):"/global/spend/provider";o&&r&&(a+="?start_date=".concat(o,"&end_date=").concat(r)),t&&(a+="&api_key=".concat(t));let c={method:"GET",headers:{[l]:"Bearer ".concat(e)}},s=await fetch(a,c);if(!s.ok){let e=await s.text();throw i(e),Error("Network response was not ok")}let d=await s.json();return console.log(d),d}catch(e){throw console.error("Failed to fetch spend data:",e),e}},ed=async(e,t,o)=>{try{let r=n?"".concat(n,"/global/activity"):"/global/activity";t&&o&&(r+="?start_date=".concat(t,"&end_date=").concat(o));let a={method:"GET",headers:{[l]:"Bearer ".concat(e)}},c=await fetch(r,a);if(!c.ok)throw await c.text(),Error("Network response was not ok");let s=await c.json();return console.log(s),s}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eh=async(e,t,o)=>{try{let r=n?"".concat(n,"/global/activity/cache_hits"):"/global/activity/cache_hits";t&&o&&(r+="?start_date=".concat(t,"&end_date=").concat(o));let a={method:"GET",headers:{[l]:"Bearer ".concat(e)}},c=await fetch(r,a);if(!c.ok)throw await c.text(),Error("Network response was not ok");let s=await c.json();return console.log(s),s}catch(e){throw console.error("Failed to fetch spend data:",e),e}},ew=async(e,t,o)=>{try{let r=n?"".concat(n,"/global/activity/model"):"/global/activity/model";t&&o&&(r+="?start_date=".concat(t,"&end_date=").concat(o));let a={method:"GET",headers:{[l]:"Bearer ".concat(e)}},c=await fetch(r,a);if(!c.ok)throw await c.text(),Error("Network response was not ok");let s=await c.json();return console.log(s),s}catch(e){throw console.error("Failed to fetch spend data:",e),e}},ep=async(e,t,o,r)=>{try{let a=n?"".concat(n,"/global/activity/exceptions"):"/global/activity/exceptions";t&&o&&(a+="?start_date=".concat(t,"&end_date=").concat(o)),r&&(a+="&model_group=".concat(r));let c={method:"GET",headers:{[l]:"Bearer ".concat(e)}},s=await fetch(a,c);if(!s.ok)throw await s.text(),Error("Network response was not ok");let i=await s.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eu=async(e,t,o,r)=>{try{let a=n?"".concat(n,"/global/activity/exceptions/deployment"):"/global/activity/exceptions/deployment";t&&o&&(a+="?start_date=".concat(t,"&end_date=").concat(o)),r&&(a+="&model_group=".concat(r));let c={method:"GET",headers:{[l]:"Bearer ".concat(e)}},s=await fetch(a,c);if(!s.ok)throw await s.text(),Error("Network response was not ok");let i=await s.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},ef=async e=>{try{let t=n?"".concat(n,"/global/spend/models?limit=5"):"/global/spend/models?limit=5",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log(r),r}catch(e){throw console.error("Failed to create key:",e),e}},ey=async(e,t,o)=>{try{console.log("Sending model connection test request:",JSON.stringify(t));let a=n?"".concat(n,"/health/test_connection"):"/health/test_connection",c=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json",[l]:"Bearer ".concat(e)},body:JSON.stringify({litellm_params:t,mode:o})}),s=c.headers.get("content-type");if(!s||!s.includes("application/json")){let e=await c.text();throw console.error("Received non-JSON response:",e),Error("Received non-JSON response (".concat(c.status,": ").concat(c.statusText,"). Check network tab for details."))}let i=await c.json();if(!c.ok||"error"===i.status){if("error"===i.status);else{var r;return{status:"error",message:(null===(r=i.error)||void 0===r?void 0:r.message)||"Connection test failed: ".concat(c.status," ").concat(c.statusText)}}}return i}catch(e){throw console.error("Model connection test error:",e),e}},em=async(e,t)=>{try{console.log("entering keyInfoV1Call");let o=n?"".concat(n,"/key/info"):"/key/info";o="".concat(o,"?key=").concat(t);let r=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(console.log("response",r),!r.ok){let e=await r.text();i(e),a.ZP.error("Failed to fetch key info - "+e)}let c=await r.json();return console.log("data",c),c}catch(e){throw console.error("Failed to fetch key info:",e),e}},eg=async(e,t,o,r,a)=>{try{let c=n?"".concat(n,"/key/list"):"/key/list";console.log("in keyListCall");let s=new URLSearchParams;o&&s.append("team_id",o.toString()),t&&s.append("organization_id",t.toString()),r&&s.append("page",r.toString()),a&&s.append("size",a.toString()),s.append("return_full_object","true"),s.append("include_team_keys","true");let d=s.toString();d&&(c+="?".concat(d));let h=await fetch(c,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!h.ok){let e=await h.text();throw i(e),Error("Network response was not ok")}let w=await h.json();return console.log("/team/list API Response:",w),w}catch(e){throw console.error("Failed to create key:",e),e}},ek=async(e,t)=>{try{let o=n?"".concat(n,"/user/get_users?role=").concat(t):"/user/get_users?role=".concat(t);console.log("in userGetAllUsersCall:",o);let r=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let a=await r.json();return console.log(a),a}catch(e){throw console.error("Failed to get requested models:",e),e}},e_=async e=>{try{let t=n?"".concat(n,"/user/available_roles"):"/user/available_roles",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");let r=await o.json();return console.log("response from user/available_role",r),r}catch(e){throw e}},eT=async(e,t)=>{try{if(console.log("Form Values in teamCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let o=n?"".concat(n,"/team/new"):"/team/new",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},eE=async(e,t)=>{try{if(console.log("Form Values in credentialCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let o=n?"".concat(n,"/credentials"):"/credentials",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},ej=async e=>{try{let t=n?"".concat(n,"/credentials"):"/credentials";console.log("in credentialListCall");let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log("/credentials API Response:",r),r}catch(e){throw console.error("Failed to create key:",e),e}},eC=async(e,t,o)=>{try{let r=n?"".concat(n,"/credentials"):"/credentials";t?r+="/by_name/".concat(t):o&&(r+="/by_model/".concat(o)),console.log("in credentialListCall");let a=await fetch(r,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let c=await a.json();return console.log("/credentials API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},eN=async(e,t)=>{try{let o=n?"".concat(n,"/credentials/").concat(t):"/credentials/".concat(t);console.log("in credentialDeleteCall:",t);let r=await fetch(o,{method:"DELETE",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let a=await r.json();return console.log(a),a}catch(e){throw console.error("Failed to delete key:",e),e}},eb=async(e,t,o)=>{try{if(console.log("Form Values in credentialUpdateCall:",o),o.metadata){console.log("formValues.metadata:",o.metadata);try{o.metadata=JSON.parse(o.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=n?"".concat(n,"/credentials/").concat(t):"/credentials/".concat(t),a=await fetch(r,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...o})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},eS=async(e,t)=>{try{if(console.log("Form Values in keyUpdateCall:",t),t.model_tpm_limit){console.log("formValues.model_tpm_limit:",t.model_tpm_limit);try{t.model_tpm_limit=JSON.parse(t.model_tpm_limit)}catch(e){throw Error("Failed to parse model_tpm_limit: "+e)}}if(t.model_rpm_limit){console.log("formValues.model_rpm_limit:",t.model_rpm_limit);try{t.model_rpm_limit=JSON.parse(t.model_rpm_limit)}catch(e){throw Error("Failed to parse model_rpm_limit: "+e)}}let o=n?"".concat(n,"/key/update"):"/key/update",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("Update key Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},eF=async(e,t)=>{try{console.log("Form Values in teamUpateCall:",t);let o=n?"".concat(n,"/team/update"):"/team/update",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("Update Team Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},ex=async(e,t)=>{try{console.log("Form Values in modelUpateCall:",t);let o=n?"".concat(n,"/model/update"):"/model/update",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),console.error("Error update from the server:",e),Error("Network response was not ok")}let a=await r.json();return console.log("Update model Response:",a),a}catch(e){throw console.error("Failed to update model:",e),e}},eO=async(e,t,o)=>{try{console.log("Form Values in teamMemberAddCall:",o);let r=n?"".concat(n,"/team/member_add"):"/team/member_add",a=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:o})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},eB=async(e,t,o)=>{try{console.log("Form Values in teamMemberAddCall:",o);let r=n?"".concat(n,"/team/member_update"):"/team/member_update",a=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_id:t,role:o.role,user_id:o.user_id})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},eP=async(e,t,o)=>{try{console.log("Form Values in teamMemberAddCall:",o);let r=n?"".concat(n,"/team/member_delete"):"/team/member_delete",a=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_id:t,...void 0!==o.user_email&&{user_email:o.user_email},...void 0!==o.user_id&&{user_id:o.user_id}})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},ev=async(e,t,o)=>{try{console.log("Form Values in teamMemberAddCall:",o);let r=n?"".concat(n,"/organization/member_add"):"/organization/member_add",a=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,member:o})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error(e)}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to create organization member:",e),e}},eA=async(e,t,o)=>{try{console.log("Form Values in organizationMemberDeleteCall:",o);let r=n?"".concat(n,"/organization/member_delete"):"/organization/member_delete",a=await fetch(r,{method:"DELETE",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,user_id:o})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to delete organization member:",e),e}},eG=async(e,t,o)=>{try{console.log("Form Values in organizationMemberUpdateCall:",o);let r=n?"".concat(n,"/organization/member_update"):"/organization/member_update",a=await fetch(r,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,...o})});if(!a.ok){let e=await a.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let c=await a.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to update organization member:",e),e}},eJ=async(e,t,o)=>{try{console.log("Form Values in userUpdateUserCall:",t);let r=n?"".concat(n,"/user/update"):"/user/update",a={...t};null!==o&&(a.user_role=o),a=JSON.stringify(a);let c=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:a});if(!c.ok){let e=await c.text();throw i(e),console.error("Error response from the server:",e),Error("Network response was not ok")}let s=await c.json();return console.log("API Response:",s),s}catch(e){throw console.error("Failed to create key:",e),e}},eI=async(e,t)=>{try{let o=n?"".concat(n,"/health/services?service=").concat(t):"/health/services?service=".concat(t);console.log("Checking Slack Budget Alerts service health");let r=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error(e)}let c=await r.json();return a.ZP.success("Test request to ".concat(t," made - check logs/alerts on ").concat(t," to verify")),c}catch(e){throw console.error("Failed to perform health check:",e),e}},eR=async e=>{try{let t=n?"".concat(n,"/budget/list"):"/budget/list",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},ez=async(e,t,o)=>{try{let t=n?"".concat(n,"/get/config/callbacks"):"/get/config/callbacks",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eV=async e=>{try{let t=n?"".concat(n,"/config/list?config_type=general_settings"):"/config/list?config_type=general_settings",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eU=async e=>{try{let t=n?"".concat(n,"/config/pass_through_endpoint"):"/config/pass_through_endpoint",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eL=async(e,t)=>{try{let o=n?"".concat(n,"/config/field/info?field_name=").concat(t):"/config/field/info?field_name=".concat(t),r=await fetch(o,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok)throw await r.text(),Error("Network response was not ok");return await r.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},eM=async(e,t)=>{try{let o=n?"".concat(n,"/config/pass_through_endpoint"):"/config/pass_through_endpoint",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},eZ=async(e,t,o)=>{try{let r=n?"".concat(n,"/config/field/update"):"/config/field/update",c=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({field_name:t,field_value:o,config_type:"general_settings"})});if(!c.ok){let e=await c.text();throw i(e),Error("Network response was not ok")}let s=await c.json();return a.ZP.success("Successfully updated value!"),s}catch(e){throw console.error("Failed to set callbacks:",e),e}},eD=async(e,t)=>{try{let o=n?"".concat(n,"/config/field/delete"):"/config/field/delete",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({field_name:t,config_type:"general_settings"})});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let c=await r.json();return a.ZP.success("Field reset on proxy"),c}catch(e){throw console.error("Failed to get callbacks:",e),e}},eH=async(e,t)=>{try{let o=n?"".concat(n,"/config/pass_through_endpoint?endpoint_id=").concat(t):"/config/pass_through_endpoint".concat(t),r=await fetch(o,{method:"DELETE",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},eq=async(e,t)=>{try{let o=n?"".concat(n,"/config/update"):"/config/update",r=await fetch(o,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},eX=async e=>{try{let t=n?"".concat(n,"/health"):"/health",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}return await o.json()}catch(e){throw console.error("Failed to call /health:",e),e}},eY=async e=>{try{let t=n?"".concat(n,"/cache/ping"):"/cache/ping",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error(e)}return await o.json()}catch(e){throw console.error("Failed to call /cache/ping:",e),e}},eK=async e=>{try{let t=n?"".concat(n,"/sso/get/ui_settings"):"/sso/get/ui_settings",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok)throw await o.text(),Error("Network response was not ok");return await o.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},e$=async e=>{try{let t=n?"".concat(n,"/guardrails/list"):"/guardrails/list",o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log("Guardrails list response:",r),r}catch(e){throw console.error("Failed to fetch guardrails list:",e),e}},eQ=async(e,t,o)=>{try{let r=n?"".concat(n,"/spend/logs/ui/").concat(t,"?start_date=").concat(encodeURIComponent(o)):"/spend/logs/ui/".concat(t,"?start_date=").concat(encodeURIComponent(o));console.log("Fetching log details from:",r);let a=await fetch(r,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let c=await a.json();return console.log("Fetched log details:",c),c}catch(e){throw console.error("Failed to fetch log details:",e),e}},eW=async e=>{try{let t=n?"".concat(n,"/get/internal_user_settings"):"/get/internal_user_settings";console.log("Fetching SSO settings from:",t);let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log("Fetched SSO settings:",r),r}catch(e){throw console.error("Failed to fetch SSO settings:",e),e}},e0=async(e,t)=>{try{let o=n?"".concat(n,"/update/internal_user_settings"):"/update/internal_user_settings";console.log("Updating internal user settings:",t);let r=await fetch(o,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify(t)});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let c=await r.json();return console.log("Updated internal user settings:",c),a.ZP.success("Internal user settings updated successfully"),c}catch(e){throw console.error("Failed to update internal user settings:",e),e}},e1=async e=>{try{let t=n?"".concat(n,"/mcp/tools/list"):"/mcp/tools/list";console.log("Fetching MCP tools from:",t);let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log("Fetched MCP tools:",r),r}catch(e){throw console.error("Failed to fetch MCP tools:",e),e}},e3=async(e,t,o)=>{try{let r=n?"".concat(n,"/mcp/tools/call"):"/mcp/tools/call";console.log("Calling MCP tool:",t,"with arguments:",o);let a=await fetch(r,{method:"POST",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({name:t,arguments:o})});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let c=await a.json();return console.log("MCP tool call response:",c),c}catch(e){throw console.error("Failed to call MCP tool:",e),e}},e2=async(e,t)=>{try{let o=n?"".concat(n,"/tag/new"):"/tag/new",r=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify(t)});if(!r.ok){let e=await r.text();await i(e);return}return await r.json()}catch(e){throw console.error("Error creating tag:",e),e}},e4=async(e,t)=>{try{let o=n?"".concat(n,"/tag/update"):"/tag/update",r=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify(t)});if(!r.ok){let e=await r.text();await i(e);return}return await r.json()}catch(e){throw console.error("Error updating tag:",e),e}},e5=async(e,t)=>{try{let o=n?"".concat(n,"/tag/info"):"/tag/info",r=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify({names:t})});if(!r.ok){let e=await r.text();return await i(e),{}}return await r.json()}catch(e){throw console.error("Error getting tag info:",e),e}},e9=async e=>{try{let t=n?"".concat(n,"/tag/list"):"/tag/list",o=await fetch(t,{method:"GET",headers:{Authorization:"Bearer ".concat(e)}});if(!o.ok){let e=await o.text();return await i(e),{}}return await o.json()}catch(e){throw console.error("Error listing tags:",e),e}},e6=async(e,t)=>{try{let o=n?"".concat(n,"/tag/delete"):"/tag/delete",r=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify({name:t})});if(!r.ok){let e=await r.text();await i(e);return}return await r.json()}catch(e){throw console.error("Error deleting tag:",e),e}},e7=async e=>{try{let t=n?"".concat(n,"/get/default_team_settings"):"/get/default_team_settings";console.log("Fetching default team settings from:",t);let o=await fetch(t,{method:"GET",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw i(e),Error("Network response was not ok")}let r=await o.json();return console.log("Fetched default team settings:",r),r}catch(e){throw console.error("Failed to fetch default team settings:",e),e}},e8=async(e,t)=>{try{let o=n?"".concat(n,"/update/default_team_settings"):"/update/default_team_settings";console.log("Updating default team settings:",t);let r=await fetch(o,{method:"PATCH",headers:{[l]:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify(t)});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let c=await r.json();return console.log("Updated default team settings:",c),a.ZP.success("Default team settings updated successfully"),c}catch(e){throw console.error("Failed to update default team settings:",e),e}},te=async(e,t)=>{try{let o=n?"".concat(n,"/team/permissions_list?team_id=").concat(t):"/team/permissions_list?team_id=".concat(t),r=await fetch(o,{method:"GET",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)}});if(!r.ok){let e=await r.text();throw i(e),Error("Network response was not ok")}let a=await r.json();return console.log("Team permissions response:",a),a}catch(e){throw console.error("Failed to get team permissions:",e),e}},tt=async(e,t,o)=>{try{let r=n?"".concat(n,"/team/permissions_update"):"/team/permissions_update",a=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(e)},body:JSON.stringify({team_id:t,team_member_permissions:o})});if(!a.ok){let e=await a.text();throw i(e),Error("Network response was not ok")}let c=await a.json();return console.log("Team permissions response:",c),c}catch(e){throw console.error("Failed to update team permissions:",e),e}}},20347:function(e,t,o){o.d(t,{LQ:function(){return n},ZL:function(){return r},lo:function(){return a},tY:function(){return c}});let r=["Admin","Admin Viewer","proxy_admin","proxy_admin_viewer","org_admin"],a=["Internal User","Internal Viewer"],n=["Internal User","Admin"],c=e=>r.includes(e)}}]);
\ No newline at end of file
diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/261-d4b99bc9f53d4ef3.js b/litellm/proxy/_experimental/out/_next/static/chunks/261-57d48f76eec1e568.js
similarity index 99%
rename from litellm/proxy/_experimental/out/_next/static/chunks/261-d4b99bc9f53d4ef3.js
rename to litellm/proxy/_experimental/out/_next/static/chunks/261-57d48f76eec1e568.js
index f21f16362b..44e5f1be73 100644
--- a/litellm/proxy/_experimental/out/_next/static/chunks/261-d4b99bc9f53d4ef3.js
+++ b/litellm/proxy/_experimental/out/_next/static/chunks/261-57d48f76eec1e568.js
@@ -1 +1 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[261],{23639:function(e,t,n){"use strict";n.d(t,{Z:function(){return s}});var a=n(1119),r=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32zM704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c2.2 2.2 4.7 4 7.4 5.5v1.9h4.2c3.5 1.3 7.2 2 11 2H704c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM350 856.2L263.9 770H350v86.2zM664 888H414V746c0-22.1-17.9-40-40-40H232V264h432v624z"}}]},name:"copy",theme:"outlined"},o=n(55015),s=r.forwardRef(function(e,t){return r.createElement(o.Z,(0,a.Z)({},e,{ref:t,icon:i}))})},77565:function(e,t,n){"use strict";n.d(t,{Z:function(){return s}});var a=n(1119),r=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"}}]},name:"right",theme:"outlined"},o=n(55015),s=r.forwardRef(function(e,t){return r.createElement(o.Z,(0,a.Z)({},e,{ref:t,icon:i}))})},12485:function(e,t,n){"use strict";n.d(t,{Z:function(){return p}});var a=n(5853),r=n(31492),i=n(26898),o=n(65954),s=n(1153),l=n(2265),c=n(35242),u=n(42698);n(64016),n(8710),n(33232);let d=(0,s.fn)("Tab"),p=l.forwardRef((e,t)=>{let{icon:n,className:p,children:g}=e,m=(0,a._T)(e,["icon","className","children"]),b=(0,l.useContext)(c.O),f=(0,l.useContext)(u.Z);return l.createElement(r.O,Object.assign({ref:t,className:(0,o.q)(d("root"),"flex whitespace-nowrap truncate max-w-xs outline-none focus:ring-0 text-tremor-default transition duration-100",f?(0,s.bM)(f,i.K.text).selectTextColor:"solid"===b?"ui-selected:text-tremor-content-emphasis dark:ui-selected:text-dark-tremor-content-emphasis":"ui-selected:text-tremor-brand dark:ui-selected:text-dark-tremor-brand",function(e,t){switch(e){case"line":return(0,o.q)("ui-selected:border-b-2 hover:border-b-2 border-transparent transition duration-100 -mb-px px-2 py-2","hover:border-tremor-content hover:text-tremor-content-emphasis text-tremor-content","dark:hover:border-dark-tremor-content-emphasis dark:hover:text-dark-tremor-content-emphasis dark:text-dark-tremor-content",t?(0,s.bM)(t,i.K.border).selectBorderColor:"ui-selected:border-tremor-brand dark:ui-selected:border-dark-tremor-brand");case"solid":return(0,o.q)("border-transparent border rounded-tremor-small px-2.5 py-1","ui-selected:border-tremor-border ui-selected:bg-tremor-background ui-selected:shadow-tremor-input hover:text-tremor-content-emphasis ui-selected:text-tremor-brand","dark:ui-selected:border-dark-tremor-border dark:ui-selected:bg-dark-tremor-background dark:ui-selected:shadow-dark-tremor-input dark:hover:text-dark-tremor-content-emphasis dark:ui-selected:text-dark-tremor-brand",t?(0,s.bM)(t,i.K.text).selectTextColor:"text-tremor-content dark:text-dark-tremor-content")}}(b,f),p)},m),n?l.createElement(n,{className:(0,o.q)(d("icon"),"flex-none h-5 w-5",g?"mr-2":"")}):null,g?l.createElement("span",null,g):null)});p.displayName="Tab"},18135:function(e,t,n){"use strict";n.d(t,{Z:function(){return c}});var a=n(5853),r=n(31492),i=n(65954),o=n(1153),s=n(2265);let l=(0,o.fn)("TabGroup"),c=s.forwardRef((e,t)=>{let{defaultIndex:n,index:o,onIndexChange:c,children:u,className:d}=e,p=(0,a._T)(e,["defaultIndex","index","onIndexChange","children","className"]);return s.createElement(r.O.Group,Object.assign({as:"div",ref:t,defaultIndex:n,selectedIndex:o,onChange:c,className:(0,i.q)(l("root"),"w-full",d)},p),u)});c.displayName="TabGroup"},35242:function(e,t,n){"use strict";n.d(t,{O:function(){return c},Z:function(){return d}});var a=n(5853),r=n(2265),i=n(42698);n(64016),n(8710),n(33232);var o=n(31492),s=n(65954);let l=(0,n(1153).fn)("TabList"),c=(0,r.createContext)("line"),u={line:(0,s.q)("flex border-b space-x-4","border-tremor-border","dark:border-dark-tremor-border"),solid:(0,s.q)("inline-flex p-0.5 rounded-tremor-default space-x-1.5","bg-tremor-background-subtle","dark:bg-dark-tremor-background-subtle")},d=r.forwardRef((e,t)=>{let{color:n,variant:d="line",children:p,className:g}=e,m=(0,a._T)(e,["color","variant","children","className"]);return r.createElement(o.O.List,Object.assign({ref:t,className:(0,s.q)(l("root"),"justify-start overflow-x-clip",u[d],g)},m),r.createElement(c.Provider,{value:d},r.createElement(i.Z.Provider,{value:n},p)))});d.displayName="TabList"},29706:function(e,t,n){"use strict";n.d(t,{Z:function(){return u}});var a=n(5853);n(42698);var r=n(64016);n(8710);var i=n(33232),o=n(65954),s=n(1153),l=n(2265);let c=(0,s.fn)("TabPanel"),u=l.forwardRef((e,t)=>{let{children:n,className:s}=e,u=(0,a._T)(e,["children","className"]),{selectedValue:d}=(0,l.useContext)(i.Z),p=d===(0,l.useContext)(r.Z);return l.createElement("div",Object.assign({ref:t,className:(0,o.q)(c("root"),"w-full mt-2",p?"":"hidden",s),"aria-selected":p?"true":"false"},u),n)});u.displayName="TabPanel"},77991:function(e,t,n){"use strict";n.d(t,{Z:function(){return d}});var a=n(5853),r=n(31492);n(42698);var i=n(64016);n(8710);var o=n(33232),s=n(65954),l=n(1153),c=n(2265);let u=(0,l.fn)("TabPanels"),d=c.forwardRef((e,t)=>{let{children:n,className:l}=e,d=(0,a._T)(e,["children","className"]);return c.createElement(r.O.Panels,Object.assign({as:"div",ref:t,className:(0,s.q)(u("root"),"w-full",l)},d),e=>{let{selectedIndex:t}=e;return c.createElement(o.Z.Provider,{value:{selectedValue:t}},c.Children.map(n,(e,t)=>c.createElement(i.Z.Provider,{value:t},e)))})});d.displayName="TabPanels"},42698:function(e,t,n){"use strict";n.d(t,{Z:function(){return i}});var a=n(2265),r=n(7084);n(65954);let i=(0,a.createContext)(r.fr.Blue)},64016:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});let a=(0,n(2265).createContext)(0)},8710:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});let a=(0,n(2265).createContext)(void 0)},33232:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});let a=(0,n(2265).createContext)({selectedValue:void 0,handleValueChange:void 0})},93942:function(e,t,n){"use strict";n.d(t,{i:function(){return s}});var a=n(2265),r=n(50506),i=n(13959),o=n(71744);function s(e){return t=>a.createElement(i.ZP,{theme:{token:{motion:!1,zIndexPopupBase:0}}},a.createElement(e,Object.assign({},t)))}t.Z=(e,t,n,i)=>s(s=>{let{prefixCls:l,style:c}=s,u=a.useRef(null),[d,p]=a.useState(0),[g,m]=a.useState(0),[b,f]=(0,r.Z)(!1,{value:s.open}),{getPrefixCls:E}=a.useContext(o.E_),h=E(t||"select",l);a.useEffect(()=>{if(f(!0),"undefined"!=typeof ResizeObserver){let e=new ResizeObserver(e=>{let t=e[0].target;p(t.offsetHeight+8),m(t.offsetWidth)}),t=setInterval(()=>{var a;let r=n?".".concat(n(h)):".".concat(h,"-dropdown"),i=null===(a=u.current)||void 0===a?void 0:a.querySelector(r);i&&(clearInterval(t),e.observe(i))},10);return()=>{clearInterval(t),e.disconnect()}}},[]);let S=Object.assign(Object.assign({},s),{style:Object.assign(Object.assign({},c),{margin:0}),open:b,visible:b,getPopupContainer:()=>u.current});return i&&(S=i(S)),a.createElement("div",{ref:u,style:{paddingBottom:d,position:"relative",minWidth:g}},a.createElement(e,Object.assign({},S)))})},51369:function(e,t,n){"use strict";let a;n.d(t,{Z:function(){return eY}});var r=n(83145),i=n(2265),o=n(18404),s=n(71744),l=n(13959),c=n(8900),u=n(39725),d=n(54537),p=n(55726),g=n(36760),m=n.n(g),b=n(62236),f=n(68710),E=n(55274),h=n(29961),S=n(69819),y=n(73002),T=n(51248),A=e=>{let{type:t,children:n,prefixCls:a,buttonProps:r,close:o,autoFocus:s,emitEvent:l,isSilent:c,quitOnNullishReturnValue:u,actionFn:d}=e,p=i.useRef(!1),g=i.useRef(null),[m,b]=(0,S.Z)(!1),f=function(){null==o||o.apply(void 0,arguments)};i.useEffect(()=>{let e=null;return s&&(e=setTimeout(()=>{var e;null===(e=g.current)||void 0===e||e.focus()})),()=>{e&&clearTimeout(e)}},[]);let E=e=>{e&&e.then&&(b(!0),e.then(function(){b(!1,!0),f.apply(void 0,arguments),p.current=!1},e=>{if(b(!1,!0),p.current=!1,null==c||!c())return Promise.reject(e)}))};return i.createElement(y.ZP,Object.assign({},(0,T.nx)(t),{onClick:e=>{let t;if(!p.current){if(p.current=!0,!d){f();return}if(l){var n;if(t=d(e),u&&!((n=t)&&n.then)){p.current=!1,f(e);return}}else if(d.length)t=d(o),p.current=!1;else if(!(t=d())){f();return}E(t)}},loading:m,prefixCls:a},r,{ref:g}),n)};let R=i.createContext({}),{Provider:I}=R;var N=()=>{let{autoFocusButton:e,cancelButtonProps:t,cancelTextLocale:n,isSilent:a,mergedOkCancel:r,rootPrefixCls:o,close:s,onCancel:l,onConfirm:c}=(0,i.useContext)(R);return r?i.createElement(A,{isSilent:a,actionFn:l,close:function(){null==s||s.apply(void 0,arguments),null==c||c(!1)},autoFocus:"cancel"===e,buttonProps:t,prefixCls:"".concat(o,"-btn")},n):null},_=()=>{let{autoFocusButton:e,close:t,isSilent:n,okButtonProps:a,rootPrefixCls:r,okTextLocale:o,okType:s,onConfirm:l,onOk:c}=(0,i.useContext)(R);return i.createElement(A,{isSilent:n,type:s||"primary",actionFn:c,close:function(){null==t||t.apply(void 0,arguments),null==l||l(!0)},autoFocus:"ok"===e,buttonProps:a,prefixCls:"".concat(r,"-btn")},o)},v=n(49638),w=n(1119),k=n(26365),C=n(28036),O=i.createContext({}),x=n(31686),L=n(2161),D=n(92491),P=n(95814),M=n(18242);function F(e,t,n){var a=t;return!a&&n&&(a="".concat(e,"-").concat(n)),a}function U(e,t){var n=e["page".concat(t?"Y":"X","Offset")],a="scroll".concat(t?"Top":"Left");if("number"!=typeof n){var r=e.document;"number"!=typeof(n=r.documentElement[a])&&(n=r.body[a])}return n}var B=n(47970),G=n(28791),$=i.memo(function(e){return e.children},function(e,t){return!t.shouldUpdate}),H={width:0,height:0,overflow:"hidden",outline:"none"},z=i.forwardRef(function(e,t){var n,a,r,o=e.prefixCls,s=e.className,l=e.style,c=e.title,u=e.ariaId,d=e.footer,p=e.closable,g=e.closeIcon,b=e.onClose,f=e.children,E=e.bodyStyle,h=e.bodyProps,S=e.modalRender,y=e.onMouseDown,T=e.onMouseUp,A=e.holderRef,R=e.visible,I=e.forceRender,N=e.width,_=e.height,v=e.classNames,k=e.styles,C=i.useContext(O).panel,L=(0,G.x1)(A,C),D=(0,i.useRef)(),P=(0,i.useRef)();i.useImperativeHandle(t,function(){return{focus:function(){var e;null===(e=D.current)||void 0===e||e.focus()},changeActive:function(e){var t=document.activeElement;e&&t===P.current?D.current.focus():e||t!==D.current||P.current.focus()}}});var M={};void 0!==N&&(M.width=N),void 0!==_&&(M.height=_),d&&(n=i.createElement("div",{className:m()("".concat(o,"-footer"),null==v?void 0:v.footer),style:(0,x.Z)({},null==k?void 0:k.footer)},d)),c&&(a=i.createElement("div",{className:m()("".concat(o,"-header"),null==v?void 0:v.header),style:(0,x.Z)({},null==k?void 0:k.header)},i.createElement("div",{className:"".concat(o,"-title"),id:u},c))),p&&(r=i.createElement("button",{type:"button",onClick:b,"aria-label":"Close",className:"".concat(o,"-close")},g||i.createElement("span",{className:"".concat(o,"-close-x")})));var F=i.createElement("div",{className:m()("".concat(o,"-content"),null==v?void 0:v.content),style:null==k?void 0:k.content},r,a,i.createElement("div",(0,w.Z)({className:m()("".concat(o,"-body"),null==v?void 0:v.body),style:(0,x.Z)((0,x.Z)({},E),null==k?void 0:k.body)},h),f),n);return i.createElement("div",{key:"dialog-element",role:"dialog","aria-labelledby":c?u:null,"aria-modal":"true",ref:L,style:(0,x.Z)((0,x.Z)({},l),M),className:m()(o,s),onMouseDown:y,onMouseUp:T},i.createElement("div",{tabIndex:0,ref:D,style:H,"aria-hidden":"true"}),i.createElement($,{shouldUpdate:R||I},S?S(F):F),i.createElement("div",{tabIndex:0,ref:P,style:H,"aria-hidden":"true"}))}),j=i.forwardRef(function(e,t){var n=e.prefixCls,a=e.title,r=e.style,o=e.className,s=e.visible,l=e.forceRender,c=e.destroyOnClose,u=e.motionName,d=e.ariaId,p=e.onVisibleChanged,g=e.mousePosition,b=(0,i.useRef)(),f=i.useState(),E=(0,k.Z)(f,2),h=E[0],S=E[1],y={};function T(){var e,t,n,a,r,i=(n={left:(t=(e=b.current).getBoundingClientRect()).left,top:t.top},r=(a=e.ownerDocument).defaultView||a.parentWindow,n.left+=U(r),n.top+=U(r,!0),n);S(g?"".concat(g.x-i.left,"px ").concat(g.y-i.top,"px"):"")}return h&&(y.transformOrigin=h),i.createElement(B.ZP,{visible:s,onVisibleChanged:p,onAppearPrepare:T,onEnterPrepare:T,forceRender:l,motionName:u,removeOnLeave:c,ref:b},function(s,l){var c=s.className,u=s.style;return i.createElement(z,(0,w.Z)({},e,{ref:t,title:a,ariaId:d,prefixCls:n,holderRef:l,style:(0,x.Z)((0,x.Z)((0,x.Z)({},u),r),y),className:m()(o,c)}))})});function V(e){var t=e.prefixCls,n=e.style,a=e.visible,r=e.maskProps,o=e.motionName,s=e.className;return i.createElement(B.ZP,{key:"mask",visible:a,motionName:o,leavedClassName:"".concat(t,"-mask-hidden")},function(e,a){var o=e.className,l=e.style;return i.createElement("div",(0,w.Z)({ref:a,style:(0,x.Z)((0,x.Z)({},l),n),className:m()("".concat(t,"-mask"),o,s)},r))})}function W(e){var t=e.prefixCls,n=void 0===t?"rc-dialog":t,a=e.zIndex,r=e.visible,o=void 0!==r&&r,s=e.keyboard,l=void 0===s||s,c=e.focusTriggerAfterClose,u=void 0===c||c,d=e.wrapStyle,p=e.wrapClassName,g=e.wrapProps,b=e.onClose,f=e.afterOpenChange,E=e.afterClose,h=e.transitionName,S=e.animation,y=e.closable,T=e.mask,A=void 0===T||T,R=e.maskTransitionName,I=e.maskAnimation,N=e.maskClosable,_=e.maskStyle,v=e.maskProps,C=e.rootClassName,O=e.classNames,U=e.styles,B=(0,i.useRef)(),G=(0,i.useRef)(),$=(0,i.useRef)(),H=i.useState(o),z=(0,k.Z)(H,2),W=z[0],q=z[1],Y=(0,D.Z)();function K(e){null==b||b(e)}var Z=(0,i.useRef)(!1),X=(0,i.useRef)(),Q=null;return(void 0===N||N)&&(Q=function(e){Z.current?Z.current=!1:G.current===e.target&&K(e)}),(0,i.useEffect)(function(){o&&(q(!0),(0,L.Z)(G.current,document.activeElement)||(B.current=document.activeElement))},[o]),(0,i.useEffect)(function(){return function(){clearTimeout(X.current)}},[]),i.createElement("div",(0,w.Z)({className:m()("".concat(n,"-root"),C)},(0,M.Z)(e,{data:!0})),i.createElement(V,{prefixCls:n,visible:A&&o,motionName:F(n,R,I),style:(0,x.Z)((0,x.Z)({zIndex:a},_),null==U?void 0:U.mask),maskProps:v,className:null==O?void 0:O.mask}),i.createElement("div",(0,w.Z)({tabIndex:-1,onKeyDown:function(e){if(l&&e.keyCode===P.Z.ESC){e.stopPropagation(),K(e);return}o&&e.keyCode===P.Z.TAB&&$.current.changeActive(!e.shiftKey)},className:m()("".concat(n,"-wrap"),p,null==O?void 0:O.wrapper),ref:G,onClick:Q,style:(0,x.Z)((0,x.Z)((0,x.Z)({zIndex:a},d),null==U?void 0:U.wrapper),{},{display:W?null:"none"})},g),i.createElement(j,(0,w.Z)({},e,{onMouseDown:function(){clearTimeout(X.current),Z.current=!0},onMouseUp:function(){X.current=setTimeout(function(){Z.current=!1})},ref:$,closable:void 0===y||y,ariaId:Y,prefixCls:n,visible:o&&W,onClose:K,onVisibleChanged:function(e){if(e)!function(){if(!(0,L.Z)(G.current,document.activeElement)){var e;null===(e=$.current)||void 0===e||e.focus()}}();else{if(q(!1),A&&B.current&&u){try{B.current.focus({preventScroll:!0})}catch(e){}B.current=null}W&&(null==E||E())}null==f||f(e)},motionName:F(n,h,S)}))))}j.displayName="Content",n(32559);var q=function(e){var t=e.visible,n=e.getContainer,a=e.forceRender,r=e.destroyOnClose,o=void 0!==r&&r,s=e.afterClose,l=e.panelRef,c=i.useState(t),u=(0,k.Z)(c,2),d=u[0],p=u[1],g=i.useMemo(function(){return{panel:l}},[l]);return(i.useEffect(function(){t&&p(!0)},[t]),a||!o||d)?i.createElement(O.Provider,{value:g},i.createElement(C.Z,{open:t||a||d,autoDestroy:!1,getContainer:n,autoLock:t||d},i.createElement(W,(0,w.Z)({},e,{destroyOnClose:o,afterClose:function(){null==s||s(),p(!1)}})))):null};q.displayName="Dialog";var Y=function(e,t,n){let a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:i.createElement(v.Z,null),r=arguments.length>4&&void 0!==arguments[4]&&arguments[4];if("boolean"==typeof e?!e:void 0===t?!r:!1===t||null===t)return[!1,null];let o="boolean"==typeof t||null==t?a:t;return[!0,n?n(o):o]},K=n(94981),Z=n(95140),X=n(39109),Q=n(65658),J=n(74126);function ee(){}let et=i.createContext({add:ee,remove:ee});var en=n(86586),ea=()=>{let{cancelButtonProps:e,cancelTextLocale:t,onCancel:n}=(0,i.useContext)(R);return i.createElement(y.ZP,Object.assign({onClick:n},e),t)},er=()=>{let{confirmLoading:e,okButtonProps:t,okType:n,okTextLocale:a,onOk:r}=(0,i.useContext)(R);return i.createElement(y.ZP,Object.assign({},(0,T.nx)(n),{loading:e,onClick:r},t),a)},ei=n(92246);function eo(e,t){return i.createElement("span",{className:"".concat(e,"-close-x")},t||i.createElement(v.Z,{className:"".concat(e,"-close-icon")}))}let es=e=>{let t;let{okText:n,okType:a="primary",cancelText:o,confirmLoading:s,onOk:l,onCancel:c,okButtonProps:u,cancelButtonProps:d,footer:p}=e,[g]=(0,E.Z)("Modal",(0,ei.A)()),m={confirmLoading:s,okButtonProps:u,cancelButtonProps:d,okTextLocale:n||(null==g?void 0:g.okText),cancelTextLocale:o||(null==g?void 0:g.cancelText),okType:a,onOk:l,onCancel:c},b=i.useMemo(()=>m,(0,r.Z)(Object.values(m)));return"function"==typeof p||void 0===p?(t=i.createElement(i.Fragment,null,i.createElement(ea,null),i.createElement(er,null)),"function"==typeof p&&(t=p(t,{OkBtn:er,CancelBtn:ea})),t=i.createElement(I,{value:b},t)):t=p,i.createElement(en.n,{disabled:!1},t)};var el=n(12918),ec=n(11699),eu=n(691),ed=n(3104),ep=n(80669),eg=n(352);function em(e){return{position:e,inset:0}}let eb=e=>{let{componentCls:t,antCls:n}=e;return[{["".concat(t,"-root")]:{["".concat(t).concat(n,"-zoom-enter, ").concat(t).concat(n,"-zoom-appear")]:{transform:"none",opacity:0,animationDuration:e.motionDurationSlow,userSelect:"none"},["".concat(t).concat(n,"-zoom-leave ").concat(t,"-content")]:{pointerEvents:"none"},["".concat(t,"-mask")]:Object.assign(Object.assign({},em("fixed")),{zIndex:e.zIndexPopupBase,height:"100%",backgroundColor:e.colorBgMask,pointerEvents:"none",["".concat(t,"-hidden")]:{display:"none"}}),["".concat(t,"-wrap")]:Object.assign(Object.assign({},em("fixed")),{zIndex:e.zIndexPopupBase,overflow:"auto",outline:0,WebkitOverflowScrolling:"touch",["&:has(".concat(t).concat(n,"-zoom-enter), &:has(").concat(t).concat(n,"-zoom-appear)")]:{pointerEvents:"none"}})}},{["".concat(t,"-root")]:(0,ec.J$)(e)}]},ef=e=>{let{componentCls:t}=e;return[{["".concat(t,"-root")]:{["".concat(t,"-wrap-rtl")]:{direction:"rtl"},["".concat(t,"-centered")]:{textAlign:"center","&::before":{display:"inline-block",width:0,height:"100%",verticalAlign:"middle",content:'""'},[t]:{top:0,display:"inline-block",paddingBottom:0,textAlign:"start",verticalAlign:"middle"}},["@media (max-width: ".concat(e.screenSMMax,"px)")]:{[t]:{maxWidth:"calc(100vw - 16px)",margin:"".concat((0,eg.bf)(e.marginXS)," auto")},["".concat(t,"-centered")]:{[t]:{flex:1}}}}},{[t]:Object.assign(Object.assign({},(0,el.Wf)(e)),{pointerEvents:"none",position:"relative",top:100,width:"auto",maxWidth:"calc(100vw - ".concat((0,eg.bf)(e.calc(e.margin).mul(2).equal()),")"),margin:"0 auto",paddingBottom:e.paddingLG,["".concat(t,"-title")]:{margin:0,color:e.titleColor,fontWeight:e.fontWeightStrong,fontSize:e.titleFontSize,lineHeight:e.titleLineHeight,wordWrap:"break-word"},["".concat(t,"-content")]:{position:"relative",backgroundColor:e.contentBg,backgroundClip:"padding-box",border:0,borderRadius:e.borderRadiusLG,boxShadow:e.boxShadow,pointerEvents:"auto",padding:e.contentPadding},["".concat(t,"-close")]:Object.assign({position:"absolute",top:e.calc(e.modalHeaderHeight).sub(e.modalCloseBtnSize).div(2).equal(),insetInlineEnd:e.calc(e.modalHeaderHeight).sub(e.modalCloseBtnSize).div(2).equal(),zIndex:e.calc(e.zIndexPopupBase).add(10).equal(),padding:0,color:e.modalCloseIconColor,fontWeight:e.fontWeightStrong,lineHeight:1,textDecoration:"none",background:"transparent",borderRadius:e.borderRadiusSM,width:e.modalCloseBtnSize,height:e.modalCloseBtnSize,border:0,outline:0,cursor:"pointer",transition:"color ".concat(e.motionDurationMid,", background-color ").concat(e.motionDurationMid),"&-x":{display:"flex",fontSize:e.fontSizeLG,fontStyle:"normal",lineHeight:"".concat((0,eg.bf)(e.modalCloseBtnSize)),justifyContent:"center",textTransform:"none",textRendering:"auto"},"&:hover":{color:e.modalIconHoverColor,backgroundColor:e.closeBtnHoverBg,textDecoration:"none"},"&:active":{backgroundColor:e.closeBtnActiveBg}},(0,el.Qy)(e)),["".concat(t,"-header")]:{color:e.colorText,background:e.headerBg,borderRadius:"".concat((0,eg.bf)(e.borderRadiusLG)," ").concat((0,eg.bf)(e.borderRadiusLG)," 0 0"),marginBottom:e.headerMarginBottom,padding:e.headerPadding,borderBottom:e.headerBorderBottom},["".concat(t,"-body")]:{fontSize:e.fontSize,lineHeight:e.lineHeight,wordWrap:"break-word",padding:e.bodyPadding},["".concat(t,"-footer")]:{textAlign:"end",background:e.footerBg,marginTop:e.footerMarginTop,padding:e.footerPadding,borderTop:e.footerBorderTop,borderRadius:e.footerBorderRadius,["> ".concat(e.antCls,"-btn + ").concat(e.antCls,"-btn")]:{marginInlineStart:e.marginXS}},["".concat(t,"-open")]:{overflow:"hidden"}})},{["".concat(t,"-pure-panel")]:{top:"auto",padding:0,display:"flex",flexDirection:"column",["".concat(t,"-content,\n ").concat(t,"-body,\n ").concat(t,"-confirm-body-wrapper")]:{display:"flex",flexDirection:"column",flex:"auto"},["".concat(t,"-confirm-body")]:{marginBottom:"auto"}}}]},eE=e=>{let{componentCls:t}=e;return{["".concat(t,"-root")]:{["".concat(t,"-wrap-rtl")]:{direction:"rtl",["".concat(t,"-confirm-body")]:{direction:"rtl"}}}}},eh=e=>{let t=e.padding,n=e.fontSizeHeading5,a=e.lineHeightHeading5;return(0,ed.TS)(e,{modalHeaderHeight:e.calc(e.calc(a).mul(n).equal()).add(e.calc(t).mul(2).equal()).equal(),modalFooterBorderColorSplit:e.colorSplit,modalFooterBorderStyle:e.lineType,modalFooterBorderWidth:e.lineWidth,modalIconHoverColor:e.colorIconHover,modalCloseIconColor:e.colorIcon,modalCloseBtnSize:e.fontHeight,modalConfirmIconSize:e.fontHeight,modalTitleHeight:e.calc(e.titleFontSize).mul(e.titleLineHeight).equal()})},eS=e=>({footerBg:"transparent",headerBg:e.colorBgElevated,titleLineHeight:e.lineHeightHeading5,titleFontSize:e.fontSizeHeading5,contentBg:e.colorBgElevated,titleColor:e.colorTextHeading,closeBtnHoverBg:e.wireframe?"transparent":e.colorFillContent,closeBtnActiveBg:e.wireframe?"transparent":e.colorFillContentHover,contentPadding:e.wireframe?0:"".concat((0,eg.bf)(e.paddingMD)," ").concat((0,eg.bf)(e.paddingContentHorizontalLG)),headerPadding:e.wireframe?"".concat((0,eg.bf)(e.padding)," ").concat((0,eg.bf)(e.paddingLG)):0,headerBorderBottom:e.wireframe?"".concat((0,eg.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorSplit):"none",headerMarginBottom:e.wireframe?0:e.marginXS,bodyPadding:e.wireframe?e.paddingLG:0,footerPadding:e.wireframe?"".concat((0,eg.bf)(e.paddingXS)," ").concat((0,eg.bf)(e.padding)):0,footerBorderTop:e.wireframe?"".concat((0,eg.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorSplit):"none",footerBorderRadius:e.wireframe?"0 0 ".concat((0,eg.bf)(e.borderRadiusLG)," ").concat((0,eg.bf)(e.borderRadiusLG)):0,footerMarginTop:e.wireframe?0:e.marginSM,confirmBodyPadding:e.wireframe?"".concat((0,eg.bf)(2*e.padding)," ").concat((0,eg.bf)(2*e.padding)," ").concat((0,eg.bf)(e.paddingLG)):0,confirmIconMarginInlineEnd:e.wireframe?e.margin:e.marginSM,confirmBtnsMarginTop:e.wireframe?e.marginLG:e.marginSM});var ey=(0,ep.I$)("Modal",e=>{let t=eh(e);return[ef(t),eE(t),eb(t),(0,eu._y)(t,"zoom")]},eS,{unitless:{titleLineHeight:!0}}),eT=n(64024),eA=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n};(0,K.Z)()&&window.document.documentElement&&document.documentElement.addEventListener("click",e=>{a={x:e.pageX,y:e.pageY},setTimeout(()=>{a=null},100)},!0);var eR=e=>{var t;let{getPopupContainer:n,getPrefixCls:r,direction:o,modal:l}=i.useContext(s.E_),c=t=>{let{onCancel:n}=e;null==n||n(t)},{prefixCls:u,className:d,rootClassName:p,open:g,wrapClassName:E,centered:h,getContainer:S,closeIcon:y,closable:T,focusTriggerAfterClose:A=!0,style:R,visible:I,width:N=520,footer:_,classNames:w,styles:k}=e,C=eA(e,["prefixCls","className","rootClassName","open","wrapClassName","centered","getContainer","closeIcon","closable","focusTriggerAfterClose","style","visible","width","footer","classNames","styles"]),O=r("modal",u),x=r(),L=(0,eT.Z)(O),[D,P,M]=ey(O,L),F=m()(E,{["".concat(O,"-centered")]:!!h,["".concat(O,"-wrap-rtl")]:"rtl"===o}),U=null!==_&&i.createElement(es,Object.assign({},e,{onOk:t=>{let{onOk:n}=e;null==n||n(t)},onCancel:c})),[B,G]=Y(T,y,e=>eo(O,e),i.createElement(v.Z,{className:"".concat(O,"-close-icon")}),!0),$=function(e){let t=i.useContext(et),n=i.useRef();return(0,J.zX)(a=>{if(a){let r=e?a.querySelector(e):a;t.add(r),n.current=r}else t.remove(n.current)})}(".".concat(O,"-content")),[H,z]=(0,b.Cn)("Modal",C.zIndex);return D(i.createElement(Q.BR,null,i.createElement(X.Ux,{status:!0,override:!0},i.createElement(Z.Z.Provider,{value:z},i.createElement(q,Object.assign({width:N},C,{zIndex:H,getContainer:void 0===S?n:S,prefixCls:O,rootClassName:m()(P,p,M,L),footer:U,visible:null!=g?g:I,mousePosition:null!==(t=C.mousePosition)&&void 0!==t?t:a,onClose:c,closable:B,closeIcon:G,focusTriggerAfterClose:A,transitionName:(0,f.m)(x,"zoom",e.transitionName),maskTransitionName:(0,f.m)(x,"fade",e.maskTransitionName),className:m()(P,d,null==l?void 0:l.className),style:Object.assign(Object.assign({},null==l?void 0:l.style),R),classNames:Object.assign(Object.assign({wrapper:F},null==l?void 0:l.classNames),w),styles:Object.assign(Object.assign({},null==l?void 0:l.styles),k),panelRef:$}))))))};let eI=e=>{let{componentCls:t,titleFontSize:n,titleLineHeight:a,modalConfirmIconSize:r,fontSize:i,lineHeight:o,modalTitleHeight:s,fontHeight:l,confirmBodyPadding:c}=e,u="".concat(t,"-confirm");return{[u]:{"&-rtl":{direction:"rtl"},["".concat(e.antCls,"-modal-header")]:{display:"none"},["".concat(u,"-body-wrapper")]:Object.assign({},(0,el.dF)()),["&".concat(t," ").concat(t,"-body")]:{padding:c},["".concat(u,"-body")]:{display:"flex",flexWrap:"nowrap",alignItems:"start",["> ".concat(e.iconCls)]:{flex:"none",fontSize:r,marginInlineEnd:e.confirmIconMarginInlineEnd,marginTop:e.calc(e.calc(l).sub(r).equal()).div(2).equal()},["&-has-title > ".concat(e.iconCls)]:{marginTop:e.calc(e.calc(s).sub(r).equal()).div(2).equal()}},["".concat(u,"-paragraph")]:{display:"flex",flexDirection:"column",flex:"auto",rowGap:e.marginXS,maxWidth:"calc(100% - ".concat((0,eg.bf)(e.calc(e.modalConfirmIconSize).add(e.marginSM).equal()),")")},["".concat(u,"-title")]:{color:e.colorTextHeading,fontWeight:e.fontWeightStrong,fontSize:n,lineHeight:a},["".concat(u,"-content")]:{color:e.colorText,fontSize:i,lineHeight:o},["".concat(u,"-btns")]:{textAlign:"end",marginTop:e.confirmBtnsMarginTop,["".concat(e.antCls,"-btn + ").concat(e.antCls,"-btn")]:{marginBottom:0,marginInlineStart:e.marginXS}}},["".concat(u,"-error ").concat(u,"-body > ").concat(e.iconCls)]:{color:e.colorError},["".concat(u,"-warning ").concat(u,"-body > ").concat(e.iconCls,",\n ").concat(u,"-confirm ").concat(u,"-body > ").concat(e.iconCls)]:{color:e.colorWarning},["".concat(u,"-info ").concat(u,"-body > ").concat(e.iconCls)]:{color:e.colorInfo},["".concat(u,"-success ").concat(u,"-body > ").concat(e.iconCls)]:{color:e.colorSuccess}}};var eN=(0,ep.bk)(["Modal","confirm"],e=>[eI(eh(e))],eS,{order:-1e3}),e_=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n};function ev(e){let{prefixCls:t,icon:n,okText:a,cancelText:o,confirmPrefixCls:s,type:l,okCancel:g,footer:b,locale:f}=e,h=e_(e,["prefixCls","icon","okText","cancelText","confirmPrefixCls","type","okCancel","footer","locale"]),S=n;if(!n&&null!==n)switch(l){case"info":S=i.createElement(p.Z,null);break;case"success":S=i.createElement(c.Z,null);break;case"error":S=i.createElement(u.Z,null);break;default:S=i.createElement(d.Z,null)}let y=null!=g?g:"confirm"===l,T=null!==e.autoFocusButton&&(e.autoFocusButton||"ok"),[A]=(0,E.Z)("Modal"),R=f||A,v=a||(y?null==R?void 0:R.okText:null==R?void 0:R.justOkText),w=Object.assign({autoFocusButton:T,cancelTextLocale:o||(null==R?void 0:R.cancelText),okTextLocale:v,mergedOkCancel:y},h),k=i.useMemo(()=>w,(0,r.Z)(Object.values(w))),C=i.createElement(i.Fragment,null,i.createElement(N,null),i.createElement(_,null)),O=void 0!==e.title&&null!==e.title,x="".concat(s,"-body");return i.createElement("div",{className:"".concat(s,"-body-wrapper")},i.createElement("div",{className:m()(x,{["".concat(x,"-has-title")]:O})},S,i.createElement("div",{className:"".concat(s,"-paragraph")},O&&i.createElement("span",{className:"".concat(s,"-title")},e.title),i.createElement("div",{className:"".concat(s,"-content")},e.content))),void 0===b||"function"==typeof b?i.createElement(I,{value:k},i.createElement("div",{className:"".concat(s,"-btns")},"function"==typeof b?b(C,{OkBtn:_,CancelBtn:N}):C)):b,i.createElement(eN,{prefixCls:t}))}let ew=e=>{let{close:t,zIndex:n,afterClose:a,open:r,keyboard:o,centered:s,getContainer:l,maskStyle:c,direction:u,prefixCls:d,wrapClassName:p,rootPrefixCls:g,bodyStyle:E,closable:S=!1,closeIcon:y,modalRender:T,focusTriggerAfterClose:A,onConfirm:R,styles:I}=e,N="".concat(d,"-confirm"),_=e.width||416,v=e.style||{},w=void 0===e.mask||e.mask,k=void 0!==e.maskClosable&&e.maskClosable,C=m()(N,"".concat(N,"-").concat(e.type),{["".concat(N,"-rtl")]:"rtl"===u},e.className),[,O]=(0,h.ZP)(),x=i.useMemo(()=>void 0!==n?n:O.zIndexPopupBase+b.u6,[n,O]);return i.createElement(eR,{prefixCls:d,className:C,wrapClassName:m()({["".concat(N,"-centered")]:!!e.centered},p),onCancel:()=>{null==t||t({triggerCancel:!0}),null==R||R(!1)},open:r,title:"",footer:null,transitionName:(0,f.m)(g||"","zoom",e.transitionName),maskTransitionName:(0,f.m)(g||"","fade",e.maskTransitionName),mask:w,maskClosable:k,style:v,styles:Object.assign({body:E,mask:c},I),width:_,zIndex:x,afterClose:a,keyboard:o,centered:s,getContainer:l,closable:S,closeIcon:y,modalRender:T,focusTriggerAfterClose:A},i.createElement(ev,Object.assign({},e,{confirmPrefixCls:N})))};var ek=e=>{let{rootPrefixCls:t,iconPrefixCls:n,direction:a,theme:r}=e;return i.createElement(l.ZP,{prefixCls:t,iconPrefixCls:n,direction:a,theme:r},i.createElement(ew,Object.assign({},e)))},eC=[];let eO="",ex=e=>{var t,n;let{prefixCls:a,getContainer:r,direction:o}=e,l=(0,ei.A)(),c=(0,i.useContext)(s.E_),u=eO||c.getPrefixCls(),d=a||"".concat(u,"-modal"),p=r;return!1===p&&(p=void 0),i.createElement(ek,Object.assign({},e,{rootPrefixCls:u,prefixCls:d,iconPrefixCls:c.iconPrefixCls,theme:c.theme,direction:null!=o?o:c.direction,locale:null!==(n=null===(t=c.locale)||void 0===t?void 0:t.Modal)&&void 0!==n?n:l,getContainer:p}))};function eL(e){let t;let n=(0,l.w6)(),a=document.createDocumentFragment(),s=Object.assign(Object.assign({},e),{close:d,open:!0});function c(){for(var t=arguments.length,n=Array(t),i=0;ie&&e.triggerCancel);e.onCancel&&s&&e.onCancel.apply(e,[()=>{}].concat((0,r.Z)(n.slice(1))));for(let e=0;e{let t=n.getPrefixCls(void 0,eO),r=n.getIconPrefixCls(),s=n.getTheme(),c=i.createElement(ex,Object.assign({},e));(0,o.s)(i.createElement(l.ZP,{prefixCls:t,iconPrefixCls:r,theme:s},n.holderRender?n.holderRender(c):c),a)})}function d(){for(var t=arguments.length,n=Array(t),a=0;a{"function"==typeof e.afterClose&&e.afterClose(),c.apply(this,n)}})).visible&&delete s.visible,u(s)}return u(s),eC.push(d),{destroy:d,update:function(e){u(s="function"==typeof e?e(s):Object.assign(Object.assign({},s),e))}}}function eD(e){return Object.assign(Object.assign({},e),{type:"warning"})}function eP(e){return Object.assign(Object.assign({},e),{type:"info"})}function eM(e){return Object.assign(Object.assign({},e),{type:"success"})}function eF(e){return Object.assign(Object.assign({},e),{type:"error"})}function eU(e){return Object.assign(Object.assign({},e),{type:"confirm"})}var eB=n(93942),eG=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n},e$=(0,eB.i)(e=>{let{prefixCls:t,className:n,closeIcon:a,closable:r,type:o,title:l,children:c,footer:u}=e,d=eG(e,["prefixCls","className","closeIcon","closable","type","title","children","footer"]),{getPrefixCls:p}=i.useContext(s.E_),g=p(),b=t||p("modal"),f=(0,eT.Z)(g),[E,h,S]=ey(b,f),y="".concat(b,"-confirm"),T={};return T=o?{closable:null!=r&&r,title:"",footer:"",children:i.createElement(ev,Object.assign({},e,{prefixCls:b,confirmPrefixCls:y,rootPrefixCls:g,content:c}))}:{closable:null==r||r,title:l,footer:null!==u&&i.createElement(es,Object.assign({},e)),children:c},E(i.createElement(z,Object.assign({prefixCls:b,className:m()(h,"".concat(b,"-pure-panel"),o&&y,o&&"".concat(y,"-").concat(o),n,S,f)},d,{closeIcon:eo(b,a),closable:r},T)))}),eH=n(13823),ez=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n},ej=i.forwardRef((e,t)=>{var n,{afterClose:a,config:o}=e,l=ez(e,["afterClose","config"]);let[c,u]=i.useState(!0),[d,p]=i.useState(o),{direction:g,getPrefixCls:m}=i.useContext(s.E_),b=m("modal"),f=m(),h=function(){u(!1);for(var e=arguments.length,t=Array(e),n=0;ne&&e.triggerCancel);d.onCancel&&a&&d.onCancel.apply(d,[()=>{}].concat((0,r.Z)(t.slice(1))))};i.useImperativeHandle(t,()=>({destroy:h,update:e=>{p(t=>Object.assign(Object.assign({},t),e))}}));let S=null!==(n=d.okCancel)&&void 0!==n?n:"confirm"===d.type,[y]=(0,E.Z)("Modal",eH.Z.Modal);return i.createElement(ek,Object.assign({prefixCls:b,rootPrefixCls:f},d,{close:h,open:c,afterClose:()=>{var e;a(),null===(e=d.afterClose)||void 0===e||e.call(d)},okText:d.okText||(S?null==y?void 0:y.okText:null==y?void 0:y.justOkText),direction:d.direction||g,cancelText:d.cancelText||(null==y?void 0:y.cancelText)},l))});let eV=0,eW=i.memo(i.forwardRef((e,t)=>{let[n,a]=function(){let[e,t]=i.useState([]);return[e,i.useCallback(e=>(t(t=>[].concat((0,r.Z)(t),[e])),()=>{t(t=>t.filter(t=>t!==e))}),[])]}();return i.useImperativeHandle(t,()=>({patchElement:a}),[]),i.createElement(i.Fragment,null,n)}));function eq(e){return eL(eD(e))}eR.useModal=function(){let e=i.useRef(null),[t,n]=i.useState([]);i.useEffect(()=>{t.length&&((0,r.Z)(t).forEach(e=>{e()}),n([]))},[t]);let a=i.useCallback(t=>function(a){var o;let s,l;eV+=1;let c=i.createRef(),u=new Promise(e=>{s=e}),d=!1,p=i.createElement(ej,{key:"modal-".concat(eV),config:t(a),ref:c,afterClose:()=>{null==l||l()},isSilent:()=>d,onConfirm:e=>{s(e)}});return(l=null===(o=e.current)||void 0===o?void 0:o.patchElement(p))&&eC.push(l),{destroy:()=>{function e(){var e;null===(e=c.current)||void 0===e||e.destroy()}c.current?e():n(t=>[].concat((0,r.Z)(t),[e]))},update:e=>{function t(){var t;null===(t=c.current)||void 0===t||t.update(e)}c.current?t():n(e=>[].concat((0,r.Z)(e),[t]))},then:e=>(d=!0,u.then(e))}},[]);return[i.useMemo(()=>({info:a(eP),success:a(eM),error:a(eF),warning:a(eD),confirm:a(eU)}),[]),i.createElement(eW,{key:"modal-holder",ref:e})]},eR.info=function(e){return eL(eP(e))},eR.success=function(e){return eL(eM(e))},eR.error=function(e){return eL(eF(e))},eR.warning=eq,eR.warn=eq,eR.confirm=function(e){return eL(eU(e))},eR.destroyAll=function(){for(;eC.length;){let e=eC.pop();e&&e()}},eR.config=function(e){let{rootPrefixCls:t}=e;eO=t},eR._InternalPanelDoNotUseOrYouWillBeFired=e$;var eY=eR},11699:function(e,t,n){"use strict";n.d(t,{J$:function(){return s}});var a=n(352),r=n(37133);let i=new a.E4("antFadeIn",{"0%":{opacity:0},"100%":{opacity:1}}),o=new a.E4("antFadeOut",{"0%":{opacity:1},"100%":{opacity:0}}),s=function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],{antCls:n}=e,a="".concat(n,"-fade"),s=t?"&":"";return[(0,r.R)(a,i,o,e.motionDurationMid,t),{["\n ".concat(s).concat(a,"-enter,\n ").concat(s).concat(a,"-appear\n ")]:{opacity:0,animationTimingFunction:"linear"},["".concat(s).concat(a,"-leave")]:{animationTimingFunction:"linear"}}]}},26035:function(e){"use strict";e.exports=function(e,n){for(var a,r,i,o=e||"",s=n||"div",l={},c=0;c4&&m.slice(0,4)===o&&s.test(t)&&("-"===t.charAt(4)?b=o+(n=t.slice(5).replace(l,d)).charAt(0).toUpperCase()+n.slice(1):(g=(p=t).slice(4),t=l.test(g)?p:("-"!==(g=g.replace(c,u)).charAt(0)&&(g="-"+g),o+g)),f=r),new f(b,t))};var s=/^data[-\w.:]+$/i,l=/-[a-z]/g,c=/[A-Z]/g;function u(e){return"-"+e.toLowerCase()}function d(e){return e.charAt(1).toUpperCase()}},30466:function(e,t,n){"use strict";var a=n(82855),r=n(64541),i=n(80808),o=n(44987),s=n(72731),l=n(98946);e.exports=a([i,r,o,s,l])},72731:function(e,t,n){"use strict";var a=n(20321),r=n(41757),i=a.booleanish,o=a.number,s=a.spaceSeparated;e.exports=r({transform:function(e,t){return"role"===t?t:"aria-"+t.slice(4).toLowerCase()},properties:{ariaActiveDescendant:null,ariaAtomic:i,ariaAutoComplete:null,ariaBusy:i,ariaChecked:i,ariaColCount:o,ariaColIndex:o,ariaColSpan:o,ariaControls:s,ariaCurrent:null,ariaDescribedBy:s,ariaDetails:null,ariaDisabled:i,ariaDropEffect:s,ariaErrorMessage:null,ariaExpanded:i,ariaFlowTo:s,ariaGrabbed:i,ariaHasPopup:null,ariaHidden:i,ariaInvalid:null,ariaKeyShortcuts:null,ariaLabel:null,ariaLabelledBy:s,ariaLevel:o,ariaLive:null,ariaModal:i,ariaMultiLine:i,ariaMultiSelectable:i,ariaOrientation:null,ariaOwns:s,ariaPlaceholder:null,ariaPosInSet:o,ariaPressed:i,ariaReadOnly:i,ariaRelevant:null,ariaRequired:i,ariaRoleDescription:s,ariaRowCount:o,ariaRowIndex:o,ariaRowSpan:o,ariaSelected:i,ariaSetSize:o,ariaSort:null,ariaValueMax:o,ariaValueMin:o,ariaValueNow:o,ariaValueText:null,role:null}})},98946:function(e,t,n){"use strict";var a=n(20321),r=n(41757),i=n(53296),o=a.boolean,s=a.overloadedBoolean,l=a.booleanish,c=a.number,u=a.spaceSeparated,d=a.commaSeparated;e.exports=r({space:"html",attributes:{acceptcharset:"accept-charset",classname:"class",htmlfor:"for",httpequiv:"http-equiv"},transform:i,mustUseProperty:["checked","multiple","muted","selected"],properties:{abbr:null,accept:d,acceptCharset:u,accessKey:u,action:null,allow:null,allowFullScreen:o,allowPaymentRequest:o,allowUserMedia:o,alt:null,as:null,async:o,autoCapitalize:null,autoComplete:u,autoFocus:o,autoPlay:o,capture:o,charSet:null,checked:o,cite:null,className:u,cols:c,colSpan:null,content:null,contentEditable:l,controls:o,controlsList:u,coords:c|d,crossOrigin:null,data:null,dateTime:null,decoding:null,default:o,defer:o,dir:null,dirName:null,disabled:o,download:s,draggable:l,encType:null,enterKeyHint:null,form:null,formAction:null,formEncType:null,formMethod:null,formNoValidate:o,formTarget:null,headers:u,height:c,hidden:o,high:c,href:null,hrefLang:null,htmlFor:u,httpEquiv:u,id:null,imageSizes:null,imageSrcSet:d,inputMode:null,integrity:null,is:null,isMap:o,itemId:null,itemProp:u,itemRef:u,itemScope:o,itemType:u,kind:null,label:null,lang:null,language:null,list:null,loading:null,loop:o,low:c,manifest:null,max:null,maxLength:c,media:null,method:null,min:null,minLength:c,multiple:o,muted:o,name:null,nonce:null,noModule:o,noValidate:o,onAbort:null,onAfterPrint:null,onAuxClick:null,onBeforePrint:null,onBeforeUnload:null,onBlur:null,onCancel:null,onCanPlay:null,onCanPlayThrough:null,onChange:null,onClick:null,onClose:null,onContextMenu:null,onCopy:null,onCueChange:null,onCut:null,onDblClick:null,onDrag:null,onDragEnd:null,onDragEnter:null,onDragExit:null,onDragLeave:null,onDragOver:null,onDragStart:null,onDrop:null,onDurationChange:null,onEmptied:null,onEnded:null,onError:null,onFocus:null,onFormData:null,onHashChange:null,onInput:null,onInvalid:null,onKeyDown:null,onKeyPress:null,onKeyUp:null,onLanguageChange:null,onLoad:null,onLoadedData:null,onLoadedMetadata:null,onLoadEnd:null,onLoadStart:null,onMessage:null,onMessageError:null,onMouseDown:null,onMouseEnter:null,onMouseLeave:null,onMouseMove:null,onMouseOut:null,onMouseOver:null,onMouseUp:null,onOffline:null,onOnline:null,onPageHide:null,onPageShow:null,onPaste:null,onPause:null,onPlay:null,onPlaying:null,onPopState:null,onProgress:null,onRateChange:null,onRejectionHandled:null,onReset:null,onResize:null,onScroll:null,onSecurityPolicyViolation:null,onSeeked:null,onSeeking:null,onSelect:null,onSlotChange:null,onStalled:null,onStorage:null,onSubmit:null,onSuspend:null,onTimeUpdate:null,onToggle:null,onUnhandledRejection:null,onUnload:null,onVolumeChange:null,onWaiting:null,onWheel:null,open:o,optimum:c,pattern:null,ping:u,placeholder:null,playsInline:o,poster:null,preload:null,readOnly:o,referrerPolicy:null,rel:u,required:o,reversed:o,rows:c,rowSpan:c,sandbox:u,scope:null,scoped:o,seamless:o,selected:o,shape:null,size:c,sizes:null,slot:null,span:c,spellCheck:l,src:null,srcDoc:null,srcLang:null,srcSet:d,start:c,step:null,style:null,tabIndex:c,target:null,title:null,translate:null,type:null,typeMustMatch:o,useMap:null,value:l,width:c,wrap:null,align:null,aLink:null,archive:u,axis:null,background:null,bgColor:null,border:c,borderColor:null,bottomMargin:c,cellPadding:null,cellSpacing:null,char:null,charOff:null,classId:null,clear:null,code:null,codeBase:null,codeType:null,color:null,compact:o,declare:o,event:null,face:null,frame:null,frameBorder:null,hSpace:c,leftMargin:c,link:null,longDesc:null,lowSrc:null,marginHeight:c,marginWidth:c,noResize:o,noHref:o,noShade:o,noWrap:o,object:null,profile:null,prompt:null,rev:null,rightMargin:c,rules:null,scheme:null,scrolling:l,standby:null,summary:null,text:null,topMargin:c,valueType:null,version:null,vAlign:null,vLink:null,vSpace:c,allowTransparency:null,autoCorrect:null,autoSave:null,disablePictureInPicture:o,disableRemotePlayback:o,prefix:null,property:null,results:c,security:null,unselectable:null}})},53296:function(e,t,n){"use strict";var a=n(38781);e.exports=function(e,t){return a(e,t.toLowerCase())}},38781:function(e){"use strict";e.exports=function(e,t){return t in e?e[t]:t}},41757:function(e,t,n){"use strict";var a=n(96532),r=n(61723),i=n(51351);e.exports=function(e){var t,n,o=e.space,s=e.mustUseProperty||[],l=e.attributes||{},c=e.properties,u=e.transform,d={},p={};for(t in c)n=new i(t,u(l,t),c[t],o),-1!==s.indexOf(t)&&(n.mustUseProperty=!0),d[t]=n,p[a(t)]=t,p[a(n.attribute)]=t;return new r(d,p,o)}},51351:function(e,t,n){"use strict";var a=n(24192),r=n(20321);e.exports=s,s.prototype=new a,s.prototype.defined=!0;var i=["boolean","booleanish","overloadedBoolean","number","commaSeparated","spaceSeparated","commaOrSpaceSeparated"],o=i.length;function s(e,t,n,s){var l,c,u,d=-1;for(s&&(this.space=s),a.call(this,e,t);++d1&&void 0!==arguments[1]&&arguments[1];t=!1===n?{aria:!0,data:!0,attr:!0}:!0===n?{aria:!0}:(0,a.Z)({},n);var o={};return Object.keys(e).forEach(function(n){(t.aria&&("role"===n||i(n,"aria-"))||t.data&&i(n,"data-")||t.attr&&r.includes(n))&&(o[n]=e[n])}),o}},17906:function(e,t,n){"use strict";n.d(t,{Z:function(){return N}});var a,r,i=n(6989),o=n(83145),s=n(11993),l=n(2265),c=n(1119);function u(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,a)}return n}function d(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return(function(e){if(0===e.length||1===e.length)return e;var t,n=e.join(".");return p[n]||(p[n]=0===(t=e.length)||1===t?e:2===t?[e[0],e[1],"".concat(e[0],".").concat(e[1]),"".concat(e[1],".").concat(e[0])]:3===t?[e[0],e[1],e[2],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0])]:t>=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0),p[n]})(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return d(d({},e),n[t])},t)}(s.className,Object.assign({},s.style,void 0===r?{}:r),a)})}else f=d(d({},s),{},{className:s.className.join(" ")});var T=E(n.children);return l.createElement(g,(0,c.Z)({key:o},f),T)}}({node:e,stylesheet:n,useInlineStyles:a,key:"code-segement".concat(t)})})}function A(e){return e&&void 0!==e.highlightAuto}var R=n(99113),I=(a=n.n(R)(),r={'code[class*="language-"]':{color:"black",background:"none",textShadow:"0 1px white",fontFamily:"Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace",fontSize:"1em",textAlign:"left",whiteSpace:"pre",wordSpacing:"normal",wordBreak:"normal",wordWrap:"normal",lineHeight:"1.5",MozTabSize:"4",OTabSize:"4",tabSize:"4",WebkitHyphens:"none",MozHyphens:"none",msHyphens:"none",hyphens:"none"},'pre[class*="language-"]':{color:"black",background:"#f5f2f0",textShadow:"0 1px white",fontFamily:"Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace",fontSize:"1em",textAlign:"left",whiteSpace:"pre",wordSpacing:"normal",wordBreak:"normal",wordWrap:"normal",lineHeight:"1.5",MozTabSize:"4",OTabSize:"4",tabSize:"4",WebkitHyphens:"none",MozHyphens:"none",msHyphens:"none",hyphens:"none",padding:"1em",margin:".5em 0",overflow:"auto"},'pre[class*="language-"]::-moz-selection':{textShadow:"none",background:"#b3d4fc"},'pre[class*="language-"] ::-moz-selection':{textShadow:"none",background:"#b3d4fc"},'code[class*="language-"]::-moz-selection':{textShadow:"none",background:"#b3d4fc"},'code[class*="language-"] ::-moz-selection':{textShadow:"none",background:"#b3d4fc"},'pre[class*="language-"]::selection':{textShadow:"none",background:"#b3d4fc"},'pre[class*="language-"] ::selection':{textShadow:"none",background:"#b3d4fc"},'code[class*="language-"]::selection':{textShadow:"none",background:"#b3d4fc"},'code[class*="language-"] ::selection':{textShadow:"none",background:"#b3d4fc"},':not(pre) > code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}},function(e){var t=e.language,n=e.children,s=e.style,c=void 0===s?r:s,u=e.customStyle,d=void 0===u?{}:u,p=e.codeTagProps,m=void 0===p?{className:t?"language-".concat(t):void 0,style:b(b({},c['code[class*="language-"]']),c['code[class*="language-'.concat(t,'"]')])}:p,R=e.useInlineStyles,I=void 0===R||R,N=e.showLineNumbers,_=void 0!==N&&N,v=e.showInlineLineNumbers,w=void 0===v||v,k=e.startingLineNumber,C=void 0===k?1:k,O=e.lineNumberContainerStyle,x=e.lineNumberStyle,L=void 0===x?{}:x,D=e.wrapLines,P=e.wrapLongLines,M=void 0!==P&&P,F=e.lineProps,U=e.renderer,B=e.PreTag,G=void 0===B?"pre":B,$=e.CodeTag,H=void 0===$?"code":$,z=e.code,j=void 0===z?(Array.isArray(n)?n[0]:n)||"":z,V=e.astGenerator,W=(0,i.Z)(e,g);V=V||a;var q=_?l.createElement(E,{containerStyle:O,codeStyle:m.style||{},numberStyle:L,startingLineNumber:C,codeString:j}):null,Y=c.hljs||c['pre[class*="language-"]']||{backgroundColor:"#fff"},K=A(V)?"hljs":"prismjs",Z=I?Object.assign({},W,{style:Object.assign({},Y,d)}):Object.assign({},W,{className:W.className?"".concat(K," ").concat(W.className):K,style:Object.assign({},d)});if(M?m.style=b({whiteSpace:"pre-wrap"},m.style):m.style=b({whiteSpace:"pre"},m.style),!V)return l.createElement(G,Z,q,l.createElement(H,m,j));(void 0===D&&U||M)&&(D=!0),U=U||T;var X=[{type:"text",value:j}],Q=function(e){var t=e.astGenerator,n=e.language,a=e.code,r=e.defaultCodeValue;if(A(t)){var i=-1!==t.listLanguages().indexOf(n);return"text"===n?{value:r,language:"text"}:i?t.highlight(n,a):t.highlightAuto(a)}try{return n&&"text"!==n?{value:t.highlight(a,n)}:{value:r}}catch(e){return{value:r}}}({astGenerator:V,language:t,code:j,defaultCodeValue:X});null===Q.language&&(Q.value=X);var J=Q.value.length;1===J&&"text"===Q.value[0].type&&(J=Q.value[0].value.split("\n").length);var ee=J+C,et=function(e,t,n,a,r,i,s,l,c){var u,d=function e(t){for(var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return t||o.length>0?function(e,i){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return y({children:e,lineNumber:i,lineNumberStyle:l,largestLineNumber:s,showInlineLineNumbers:r,lineProps:n,className:o,showLineNumbers:a,wrapLongLines:c,wrapLines:t})}(e,i,o):function(e,t){if(a&&t&&r){var n=S(l,t,s);e.unshift(h(t,n))}return e}(e,i)}for(;m]?|>=?|\?=|[-+\/=])(?=\s)/,lookbehind:!0},"string-operator":{pattern:/(\s)&&?(?=\s)/,lookbehind:!0,alias:"keyword"},"token-operator":[{pattern:/(\w)(?:->?|=>|[~|{}])(?=\w)/,lookbehind:!0,alias:"punctuation"},{pattern:/[|{}]/,alias:"punctuation"}],punctuation:/[,.:()]/}}e.exports=t,t.displayName="abap",t.aliases=[]},36463:function(e){"use strict";function t(e){var t;t="(?:ALPHA|BIT|CHAR|CR|CRLF|CTL|DIGIT|DQUOTE|HEXDIG|HTAB|LF|LWSP|OCTET|SP|VCHAR|WSP)",e.languages.abnf={comment:/;.*/,string:{pattern:/(?:%[is])?"[^"\n\r]*"/,greedy:!0,inside:{punctuation:/^%[is]/}},range:{pattern:/%(?:b[01]+-[01]+|d\d+-\d+|x[A-F\d]+-[A-F\d]+)/i,alias:"number"},terminal:{pattern:/%(?:b[01]+(?:\.[01]+)*|d\d+(?:\.\d+)*|x[A-F\d]+(?:\.[A-F\d]+)*)/i,alias:"number"},repetition:{pattern:/(^|[^\w-])(?:\d*\*\d*|\d+)/,lookbehind:!0,alias:"operator"},definition:{pattern:/(^[ \t]*)(?:[a-z][\w-]*|<[^<>\r\n]*>)(?=\s*=)/m,lookbehind:!0,alias:"keyword",inside:{punctuation:/<|>/}},"core-rule":{pattern:RegExp("(?:(^|[^<\\w-])"+t+"|<"+t+">)(?![\\w-])","i"),lookbehind:!0,alias:["rule","constant"],inside:{punctuation:/<|>/}},rule:{pattern:/(^|[^<\w-])[a-z][\w-]*|<[^<>\r\n]*>/i,lookbehind:!0,inside:{punctuation:/<|>/}},operator:/=\/?|\//,punctuation:/[()\[\]]/}}e.exports=t,t.displayName="abnf",t.aliases=[]},25276:function(e){"use strict";function t(e){e.languages.actionscript=e.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|dynamic|each|else|extends|final|finally|for|function|get|if|implements|import|in|include|instanceof|interface|internal|is|namespace|native|new|null|override|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|use|var|void|while|with)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<|>>?>?|[!=]=?)=?|[~?@]/}),e.languages.actionscript["class-name"].alias="function",delete e.languages.actionscript.parameter,delete e.languages.actionscript["literal-property"],e.languages.markup&&e.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/,lookbehind:!0,inside:e.languages.markup}})}e.exports=t,t.displayName="actionscript",t.aliases=[]},82679:function(e){"use strict";function t(e){e.languages.ada={comment:/--.*/,string:/"(?:""|[^"\r\f\n])*"/,number:[{pattern:/\b\d(?:_?\d)*#[\dA-F](?:_?[\dA-F])*(?:\.[\dA-F](?:_?[\dA-F])*)?#(?:E[+-]?\d(?:_?\d)*)?/i},{pattern:/\b\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:E[+-]?\d(?:_?\d)*)?\b/i}],"attr-name":/\b'\w+/,keyword:/\b(?:abort|abs|abstract|accept|access|aliased|all|and|array|at|begin|body|case|constant|declare|delay|delta|digits|do|else|elsif|end|entry|exception|exit|for|function|generic|goto|if|in|interface|is|limited|loop|mod|new|not|null|of|others|out|overriding|package|pragma|private|procedure|protected|raise|range|record|rem|renames|requeue|return|reverse|select|separate|some|subtype|synchronized|tagged|task|terminate|then|type|until|use|when|while|with|xor)\b/i,boolean:/\b(?:false|true)\b/i,operator:/<[=>]?|>=?|=>?|:=|\/=?|\*\*?|[&+-]/,punctuation:/\.\.?|[,;():]/,char:/'.'/,variable:/\b[a-z](?:\w)*\b/i}}e.exports=t,t.displayName="ada",t.aliases=[]},80943:function(e){"use strict";function t(e){e.languages.agda={comment:/\{-[\s\S]*?(?:-\}|$)|--.*/,string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},punctuation:/[(){}⦃⦄.;@]/,"class-name":{pattern:/((?:data|record) +)\S+/,lookbehind:!0},function:{pattern:/(^[ \t]*)(?!\s)[^:\r\n]+(?=:)/m,lookbehind:!0},operator:{pattern:/(^\s*|\s)(?:[=|:∀→λ\\?_]|->)(?=\s)/,lookbehind:!0},keyword:/\b(?:Set|abstract|constructor|data|eta-equality|field|forall|hiding|import|in|inductive|infix|infixl|infixr|instance|let|macro|module|mutual|no-eta-equality|open|overlap|pattern|postulate|primitive|private|public|quote|quoteContext|quoteGoal|quoteTerm|record|renaming|rewrite|syntax|tactic|unquote|unquoteDecl|unquoteDef|using|variable|where|with)\b/}}e.exports=t,t.displayName="agda",t.aliases=[]},34168:function(e){"use strict";function t(e){e.languages.al={comment:/\/\/.*|\/\*[\s\S]*?\*\//,string:{pattern:/'(?:''|[^'\r\n])*'(?!')|"(?:""|[^"\r\n])*"(?!")/,greedy:!0},function:{pattern:/(\b(?:event|procedure|trigger)\s+|(?:^|[^.])\.\s*)[a-z_]\w*(?=\s*\()/i,lookbehind:!0},keyword:[/\b(?:array|asserterror|begin|break|case|do|downto|else|end|event|exit|for|foreach|function|if|implements|in|indataset|interface|internal|local|of|procedure|program|protected|repeat|runonclient|securityfiltering|suppressdispose|temporary|then|to|trigger|until|var|while|with|withevents)\b/i,/\b(?:action|actions|addafter|addbefore|addfirst|addlast|area|assembly|chartpart|codeunit|column|controladdin|cuegroup|customizes|dataitem|dataset|dotnet|elements|enum|enumextension|extends|field|fieldattribute|fieldelement|fieldgroup|fieldgroups|fields|filter|fixed|grid|group|key|keys|label|labels|layout|modify|moveafter|movebefore|movefirst|movelast|page|pagecustomization|pageextension|part|profile|query|repeater|report|requestpage|schema|separator|systempart|table|tableelement|tableextension|textattribute|textelement|type|usercontrol|value|xmlport)\b/i],number:/\b(?:0x[\da-f]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?)(?:F|LL?|U(?:LL?)?)?\b/i,boolean:/\b(?:false|true)\b/i,variable:/\b(?:Curr(?:FieldNo|Page|Report)|x?Rec|RequestOptionsPage)\b/,"class-name":/\b(?:automation|biginteger|bigtext|blob|boolean|byte|char|clienttype|code|completiontriggererrorlevel|connectiontype|database|dataclassification|datascope|date|dateformula|datetime|decimal|defaultlayout|dialog|dictionary|dotnetassembly|dotnettypedeclaration|duration|errorinfo|errortype|executioncontext|executionmode|fieldclass|fieldref|fieldtype|file|filterpagebuilder|guid|httpclient|httpcontent|httpheaders|httprequestmessage|httpresponsemessage|instream|integer|joker|jsonarray|jsonobject|jsontoken|jsonvalue|keyref|list|moduledependencyinfo|moduleinfo|none|notification|notificationscope|objecttype|option|outstream|pageresult|record|recordid|recordref|reportformat|securityfilter|sessionsettings|tableconnectiontype|tablefilter|testaction|testfield|testfilterfield|testpage|testpermissions|testrequestpage|text|textbuilder|textconst|textencoding|time|transactionmodel|transactiontype|variant|verbosity|version|view|views|webserviceactioncontext|webserviceactionresultcode|xmlattribute|xmlattributecollection|xmlcdata|xmlcomment|xmldeclaration|xmldocument|xmldocumenttype|xmlelement|xmlnamespacemanager|xmlnametable|xmlnode|xmlnodelist|xmlprocessinginstruction|xmlreadoptions|xmltext|xmlwriteoptions)\b/i,operator:/\.\.|:[=:]|[-+*/]=?|<>|[<>]=?|=|\b(?:and|div|mod|not|or|xor)\b/i,punctuation:/[()\[\]{}:.;,]/}}e.exports=t,t.displayName="al",t.aliases=[]},25262:function(e){"use strict";function t(e){e.languages.antlr4={comment:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,string:{pattern:/'(?:\\.|[^\\'\r\n])*'/,greedy:!0},"character-class":{pattern:/\[(?:\\.|[^\\\]\r\n])*\]/,greedy:!0,alias:"regex",inside:{range:{pattern:/([^[]|(?:^|[^\\])(?:\\\\)*\\\[)-(?!\])/,lookbehind:!0,alias:"punctuation"},escape:/\\(?:u(?:[a-fA-F\d]{4}|\{[a-fA-F\d]+\})|[pP]\{[=\w-]+\}|[^\r\nupP])/,punctuation:/[\[\]]/}},action:{pattern:/\{(?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*\}/,greedy:!0,inside:{content:{pattern:/(\{)[\s\S]+(?=\})/,lookbehind:!0},punctuation:/[{}]/}},command:{pattern:/(->\s*(?!\s))(?:\s*(?:,\s*)?\b[a-z]\w*(?:\s*\([^()\r\n]*\))?)+(?=\s*;)/i,lookbehind:!0,inside:{function:/\b\w+(?=\s*(?:[,(]|$))/,punctuation:/[,()]/}},annotation:{pattern:/@\w+(?:::\w+)*/,alias:"keyword"},label:{pattern:/#[ \t]*\w+/,alias:"punctuation"},keyword:/\b(?:catch|channels|finally|fragment|grammar|import|lexer|locals|mode|options|parser|returns|throws|tokens)\b/,definition:[{pattern:/\b[a-z]\w*(?=\s*:)/,alias:["rule","class-name"]},{pattern:/\b[A-Z]\w*(?=\s*:)/,alias:["token","constant"]}],constant:/\b[A-Z][A-Z_]*\b/,operator:/\.\.|->|[|~]|[*+?]\??/,punctuation:/[;:()=]/},e.languages.g4=e.languages.antlr4}e.exports=t,t.displayName="antlr4",t.aliases=["g4"]},60486:function(e){"use strict";function t(e){e.languages.apacheconf={comment:/#.*/,"directive-inline":{pattern:/(^[\t ]*)\b(?:AcceptFilter|AcceptPathInfo|AccessFileName|Action|Add(?:Alt|AltByEncoding|AltByType|Charset|DefaultCharset|Description|Encoding|Handler|Icon|IconByEncoding|IconByType|InputFilter|Language|ModuleInfo|OutputFilter|OutputFilterByType|Type)|Alias|AliasMatch|Allow(?:CONNECT|EncodedSlashes|Methods|Override|OverrideList)?|Anonymous(?:_LogEmail|_MustGiveEmail|_NoUserID|_VerifyEmail)?|AsyncRequestWorkerFactor|Auth(?:BasicAuthoritative|BasicFake|BasicProvider|BasicUseDigestAlgorithm|DBDUserPWQuery|DBDUserRealmQuery|DBMGroupFile|DBMType|DBMUserFile|Digest(?:Algorithm|Domain|NonceLifetime|Provider|Qop|ShmemSize)|Form(?:Authoritative|Body|DisableNoStore|FakeBasicAuth|Location|LoginRequiredLocation|LoginSuccessLocation|LogoutLocation|Method|Mimetype|Password|Provider|SitePassphrase|Size|Username)|GroupFile|LDAP(?:AuthorizePrefix|BindAuthoritative|BindDN|BindPassword|CharsetConfig|CompareAsUser|CompareDNOnServer|DereferenceAliases|GroupAttribute|GroupAttributeIsDN|InitialBindAsUser|InitialBindPattern|MaxSubGroupDepth|RemoteUserAttribute|RemoteUserIsDN|SearchAsUser|SubGroupAttribute|SubGroupClass|Url)|Merging|Name|nCache(?:Context|Enable|ProvideFor|SOCache|Timeout)|nzFcgiCheckAuthnProvider|nzFcgiDefineProvider|Type|UserFile|zDBDLoginToReferer|zDBDQuery|zDBDRedirectQuery|zDBMType|zSendForbiddenOnFailure)|BalancerGrowth|BalancerInherit|BalancerMember|BalancerPersist|BrowserMatch|BrowserMatchNoCase|BufferedLogs|BufferSize|Cache(?:DefaultExpire|DetailHeader|DirLength|DirLevels|Disable|Enable|File|Header|IgnoreCacheControl|IgnoreHeaders|IgnoreNoLastMod|IgnoreQueryString|IgnoreURLSessionIdentifiers|KeyBaseURL|LastModifiedFactor|Lock|LockMaxAge|LockPath|MaxExpire|MaxFileSize|MinExpire|MinFileSize|NegotiatedDocs|QuickHandler|ReadSize|ReadTime|Root|Socache(?:MaxSize|MaxTime|MinTime|ReadSize|ReadTime)?|StaleOnError|StoreExpired|StoreNoStore|StorePrivate)|CGIDScriptTimeout|CGIMapExtension|CharsetDefault|CharsetOptions|CharsetSourceEnc|CheckCaseOnly|CheckSpelling|ChrootDir|ContentDigest|CookieDomain|CookieExpires|CookieName|CookieStyle|CookieTracking|CoreDumpDirectory|CustomLog|Dav|DavDepthInfinity|DavGenericLockDB|DavLockDB|DavMinTimeout|DBDExptime|DBDInitSQL|DBDKeep|DBDMax|DBDMin|DBDParams|DBDPersist|DBDPrepareSQL|DBDriver|DefaultIcon|DefaultLanguage|DefaultRuntimeDir|DefaultType|Define|Deflate(?:BufferSize|CompressionLevel|FilterNote|InflateLimitRequestBody|InflateRatio(?:Burst|Limit)|MemLevel|WindowSize)|Deny|DirectoryCheckHandler|DirectoryIndex|DirectoryIndexRedirect|DirectorySlash|DocumentRoot|DTracePrivileges|DumpIOInput|DumpIOOutput|EnableExceptionHook|EnableMMAP|EnableSendfile|Error|ErrorDocument|ErrorLog|ErrorLogFormat|Example|ExpiresActive|ExpiresByType|ExpiresDefault|ExtendedStatus|ExtFilterDefine|ExtFilterOptions|FallbackResource|FileETag|FilterChain|FilterDeclare|FilterProtocol|FilterProvider|FilterTrace|ForceLanguagePriority|ForceType|ForensicLog|GprofDir|GracefulShutdownTimeout|Group|Header|HeaderName|Heartbeat(?:Address|Listen|MaxServers|Storage)|HostnameLookups|IdentityCheck|IdentityCheckTimeout|ImapBase|ImapDefault|ImapMenu|Include|IncludeOptional|Index(?:HeadInsert|Ignore|IgnoreReset|Options|OrderDefault|StyleSheet)|InputSed|ISAPI(?:AppendLogToErrors|AppendLogToQuery|CacheFile|FakeAsync|LogNotSupported|ReadAheadBuffer)|KeepAlive|KeepAliveTimeout|KeptBodySize|LanguagePriority|LDAP(?:CacheEntries|CacheTTL|ConnectionPoolTTL|ConnectionTimeout|LibraryDebug|OpCacheEntries|OpCacheTTL|ReferralHopLimit|Referrals|Retries|RetryDelay|SharedCacheFile|SharedCacheSize|Timeout|TrustedClientCert|TrustedGlobalCert|TrustedMode|VerifyServerCert)|Limit(?:InternalRecursion|Request(?:Body|Fields|FieldSize|Line)|XMLRequestBody)|Listen|ListenBackLog|LoadFile|LoadModule|LogFormat|LogLevel|LogMessage|LuaAuthzProvider|LuaCodeCache|Lua(?:Hook(?:AccessChecker|AuthChecker|CheckUserID|Fixups|InsertFilter|Log|MapToStorage|TranslateName|TypeChecker)|Inherit|InputFilter|MapHandler|OutputFilter|PackageCPath|PackagePath|QuickHandler|Root|Scope)|Max(?:ConnectionsPerChild|KeepAliveRequests|MemFree|RangeOverlaps|RangeReversals|Ranges|RequestWorkers|SpareServers|SpareThreads|Threads)|MergeTrailers|MetaDir|MetaFiles|MetaSuffix|MimeMagicFile|MinSpareServers|MinSpareThreads|MMapFile|ModemStandard|ModMimeUsePathInfo|MultiviewsMatch|Mutex|NameVirtualHost|NoProxy|NWSSLTrustedCerts|NWSSLUpgradeable|Options|Order|OutputSed|PassEnv|PidFile|PrivilegesMode|Protocol|ProtocolEcho|Proxy(?:AddHeaders|BadHeader|Block|Domain|ErrorOverride|ExpressDBMFile|ExpressDBMType|ExpressEnable|FtpDirCharset|FtpEscapeWildcards|FtpListOnWildcard|HTML(?:BufSize|CharsetOut|DocType|Enable|Events|Extended|Fixups|Interp|Links|Meta|StripComments|URLMap)|IOBufferSize|MaxForwards|Pass(?:Inherit|InterpolateEnv|Match|Reverse|ReverseCookieDomain|ReverseCookiePath)?|PreserveHost|ReceiveBufferSize|Remote|RemoteMatch|Requests|SCGIInternalRedirect|SCGISendfile|Set|SourceAddress|Status|Timeout|Via)|ReadmeName|ReceiveBufferSize|Redirect|RedirectMatch|RedirectPermanent|RedirectTemp|ReflectorHeader|RemoteIP(?:Header|InternalProxy|InternalProxyList|ProxiesHeader|TrustedProxy|TrustedProxyList)|RemoveCharset|RemoveEncoding|RemoveHandler|RemoveInputFilter|RemoveLanguage|RemoveOutputFilter|RemoveType|RequestHeader|RequestReadTimeout|Require|Rewrite(?:Base|Cond|Engine|Map|Options|Rule)|RLimitCPU|RLimitMEM|RLimitNPROC|Satisfy|ScoreBoardFile|Script(?:Alias|AliasMatch|InterpreterSource|Log|LogBuffer|LogLength|Sock)?|SecureListen|SeeRequestTail|SendBufferSize|Server(?:Admin|Alias|Limit|Name|Path|Root|Signature|Tokens)|Session(?:Cookie(?:Name|Name2|Remove)|Crypto(?:Cipher|Driver|Passphrase|PassphraseFile)|DBD(?:CookieName|CookieName2|CookieRemove|DeleteLabel|InsertLabel|PerUser|SelectLabel|UpdateLabel)|Env|Exclude|Header|Include|MaxAge)?|SetEnv|SetEnvIf|SetEnvIfExpr|SetEnvIfNoCase|SetHandler|SetInputFilter|SetOutputFilter|SSIEndTag|SSIErrorMsg|SSIETag|SSILastModified|SSILegacyExprParser|SSIStartTag|SSITimeFormat|SSIUndefinedEcho|SSL(?:CACertificateFile|CACertificatePath|CADNRequestFile|CADNRequestPath|CARevocationCheck|CARevocationFile|CARevocationPath|CertificateChainFile|CertificateFile|CertificateKeyFile|CipherSuite|Compression|CryptoDevice|Engine|FIPS|HonorCipherOrder|InsecureRenegotiation|OCSP(?:DefaultResponder|Enable|OverrideResponder|ResponderTimeout|ResponseMaxAge|ResponseTimeSkew|UseRequestNonce)|OpenSSLConfCmd|Options|PassPhraseDialog|Protocol|Proxy(?:CACertificateFile|CACertificatePath|CARevocation(?:Check|File|Path)|CheckPeer(?:CN|Expire|Name)|CipherSuite|Engine|MachineCertificate(?:ChainFile|File|Path)|Protocol|Verify|VerifyDepth)|RandomSeed|RenegBufferSize|Require|RequireSSL|Session(?:Cache|CacheTimeout|TicketKeyFile|Tickets)|SRPUnknownUserSeed|SRPVerifierFile|Stapling(?:Cache|ErrorCacheTimeout|FakeTryLater|ForceURL|ResponderTimeout|ResponseMaxAge|ResponseTimeSkew|ReturnResponderErrors|StandardCacheTimeout)|StrictSNIVHostCheck|UserName|UseStapling|VerifyClient|VerifyDepth)|StartServers|StartThreads|Substitute|Suexec|SuexecUserGroup|ThreadLimit|ThreadsPerChild|ThreadStackSize|TimeOut|TraceEnable|TransferLog|TypesConfig|UnDefine|UndefMacro|UnsetEnv|Use|UseCanonicalName|UseCanonicalPhysicalPort|User|UserDir|VHostCGIMode|VHostCGIPrivs|VHostGroup|VHostPrivs|VHostSecure|VHostUser|Virtual(?:DocumentRoot|ScriptAlias)(?:IP)?|WatchdogInterval|XBitHack|xml2EncAlias|xml2EncDefault|xml2StartParse)\b/im,lookbehind:!0,alias:"property"},"directive-block":{pattern:/<\/?\b(?:Auth[nz]ProviderAlias|Directory|DirectoryMatch|Else|ElseIf|Files|FilesMatch|If|IfDefine|IfModule|IfVersion|Limit|LimitExcept|Location|LocationMatch|Macro|Proxy|Require(?:All|Any|None)|VirtualHost)\b.*>/i,inside:{"directive-block":{pattern:/^<\/?\w+/,inside:{punctuation:/^<\/?/},alias:"tag"},"directive-block-parameter":{pattern:/.*[^>]/,inside:{punctuation:/:/,string:{pattern:/("|').*\1/,inside:{variable:/[$%]\{?(?:\w\.?[-+:]?)+\}?/}}},alias:"attr-value"},punctuation:/>/},alias:"tag"},"directive-flags":{pattern:/\[(?:[\w=],?)+\]/,alias:"keyword"},string:{pattern:/("|').*\1/,inside:{variable:/[$%]\{?(?:\w\.?[-+:]?)+\}?/}},variable:/[$%]\{?(?:\w\.?[-+:]?)+\}?/,regex:/\^?.*\$|\^.*\$?/}}e.exports=t,t.displayName="apacheconf",t.aliases=[]},5134:function(e,t,n){"use strict";var a=n(12782);function r(e){e.register(a),function(e){var t=/\b(?:(?:after|before)(?=\s+[a-z])|abstract|activate|and|any|array|as|asc|autonomous|begin|bigdecimal|blob|boolean|break|bulk|by|byte|case|cast|catch|char|class|collect|commit|const|continue|currency|date|datetime|decimal|default|delete|desc|do|double|else|end|enum|exception|exit|export|extends|final|finally|float|for|from|get(?=\s*[{};])|global|goto|group|having|hint|if|implements|import|in|inner|insert|instanceof|int|integer|interface|into|join|like|limit|list|long|loop|map|merge|new|not|null|nulls|number|object|of|on|or|outer|override|package|parallel|pragma|private|protected|public|retrieve|return|rollback|select|set|short|sObject|sort|static|string|super|switch|synchronized|system|testmethod|then|this|throw|time|transaction|transient|trigger|try|undelete|update|upsert|using|virtual|void|webservice|when|where|while|(?:inherited|with|without)\s+sharing)\b/i,n=/\b(?:(?=[a-z_]\w*\s*[<\[])|(?!))[A-Z_]\w*(?:\s*\.\s*[A-Z_]\w*)*\b(?:\s*(?:\[\s*\]|<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>))*/.source.replace(//g,function(){return t.source});function a(e){return RegExp(e.replace(//g,function(){return n}),"i")}var r={keyword:t,punctuation:/[()\[\]{};,:.<>]/};e.languages.apex={comment:e.languages.clike.comment,string:e.languages.clike.string,sql:{pattern:/((?:[=,({:]|\breturn)\s*)\[[^\[\]]*\]/i,lookbehind:!0,greedy:!0,alias:"language-sql",inside:e.languages.sql},annotation:{pattern:/@\w+\b/,alias:"punctuation"},"class-name":[{pattern:a(/(\b(?:class|enum|extends|implements|instanceof|interface|new|trigger\s+\w+\s+on)\s+)/.source),lookbehind:!0,inside:r},{pattern:a(/(\(\s*)(?=\s*\)\s*[\w(])/.source),lookbehind:!0,inside:r},{pattern:a(/(?=\s*\w+\s*[;=,(){:])/.source),inside:r}],trigger:{pattern:/(\btrigger\s+)\w+\b/i,lookbehind:!0,alias:"class-name"},keyword:t,function:/\b[a-z_]\w*(?=\s*\()/i,boolean:/\b(?:false|true)\b/i,number:/(?:\B\.\d+|\b\d+(?:\.\d+|L)?)\b/i,operator:/[!=](?:==?)?|\?\.?|&&|\|\||--|\+\+|[-+*/^&|]=?|:|<=?|>{1,3}=?/,punctuation:/[()\[\]{};,.]/}}(e)}e.exports=r,r.displayName="apex",r.aliases=[]},63960:function(e){"use strict";function t(e){e.languages.apl={comment:/(?:⍝|#[! ]).*$/m,string:{pattern:/'(?:[^'\r\n]|'')*'/,greedy:!0},number:/¯?(?:\d*\.?\b\d+(?:e[+¯]?\d+)?|¯|∞)(?:j¯?(?:(?:\d+(?:\.\d+)?|\.\d+)(?:e[+¯]?\d+)?|¯|∞))?/i,statement:/:[A-Z][a-z][A-Za-z]*\b/,"system-function":{pattern:/⎕[A-Z]+/i,alias:"function"},constant:/[⍬⌾#⎕⍞]/,function:/[-+×÷⌈⌊∣|⍳⍸?*⍟○!⌹<≤=>≥≠≡≢∊⍷∪∩~∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⊆⊇⌷⍋⍒⊤⊥⍕⍎⊣⊢⍁⍂≈⍯↗¤→]/,"monadic-operator":{pattern:/[\\\/⌿⍀¨⍨⌶&∥]/,alias:"operator"},"dyadic-operator":{pattern:/[.⍣⍠⍤∘⌸@⌺⍥]/,alias:"operator"},assignment:{pattern:/←/,alias:"keyword"},punctuation:/[\[;\]()◇⋄]/,dfn:{pattern:/[{}⍺⍵⍶⍹∇⍫:]/,alias:"builtin"}}}e.exports=t,t.displayName="apl",t.aliases=[]},51228:function(e){"use strict";function t(e){e.languages.applescript={comment:[/\(\*(?:\(\*(?:[^*]|\*(?!\)))*\*\)|(?!\(\*)[\s\S])*?\*\)/,/--.+/,/#.+/],string:/"(?:\\.|[^"\\\r\n])*"/,number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e-?\d+)?\b/i,operator:[/[&=≠≤≥*+\-\/÷^]|[<>]=?/,/\b(?:(?:begin|end|start)s? with|(?:contains?|(?:does not|doesn't) contain)|(?:is|isn't|is not) (?:contained by|in)|(?:(?:is|isn't|is not) )?(?:greater|less) than(?: or equal)?(?: to)?|(?:comes|(?:does not|doesn't) come) (?:after|before)|(?:is|isn't|is not) equal(?: to)?|(?:(?:does not|doesn't) equal|equal to|equals|is not|isn't)|(?:a )?(?:ref(?: to)?|reference to)|(?:and|as|div|mod|not|or))\b/],keyword:/\b(?:about|above|after|against|apart from|around|aside from|at|back|before|beginning|behind|below|beneath|beside|between|but|by|considering|continue|copy|does|eighth|else|end|equal|error|every|exit|false|fifth|first|for|fourth|from|front|get|given|global|if|ignoring|in|instead of|into|is|it|its|last|local|me|middle|my|ninth|of|on|onto|out of|over|prop|property|put|repeat|return|returning|second|set|seventh|since|sixth|some|tell|tenth|that|the|then|third|through|thru|timeout|times|to|transaction|true|try|until|where|while|whose|with|without)\b/,"class-name":/\b(?:POSIX file|RGB color|alias|application|boolean|centimeters|centimetres|class|constant|cubic centimeters|cubic centimetres|cubic feet|cubic inches|cubic meters|cubic metres|cubic yards|date|degrees Celsius|degrees Fahrenheit|degrees Kelvin|feet|file|gallons|grams|inches|integer|kilograms|kilometers|kilometres|list|liters|litres|meters|metres|miles|number|ounces|pounds|quarts|real|record|reference|script|square feet|square kilometers|square kilometres|square meters|square metres|square miles|square yards|text|yards)\b/,punctuation:/[{}():,¬«»《》]/}}e.exports=t,t.displayName="applescript",t.aliases=[]},29606:function(e){"use strict";function t(e){e.languages.aql={comment:/\/\/.*|\/\*[\s\S]*?\*\//,property:{pattern:/([{,]\s*)(?:(?!\d)\w+|(["'´`])(?:(?!\2)[^\\\r\n]|\\.)*\2)(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\.)*\1/,greedy:!0},identifier:{pattern:/([´`])(?:(?!\1)[^\\\r\n]|\\.)*\1/,greedy:!0},variable:/@@?\w+/,keyword:[{pattern:/(\bWITH\s+)COUNT(?=\s+INTO\b)/i,lookbehind:!0},/\b(?:AGGREGATE|ALL|AND|ANY|ASC|COLLECT|DESC|DISTINCT|FILTER|FOR|GRAPH|IN|INBOUND|INSERT|INTO|K_PATHS|K_SHORTEST_PATHS|LET|LIKE|LIMIT|NONE|NOT|NULL|OR|OUTBOUND|REMOVE|REPLACE|RETURN|SHORTEST_PATH|SORT|UPDATE|UPSERT|WINDOW|WITH)\b/i,{pattern:/(^|[^\w.[])(?:KEEP|PRUNE|SEARCH|TO)\b/i,lookbehind:!0},{pattern:/(^|[^\w.[])(?:CURRENT|NEW|OLD)\b/,lookbehind:!0},{pattern:/\bOPTIONS(?=\s*\{)/i}],function:/\b(?!\d)\w+(?=\s*\()/,boolean:/\b(?:false|true)\b/i,range:{pattern:/\.\./,alias:"operator"},number:[/\b0b[01]+/i,/\b0x[0-9a-f]+/i,/(?:\B\.\d+|\b(?:0|[1-9]\d*)(?:\.\d+)?)(?:e[+-]?\d+)?/i],operator:/\*{2,}|[=!]~|[!=<>]=?|&&|\|\||[-+*/%]/,punctuation:/::|[?.:,;()[\]{}]/}}e.exports=t,t.displayName="aql",t.aliases=[]},59760:function(e,t,n){"use strict";var a=n(85028);function r(e){e.register(a),e.languages.arduino=e.languages.extend("cpp",{keyword:/\b(?:String|array|bool|boolean|break|byte|case|catch|continue|default|do|double|else|finally|for|function|goto|if|in|instanceof|int|integer|long|loop|new|null|return|setup|string|switch|throw|try|void|while|word)\b/,constant:/\b(?:ANALOG_MESSAGE|DEFAULT|DIGITAL_MESSAGE|EXTERNAL|FIRMATA_STRING|HIGH|INPUT|INPUT_PULLUP|INTERNAL|INTERNAL1V1|INTERNAL2V56|LED_BUILTIN|LOW|OUTPUT|REPORT_ANALOG|REPORT_DIGITAL|SET_PIN_MODE|SYSEX_START|SYSTEM_RESET)\b/,builtin:/\b(?:Audio|BSSID|Bridge|Client|Console|EEPROM|Esplora|EsploraTFT|Ethernet|EthernetClient|EthernetServer|EthernetUDP|File|FileIO|FileSystem|Firmata|GPRS|GSM|GSMBand|GSMClient|GSMModem|GSMPIN|GSMScanner|GSMServer|GSMVoiceCall|GSM_SMS|HttpClient|IPAddress|IRread|Keyboard|KeyboardController|LiquidCrystal|LiquidCrystal_I2C|Mailbox|Mouse|MouseController|PImage|Process|RSSI|RobotControl|RobotMotor|SD|SPI|SSID|Scheduler|Serial|Server|Servo|SoftwareSerial|Stepper|Stream|TFT|Task|USBHost|WiFi|WiFiClient|WiFiServer|WiFiUDP|Wire|YunClient|YunServer|abs|addParameter|analogRead|analogReadResolution|analogReference|analogWrite|analogWriteResolution|answerCall|attach|attachGPRS|attachInterrupt|attached|autoscroll|available|background|beep|begin|beginPacket|beginSD|beginSMS|beginSpeaker|beginTFT|beginTransmission|beginWrite|bit|bitClear|bitRead|bitSet|bitWrite|blink|blinkVersion|buffer|changePIN|checkPIN|checkPUK|checkReg|circle|cityNameRead|cityNameWrite|clear|clearScreen|click|close|compassRead|config|connect|connected|constrain|cos|countryNameRead|countryNameWrite|createChar|cursor|debugPrint|delay|delayMicroseconds|detach|detachInterrupt|digitalRead|digitalWrite|disconnect|display|displayLogos|drawBMP|drawCompass|encryptionType|end|endPacket|endSMS|endTransmission|endWrite|exists|exitValue|fill|find|findUntil|flush|gatewayIP|get|getAsynchronously|getBand|getButton|getCurrentCarrier|getIMEI|getKey|getModifiers|getOemKey|getPINUsed|getResult|getSignalStrength|getSocket|getVoiceCallStatus|getXChange|getYChange|hangCall|height|highByte|home|image|interrupts|isActionDone|isDirectory|isListening|isPIN|isPressed|isValid|keyPressed|keyReleased|keyboardRead|knobRead|leftToRight|line|lineFollowConfig|listen|listenOnLocalhost|loadImage|localIP|lowByte|macAddress|maintain|map|max|messageAvailable|micros|millis|min|mkdir|motorsStop|motorsWrite|mouseDragged|mouseMoved|mousePressed|mouseReleased|move|noAutoscroll|noBlink|noBuffer|noCursor|noDisplay|noFill|noInterrupts|noListenOnLocalhost|noStroke|noTone|onReceive|onRequest|open|openNextFile|overflow|parseCommand|parseFloat|parseInt|parsePacket|pauseMode|peek|pinMode|playFile|playMelody|point|pointTo|position|pow|prepare|press|print|printFirmwareVersion|printVersion|println|process|processInput|pulseIn|put|random|randomSeed|read|readAccelerometer|readBlue|readButton|readBytes|readBytesUntil|readGreen|readJoystickButton|readJoystickSwitch|readJoystickX|readJoystickY|readLightSensor|readMessage|readMicrophone|readNetworks|readRed|readSlider|readString|readStringUntil|readTemperature|ready|rect|release|releaseAll|remoteIP|remoteNumber|remotePort|remove|requestFrom|retrieveCallingNumber|rewindDirectory|rightToLeft|rmdir|robotNameRead|robotNameWrite|run|runAsynchronously|runShellCommand|runShellCommandAsynchronously|running|scanNetworks|scrollDisplayLeft|scrollDisplayRight|seek|sendAnalog|sendDigitalPortPair|sendDigitalPorts|sendString|sendSysex|serialEvent|setBand|setBitOrder|setClockDivider|setCursor|setDNS|setDataMode|setFirmwareVersion|setMode|setPINUsed|setSpeed|setTextSize|setTimeout|shiftIn|shiftOut|shutdown|sin|size|sqrt|startLoop|step|stop|stroke|subnetMask|switchPIN|tan|tempoWrite|text|tone|transfer|tuneWrite|turn|updateIR|userNameRead|userNameWrite|voiceCall|waitContinue|width|write|writeBlue|writeGreen|writeJSON|writeMessage|writeMicroseconds|writeRGB|writeRed|yield)\b/}),e.languages.ino=e.languages.arduino}e.exports=r,r.displayName="arduino",r.aliases=["ino"]},36023:function(e){"use strict";function t(e){e.languages.arff={comment:/%.*/,string:{pattern:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},keyword:/@(?:attribute|data|end|relation)\b/i,number:/\b\d+(?:\.\d+)?\b/,punctuation:/[{},]/}}e.exports=t,t.displayName="arff",t.aliases=[]},26894:function(e){"use strict";function t(e){!function(e){var t={pattern:/(^[ \t]*)\[(?!\[)(?:(["'$`])(?:(?!\2)[^\\]|\\.)*\2|\[(?:[^\[\]\\]|\\.)*\]|[^\[\]\\"'$`]|\\.)*\]/m,lookbehind:!0,inside:{quoted:{pattern:/([$`])(?:(?!\1)[^\\]|\\.)*\1/,inside:{punctuation:/^[$`]|[$`]$/}},interpreted:{pattern:/'(?:[^'\\]|\\.)*'/,inside:{punctuation:/^'|'$/}},string:/"(?:[^"\\]|\\.)*"/,variable:/\w+(?==)/,punctuation:/^\[|\]$|,/,operator:/=/,"attr-value":/(?!^\s+$).+/}},n=e.languages.asciidoc={"comment-block":{pattern:/^(\/{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1/m,alias:"comment"},table:{pattern:/^\|={3,}(?:(?:\r?\n|\r(?!\n)).*)*?(?:\r?\n|\r)\|={3,}$/m,inside:{specifiers:{pattern:/(?:(?:(?:\d+(?:\.\d+)?|\.\d+)[+*](?:[<^>](?:\.[<^>])?|\.[<^>])?|[<^>](?:\.[<^>])?|\.[<^>])[a-z]*|[a-z]+)(?=\|)/,alias:"attr-value"},punctuation:{pattern:/(^|[^\\])[|!]=*/,lookbehind:!0}}},"passthrough-block":{pattern:/^(\+{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,inside:{punctuation:/^\++|\++$/}},"literal-block":{pattern:/^(-{4,}|\.{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,inside:{punctuation:/^(?:-+|\.+)|(?:-+|\.+)$/}},"other-block":{pattern:/^(--|\*{4,}|_{4,}|={4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,inside:{punctuation:/^(?:-+|\*+|_+|=+)|(?:-+|\*+|_+|=+)$/}},"list-punctuation":{pattern:/(^[ \t]*)(?:-|\*{1,5}|\.{1,5}|(?:[a-z]|\d+)\.|[xvi]+\))(?= )/im,lookbehind:!0,alias:"punctuation"},"list-label":{pattern:/(^[ \t]*)[a-z\d].+(?::{2,4}|;;)(?=\s)/im,lookbehind:!0,alias:"symbol"},"indented-block":{pattern:/((\r?\n|\r)\2)([ \t]+)\S.*(?:(?:\r?\n|\r)\3.+)*(?=\2{2}|$)/,lookbehind:!0},comment:/^\/\/.*/m,title:{pattern:/^.+(?:\r?\n|\r)(?:={3,}|-{3,}|~{3,}|\^{3,}|\+{3,})$|^={1,5} .+|^\.(?![\s.]).*/m,alias:"important",inside:{punctuation:/^(?:\.|=+)|(?:=+|-+|~+|\^+|\++)$/}},"attribute-entry":{pattern:/^:[^:\r\n]+:(?: .*?(?: \+(?:\r?\n|\r).*?)*)?$/m,alias:"tag"},attributes:t,hr:{pattern:/^'{3,}$/m,alias:"punctuation"},"page-break":{pattern:/^<{3,}$/m,alias:"punctuation"},admonition:{pattern:/^(?:CAUTION|IMPORTANT|NOTE|TIP|WARNING):/m,alias:"keyword"},callout:[{pattern:/(^[ \t]*)\d*>/m,lookbehind:!0,alias:"symbol"},{pattern:/<\d+>/,alias:"symbol"}],macro:{pattern:/\b[a-z\d][a-z\d-]*::?(?:[^\s\[\]]*\[(?:[^\]\\"']|(["'])(?:(?!\1)[^\\]|\\.)*\1|\\.)*\])/,inside:{function:/^[a-z\d-]+(?=:)/,punctuation:/^::?/,attributes:{pattern:/(?:\[(?:[^\]\\"']|(["'])(?:(?!\1)[^\\]|\\.)*\1|\\.)*\])/,inside:t.inside}}},inline:{pattern:/(^|[^\\])(?:(?:\B\[(?:[^\]\\"']|(["'])(?:(?!\2)[^\\]|\\.)*\2|\\.)*\])?(?:\b_(?!\s)(?: _|[^_\\\r\n]|\\.)+(?:(?:\r?\n|\r)(?: _|[^_\\\r\n]|\\.)+)*_\b|\B``(?!\s).+?(?:(?:\r?\n|\r).+?)*''\B|\B`(?!\s)(?:[^`'\s]|\s+\S)+['`]\B|\B(['*+#])(?!\s)(?: \3|(?!\3)[^\\\r\n]|\\.)+(?:(?:\r?\n|\r)(?: \3|(?!\3)[^\\\r\n]|\\.)+)*\3\B)|(?:\[(?:[^\]\\"']|(["'])(?:(?!\4)[^\\]|\\.)*\4|\\.)*\])?(?:(__|\*\*|\+\+\+?|##|\$\$|[~^]).+?(?:(?:\r?\n|\r).+?)*\5|\{[^}\r\n]+\}|\[\[\[?.+?(?:(?:\r?\n|\r).+?)*\]?\]\]|<<.+?(?:(?:\r?\n|\r).+?)*>>|\(\(\(?.+?(?:(?:\r?\n|\r).+?)*\)?\)\)))/m,lookbehind:!0,inside:{attributes:t,url:{pattern:/^(?:\[\[\[?.+?\]?\]\]|<<.+?>>)$/,inside:{punctuation:/^(?:\[\[\[?|<<)|(?:\]\]\]?|>>)$/}},"attribute-ref":{pattern:/^\{.+\}$/,inside:{variable:{pattern:/(^\{)[a-z\d,+_-]+/,lookbehind:!0},operator:/^[=?!#%@$]|!(?=[:}])/,punctuation:/^\{|\}$|::?/}},italic:{pattern:/^(['_])[\s\S]+\1$/,inside:{punctuation:/^(?:''?|__?)|(?:''?|__?)$/}},bold:{pattern:/^\*[\s\S]+\*$/,inside:{punctuation:/^\*\*?|\*\*?$/}},punctuation:/^(?:``?|\+{1,3}|##?|\$\$|[~^]|\(\(\(?)|(?:''?|\+{1,3}|##?|\$\$|[~^`]|\)?\)\))$/}},replacement:{pattern:/\((?:C|R|TM)\)/,alias:"builtin"},entity:/?[\da-z]{1,8};/i,"line-continuation":{pattern:/(^| )\+$/m,lookbehind:!0,alias:"punctuation"}};function a(e){e=e.split(" ");for(var t={},a=0,r=e.length;a>=?|<<=?|&&?|\|\|?|[-+*/%&|^!=<>?]=?/,punctuation:/[(),:]/}}e.exports=t,t.displayName="asmatmel",t.aliases=[]},82592:function(e,t,n){"use strict";var a=n(53494);function r(e){e.register(a),e.languages.aspnet=e.languages.extend("markup",{"page-directive":{pattern:/<%\s*@.*%>/,alias:"tag",inside:{"page-directive":{pattern:/<%\s*@\s*(?:Assembly|Control|Implements|Import|Master(?:Type)?|OutputCache|Page|PreviousPageType|Reference|Register)?|%>/i,alias:"tag"},rest:e.languages.markup.tag.inside}},directive:{pattern:/<%.*%>/,alias:"tag",inside:{directive:{pattern:/<%\s*?[$=%#:]{0,2}|%>/,alias:"tag"},rest:e.languages.csharp}}}),e.languages.aspnet.tag.pattern=/<(?!%)\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/,e.languages.insertBefore("inside","punctuation",{directive:e.languages.aspnet.directive},e.languages.aspnet.tag.inside["attr-value"]),e.languages.insertBefore("aspnet","comment",{"asp-comment":{pattern:/<%--[\s\S]*?--%>/,alias:["asp","comment"]}}),e.languages.insertBefore("aspnet",e.languages.javascript?"script":"tag",{"asp-script":{pattern:/(LiteLLM Dashboard