diff --git a/.circleci/config.yml b/.circleci/config.yml index faf43ff0b8b..7debc582915 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1477,6 +1477,7 @@ jobs: docker run -d \ -p 4000:4000 \ -e DATABASE_URL=$PROXY_DATABASE_URL \ + -e DEFAULT_NUM_WORKERS_LITELLM_PROXY=1 \ -e DISABLE_SCHEMA_UPDATE="True" \ -v $(pwd)/litellm/proxy/example_config_yaml/bad_schema.prisma:/app/schema.prisma \ -v $(pwd)/litellm/proxy/example_config_yaml/bad_schema.prisma:/app/litellm/proxy/schema.prisma \ @@ -1912,6 +1913,7 @@ jobs: -e APORIA_API_BASE_1=$APORIA_API_BASE_1 \ -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \ -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \ + -e DEFAULT_NUM_WORKERS_LITELLM_PROXY=1 \ -e USE_DDTRACE=True \ -e DD_API_KEY=$DD_API_KEY \ -e DD_SITE=$DD_SITE \ @@ -2962,6 +2964,7 @@ jobs: command: | docker run --name my-app \ -p 4000:4000 \ + -e DEFAULT_NUM_WORKERS_LITELLM_PROXY=1 \ -e DATABASE_URL="postgresql://wrong:wrong@wrong:5432/wrong" \ myapp:latest \ --port 4000 > docker_output.log 2>&1 || true diff --git a/.github/workflows/auto_update_price_and_context_window_file.py b/.github/workflows/auto_update_price_and_context_window_file.py index 3e0731b94bd..461d8d347d9 100644 --- a/.github/workflows/auto_update_price_and_context_window_file.py +++ b/.github/workflows/auto_update_price_and_context_window_file.py @@ -43,8 +43,8 @@ def write_to_file(file_path, data): # Print an error message if writing to file fails print("Error updating JSON file:", e) -# Update the existing models and add the missing models -def transform_remote_data(data): +# Update the existing models and add the missing models for OpenRouter +def transform_openrouter_data(data): transformed = {} for row in data: # Add the fields 'max_tokens' and 'input_cost_per_token' @@ -81,6 +81,34 @@ def transform_remote_data(data): return transformed +# Update the existing models and add the missing models for Vercel AI Gateway +def transform_vercel_ai_gateway_data(data): + transformed = {} + for row in data: + obj = { + "max_tokens": row["context_window"], + "input_cost_per_token": float(row["pricing"]["input"]), + "output_cost_per_token": float(row["pricing"]["output"]), + 'max_output_tokens': row['max_tokens'], + 'max_input_tokens': row["context_window"], + } + + # Handle cache pricing if available + if "pricing" in row: + if "input_cache_read" in row["pricing"] and row["pricing"]["input_cache_read"] is not None: + obj['cache_read_input_token_cost'] = float(f"{float(row['pricing']['input_cache_read']):e}") + + if "input_cache_write" in row["pricing"] and row["pricing"]["input_cache_write"] is not None: + obj['cache_creation_input_token_cost'] = float(f"{float(row['pricing']['input_cache_write']):e}") + + mode = "embedding" if "embedding" in row["id"].lower() else "chat" + + obj.update({"litellm_provider": "vercel_ai_gateway", "mode": mode}) + + transformed[f'vercel_ai_gateway/{row["id"]}'] = obj + + return transformed + # Load local data from a specified file def load_local_data(file_path): @@ -100,22 +128,32 @@ def load_local_data(file_path): def main(): local_file_path = "model_prices_and_context_window.json" # Path to the local data file - url = "https://openrouter.ai/api/v1/models" # URL to fetch remote data + openrouter_url = "https://openrouter.ai/api/v1/models" # URL to fetch OpenRouter data + vercel_ai_gateway_url = "https://ai-gateway.vercel.sh/v1/models" # URL to fetch Vercel AI Gateway data # Load local data from file local_data = load_local_data(local_file_path) - # Fetch remote data asynchronously - remote_data = asyncio.run(fetch_data(url)) - # Transform the fetched remote data - remote_data = transform_remote_data(remote_data) + + # Fetch OpenRouter data + openrouter_data = asyncio.run(fetch_data(openrouter_url)) + # Transform the fetched OpenRouter data + openrouter_data = transform_openrouter_data(openrouter_data) + + # Fetch Vercel AI Gateway data + vercel_data = asyncio.run(fetch_data(vercel_ai_gateway_url)) + # Transform the fetched Vercel AI Gateway data + vercel_data = transform_vercel_ai_gateway_data(vercel_data) + + # Combine both datasets + all_remote_data = {**openrouter_data, **vercel_data} - # If both local and remote data are available, synchronize and save - if local_data and remote_data: - sync_local_data_with_remote(local_data, remote_data) + # If both local and openrouter data are available, synchronize and save + if local_data and all_remote_data: + sync_local_data_with_remote(local_data, all_remote_data) write_to_file(local_file_path, local_data) else: print("Failed to fetch model data from either local file or URL.") # Entry point of the script if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/.github/workflows/test-litellm.yml b/.github/workflows/test-litellm.yml index 7e67aee8d73..0d3a9f2b5d4 100644 --- a/.github/workflows/test-litellm.yml +++ b/.github/workflows/test-litellm.yml @@ -31,6 +31,7 @@ jobs: poetry run pip install "pytest-retry==1.6.3" poetry run pip install pytest-xdist poetry run pip install "google-genai==1.22.0" + poetry run pip install "google-cloud-aiplatform>=1.38" poetry run pip install "fastapi-offline==1.7.3" - name: Setup litellm-enterprise as local package run: | diff --git a/Makefile b/Makefile index edeb27bac3f..159fe4fa2ef 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ install-test-deps: install-proxy-dev cd enterprise && python -m pip install -e . && cd .. install-helm-unittest: - helm plugin install https://github.com/helm-unittest/helm-unittest --version v0.4.4 + helm plugin install https://github.com/helm-unittest/helm-unittest --version v0.4.4 || echo "ignore error if plugin exists" # Formatting format: install-dev diff --git a/certifi-2025.8.3-py3-none-any.whl b/certifi-2025.8.3-py3-none-any.whl new file mode 100644 index 00000000000..b4158ec6717 Binary files /dev/null and b/certifi-2025.8.3-py3-none-any.whl differ diff --git a/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl b/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl new file mode 100644 index 00000000000..659c5408658 Binary files /dev/null and b/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl differ diff --git a/cookbook/veo_video_generation.py b/cookbook/veo_video_generation.py new file mode 100644 index 00000000000..64a7207feb1 --- /dev/null +++ b/cookbook/veo_video_generation.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python3 +""" +Complete example for Veo video generation through LiteLLM proxy. + +This script demonstrates how to: +1. Generate videos using Google's Veo model +2. Poll for completion status +3. Download the generated video file + +Requirements: +- LiteLLM proxy running with Google AI Studio pass-through configured +- Google AI Studio API key with Veo access +""" + +import json +import os +import time +import requests +from typing import Optional + + +class VeoVideoGenerator: + """Complete Veo video generation client using LiteLLM proxy.""" + + def __init__(self, base_url: str = "http://localhost:4000/gemini/v1beta", + api_key: str = "sk-1234"): + """ + Initialize the Veo video generator. + + Args: + base_url: Base URL for the LiteLLM proxy with Gemini pass-through + api_key: API key for LiteLLM proxy authentication + """ + self.base_url = base_url + self.api_key = api_key + self.headers = { + "x-goog-api-key": api_key, + "Content-Type": "application/json" + } + + def generate_video(self, prompt: str) -> Optional[str]: + """ + Initiate video generation with Veo. + + Args: + prompt: Text description of the video to generate + + Returns: + Operation name if successful, None otherwise + """ + print(f"🎬 Generating video with prompt: '{prompt}'") + + url = f"{self.base_url}/models/veo-3.0-generate-preview:predictLongRunning" + payload = { + "instances": [{ + "prompt": prompt + }] + } + + try: + response = requests.post(url, headers=self.headers, json=payload) + response.raise_for_status() + + data = response.json() + operation_name = data.get("name") + + if operation_name: + print(f"✅ Video generation started: {operation_name}") + return operation_name + else: + print("❌ No operation name returned") + print(f"Response: {json.dumps(data, indent=2)}") + return None + + except requests.RequestException as e: + print(f"❌ Failed to start video generation: {e}") + if hasattr(e, 'response') and e.response is not None: + try: + error_data = e.response.json() + print(f"Error details: {json.dumps(error_data, indent=2)}") + except: + print(f"Error response: {e.response.text}") + return None + + def wait_for_completion(self, operation_name: str, max_wait_time: int = 600) -> Optional[str]: + """ + Poll operation status until video generation is complete. + + Args: + operation_name: Name of the operation to monitor + max_wait_time: Maximum time to wait in seconds (default: 10 minutes) + + Returns: + Video URI if successful, None otherwise + """ + print("⏳ Waiting for video generation to complete...") + + operation_url = f"{self.base_url}/{operation_name}" + start_time = time.time() + poll_interval = 10 # Start with 10 seconds + + while time.time() - start_time < max_wait_time: + try: + print(f"🔍 Polling status... ({int(time.time() - start_time)}s elapsed)") + + response = requests.get(operation_url, headers=self.headers) + response.raise_for_status() + + data = response.json() + + # Check for errors + if "error" in data: + print("❌ Error in video generation:") + print(json.dumps(data["error"], indent=2)) + return None + + # Check if operation is complete + is_done = data.get("done", False) + + if is_done: + print("🎉 Video generation complete!") + + try: + # Extract video URI from nested response + video_uri = data["response"]["generateVideoResponse"]["generatedSamples"][0]["video"]["uri"] + print(f"📹 Video URI: {video_uri}") + return video_uri + except KeyError as e: + print(f"❌ Could not extract video URI: {e}") + print("Full response:") + print(json.dumps(data, indent=2)) + return None + + # Wait before next poll, with exponential backoff + time.sleep(poll_interval) + poll_interval = min(poll_interval * 1.2, 30) # Cap at 30 seconds + + except requests.RequestException as e: + print(f"❌ Error polling operation status: {e}") + time.sleep(poll_interval) + + print(f"⏰ Timeout after {max_wait_time} seconds") + return None + + def download_video(self, video_uri: str, output_filename: str = "generated_video.mp4") -> bool: + """ + Download the generated video file. + + Args: + video_uri: URI of the video to download (from Google's response) + output_filename: Local filename to save the video + + Returns: + True if download successful, False otherwise + """ + print(f"⬇️ Downloading video...") + print(f"Original URI: {video_uri}") + + # Convert Google URI to LiteLLM proxy URI + # Example: files/abc123 -> /gemini/v1beta/files/abc123:download?alt=media + if video_uri.startswith("files/"): + download_path = f"{video_uri}:download?alt=media" + else: + download_path = video_uri + + litellm_download_url = f"{self.base_url}/{download_path}" + print(f"Download URL: {litellm_download_url}") + + try: + # Download with streaming and redirect handling + response = requests.get( + litellm_download_url, + headers=self.headers, + stream=True, + allow_redirects=True # Handle redirects automatically + ) + response.raise_for_status() + + # Save video file + with open(output_filename, 'wb') as f: + downloaded_size = 0 + for chunk in response.iter_content(chunk_size=8192): + if chunk: + f.write(chunk) + downloaded_size += len(chunk) + + # Progress indicator for large files + if downloaded_size % (1024 * 1024) == 0: # Every MB + print(f"📦 Downloaded {downloaded_size / (1024*1024):.1f} MB...") + + # Verify file was created and has content + if os.path.exists(output_filename): + file_size = os.path.getsize(output_filename) + if file_size > 0: + print(f"✅ Video downloaded successfully!") + print(f"📁 Saved as: {output_filename}") + print(f"📏 File size: {file_size / (1024*1024):.2f} MB") + return True + else: + print("❌ Downloaded file is empty") + os.remove(output_filename) + return False + else: + print("❌ File was not created") + return False + + except requests.RequestException as e: + print(f"❌ Download failed: {e}") + if hasattr(e, 'response') and e.response is not None: + print(f"Status code: {e.response.status_code}") + print(f"Response headers: {dict(e.response.headers)}") + return False + + def generate_and_download(self, prompt: str, output_filename: str = None) -> bool: + """ + Complete workflow: generate video and download it. + + Args: + prompt: Text description for video generation + output_filename: Output filename (auto-generated if None) + + Returns: + True if successful, False otherwise + """ + # Auto-generate filename if not provided + if output_filename is None: + timestamp = int(time.time()) + safe_prompt = "".join(c for c in prompt[:30] if c.isalnum() or c in (' ', '-', '_')).rstrip() + output_filename = f"veo_video_{safe_prompt.replace(' ', '_')}_{timestamp}.mp4" + + print("=" * 60) + print("🎬 VEO VIDEO GENERATION WORKFLOW") + print("=" * 60) + + # Step 1: Generate video + operation_name = self.generate_video(prompt) + if not operation_name: + return False + + # Step 2: Wait for completion + video_uri = self.wait_for_completion(operation_name) + if not video_uri: + return False + + # Step 3: Download video + success = self.download_video(video_uri, output_filename) + + if success: + print("=" * 60) + print("🎉 SUCCESS! Video generation complete!") + print(f"📁 Video saved as: {output_filename}") + print("=" * 60) + else: + print("=" * 60) + print("❌ FAILED! Video generation or download failed") + print("=" * 60) + + return success + + +def main(): + """ + Example usage of the VeoVideoGenerator. + + Configure these environment variables: + - LITELLM_BASE_URL: Your LiteLLM proxy URL (default: http://localhost:4000/gemini/v1beta) + - LITELLM_API_KEY: Your LiteLLM API key (default: sk-1234) + """ + + # Configuration from environment or defaults + base_url = os.getenv("LITELLM_BASE_URL", "http://localhost:4000/gemini/v1beta") + api_key = os.getenv("LITELLM_API_KEY", "sk-1234") + + print("🚀 Starting Veo Video Generation Example") + print(f"📡 Using LiteLLM proxy at: {base_url}") + + # Initialize generator + generator = VeoVideoGenerator(base_url=base_url, api_key=api_key) + + # Example prompts - try different ones! + example_prompts = [ + "A cat playing with a ball of yarn in a sunny garden", + "Ocean waves crashing against rocky cliffs at sunset", + "A bustling city street with people walking and cars passing by", + "A peaceful forest with sunlight filtering through the trees" + ] + + # Use first example or get from user + prompt = example_prompts[0] + print(f"🎬 Using prompt: '{prompt}'") + + # Generate and download video + success = generator.generate_and_download(prompt) + + if success: + print("\n✅ Example completed successfully!") + print("💡 Try modifying the prompt in the script for different videos!") + else: + print("\n❌ Example failed!") + print("🔧 Check your LiteLLM proxy configuration and Google AI Studio API key") + + # Troubleshooting tips + print("\n🔍 Troubleshooting:") + print("1. Ensure LiteLLM proxy is running with Google AI Studio pass-through") + print("2. Verify your Google AI Studio API key has Veo access") + print("3. Check that your prompt meets Veo's content guidelines") + print("4. Review the LiteLLM proxy logs for detailed error information") + + +if __name__ == "__main__": + main() diff --git a/deploy/charts/litellm-helm/Chart.yaml b/deploy/charts/litellm-helm/Chart.yaml index b6ac264a228..e361ee226b7 100644 --- a/deploy/charts/litellm-helm/Chart.yaml +++ b/deploy/charts/litellm-helm/Chart.yaml @@ -18,7 +18,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.5 +version: 0.4.6 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/deploy/charts/litellm-helm/README.md b/deploy/charts/litellm-helm/README.md index 73b722b64c6..352c3e9ddff 100644 --- a/deploy/charts/litellm-helm/README.md +++ b/deploy/charts/litellm-helm/README.md @@ -36,11 +36,50 @@ If `db.useStackgresOperator` is used (not yet implemented): | `service.port` | TCP port that the Kubernetes Service will listen on. Also the TCP port within the Pod that the proxy will listen on. | `4000` | | `service.loadBalancerClass` | Optional LoadBalancer implementation class (only used when `service.type` is `LoadBalancer`) | `""` | | `ingress.*` | See [values.yaml](./values.yaml) for example settings | N/A | -| `proxy_config.*` | See [values.yaml](./values.yaml) for default settings. See [example_config_yaml](../../../litellm/proxy/example_config_yaml/) for configuration examples. | N/A | -| `extraContainers[]` | An array of additional containers to be deployed as sidecars alongside the LiteLLM Proxy. | `[]` | +| `proxyConfigMap.create` | When `true`, render a ConfigMap from `.Values.proxy_config` and mount it. | `true` | +| `proxyConfigMap.name` | When `create=false`, name of the existing ConfigMap to mount. | `""` | +| `proxyConfigMap.key` | Key in the ConfigMap that contains the proxy config file. | `"config.yaml"` | +| `proxy_config.*` | See [values.yaml](./values.yaml) for default settings. Rendered into the ConfigMap’s `config.yaml` only when `proxyConfigMap.create=true`. See [example_config_yaml](../../../litellm/proxy/example_config_yaml/) for configuration examples. | `N/A` | +| `extraContainers[]` | An array of additional containers to be deployed as sidecars alongside the LiteLLM Proxy. +| `pdb.enabled` | Enable a PodDisruptionBudget for the LiteLLM proxy Deployment | `false` | +| `pdb.minAvailable` | Minimum number/percentage of pods that must be available during **voluntary** disruptions (choose **one** of minAvailable/maxUnavailable) | `null` | +| `pdb.maxUnavailable` | Maximum number/percentage of pods that can be unavailable during **voluntary** disruptions (choose **one** of minAvailable/maxUnavailable) | `null` | +| `pdb.annotations` | Extra metadata annotations to add to the PDB | `{}` | +| `pdb.labels` | Extra metadata labels to add to the PDB | `{}` | + +#### Example `proxy_config` ConfigMap from values (default): + + +``` +proxyConfigMap: + create: true + key: "config.yaml" + +proxy_config: + general_settings: + master_key: os.environ/PROXY_MASTER_KEY + model_list: + - model_name: gpt-3.5-turbo + litellm_params: + model: gpt-3.5-turbo + api_key: eXaMpLeOnLy +``` + +#### Example using existing `proxyConfigMap` instead of creating it: + + +``` +proxyConfigMap: + create: false + name: my-litellm-config + key: config.yaml + +# proxy_config is ignored in this mode +``` #### Example `environmentSecrets` Secret + ``` apiVersion: v1 kind: Secret diff --git a/deploy/charts/litellm-helm/templates/NOTES.txt b/deploy/charts/litellm-helm/templates/NOTES.txt index e72c9916080..017bbfa78bd 100644 --- a/deploy/charts/litellm-helm/templates/NOTES.txt +++ b/deploy/charts/litellm-helm/templates/NOTES.txt @@ -20,3 +20,4 @@ echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT {{- end }} +PDB: {{ if .Values.pdb.enabled }}enabled{{ else }}disabled{{ end }}. Configure via .Values.pdb.* \ No newline at end of file diff --git a/deploy/charts/litellm-helm/templates/configmap-litellm.yaml b/deploy/charts/litellm-helm/templates/configmap-litellm.yaml index 4598054a9d0..cf35917da03 100644 --- a/deploy/charts/litellm-helm/templates/configmap-litellm.yaml +++ b/deploy/charts/litellm-helm/templates/configmap-litellm.yaml @@ -1,7 +1,9 @@ +{{- if .Values.proxyConfigMap.create }} apiVersion: v1 kind: ConfigMap metadata: name: {{ include "litellm.fullname" . }}-config data: config.yaml: | -{{ .Values.proxy_config | toYaml | indent 6 }} \ No newline at end of file +{{ .Values.proxy_config | toYaml | indent 6 }} +{{- end }} \ No newline at end of file diff --git a/deploy/charts/litellm-helm/templates/deployment.yaml b/deploy/charts/litellm-helm/templates/deployment.yaml index b30b8829325..6a5a6e87577 100644 --- a/deploy/charts/litellm-helm/templates/deployment.yaml +++ b/deploy/charts/litellm-helm/templates/deployment.yaml @@ -16,7 +16,9 @@ spec: template: metadata: annotations: + {{- if .Values.proxyConfigMap.create }} checksum/config: {{ include (print $.Template.BasePath "/configmap-litellm.yaml") . | sha256sum }} + {{- end }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} @@ -183,9 +185,13 @@ spec: {{- end }} - name: litellm-config configMap: + {{- if .Values.proxyConfigMap.create }} name: {{ include "litellm.fullname" . }}-config + {{- else }} + name: {{ .Values.proxyConfigMap.name }} + {{- end }} items: - - key: "config.yaml" + - key: {{ .Values.proxyConfigMap.key | default "config.yaml" }} path: "config.yaml" {{- with .Values.volumes }} {{- toYaml . | nindent 8 }} diff --git a/deploy/charts/litellm-helm/templates/migrations-job.yaml b/deploy/charts/litellm-helm/templates/migrations-job.yaml index 4c8925564af..7a6893f28f1 100644 --- a/deploy/charts/litellm-helm/templates/migrations-job.yaml +++ b/deploy/charts/litellm-helm/templates/migrations-job.yaml @@ -61,7 +61,7 @@ spec: value: {{ .Values.db.database }} - name: DATABASE_URL value: {{ .Values.db.url | quote }} - {{- else }} + {{- else if .Values.db.deployStandalone }} - name: DATABASE_URL value: postgresql://{{ .Values.postgresql.auth.username }}:{{ .Values.postgresql.auth.password }}@{{ .Release.Name }}-postgresql/{{ .Values.postgresql.auth.database }} {{- end }} diff --git a/deploy/charts/litellm-helm/templates/poddisruptionbudget.yaml b/deploy/charts/litellm-helm/templates/poddisruptionbudget.yaml new file mode 100644 index 00000000000..1715b94c1f6 --- /dev/null +++ b/deploy/charts/litellm-helm/templates/poddisruptionbudget.yaml @@ -0,0 +1,33 @@ +{{- /* +PodDisruptionBudget for LiteLLM proxy +Controlled via .Values.pdb.enabled and .Values.pdb.{minAvailable|maxUnavailable} +Only one of minAvailable / maxUnavailable should be set. If both are set, minAvailable wins. +*/ -}} +{{- if .Values.pdb.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "litellm.fullname" . }} + labels: + {{- include "litellm.labels" . | nindent 4 }} + {{- with .Values.pdb.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.pdb.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- /* Match the Deployment selector to target the same pod set */ -}} + {{- include "litellm.selectorLabels" . | nindent 6 }} + {{- if .Values.pdb.minAvailable }} + minAvailable: {{ .Values.pdb.minAvailable }} + {{- else if .Values.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.pdb.maxUnavailable }} + {{- else }} + # Safe default if enabled but not configured + maxUnavailable: 1 + {{- end }} +{{- end }} diff --git a/deploy/charts/litellm-helm/tests/deployment_tests.yaml b/deploy/charts/litellm-helm/tests/deployment_tests.yaml index b71f91377f1..f9c83966696 100644 --- a/deploy/charts/litellm-helm/tests/deployment_tests.yaml +++ b/deploy/charts/litellm-helm/tests/deployment_tests.yaml @@ -115,3 +115,25 @@ tests: content: name: EXTRA_ENV_VAR value: EXTRA_ENV_VAR_VALUE + - it: should mount existing configmap when create=false + template: deployment.yaml + set: + proxyConfigMap: + create: false + name: my-litellm-config + key: custom.yaml + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: litellm-config + configMap: + name: my-litellm-config + items: + - key: custom.yaml + path: config.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: litellm-config + mountPath: /etc/litellm/ \ No newline at end of file diff --git a/deploy/charts/litellm-helm/tests/migrations-job_tests.yaml b/deploy/charts/litellm-helm/tests/migrations-job_tests.yaml index 686d20efa55..3a7bfa5eb0c 100644 --- a/deploy/charts/litellm-helm/tests/migrations-job_tests.yaml +++ b/deploy/charts/litellm-helm/tests/migrations-job_tests.yaml @@ -110,4 +110,18 @@ tests: path: spec.template.spec.containers[0].env content: name: CUSTOM_VAR - value: "custom_value" \ No newline at end of file + value: "custom_value" + + - it: should not include DATABASE_URL when deployStandalone is false + template: migrations-job.yaml + set: + migrationJob: + enabled: true + db: + deployStandalone: false + useExisting: false + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: DATABASE_URL \ No newline at end of file diff --git a/deploy/charts/litellm-helm/tests/pdb_tests.yaml b/deploy/charts/litellm-helm/tests/pdb_tests.yaml new file mode 100644 index 00000000000..5e042e80bd3 --- /dev/null +++ b/deploy/charts/litellm-helm/tests/pdb_tests.yaml @@ -0,0 +1,45 @@ +suite: "pdb enabled" +templates: + - poddisruptionbudget.yaml +tests: + - it: "renders a PDB with maxUnavailable=1" + set: + pdb.enabled: true + pdb.maxUnavailable: 1 + asserts: + - hasDocuments: { count: 1 } + - isKind: { of: PodDisruptionBudget } + - equal: { path: apiVersion, value: policy/v1 } + - equal: { path: spec.maxUnavailable, value: 1 } + - equal: + path: spec.selector.matchLabels + value: + app.kubernetes.io/name: litellm + app.kubernetes.io/instance: RELEASE-NAME + +--- +suite: "pdb disabled" +templates: + - poddisruptionbudget.yaml +tests: + - it: "does not render when disabled" + set: + pdb.enabled: false + asserts: + - hasDocuments: { count: 0 } + +--- +suite: "pdb minAvailable precedence" +templates: + - poddisruptionbudget.yaml +tests: + - it: "uses minAvailable when both are set" + set: + pdb.enabled: true + pdb.minAvailable: "50%" + pdb.maxUnavailable: 1 + asserts: + - isKind: { of: PodDisruptionBudget } + - equal: { path: apiVersion, value: policy/v1 } + - equal: { path: spec.minAvailable, value: "50%" } + - isNull: { path: spec.maxUnavailable } diff --git a/deploy/charts/litellm-helm/values.yaml b/deploy/charts/litellm-helm/values.yaml index 0bd95003c10..c1792497d29 100644 --- a/deploy/charts/litellm-helm/values.yaml +++ b/deploy/charts/litellm-helm/values.yaml @@ -93,6 +93,14 @@ masterkeySecretName: "" # if set, use this secret key for the master key; otherwise, use the default key masterkeySecretKey: "" +proxyConfigMap: + # when true, creates a new configmap + create: true + # if create is false and name is set, use existing ConfigMap + # create: false + # name: "" + # key: "config.yaml" + # The elements within proxy_config are rendered as config.yaml for the proxy # Examples: https://github.com/BerriAI/litellm/tree/main/litellm/proxy/example_config_yaml # Reference: https://docs.litellm.ai/docs/proxy/configs @@ -232,4 +240,11 @@ extraEnvVars: { # value: EXTRA_ENV_VAR_VALUE } - +# Pod Disruption Budget +pdb: + enabled: false + # Set exactly one of the following. If both are set, minAvailable takes precedence. + minAvailable: null # e.g. "50%" or 1 + maxUnavailable: null # e.g. 1 or "20%" + annotations: {} + labels: {} diff --git a/dist/litellm-1.57.6.tar.gz b/dist/litellm-1.57.6.tar.gz deleted file mode 100644 index 01a039cf6ee..00000000000 Binary files a/dist/litellm-1.57.6.tar.gz and /dev/null differ diff --git a/dist/litellm_ad-1.76.0-py3-none-any.whl b/dist/litellm_ad-1.76.0-py3-none-any.whl new file mode 100644 index 00000000000..2b0ae2adcd1 Binary files /dev/null and b/dist/litellm_ad-1.76.0-py3-none-any.whl differ diff --git a/dist/litellm_ad-1.76.0.tar.gz b/dist/litellm_ad-1.76.0.tar.gz new file mode 100644 index 00000000000..19967d5b9f1 Binary files /dev/null and b/dist/litellm_ad-1.76.0.tar.gz differ diff --git a/dist/litellm_ad-1.76.1-py3-none-any.whl b/dist/litellm_ad-1.76.1-py3-none-any.whl new file mode 100644 index 00000000000..ae45000eabe Binary files /dev/null and b/dist/litellm_ad-1.76.1-py3-none-any.whl differ diff --git a/dist/litellm_ad-1.76.1.tar.gz b/dist/litellm_ad-1.76.1.tar.gz new file mode 100644 index 00000000000..8afcb9adcda Binary files /dev/null and b/dist/litellm_ad-1.76.1.tar.gz differ diff --git a/docs/my-website/docs/completion/input.md b/docs/my-website/docs/completion/input.md index 26629a0b8f8..9699d97b352 100644 --- a/docs/my-website/docs/completion/input.md +++ b/docs/my-website/docs/completion/input.md @@ -106,6 +106,7 @@ def completion( parallel_tool_calls: Optional[bool] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, + safety_identifier: Optional[str] = None, deployment_id=None, # soon to be deprecated params by OpenAI functions: Optional[List] = None, @@ -196,6 +197,8 @@ def completion( - `top_logprobs`: *int (optional)* - An integer between 0 and 5 specifying the number of most likely tokens to return at each token position, each with an associated log probability. `logprobs` must be set to true if this parameter is used. +- `safety_identifier`: *string (optional)* - A unique identifier for tracking and managing safety-related requests. This parameter helps with safety monitoring and compliance tracking. + - `headers`: *dict (optional)* - A dictionary of headers to be sent with the request. - `extra_headers`: *dict (optional)* - Alternative to `headers`, used to send extra headers in LLM API request. diff --git a/docs/my-website/docs/completion/web_search.md b/docs/my-website/docs/completion/web_search.md index fe49be852a7..262e3fc4f9c 100644 --- a/docs/my-website/docs/completion/web_search.md +++ b/docs/my-website/docs/completion/web_search.md @@ -8,10 +8,25 @@ Use web search with litellm | Feature | Details | |---------|---------| | Supported Endpoints | - `/chat/completions`
- `/responses` | -| Supported Providers | `openai`, `xai`, `vertex_ai`, `gemini`, `perplexity` | +| Supported Providers | `openai`, `xai`, `vertex_ai`, `anthropic`, `gemini`, `perplexity` | | LiteLLM Cost Tracking | ✅ Supported | | LiteLLM Version | `v1.71.0+` | +## Which Search Engine is Used? + +Each provider uses their own search backend: + +| Provider | Search Engine | Notes | +|----------|---------------|-------| +| **OpenAI** (`gpt-4o-search-preview`) | OpenAI's internal search | Real-time web data | +| **xAI** (`grok-3`) | xAI's search + X/Twitter | Real-time social media data | +| **Google AI/Vertex** (`gemini-2.0-flash`) | **Google Search** | Uses actual Google search results | +| **Anthropic** (`claude-3-5-sonnet`) | Anthropic's web search | Real-time web data | +| **Perplexity** | Perplexity's search engine | AI-powered search and reasoning | + +:::info +**Anthropic Web Search Models**: Claude models that support web search: `claude-3-5-sonnet-latest`, `claude-3-5-sonnet-20241022`, `claude-3-5-haiku-latest`, `claude-3-5-haiku-20241022`, `claude-3-7-sonnet-20250219` +::: ## `/chat/completions` (litellm.completion) @@ -56,6 +71,12 @@ model_list: model: xai/grok-3 api_key: os.environ/XAI_API_KEY + # Anthropic + - model_name: claude-3-5-sonnet-latest + litellm_params: + model: anthropic/claude-3-5-sonnet-latest + api_key: os.environ/ANTHROPIC_API_KEY + # VertexAI - model_name: gemini-2-flash litellm_params: @@ -143,6 +164,31 @@ response = completion( ) ``` +**Anthropic (using web_search_options)** +```python showLineNumbers +from litellm import completion + +# Customize search context size for Anthropic +response = completion( + model="anthropic/claude-3-5-sonnet-latest", + messages=[ + { + "role": "user", + "content": "What was a positive news story from today?", + } + ], + web_search_options={ + "search_context_size": "medium", # Options: "low", "medium" (default), "high" + "user_location": { + "type": "approximate", + "approximate": { + "city": "San Francisco", + }, + } + } +) +``` + **VertexAI/Gemini (using web_search_options)** ```python showLineNumbers from litellm import completion @@ -375,6 +421,9 @@ assert litellm.supports_web_search(model="openai/gpt-4o-search-preview") == True # Check xAI models assert litellm.supports_web_search(model="xai/grok-3") == True +# Check Anthropic models +assert litellm.supports_web_search(model="anthropic/claude-3-5-sonnet-latest") == True + # Check VertexAI models assert litellm.supports_web_search(model="gemini-2.0-flash") == True @@ -405,6 +454,14 @@ model_list: model_info: supports_web_search: True + # Anthropic + - model_name: claude-3-5-sonnet-latest + litellm_params: + model: anthropic/claude-3-5-sonnet-latest + api_key: os.environ/ANTHROPIC_API_KEY + model_info: + supports_web_search: True + # VertexAI - model_name: gemini-2-flash litellm_params: diff --git a/docs/my-website/docs/contributing.md b/docs/my-website/docs/contributing.md index 8fc64b8f287..8768e0b4c4d 100644 --- a/docs/my-website/docs/contributing.md +++ b/docs/my-website/docs/contributing.md @@ -14,6 +14,11 @@ git clone https://github.com/BerriAI/litellm.git Tell the proxy where the UI is located ```bash export PROXY_BASE_URL="http://localhost:3000/" + +### ALSO ### - set the basic env variables +DATABASE_URL = "postgresql://:@:/" +LITELLM_MASTER_KEY = "sk-1234" +STORE_MODEL_IN_DB = "True" ``` ```bash diff --git a/docs/my-website/docs/exception_mapping.md b/docs/my-website/docs/exception_mapping.md index 13eda5b405a..2342f444e17 100644 --- a/docs/my-website/docs/exception_mapping.md +++ b/docs/my-website/docs/exception_mapping.md @@ -12,6 +12,7 @@ All exceptions can be imported from `litellm` - e.g. `from litellm import BadReq | 400 | UnsupportedParamsError | litellm.BadRequestError | Raised when unsupported params are passed | | 400 | ContextWindowExceededError| litellm.BadRequestError | Special error type for context window exceeded error messages - enables context window fallbacks | | 400 | ContentPolicyViolationError| litellm.BadRequestError | Special error type for content policy violation error messages - enables content policy fallbacks | +| 400 | ImageFetchError | litellm.BadRequestError | Raised when there are errors fetching or processing images | | 400 | InvalidRequestError | openai.BadRequestError | Deprecated error, use BadRequestError instead | | 401 | AuthenticationError | openai.AuthenticationError | | 403 | PermissionDeniedError | openai.PermissionDeniedError | diff --git a/docs/my-website/docs/extras/gemini_img_migration.md b/docs/my-website/docs/extras/gemini_img_migration.md index ae02c89e6fd..a29f301e382 100644 --- a/docs/my-website/docs/extras/gemini_img_migration.md +++ b/docs/my-website/docs/extras/gemini_img_migration.md @@ -4,11 +4,15 @@ Anyone using the following models with /chat/completions: - `gemini/gemini-2.0-flash-exp-image-generation` -- `vertex_ai/gemini-2.5-flash-image-preview` +- `vertex_ai/gemini-2.0-flash-exp-image-generation` ## Key Change -Gemini models now support image generation through chat completions. Images are returned in `response.choices[0].message.image` with base64 data URLs. +:::info +From v1.77.0, LiteLLM will return the List of images in `response.choices[0].message.images` instead of a single image in `response.choices[0].message.image`. +::: + +Gemini models now support image generation through chat completions. Images are returned in `response.choices[0].message.images` with base64 data URLs. ## Before and After @@ -37,9 +41,16 @@ response = completion( ) # Image is now available in the response -image_url = response.choices[0].message.image["url"] # "data:image/png;base64,..." +image_url = response.choices[0].message.images[0]["image_url"]["url"] # "data:image/png;base64,..." ``` +### Why the change? + +Because the newer `gemini-2.5-flash-image-preview` model sends both text and image responses in the same response. This interface allows a developer to explicitly access the image or text components of the response. Before a developer would have needed to search through the message content to find the image generated by the model. + +**Why the change from `image` to `images`?** +This is to be consistent with the OpenRouter API, making sure we are using simple, well-known interfaces where possible. + ## Usage ### Using the Python SDK @@ -50,7 +61,7 @@ image_url = response.choices[0].message.image["url"] # "data:image/png;base64,. -- base_64_image_data = response.choices[0].message.content # After -++ image_url = response.choices[0].message.image["url"] +++ image_url = response.choices[0].message.images[0]["image_url"]["url"] ``` #### Basic Image Generation @@ -71,17 +82,21 @@ response = completion( # Access the generated image print(response.choices[0].message.content) # Text response (if any) -print(response.choices[0].message.image) # Image data +print(response.choices[0].message.images[0]) # Image data ``` #### Response Format -The image is returned in the `message.image` field: +The image is returned in the `message.images` field: ```python { - "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", - "detail": "auto" + "image_url": { + "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", + "detail": "auto" + }, + "index": 0, + "type": "image_url" } ``` @@ -93,10 +108,14 @@ The image is returned in the `message.image` field: -- "content": "base64-image-data..." # After -++ "image": { -++ "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", -++ "detail": "auto" -++ } +++ "images": [{ +++ "image_url": { +++ "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", +++ "detail": "auto" +++ }, +++ "index": 0, +++ "type": "image_url" +++ }] ``` #### Configuration Setup @@ -183,7 +202,7 @@ curl -X POST 'http://0.0.0.0:4000/v1/chat/completions' \ "message": { "role": "assistant", "content": "Here's an image of a cat for you!", - "image": { + "images": [{ "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", "detail": "auto" } diff --git a/docs/my-website/docs/image_generation.md b/docs/my-website/docs/image_generation.md index 60a6356f012..7e7ff9922d6 100644 --- a/docs/my-website/docs/image_generation.md +++ b/docs/my-website/docs/image_generation.md @@ -124,8 +124,6 @@ Any non-openai params, will be treated as provider-specific params, and sent in - `size`: *string (optional)* The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. -- `input_fidelity`: *string (optional)* Controls how closely the model follows the input prompt. Supported for `gpt-image-1` model. Higher fidelity may improve prompt adherence but could affect generation speed. - - `timeout`: *integer* - The maximum time, in seconds, to wait for the API to respond. Defaults to 600 seconds (10 minutes). - `user`: *string (optional)* A unique identifier representing your end-user, diff --git a/docs/my-website/docs/index.md b/docs/my-website/docs/index.md index 58cabc81b48..d242842c24e 100644 --- a/docs/my-website/docs/index.md +++ b/docs/my-website/docs/index.md @@ -226,6 +226,23 @@ response = completion( + + +```python +from litellm import completion +import os + +## set ENV variables. Visit https://vercel.com/docs/ai-gateway#using-the-ai-gateway-with-an-api-key for insturctions on obtaining a key +os.environ["VERCEL_AI_GATEWAY_API_KEY"] = "your-vercel-api-key" + +response = completion( + model="vercel_ai_gateway/openai/gpt-4o", + messages=[{ "content": "Hello, how are you?","role": "user"}] +) +``` + + + ### Response Format (OpenAI Format) @@ -446,6 +463,24 @@ response = completion( + + +```python +from litellm import completion +import os + +## set ENV variables. Visit https://vercel.com/docs/ai-gateway#using-the-ai-gateway-with-an-api-key for insturctions on obtaining a key +os.environ["VERCEL_AI_GATEWAY_API_KEY"] = "your-vercel-api-key" + +response = completion( + model="vercel_ai_gateway/openai/gpt-4o", + messages = [{ "content": "Hello, how are you?","role": "user"}], + stream=True, +) +``` + + + ### Streaming Response Format (OpenAI Format) diff --git a/docs/my-website/docs/load_test_rpm.md b/docs/my-website/docs/load_test_rpm.md index 0954ffcdfac..b7621a76468 100644 --- a/docs/my-website/docs/load_test_rpm.md +++ b/docs/my-website/docs/load_test_rpm.md @@ -53,8 +53,8 @@ model_list = [ }, ] -router_1 = Router(model_list=model_list, num_retries=0, enable_pre_call_checks=True, routing_strategy="usage-based-routing-v2", redis_host=os.getenv("REDIS_HOST"), redis_port=os.getenv("REDIS_PORT"), redis_password=os.getenv("REDIS_PASSWORD")) -router_2 = Router(model_list=model_list, num_retries=0, routing_strategy="usage-based-routing-v2", enable_pre_call_checks=True, redis_host=os.getenv("REDIS_HOST"), redis_port=os.getenv("REDIS_PORT"), redis_password=os.getenv("REDIS_PASSWORD")) +router_1 = Router(model_list=model_list, num_retries=0, enable_pre_call_checks=True, routing_strategy="simple-shuffle", redis_host=os.getenv("REDIS_HOST"), redis_port=os.getenv("REDIS_PORT"), redis_password=os.getenv("REDIS_PASSWORD")) +router_2 = Router(model_list=model_list, num_retries=0, routing_strategy="simple-shuffle", enable_pre_call_checks=True, redis_host=os.getenv("REDIS_HOST"), redis_port=os.getenv("REDIS_PORT"), redis_password=os.getenv("REDIS_PASSWORD")) @@ -142,7 +142,7 @@ router_settings: redis_host: os.environ/REDIS_HOST ## 👈 IMPORTANT! Setup the proxy w/ redis redis_password: os.environ/REDIS_PASSWORD redis_port: os.environ/REDIS_PORT - routing_strategy: usage-based-routing-v2 + routing_strategy: simple-shuffle # recommended for best performance ``` ### 2. Start proxy 2 instances diff --git a/docs/my-website/docs/mcp.md b/docs/my-website/docs/mcp.md index 684c2e6ca74..7eaccf3180f 100644 --- a/docs/my-website/docs/mcp.md +++ b/docs/my-website/docs/mcp.md @@ -40,7 +40,28 @@ LiteLLM supports the following MCP transports: style={{width: '80%', display: 'block', margin: '0'}} /> -### Adding a stdio MCP Server +
+
+ +### Add HTTP MCP Server + +This video walks through adding and using an HTTP MCP server on LiteLLM UI and using it in Cursor IDE. + + + +
+
+ +### Add SSE MCP Server + +This video walks through adding and using an SSE MCP server on LiteLLM UI and using it in Cursor IDE. + + + +
+
+ +### Add STDIO MCP Server For stdio MCP servers, select "Standard Input/Output (stdio)" as the transport type and provide the stdio configuration in JSON format: diff --git a/docs/my-website/docs/observability/callbacks.md b/docs/my-website/docs/observability/callbacks.md index 69cb0d053ee..040d83697d3 100644 --- a/docs/my-website/docs/observability/callbacks.md +++ b/docs/my-website/docs/observability/callbacks.md @@ -4,9 +4,14 @@ liteLLM provides `input_callbacks`, `success_callbacks` and `failure_callbacks`, making it easy for you to send data to a particular provider depending on the status of your responses. +:::tip +**New to LiteLLM Callbacks?** Check out our comprehensive [Callback Management Guide](./callback_management.md) to understand when to use different callback hooks like `async_log_success_event` vs `async_post_call_success_hook`. +::: + liteLLM supports: - [Custom Callback Functions](https://docs.litellm.ai/docs/observability/custom_callback) +- [Callback Management Guide](./callback_management.md) - **Comprehensive guide for choosing the right hooks** - [Lunary](https://lunary.ai/docs) - [Langfuse](https://langfuse.com/docs) - [LangSmith](https://www.langchain.com/langsmith) diff --git a/docs/my-website/docs/observability/cloudzero.md b/docs/my-website/docs/observability/cloudzero.md new file mode 100644 index 00000000000..f213ef64e13 --- /dev/null +++ b/docs/my-website/docs/observability/cloudzero.md @@ -0,0 +1,209 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# CloudZero Integration + +LiteLLM provides an integration with CloudZero's AnyCost API, allowing you to export your LLM usage data to CloudZero for cost tracking analysis. + +## Overview + +| Property | Details | +|----------|---------| +| Description | Export LiteLLM usage data to CloudZero AnyCost API for cost tracking and analysis | +| callback name | `cloudzero`| +| Supported Operations | • Automatic hourly data export
• Manual data export
• Dry run testing
• Cost and token usage tracking | +| Data Format | CloudZero Billing Format (CBF) with proper resource tagging | +| Export Frequency | Hourly (configurable via `CLOUDZERO_EXPORT_INTERVAL_MINUTES`) | + +## Environment Variables + +| Variable | Required | Description | Example | +|----------|----------|-------------|---------| +| `CLOUDZERO_API_KEY` | Yes | Your CloudZero API key | `cz_api_xxxxxxxxxx` | +| `CLOUDZERO_CONNECTION_ID` | Yes | CloudZero connection ID for data submission | `conn_xxxxxxxxxx` | +| `CLOUDZERO_TIMEZONE` | No | Timezone for date handling (default: UTC) | `America/New_York` | +| `CLOUDZERO_EXPORT_INTERVAL_MINUTES` | No | Export frequency in minutes (default: 60) | `60` | + +## Setup + +### End to End Video Walkthrough +This video walks through the entire process of setting up LiteLLM with CloudZero integration and viewing LiteLLM exported usage data in CloudZero. + + + +### Step 1: Configure Environment Variables + +Set your CloudZero credentials in your environment: + +```bash +export CLOUDZERO_API_KEY="cz_api_xxxxxxxxxx" +export CLOUDZERO_CONNECTION_ID="conn_xxxxxxxxxx" +export CLOUDZERO_TIMEZONE="UTC" # Optional, defaults to UTC +``` + +### Step 2: Enable CloudZero Integration + +Add the CloudZero callback to your LiteLLM configuration YAML file: + + +```yaml +model_list: + - model_name: gpt-4o + litellm_params: + model: openai/gpt-4o + api_key: sk-xxxxxxx + +litellm_settings: + callbacks: ["cloudzero"] # Enable CloudZero integration +``` + +### Step 3: Start LiteLLM Proxy + +Start your LiteLLM proxy with the configuration: + +```bash +litellm --config /path/to/config.yaml +``` + +## Testing Your Setup + +### Dry Run Export + +Call the dry run endpoint to test your CloudZero configuration without sending data to CloudZero. This endpoint will not send any data to CloudZero, but will return the data that would be exported. + +```bash +curl -X POST "http://localhost:4000/cloudzero/dry-run" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-1234" \ + -d '{ + "limit": 10 + }' | jq +``` + +**Expected Response:** +```json +{ + "message": "CloudZero dry run export completed successfully.", + "status": "success", + "dry_run_data": { + "usage_data": [...], + "cbf_data": [...], + "summary": { + "total_cost": 0.05, + "total_tokens": 1250, + "total_records": 10 + } + } +} +``` + +### Manual Export + +Call the export endpoint to send data immediately to CloudZero. We suggest setting a small `limit` to test the export. This will only export the last 10 records to CloudZero. Note: Cloudzero can take up to 15 minutes to process the exported data. + +```bash +curl -X POST "http://localhost:4000/cloudzero/export" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-1234" \ + -d '{ + "limit": 10 + }' | jq +``` + +**Expected Response:** +```json +{ + "message": "CloudZero export completed successfully", + "status": "success" +} +``` + +## Data Export Details + +### Automatic Export Schedule + +- **Frequency**: Every 60 minutes (configurable via `CLOUDZERO_EXPORT_INTERVAL_MINUTES`) +- **Data Processing**: LiteLLM automatically processes and exports usage data hourly +- **CloudZero Processing**: CloudZero typically takes 10-15 minutes to process data from LiteLLM + +### Data Format + +LiteLLM exports data in CloudZero Billing Format (CBF) with the following structure: + +```json +{ + "time/usage_start": "2024-01-15T14:00:00Z", + "cost/cost": 0.002, + "usage/amount": 150, + "usage/units": "tokens", + "resource/id": "czrn:litellm:openai:cross-region:team-123:llm-usage:gpt-4o", + "resource/service": "litellm", + "resource/account": "team-123", + "resource/region": "cross-region", + "resource/usage_family": "llm-usage", + "resource/tag:provider": "openai", + "resource/tag:model": "gpt-4o", + "resource/tag:prompt_tokens": "100", + "resource/tag:completion_tokens": "50" +} +``` + +### Resource Tagging + +LiteLLM automatically creates comprehensive resource tags for cost attribution: + +- **Provider Tags**: `openai`, `anthropic`, `azure`, etc. +- **Model Tags**: Specific model names like `gpt-4o`, `claude-3-sonnet` +- **Team/User Tags**: Team IDs and user IDs for cost allocation +- **Token Breakdown**: Separate tracking of prompt and completion tokens +- **Usage Metrics**: Total tokens consumed per request + +## Advanced Configuration + +### Custom Export Frequency + +Change the export frequency (not recommended to go below 60 minutes): + +```bash +export CLOUDZERO_EXPORT_INTERVAL_MINUTES=120 # Export every 2 hours +``` + +### Custom Time Range Export + +Export data for a specific time range: + +```bash +curl -X POST "http://localhost:4000/cloudzero/export" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-1234" \ + -d '{ + "start_time_utc": "2024-01-15T00:00:00Z", + "end_time_utc": "2024-01-15T23:59:59Z", + "operation": "replace_hourly" + }' | jq +``` + +## Troubleshooting + +### Common Issues + +1. **Missing Credentials Error** + ``` + CloudZero configuration missing. Please set CLOUDZERO_API_KEY and CLOUDZERO_CONNECTION_ID environment variables. + ``` + **Solution**: Ensure both environment variables are set with valid values. + +2. **Connection Issues** + - Verify your CloudZero API key is valid + - Check that the connection ID exists in your CloudZero account + - Ensure your proxy has internet access to reach CloudZero's API + +3. **No Data in CloudZero** + - CloudZero can take 10-15 minutes to process data + - Check that your LiteLLM proxy is generating usage data + - Use the dry-run endpoint to verify data is being formatted correctly + +## Related Links + +- [CloudZero Documentation](https://docs.cloudzero.com/) +- [CloudZero AnyCost API](https://docs.cloudzero.com/reference/anycost-api) diff --git a/docs/my-website/docs/observability/custom_callback.md b/docs/my-website/docs/observability/custom_callback.md index cc586b2e5d9..c206c23d0f4 100644 --- a/docs/my-website/docs/observability/custom_callback.md +++ b/docs/my-website/docs/observability/custom_callback.md @@ -4,7 +4,6 @@ **For PROXY** [Go Here](../proxy/logging.md#custom-callback-class-async) ::: - ## Callback Class You can create a custom callback class to precisely log events as they occur in litellm. @@ -57,6 +56,17 @@ def async completion(): asyncio.run(completion()) ``` +## Common Hooks + +- `async_log_success_event` - Log successful API calls +- `async_log_failure_event` - Log failed API calls +- `log_pre_api_call` - Log before API call +- `log_post_api_call` - Log after API call + +**Proxy-only hooks** (only work with LiteLLM Proxy): +- `async_post_call_success_hook` - Access user data + modify responses +- `async_pre_call_hook` - Modify requests before sending + ## Callback Functions If you just want to log on a specific event (e.g. on input) - you can use callback functions. @@ -174,260 +184,87 @@ async def test_chat_openai(): asyncio.run(test_chat_openai()) ``` -:::info +## What's Available in kwargs? -We're actively trying to expand this to other event types. [Tell us if you need this!](https://github.com/BerriAI/litellm/issues/1007) -::: - -## What's in kwargs? - -Notice we pass in a kwargs argument to custom callback. -```python -def custom_callback( - kwargs, # kwargs to completion - completion_response, # response from completion - start_time, end_time # start/end time -): - # Your custom code here - print("LITELLM: in custom callback function") - print("kwargs", kwargs) - print("completion_response", completion_response) - print("start_time", start_time) - print("end_time", end_time) -``` - -This is a dictionary containing all the model-call details (the params we receive, the values we send to the http endpoint, the response we receive, stacktrace in case of errors, etc.). - -This is all logged in the [model_call_details via our Logger](https://github.com/BerriAI/litellm/blob/fc757dc1b47d2eb9d0ea47d6ad224955b705059d/litellm/utils.py#L246). - -Here's exactly what you can expect in the kwargs dictionary: -```shell -### DEFAULT PARAMS ### -"model": self.model, -"messages": self.messages, -"optional_params": self.optional_params, # model-specific params passed in -"litellm_params": self.litellm_params, # litellm-specific params passed in (e.g. metadata passed to completion call) -"start_time": self.start_time, # datetime object of when call was started - -### PRE-API CALL PARAMS ### (check via kwargs["log_event_type"]="pre_api_call") -"input" = input # the exact prompt sent to the LLM API -"api_key" = api_key # the api key used for that LLM API -"additional_args" = additional_args # any additional details for that API call (e.g. contains optional params sent) - -### POST-API CALL PARAMS ### (check via kwargs["log_event_type"]="post_api_call") -"original_response" = original_response # the original http response received (saved via response.text) - -### ON-SUCCESS PARAMS ### (check via kwargs["log_event_type"]="successful_api_call") -"complete_streaming_response" = complete_streaming_response # the complete streamed response (only set if `completion(..stream=True)`) -"end_time" = end_time # datetime object of when call was completed - -### ON-FAILURE PARAMS ### (check via kwargs["log_event_type"]="failed_api_call") -"exception" = exception # the Exception raised -"traceback_exception" = traceback_exception # the traceback generated via `traceback.format_exc()` -"end_time" = end_time # datetime object of when call was completed -``` - - -### Cache hits - -Cache hits are logged in success events as `kwarg["cache_hit"]`. - -Here's an example of accessing it: - - ```python - import litellm -from litellm.integrations.custom_logger import CustomLogger -from litellm import completion, acompletion, Cache - -class MyCustomHandler(CustomLogger): - async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): - print(f"On Success") - print(f"Value of Cache hit: {kwargs['cache_hit']"}) - -async def test_async_completion_azure_caching(): - customHandler_caching = MyCustomHandler() - litellm.cache = Cache(type="redis", host=os.environ['REDIS_HOST'], port=os.environ['REDIS_PORT'], password=os.environ['REDIS_PASSWORD']) - litellm.callbacks = [customHandler_caching] - unique_time = time.time() - response1 = await litellm.acompletion(model="azure/chatgpt-v-2", - messages=[{ - "role": "user", - "content": f"Hi 👋 - i'm async azure {unique_time}" - }], - caching=True) - await asyncio.sleep(1) - print(f"customHandler_caching.states pre-cache hit: {customHandler_caching.states}") - response2 = await litellm.acompletion(model="azure/chatgpt-v-2", - messages=[{ - "role": "user", - "content": f"Hi 👋 - i'm async azure {unique_time}" - }], - caching=True) - await asyncio.sleep(1) # success callbacks are done in parallel - print(f"customHandler_caching.states post-cache hit: {customHandler_caching.states}") - assert len(customHandler_caching.errors) == 0 - assert len(customHandler_caching.states) == 4 # pre, post, success, success - ``` - -### Get complete streaming response - -LiteLLM will pass you the complete streaming response in the final streaming chunk as part of the kwargs for your custom callback function. +The kwargs dictionary contains all the details about your API call: ```python -# litellm.set_verbose = False - def custom_callback( - kwargs, # kwargs to completion - completion_response, # response from completion - start_time, end_time # start/end time - ): - # print(f"streaming response: {completion_response}") - if "complete_streaming_response" in kwargs: - print(f"Complete Streaming Response: {kwargs['complete_streaming_response']}") - - # Assign the custom callback function - litellm.success_callback = [custom_callback] - - response = completion(model="claude-instant-1", messages=messages, stream=True) - for idx, chunk in enumerate(response): - pass -``` - - -### Log additional metadata - -LiteLLM accepts a metadata dictionary in the completion call. You can pass additional metadata into your completion call via `completion(..., metadata={"key": "value"})`. - -Since this is a [litellm-specific param](https://github.com/BerriAI/litellm/blob/b6a015404eed8a0fa701e98f4581604629300ee3/litellm/main.py#L235), it's accessible via kwargs["litellm_params"] - -```python -from litellm import completion -import os, litellm - -## set ENV variables -os.environ["OPENAI_API_KEY"] = "your-api-key" - -messages = [{ "content": "Hello, how are you?","role": "user"}] - -def custom_callback( - kwargs, # kwargs to completion - completion_response, # response from completion - start_time, end_time # start/end time -): - print(kwargs["litellm_params"]["metadata"]) +def custom_callback(kwargs, completion_response, start_time, end_time): + # Access common data + model = kwargs.get("model") + messages = kwargs.get("messages", []) + cost = kwargs.get("response_cost", 0) + cache_hit = kwargs.get("cache_hit", False) - -# Assign the custom callback function -litellm.success_callback = [custom_callback] - -response = litellm.completion(model="gpt-3.5-turbo", messages=messages, metadata={"hello": "world"}) + # Access metadata you passed in + metadata = kwargs.get("litellm_params", {}).get("metadata", {}) ``` -## Examples +**Key fields in kwargs:** +- `model` - The model name +- `messages` - Input messages +- `response_cost` - Calculated cost +- `cache_hit` - Whether response was cached +- `litellm_params.metadata` - Your custom metadata -### Custom Callback to track costs for Streaming + Non-Streaming -By default, the response cost is accessible in the logging object via `kwargs["response_cost"]` on success (sync + async) +## Practical Examples + +### Track API Costs ```python +def track_cost_callback(kwargs, completion_response, start_time, end_time): + cost = kwargs["response_cost"] # litellm calculates this for you + print(f"Request cost: ${cost}") -# Step 1. Write your custom callback function -def track_cost_callback( - kwargs, # kwargs to completion - completion_response, # response from completion - start_time, end_time # start/end time -): - try: - response_cost = kwargs["response_cost"] # litellm calculates response cost for you - print("regular response_cost", response_cost) - except: - pass - -# Step 2. Assign the custom callback function litellm.success_callback = [track_cost_callback] -# Step 3. Make litellm.completion call -response = completion( - model="gpt-3.5-turbo", - messages=[ - { - "role": "user", - "content": "Hi 👋 - i'm openai" - } - ] -) - -print(response) +response = completion(model="gpt-3.5-turbo", messages=[{"role": "user", "content": "Hello"}]) ``` -### Custom Callback to log transformed Input to LLMs +### Log Inputs to LLMs ```python -def get_transformed_inputs( - kwargs, -): +def get_transformed_inputs(kwargs): params_to_model = kwargs["additional_args"]["complete_input_dict"] print("params to model", params_to_model) litellm.input_callback = [get_transformed_inputs] -def test_chat_openai(): - try: - response = completion(model="claude-2", - messages=[{ - "role": "user", - "content": "Hi 👋 - i'm openai" - }]) - - print(response) - - except Exception as e: - print(e) - pass +response = completion(model="claude-2", messages=[{"role": "user", "content": "Hello"}]) ``` -#### Output -```shell -params to model {'model': 'claude-2', 'prompt': "\n\nHuman: Hi 👋 - i'm openai\n\nAssistant: ", 'max_tokens_to_sample': 256} +### Send to External Service +```python +import requests + +def send_to_analytics(kwargs, completion_response, start_time, end_time): + data = { + "model": kwargs.get("model"), + "cost": kwargs.get("response_cost", 0), + "duration": (end_time - start_time).total_seconds() + } + requests.post("https://your-analytics.com/api", json=data) + +litellm.success_callback = [send_to_analytics] ``` -### Custom Callback to write to Mixpanel +## Common Issues + +### Callback Not Called +Make sure you: +1. Register callbacks correctly: `litellm.callbacks = [MyHandler()]` +2. Use the right hook names (check spelling) +3. Don't use proxy-only hooks in library mode + +### Performance Issues +- Use async hooks for I/O operations +- Don't block in callback functions +- Handle exceptions properly: ```python -import mixpanel -import litellm -from litellm import completion - -def custom_callback( - kwargs, # kwargs to completion - completion_response, # response from completion - start_time, end_time # start/end time -): - # Your custom code here - mixpanel.track("LLM Response", {"llm_response": completion_response}) - - -# Assign the custom callback function -litellm.success_callback = [custom_callback] - -response = completion( - model="gpt-3.5-turbo", - messages=[ - { - "role": "user", - "content": "Hi 👋 - i'm openai" - } - ] -) - -print(response) - +class SafeHandler(CustomLogger): + async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): + try: + await external_service(response_obj) + except Exception as e: + print(f"Callback error: {e}") # Log but don't break the flow ``` - - - - - - - - - - - diff --git a/docs/my-website/docs/pass_through/google_ai_studio.md b/docs/my-website/docs/pass_through/google_ai_studio.md index c3671f58d36..3de7c54aa7a 100644 --- a/docs/my-website/docs/pass_through/google_ai_studio.md +++ b/docs/my-website/docs/pass_through/google_ai_studio.md @@ -230,6 +230,13 @@ curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5 ``` +## **Example 4: Video Generation with Veo** + +Generate videos using Google's Veo model through LiteLLM pass-through routes. + +[**→ Complete Veo Video Generation Guide**](../proxy/veo_video_generation.md) + + ## Advanced Pre-requisites diff --git a/docs/my-website/docs/pass_through/intro.md b/docs/my-website/docs/pass_through/intro.md index 3d6286afcc5..38218224f11 100644 --- a/docs/my-website/docs/pass_through/intro.md +++ b/docs/my-website/docs/pass_through/intro.md @@ -11,3 +11,43 @@ These endpoints are useful for 2 scenarios: ## How is your request handled? The request is passed through to the provider's endpoint. The response is then passed back to the client. **No translation is done.** + +### Request Forwarding Process + +1. **Request Reception**: LiteLLM receives your request at `/provider/endpoint` +2. **Authentication**: Your LiteLLM API key is validated and mapped to the provider's API key +3. **Request Transformation**: Request is reformatted for the target provider's API +4. **Forwarding**: Request is sent to the actual provider endpoint +5. **Response Handling**: Provider response is returned directly to you + +### Authentication Flow + +```mermaid +graph LR + A[Client Request] --> B[LiteLLM Proxy] + B --> C[Validate LiteLLM API Key] + C --> D[Map to Provider API Key] + D --> E[Forward to Provider] + E --> F[Return Response] +``` + +**Key Points:** +- Use your **LiteLLM API key** in requests, not the provider's key +- LiteLLM handles the provider authentication internally +- Same authentication works across all passthrough endpoints + +### Error Handling + +**Provider Errors**: Forwarded directly to you with original error codes and messages + +**LiteLLM Errors**: +- `401`: Invalid LiteLLM API key +- `404`: Provider or endpoint not supported +- `500`: Internal routing/forwarding errors + +### Benefits + +- **Unified Authentication**: One API key for all providers +- **Centralized Logging**: All requests logged through LiteLLM +- **Cost Tracking**: Usage tracked across all endpoints +- **Access Control**: Same permissions apply to passthrough endpoints diff --git a/docs/my-website/docs/providers/anthropic.md b/docs/my-website/docs/providers/anthropic.md index a7a9dc30013..820c2906bf0 100644 --- a/docs/my-website/docs/providers/anthropic.md +++ b/docs/my-website/docs/providers/anthropic.md @@ -55,8 +55,29 @@ import os os.environ["ANTHROPIC_API_KEY"] = "your-api-key" # os.environ["ANTHROPIC_API_BASE"] = "" # [OPTIONAL] or 'ANTHROPIC_BASE_URL' +# os.environ["LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX"] = "true" # [OPTIONAL] Disable automatic URL suffix appending ``` +### Custom API Base + +When using a custom API base for Anthropic (e.g., a proxy or custom endpoint), LiteLLM automatically appends the appropriate suffix (`/v1/messages` or `/v1/complete`) to your base URL. + +If your custom endpoint already includes the full path or doesn't follow Anthropic's standard URL structure, you can disable this automatic suffix appending: + +```python +import os + +os.environ["ANTHROPIC_API_BASE"] = "https://my-custom-endpoint.com/custom/path" +os.environ["LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX"] = "true" # Prevents automatic suffix +``` + +Without `LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX`: +- Base URL `https://my-proxy.com` → `https://my-proxy.com/v1/messages` +- Base URL `https://my-proxy.com/api` → `https://my-proxy.com/api/v1/messages` + +With `LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX=true`: +- Base URL `https://my-proxy.com/custom/path` → `https://my-proxy.com/custom/path` (unchanged) + ## Usage ```python diff --git a/docs/my-website/docs/providers/bedrock.md b/docs/my-website/docs/providers/bedrock.md index 1356ec1744e..c191b742268 100644 --- a/docs/my-website/docs/providers/bedrock.md +++ b/docs/my-website/docs/providers/bedrock.md @@ -467,7 +467,7 @@ print(f"\nResponse: {resp}") ## Usage - 'thinking' / 'reasoning content' -This is currently only supported for Anthropic's Claude 3.7 Sonnet + Deepseek R1. +This is currently only supported for Anthropic's Claude 3.7 Sonnet + Deepseek R1 + GPT-OSS models. Works on v1.61.20+. diff --git a/docs/my-website/docs/providers/databricks.md b/docs/my-website/docs/providers/databricks.md index 8631cbfdad9..921b06a17b7 100644 --- a/docs/my-website/docs/providers/databricks.md +++ b/docs/my-website/docs/providers/databricks.md @@ -282,6 +282,11 @@ ModelResponse( ) ``` +### Citations + +Anthropic models served through Databricks can return citation metadata. LiteLLM +exposes these via `response.choices[0].message.provider_specific_fields["citations"]`. + ### Pass `thinking` to Anthropic models You can also pass the `thinking` parameter to Anthropic models. diff --git a/docs/my-website/docs/providers/datarobot.md b/docs/my-website/docs/providers/datarobot.md new file mode 100644 index 00000000000..3f4a0f71ac4 --- /dev/null +++ b/docs/my-website/docs/providers/datarobot.md @@ -0,0 +1,43 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# DataRobot +LiteLLM supports all models from [DataRobot](https://datarobot.com). Select `datarobot` as the provider to route your request through the `datarobot` OpenAI-compatible endpoint using the upstream [official OpenAI Python API library](https://github.com/openai/openai-python/blob/main/README.md). + +## Usage + +### Environment variables +```python +import os +from litellm import completion +os.environ["DATAROBOT_API_KEY"] = "" +os.environ["DATAROBOT_API_BASE"] = "" # [OPTIONAL] defaults to https://app.datarobot.com + +response = completion( + model="datarobot/openai/gpt-4o-mini", + messages=messages, + ) + + +### Completion +```python +import litellm +import os + +response = litellm.completion( + model="datarobot/openai/gpt-4o-mini", # add `datarobot/` prefix to model so litellm knows to route through DataRobot + messages=[ + { + "role": "user", + "content": "Hey, how's it going?", + } + ], +) +print(response) +``` + +## DataRobot completion models + +🚨 LiteLLM supports _all_ DataRobot LLM gateway models. To get a list for your installation and user account, send the following CURL command: +`curl -X GET -H "Authorization: Bearer $DATAROBOT_API_TOKEN" "$DATAROBOT_ENDPOINT/genai/llmgw/catalog/" | jq | grep 'model":'DATAROBOT_ENDPOINT/genai/llmgw/catalog/` + diff --git a/docs/my-website/docs/providers/oci.md b/docs/my-website/docs/providers/oci.md index 28beb71094a..6fc1835154a 100644 --- a/docs/my-website/docs/providers/oci.md +++ b/docs/my-website/docs/providers/oci.md @@ -44,7 +44,11 @@ response = completion( oci_user=, oci_fingerprint=, oci_tenancy=, + # Provide either the private key string OR the path to the key file: + # Option 1: pass the private key as a string oci_key=, + # Option 2: pass the private key file path + # oci_key_file="", oci_compartment_id=, ) print(response) @@ -67,7 +71,11 @@ response = completion( oci_user=, oci_fingerprint=, oci_tenancy=, + # Provide either the private key string OR the path to the key file: + # Option 1: pass the private key as a string oci_key=, + # Option 2: pass the private key file path + # oci_key_file="", oci_compartment_id=, ) for chunk in response: diff --git a/docs/my-website/docs/providers/vercel_ai_gateway.md b/docs/my-website/docs/providers/vercel_ai_gateway.md new file mode 100644 index 00000000000..91f0a18ea1c --- /dev/null +++ b/docs/my-website/docs/providers/vercel_ai_gateway.md @@ -0,0 +1,219 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Vercel AI Gateway + +## Overview + +| Property | Details | +|-------|-------| +| Description | Vercel AI Gateway provides a unified interface to access multiple AI providers through a single endpoint, with built-in caching, rate limiting, and analytics. | +| Provider Route on LiteLLM | `vercel_ai_gateway/` | +| Link to Provider Doc | [Vercel AI Gateway Documentation ↗](https://vercel.com/docs/ai-gateway) | +| Base URL | `https://ai-gateway.vercel.sh/v1` | +| Supported Operations | `/chat/completions`, `/models` | + +
+
+ +https://vercel.com/docs/ai-gateway + +**We support ALL models available through Vercel AI Gateway, just set `vercel_ai_gateway/` as a prefix when sending completion requests** + +## Required Variables + +```python showLineNumbers title="Environment Variables" +os.environ["VERCEL_AI_GATEWAY_API_KEY"] = "" # your Vercel AI Gateway API key +# OR +os.environ["VERCEL_OIDC_TOKEN"] = "" # your Vercel OIDC token for authentication +``` + +## Optional Variables + +```python showLineNumbers title="Environment Variables" +os.environ["VERCEL_SITE_URL"] = "" # your site url +# OR +os.environ["VERCEL_APP_NAME"] = "" # your app name +``` + +Note: see the [Vercel AI Gateway docs](https://vercel.com/docs/ai-gateway#using-the-ai-gateway-with-an-api-key) for instructions on obtaining a key. + +## Usage - LiteLLM Python SDK + +### Non-streaming + +```python showLineNumbers title="Vercel AI Gateway Non-streaming Completion" +import os +import litellm +from litellm import completion + +os.environ["VERCEL_AI_GATEWAY_API_KEY"] = "your-api-key" + +messages = [{"content": "Hello, how are you?", "role": "user"}] + +# Vercel AI Gateway call +response = completion( + model="vercel_ai_gateway/openai/gpt-4o", + messages=messages +) + +print(response) +``` + +### Streaming + +```python showLineNumbers title="Vercel AI Gateway Streaming Completion" +import os +import litellm +from litellm import completion + +os.environ["VERCEL_AI_GATEWAY_API_KEY"] = "your-api-key" + +messages = [{"content": "Hello, how are you?", "role": "user"}] + +# Vercel AI Gateway call with streaming +response = completion( + model="vercel_ai_gateway/openai/gpt-4o", + messages=messages, + stream=True +) + +for chunk in response: + print(chunk) +``` + +## Usage - LiteLLM Proxy + +Add the following to your LiteLLM Proxy configuration file: + +```yaml showLineNumbers title="config.yaml" +model_list: + - model_name: gpt-4o-gateway + litellm_params: + model: vercel_ai_gateway/openai/gpt-4o + api_key: os.environ/VERCEL_AI_GATEWAY_API_KEY + + - model_name: claude-4-sonnet-gateway + litellm_params: + model: vercel_ai_gateway/anthropic/claude-4-sonnet + api_key: os.environ/VERCEL_AI_GATEWAY_API_KEY +``` + +Start your LiteLLM Proxy server: + +```bash showLineNumbers title="Start LiteLLM Proxy" +litellm --config config.yaml + +# RUNNING on http://0.0.0.0:4000 +``` + + + + +```python showLineNumbers title="Vercel AI Gateway via Proxy - Non-streaming" +from openai import OpenAI + +# Initialize client with your proxy URL +client = OpenAI( + base_url="http://localhost:4000", # Your proxy URL + api_key="your-proxy-api-key" # Your proxy API key +) + +# Non-streaming response +response = client.chat.completions.create( + model="gpt-4o-gateway", + messages=[{"role": "user", "content": "Hello, how are you?"}] +) + +print(response.choices[0].message.content) +``` + +```python showLineNumbers title="Vercel AI Gateway via Proxy - Streaming" +from openai import OpenAI + +# Initialize client with your proxy URL +client = OpenAI( + base_url="http://localhost:4000", # Your proxy URL + api_key="your-proxy-api-key" # Your proxy API key +) + +# Streaming response +response = client.chat.completions.create( + model="gpt-4o-gateway", + messages=[{"role": "user", "content": "Hello, how are you?"}], + stream=True +) + +for chunk in response: + if chunk.choices[0].delta.content is not None: + print(chunk.choices[0].delta.content, end="") +``` + + + + + +```python showLineNumbers title="Vercel AI Gateway via Proxy - LiteLLM SDK" +import litellm + +# Configure LiteLLM to use your proxy +response = litellm.completion( + model="litellm_proxy/gpt-4o-gateway", + messages=[{"role": "user", "content": "Hello, how are you?"}], + api_base="http://localhost:4000", + api_key="your-proxy-api-key" +) + +print(response.choices[0].message.content) +``` + +```python showLineNumbers title="Vercel AI Gateway via Proxy - LiteLLM SDK Streaming" +import litellm + +# Configure LiteLLM to use your proxy with streaming +response = litellm.completion( + model="litellm_proxy/gpt-4o-gateway", + messages=[{"role": "user", "content": "Hello, how are you?"}], + api_base="http://localhost:4000", + api_key="your-proxy-api-key", + stream=True +) + +for chunk in response: + if hasattr(chunk.choices[0], 'delta') and chunk.choices[0].delta.content is not None: + print(chunk.choices[0].delta.content, end="") +``` + + + + + +```bash showLineNumbers title="Vercel AI Gateway via Proxy - cURL" +curl http://localhost:4000/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer your-proxy-api-key" \ + -d '{ + "model": "gpt-4o-gateway", + "messages": [{"role": "user", "content": "Hello, how are you?"}] + }' +``` + +```bash showLineNumbers title="Vercel AI Gateway via Proxy - cURL Streaming" +curl http://localhost:4000/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer your-proxy-api-key" \ + -d '{ + "model": "gpt-4o-gateway", + "messages": [{"role": "user", "content": "Hello, how are you?"}], + "stream": true + }' +``` + + + + +For more detailed information on using the LiteLLM Proxy, see the [LiteLLM Proxy documentation](../providers/litellm_proxy). + +## Additional Resources + +- [Vercel AI Gateway Documentation](https://vercel.com/docs/ai-gateway) diff --git a/docs/my-website/docs/providers/vertex_partner.md b/docs/my-website/docs/providers/vertex_partner.md index cf780e35dbd..856f054b8e6 100644 --- a/docs/my-website/docs/providers/vertex_partner.md +++ b/docs/my-website/docs/providers/vertex_partner.md @@ -15,6 +15,7 @@ import TabItem from '@theme/TabItem'; | Mistral | `vertex_ai/mistral-*` | [Vertex AI - Mistral Models](https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/mistral) | | AI21 (Jamba) | `vertex_ai/jamba-*` | [Vertex AI - AI21 Models](https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/ai21) | | Qwen | `vertex_ai/qwen/*` | [Vertex AI - Qwen Models](https://cloud.google.com/vertex-ai/generative-ai/docs/maas/qwen) | +| OpenAI (GPT-OSS) | `vertex_ai/openai/gpt-oss-*` | [Vertex AI - GPT-OSS Models](https://console.cloud.google.com/vertex-ai/publishers/openai/model-garden/) | | Model Garden | `vertex_ai/openai/{MODEL_ID}` or `vertex_ai/{MODEL_ID}` | [Vertex Model Garden](https://cloud.google.com/model-garden?hl=en) | ## Vertex AI - Anthropic (Claude) @@ -658,6 +659,141 @@ curl --location 'http://0.0.0.0:4000/chat/completions' \ +## VertexAI GPT-OSS Models + +| Property | Details | +|----------|---------| +| Provider Route | `vertex_ai/openai/{MODEL}` | +| Vertex Documentation | [Vertex AI - GPT-OSS Models](https://console.cloud.google.com/vertex-ai/publishers/openai/model-garden/) | + +**LiteLLM Supports all Vertex AI GPT-OSS Models.** Ensure you use the `vertex_ai/openai/` prefix for all Vertex AI GPT-OSS models. + +| Model Name | Usage | +|------------------|------------------------------| +| vertex_ai/openai/gpt-oss-20b-maas | `completion('vertex_ai/openai/gpt-oss-20b-maas', messages)` | + +#### Usage + + + + +```python +from litellm import completion +import os + +os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "" + +model = "openai/gpt-oss-20b-maas" + +vertex_ai_project = "your-vertex-project" # can also set this as os.environ["VERTEXAI_PROJECT"] +vertex_ai_location = "your-vertex-location" # can also set this as os.environ["VERTEXAI_LOCATION"] + +response = completion( + model="vertex_ai/" + model, + messages=[{"role": "user", "content": "hi"}], + vertex_ai_project=vertex_ai_project, + vertex_ai_location=vertex_ai_location, +) +print("\nModel Response", response) +``` + + + +**1. Add to config** + +```yaml +model_list: + - model_name: gpt-oss + litellm_params: + model: vertex_ai/openai/gpt-oss-20b-maas + vertex_ai_project: "my-test-project" + vertex_ai_location: "us-central1" +``` + +**2. Start proxy** + +```bash +litellm --config /path/to/config.yaml + +# RUNNING at http://0.0.0.0:4000 +``` + +**3. Test it!** + +```bash +curl --location 'http://0.0.0.0:4000/chat/completions' \ + --header 'Authorization: Bearer sk-1234' \ + --header 'Content-Type: application/json' \ + --data '{ + "model": "gpt-oss", # 👈 the 'model_name' in config + "messages": [ + { + "role": "user", + "content": "what llm are you" + } + ], + }' +``` + + + + +#### Usage - `reasoning_effort` + +GPT-OSS models support the `reasoning_effort` parameter for enhanced reasoning capabilities. + + + + +```python +from litellm import completion + +response = completion( + model="vertex_ai/openai/gpt-oss-20b-maas", + messages=[{"role": "user", "content": "Solve this complex problem step by step"}], + reasoning_effort="low", # Options: "minimal", "low", "medium", "high" + vertex_ai_project="your-vertex-project", + vertex_ai_location="us-central1", +) +``` + + + + + +1. Setup config.yaml + +```yaml +model_list: +- model_name: gpt-oss + litellm_params: + model: vertex_ai/openai/gpt-oss-20b-maas + vertex_ai_project: "my-test-project" + vertex_ai_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": "gpt-oss", + "messages": [{"role": "user", "content": "Solve this complex problem step by step"}], + "reasoning_effort": "low" + }' +``` + + + + ## Model Garden :::tip diff --git a/docs/my-website/docs/providers/volcano.md b/docs/my-website/docs/providers/volcano.md index 1742a43d819..efd1e02b60b 100644 --- a/docs/my-website/docs/providers/volcano.md +++ b/docs/my-website/docs/providers/volcano.md @@ -3,7 +3,7 @@ https://www.volcengine.com/docs/82379/1263482 :::tip -**We support ALL Volcengine NIM models, just set `model=volcengine/` as a prefix when sending litellm requests** +**We support ALL Volcengine models including Chat and Embeddings, just set `model=volcengine/` as a prefix when sending litellm requests** ::: @@ -11,6 +11,8 @@ https://www.volcengine.com/docs/82379/1263482 ```python # env variable os.environ['VOLCENGINE_API_KEY'] +# or +os.environ['ARK_API_KEY'] ``` ## Sample Usage @@ -64,9 +66,42 @@ for chunk in response: print(chunk) ``` +## Sample Usage - Embedding +```python +from litellm import embedding +import os -## Supported Models - 💥 ALL Volcengine NIM Models Supported! -We support ALL `volcengine` models, just set `volcengine/` as a prefix when sending completion requests +os.environ['VOLCENGINE_API_KEY'] = "" +response = embedding( + model="volcengine/doubao-embedding-text-240715", + input=["hello world", "good morning"] +) +print(response) +``` + +### Supported Embedding Models +- `doubao-embedding-large` (2048 dimensions) +- `doubao-embedding-large-text-250515` (2048 dimensions) +- `doubao-embedding-large-text-240915` (4096 dimensions) +- `doubao-embedding` (2560 dimensions) +- `doubao-embedding-text-240715` (2560 dimensions) + +### Embedding Parameters +```python +from litellm import embedding + +response = embedding( + model="volcengine/doubao-embedding-text-240715", + input=["sample text"], + encoding_format="float", # optional: "float" (default), "base64" + user="user-123", # optional: user identifier for tracking +) +``` + +## Supported Models - 💥 ALL Volcengine Models Supported! +We support ALL `volcengine` models for both chat completions and embeddings: +- **Chat Models**: Set `volcengine/` as a prefix when sending completion requests +- **Embedding Models**: Use the specific model names listed above (e.g., `volcengine/doubao-embedding-text-240715`) ## Sample Usage - LiteLLM Proxy @@ -74,14 +109,21 @@ We support ALL `volcengine` models, just set `volcengine/` as a ```yaml model_list: + # Chat model - model_name: volcengine-model litellm_params: model: volcengine/ api_key: os.environ/VOLCENGINE_API_KEY + # Embedding model + - model_name: volcengine-embedding + litellm_params: + model: volcengine/doubao-embedding-text-240715 + api_key: os.environ/VOLCENGINE_API_KEY ``` ### Send Request +#### Chat Completion ```shell curl --location 'http://localhost:4000/chat/completions' \ --header 'Authorization: Bearer sk-1234' \ @@ -95,4 +137,15 @@ curl --location 'http://localhost:4000/chat/completions' \ } ] }' +``` + +#### Embedding +```shell +curl --location 'http://localhost:4000/embeddings' \ + --header 'Authorization: Bearer sk-1234' \ + --header 'Content-Type: application/json' \ + --data '{ + "model": "volcengine-embedding", + "input": ["hello world", "good morning"] +}' ``` \ No newline at end of file diff --git a/docs/my-website/docs/proxy/access_control.md b/docs/my-website/docs/proxy/access_control.md index 69b8a3ff6de..4ca3eb119d6 100644 --- a/docs/my-website/docs/proxy/access_control.md +++ b/docs/my-website/docs/proxy/access_control.md @@ -4,7 +4,7 @@ Role-based access control (RBAC) is based on Organizations, Teams and Internal U - `Organizations` are the top-level entities that contain Teams. - `Team` - A Team is a collection of multiple `Internal Users` -- `Internal Users` - users that can create keys, make LLM API calls, view usage on LiteLLM +- `Internal Users` - users that can create keys, make LLM API calls, view usage on LiteLLM. Users can be on multiple teams. - `Roles` define the permissions of an `Internal User` - `Virtual Keys` - Keys are used for authentication to the LiteLLM API. Keys are tied to a `Internal User` and `Team` diff --git a/docs/my-website/docs/proxy/admin_ui_sso.md b/docs/my-website/docs/proxy/admin_ui_sso.md index 86cb6b0bf8c..823301d4c38 100644 --- a/docs/my-website/docs/proxy/admin_ui_sso.md +++ b/docs/my-website/docs/proxy/admin_ui_sso.md @@ -235,6 +235,13 @@ Example setting a local image (on your container) ```shell UI_LOGO_PATH="ui_images/logo.jpg" ``` + +#### Or set your logo directly from Admin UI: +
+ + +
+ #### Set Custom Color Theme - Navigate to [/enterprise/enterprise_ui](https://github.com/BerriAI/litellm/blob/main/enterprise/enterprise_ui/_enterprise_colors.json) - Inside the `enterprise_ui` directory, rename `_enterprise_colors.json` to `enterprise_colors.json` diff --git a/docs/my-website/docs/proxy/call_hooks.md b/docs/my-website/docs/proxy/call_hooks.md index b4e22027d19..aef33f8c708 100644 --- a/docs/my-website/docs/proxy/call_hooks.md +++ b/docs/my-website/docs/proxy/call_hooks.md @@ -6,6 +6,10 @@ import Image from '@theme/IdealImage'; - Reject data before making llm api calls / before returning the response - Enforce 'user' param for all openai endpoint calls +:::tip +**Understanding Callback Hooks?** Check out our [Callback Management Guide](../observability/callback_management.md) to understand the differences between proxy-specific hooks like `async_pre_call_hook` and general logging hooks like `async_log_success_event`. +::: + See a complete example with our [parallel request rate limiter](https://github.com/BerriAI/litellm/blob/main/litellm/proxy/hooks/parallel_request_limiter.py) ## Quick Start diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 1fb4cd55aa2..36f9bbc40a5 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -236,7 +236,7 @@ Most values can also be set via `litellm_settings`. If you see overlapping value ```yaml router_settings: - routing_strategy: usage-based-routing-v2 # Literal["simple-shuffle", "least-busy", "usage-based-routing","latency-based-routing"], default="simple-shuffle" + routing_strategy: simple-shuffle # Literal["simple-shuffle", "least-busy", "usage-based-routing","latency-based-routing"], default="simple-shuffle" - RECOMMENDED for best performance redis_host: # string redis_password: # string redis_port: # string @@ -335,12 +335,15 @@ router_settings: | ANTHROPIC_API_KEY | API key for Anthropic service | ANTHROPIC_API_BASE | Base URL for Anthropic API. Default is https://api.anthropic.com | AWS_ACCESS_KEY_ID | Access Key ID for AWS services +| AWS_BATCH_ROLE_ARN | ARN of the AWS IAM role for batch operations | AWS_DEFAULT_REGION | Default AWS region for service interactions when AWS_REGION is not set | AWS_PROFILE_NAME | AWS CLI profile name to be used | AWS_REGION | AWS region for service interactions (takes precedence over AWS_DEFAULT_REGION) | AWS_REGION_NAME | Default AWS region for service interactions | AWS_ROLE_ARN | ARN of the AWS IAM role to assume for authentication | AWS_ROLE_NAME | Role name for AWS IAM usage +| AWS_S3_BUCKET_NAME | Name of the AWS S3 bucket for file operations +| AWS_S3_OUTPUT_BUCKET_NAME | Name of the AWS S3 output bucket for batch operations | AWS_SECRET_ACCESS_KEY | Secret Access Key for AWS services | AWS_SESSION_NAME | Name for AWS session | AWS_WEB_IDENTITY_TOKEN | Web identity token for AWS @@ -380,6 +383,8 @@ router_settings: | CIRCLE_OIDC_TOKEN_V2 | Version 2 of the OpenID Connect token for CircleCI | CLOUDZERO_API_KEY | CloudZero API key for authentication | CLOUDZERO_CONNECTION_ID | CloudZero connection ID for data submission +| CLOUDZERO_EXPORT_INTERVAL_MINUTES | Interval in minutes for CloudZero data export operations +| CLOUDZERO_MAX_FETCHED_DATA_RECORDS | Maximum number of data records to fetch from CloudZero | CLOUDZERO_TIMEZONE | Timezone for date handling (default: UTC) | CONFIG_FILE_PATH | File path for configuration file | CONFIDENT_API_KEY | API key for DeepEval integration @@ -412,6 +417,7 @@ router_settings: | DEFAULT_ALLOWED_FAILS | Maximum failures allowed before cooling down a model. Default is 3 | DEFAULT_ANTHROPIC_CHAT_MAX_TOKENS | Default maximum tokens for Anthropic chat completions. Default is 4096 | DEFAULT_BATCH_SIZE | Default batch size for operations. Default is 512 +| DEFAULT_CLIENT_DISCONNECT_CHECK_TIMEOUT_SECONDS | Timeout in seconds for checking client disconnection. Default is 1 | DEFAULT_COOLDOWN_TIME_SECONDS | Duration in seconds to cooldown a model after failures. Default is 5 | DEFAULT_CRON_JOB_LOCK_TTL_SECONDS | Time-to-live for cron job locks in seconds. Default is 60 (1 minute) | DEFAULT_FAILURE_THRESHOLD_PERCENT | Threshold percentage of failures to cool down a deployment. Default is 0.5 (50%) @@ -431,12 +437,17 @@ router_settings: | DEFAULT_MOCK_RESPONSE_COMPLETION_TOKEN_COUNT | Default token count for mock response completions. Default is 20 | DEFAULT_MOCK_RESPONSE_PROMPT_TOKEN_COUNT | Default token count for mock response prompts. Default is 10 | DEFAULT_MODEL_CREATED_AT_TIME | Default creation timestamp for models. Default is 1677610602 +| DEFAULT_NUM_WORKERS_LITELLM_PROXY | Default number of workers for LiteLLM proxy. Default is 4. **We strongly recommend setting NUM Workers to Number of vCPUs available** | DEFAULT_PROMPT_INJECTION_SIMILARITY_THRESHOLD | Default threshold for prompt injection similarity. Default is 0.7 | DEFAULT_POLLING_INTERVAL | Default polling interval for schedulers in seconds. Default is 0.03 | DEFAULT_REASONING_EFFORT_DISABLE_THINKING_BUDGET | Default reasoning effort disable thinking budget. Default is 0 | DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET | Default high reasoning effort thinking budget. Default is 4096 | DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET | Default low reasoning effort thinking budget. Default is 1024 | DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET | Default medium reasoning effort thinking budget. Default is 2048 +| DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET | Default minimal reasoning effort thinking budget. Default is 512 +| DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH | Default minimal reasoning effort thinking budget for Gemini 2.5 Flash. Default is 512 +| DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH_LITE | Default minimal reasoning effort thinking budget for Gemini 2.5 Flash Lite. Default is 512 +| DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_PRO | Default minimal reasoning effort thinking budget for Gemini 2.5 Pro. Default is 512 | DEFAULT_REDIS_SYNC_INTERVAL | Default Redis synchronization interval in seconds. Default is 1 | DEFAULT_REPLICATE_GPU_PRICE_PER_SECOND | Default price per second for Replicate GPU. Default is 0.001400 | DEFAULT_REPLICATE_POLLING_DELAY_SECONDS | Default delay in seconds for Replicate polling. Default is 1 @@ -558,6 +569,7 @@ router_settings: | LITERAL_API_KEY | API key for Literal integration | LITERAL_API_URL | API URL for Literal service | LITERAL_BATCH_SIZE | Batch size for Literal operations +| LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX | Disable automatic URL suffix appending for Anthropic API base URLs. When set to `true`, prevents LiteLLM from automatically adding `/v1/messages` or `/v1/complete` to custom Anthropic API endpoints | 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 @@ -571,6 +583,10 @@ router_settings: | LITELLM_LOCAL_MODEL_COST_MAP | Local configuration for model cost mapping in LiteLLM | LITELLM_LOG | Enable detailed logging for LiteLLM | LITELLM_LOG_FILE | File path to write LiteLLM logs to. When set, logs will be written to both console and the specified file +| LITELLM_LOGGER_NAME | Name for OTEL logger +| LITELLM_METER_NAME | Name for OTEL Meter +| LITELLM_OTEL_INTEGRATION_ENABLE_EVENTS | Optionally enable semantic logs for OTEL +| LITELLM_OTEL_INTEGRATION_ENABLE_METRICS | Optionally enable emantic metrics for OTEL | LITELLM_MASTER_KEY | Master key for proxy authentication | LITELLM_MODE | Operating mode for LiteLLM (e.g., production, development) | LITELLM_RATE_LIMIT_WINDOW_SIZE | Rate limit window size for LiteLLM. Default is 60 @@ -581,6 +597,7 @@ router_settings: | LITELM_ENVIRONMENT | Environment for LiteLLM Instance. This is currently only logged to DeepEval to determine the environment for DeepEval integration. | LOGFIRE_TOKEN | Token for Logfire logging service | MAX_EXCEPTION_MESSAGE_LENGTH | Maximum length for exception messages. Default is 2000 +| MAX_STRING_LENGTH_PROMPT_IN_DB | Maximum length for strings in spend logs when sanitizing request bodies. Strings longer than this will be truncated. Default is 1000 | MAX_IN_MEMORY_QUEUE_FLUSH_COUNT | Maximum count for in-memory queue flush operations. Default is 1000 | MAX_LONG_SIDE_FOR_IMAGE_HIGH_RES | Maximum length for the long side of high-resolution images. Default is 2000 | MAX_REDIS_BUFFER_DEQUEUE_COUNT | Maximum count for Redis buffer dequeue operations. Default is 100 diff --git a/docs/my-website/docs/proxy/cost_tracking.md b/docs/my-website/docs/proxy/cost_tracking.md index 19e3344f21b..35db752cbb6 100644 --- a/docs/my-website/docs/proxy/cost_tracking.md +++ b/docs/my-website/docs/proxy/cost_tracking.md @@ -17,7 +17,6 @@ LiteLLM automatically tracks spend for all known models. See our [model cost map **Step2** Send `/chat/completions` request - ```python @@ -505,11 +504,11 @@ litellm_settings: ### Disable user-agent tracking -You can disable user-agent tracking by setting `litellm_settings.disable_user_agent_tracking` to `true`. +You can disable user-agent tracking by setting `litellm_settings.disable_add_user_agent_to_request_tags` to `true`. ```yaml litellm_settings: - disable_user_agent_tracking: true + disable_add_user_agent_to_request_tags: true ``` ## ✨ (Enterprise) Generate Spend Reports @@ -860,6 +859,303 @@ Log specific key,value pairs as part of the metadata for a spend log :::info -Logging specific key,value pairs in spend logs metadata is an enterprise feature. [See here](./enterprise.md#tracking-spend-with-custom-metadata) +Logging specific key,value pairs in spend logs metadata is an enterprise feature. ::: + +Requirements: + +- Virtual Keys & a database should be set up, see [virtual keys](https://docs.litellm.ai/docs/proxy/virtual_keys) + +#### Usage - /chat/completions requests with special spend logs metadata + + + + + +```bash +curl -L -X POST 'http://0.0.0.0:4000/key/generate' \ +-H 'Authorization: Bearer sk-1234' \ +-H 'Content-Type: application/json' \ +-d '{ + "metadata": { + "spend_logs_metadata": { + "hello": "world" + } + } +} + +' +``` + + + + +```bash +curl -L -X POST 'http://0.0.0.0:4000/team/new' \ +-H 'Authorization: Bearer sk-1234' \ +-H 'Content-Type: application/json' \ +-d '{ + "metadata": { + "spend_logs_metadata": { + "hello": "world" + } + } +} + +' +``` + + + + + +Set `extra_body={"metadata": { }}` to `metadata` you want to pass + +```python +import openai +client = openai.OpenAI( + api_key="anything", + base_url="http://0.0.0.0:4000" +) + +# request sent to model set on litellm proxy, `litellm --model` +response = client.chat.completions.create( + model="gpt-3.5-turbo", + messages = [ + { + "role": "user", + "content": "this is a test request, write a short poem" + } + ], + extra_body={ + "metadata": { + "spend_logs_metadata": { + "hello": "world" + } + } + } +) + +print(response) +``` + +**Using Headers:** + +```python +import openai +client = openai.OpenAI( + api_key="sk-1234", + base_url="http://0.0.0.0:4000" +) + +# Pass spend logs metadata via headers +response = client.chat.completions.create( + model="gpt-3.5-turbo", + messages = [ + { + "role": "user", + "content": "this is a test request, write a short poem" + } + ], + extra_headers={ + "x-litellm-spend-logs-metadata": '{"user_id": "12345", "project_id": "proj_abc", "request_type": "chat_completion"}' + } +) + +print(response) +``` + + + + + + +```js +const openai = require('openai'); + +async function runOpenAI() { + const client = new openai.OpenAI({ + apiKey: 'sk-1234', + baseURL: 'http://0.0.0.0:4000' + }); + + try { + const response = await client.chat.completions.create({ + model: 'gpt-3.5-turbo', + messages: [ + { + role: 'user', + content: "this is a test request, write a short poem" + }, + ], + metadata: { + spend_logs_metadata: { // 👈 Key Change + hello: "world" + } + } + }); + console.log(response); + } catch (error) { + console.log("got this exception from server"); + console.error(error); + } +} + +// Call the asynchronous function +runOpenAI(); +``` + +**Using Headers:** + +```js +const openai = require('openai'); + +async function runOpenAI() { + const client = new openai.OpenAI({ + apiKey: 'sk-1234', + baseURL: 'http://0.0.0.0:4000' + }); + + try { + const response = await client.chat.completions.create({ + model: 'gpt-3.5-turbo', + messages: [ + { + role: 'user', + content: "this is a test request, write a short poem" + }, + ] + }, { + headers: { + 'x-litellm-spend-logs-metadata': '{"user_id": "12345", "project_id": "proj_abc", "request_type": "chat_completion"}' + } + }); + console.log(response); + } catch (error) { + console.log("got this exception from server"); + console.error(error); + } +} + +// Call the asynchronous function +runOpenAI(); +``` + + + + + +Pass `metadata` as part of the request body + +```shell +curl --location 'http://0.0.0.0:4000/chat/completions' \ + --header 'Content-Type: application/json' \ + --data '{ + "model": "gpt-3.5-turbo", + "messages": [ + { + "role": "user", + "content": "what llm are you" + } + ], + "metadata": { + "spend_logs_metadata": { + "hello": "world" + } + } +}' +``` + + + + + +Pass `x-litellm-spend-logs-metadata` as a request header with JSON string + +```shell +curl --location 'http://0.0.0.0:4000/chat/completions' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Bearer sk-1234' \ + --header 'x-litellm-spend-logs-metadata: {"user_id": "12345", "project_id": "proj_abc", "request_type": "chat_completion"}' \ + --data '{ + "model": "gpt-3.5-turbo", + "messages": [ + { + "role": "user", + "content": "what llm are you" + } + ] +}' +``` + + + + +```python +from langchain.chat_models import ChatOpenAI +from langchain.prompts.chat import ( + ChatPromptTemplate, + HumanMessagePromptTemplate, + SystemMessagePromptTemplate, +) +from langchain.schema import HumanMessage, SystemMessage + +chat = ChatOpenAI( + openai_api_base="http://0.0.0.0:4000", + model = "gpt-3.5-turbo", + temperature=0.1, + extra_body={ + "metadata": { + "spend_logs_metadata": { + "hello": "world" + } + } + } +) + +messages = [ + SystemMessage( + content="You are a helpful assistant that im using to make a test request to." + ), + HumanMessage( + content="test from litellm. tell me why it's amazing in 1 sentence" + ), +] +response = chat(messages) + +print(response) +``` + + + + + +#### Viewing Spend w/ custom metadata + +#### `/spend/logs` Request Format + +```bash +curl -X GET "http://0.0.0.0:4000/spend/logs?request_id= .env diff --git a/docs/my-website/docs/proxy/docker_quick_start.md b/docs/my-website/docs/proxy/docker_quick_start.md index 09f7dfbaf78..b21105bb829 100644 --- a/docs/my-website/docs/proxy/docker_quick_start.md +++ b/docs/my-website/docs/proxy/docker_quick_start.md @@ -35,6 +35,30 @@ $ pip install 'litellm[proxy]' + + +Use this docker compose to spin up the proxy with a postgres database running locally. + +```bash +# Get the docker compose file +curl -O https://raw.githubusercontent.com/BerriAI/litellm/main/docker-compose.yml + +# Add the master key - you can change this after setup +echo 'LITELLM_MASTER_KEY="sk-1234"' > .env + +# Add the litellm salt key - you cannot change this after adding a model +# It is used to encrypt / decrypt your LLM API Key credentials +# We recommend - https://1password.com/password-generator/ +# password generator to get a random hash for litellm salt key +echo 'LITELLM_SALT_KEY="sk-1234"' >> .env + +source .env + +# Start +docker-compose up +``` + + ## 1. Add a model @@ -43,6 +67,8 @@ Control LiteLLM Proxy with a config.yaml file. Setup your config.yaml with your azure model. +Note: When using the proxy with a database, you can also **just add models via UI** (UI is available on `/ui` route). + ```yaml model_list: - model_name: gpt-4o diff --git a/docs/my-website/docs/proxy/enterprise.md b/docs/my-website/docs/proxy/enterprise.md index 468bcad2cf8..42677264ff6 100644 --- a/docs/my-website/docs/proxy/enterprise.md +++ b/docs/my-website/docs/proxy/enterprise.md @@ -357,221 +357,13 @@ curl -X GET "http://0.0.0.0:4000/spend/tags" \ "total_spend": 0.000224 } ] - ``` +:::tip +For comprehensive spend tracking features including budgets, alerts, and detailed analytics, check out [Spend Tracking](https://docs.litellm.ai/docs/proxy/cost_tracking). -### Tracking Spend with custom metadata +::: -Requirements: - -- Virtual Keys & a database should be set up, see [virtual keys](https://docs.litellm.ai/docs/proxy/virtual_keys) - -#### Usage - /chat/completions requests with special spend logs metadata - - - - - -```bash -curl -L -X POST 'http://0.0.0.0:4000/key/generate' \ --H 'Authorization: Bearer sk-1234' \ --H 'Content-Type: application/json' \ --d '{ - "metadata": { - "spend_logs_metadata": { - "hello": "world" - } - } -} - -' -``` - - - - -```bash -curl -L -X POST 'http://0.0.0.0:4000/team/new' \ --H 'Authorization: Bearer sk-1234' \ --H 'Content-Type: application/json' \ --d '{ - "metadata": { - "spend_logs_metadata": { - "hello": "world" - } - } -} - -' -``` - - - - - -Set `extra_body={"metadata": { }}` to `metadata` you want to pass - -```python -import openai -client = openai.OpenAI( - api_key="anything", - base_url="http://0.0.0.0:4000" -) - -# request sent to model set on litellm proxy, `litellm --model` -response = client.chat.completions.create( - model="gpt-3.5-turbo", - messages = [ - { - "role": "user", - "content": "this is a test request, write a short poem" - } - ], - extra_body={ - "metadata": { - "spend_logs_metadata": { - "hello": "world" - } - } - } -) - -print(response) -``` - - - - - -```js -const openai = require('openai'); - -async function runOpenAI() { - const client = new openai.OpenAI({ - apiKey: 'sk-1234', - baseURL: 'http://0.0.0.0:4000' - }); - - try { - const response = await client.chat.completions.create({ - model: 'gpt-3.5-turbo', - messages: [ - { - role: 'user', - content: "this is a test request, write a short poem" - }, - ], - metadata: { - spend_logs_metadata: { // 👈 Key Change - hello: "world" - } - } - }); - console.log(response); - } catch (error) { - console.log("got this exception from server"); - console.error(error); - } -} - -// Call the asynchronous function -runOpenAI(); -``` - - - - -Pass `metadata` as part of the request body - -```shell -curl --location 'http://0.0.0.0:4000/chat/completions' \ - --header 'Content-Type: application/json' \ - --data '{ - "model": "gpt-3.5-turbo", - "messages": [ - { - "role": "user", - "content": "what llm are you" - } - ], - "metadata": { - "spend_logs_metadata": { - "hello": "world" - } - } -}' -``` - - - -```python -from langchain.chat_models import ChatOpenAI -from langchain.prompts.chat import ( - ChatPromptTemplate, - HumanMessagePromptTemplate, - SystemMessagePromptTemplate, -) -from langchain.schema import HumanMessage, SystemMessage - -chat = ChatOpenAI( - openai_api_base="http://0.0.0.0:4000", - model = "gpt-3.5-turbo", - temperature=0.1, - extra_body={ - "metadata": { - "spend_logs_metadata": { - "hello": "world" - } - } - } -) - -messages = [ - SystemMessage( - content="You are a helpful assistant that im using to make a test request to." - ), - HumanMessage( - content="test from litellm. tell me why it's amazing in 1 sentence" - ), -] -response = chat(messages) - -print(response) -``` - - - - - -#### Viewing Spend w/ custom metadata - -#### `/spend/logs` Request Format - -```bash -curl -X GET "http://0.0.0.0:4000/spend/logs?request_id= - - -```python -from langchain.chat_models import ChatOpenAI -from langchain.prompts.chat import ( - ChatPromptTemplate, - HumanMessagePromptTemplate, - SystemMessagePromptTemplate, -) -from langchain.schema import HumanMessage, SystemMessage -import os - -os.environ["OPENAI_API_KEY"] = "anything" - -chat = ChatOpenAI( - openai_api_base="http://0.0.0.0:4000", - model="gpt-3.5-turbo", -) - -messages = [ - SystemMessage( - content="You are a helpful assistant that im using to make a test request to." - ), - HumanMessage( - content="test from litellm. tell me why it's amazing in 1 sentence" - ), -] -response = chat(messages) - -print(response) -``` - - - ### Test - Loadbalancing In this request, the following will occur: 1. A rate limit exception will be raised -2. LiteLLM proxy will retry the request on the model group (default is 3). +2. LiteLLM proxy will retry the request on the model group (default retries are 3). ```bash curl -X POST 'http://0.0.0.0:4000/chat/completions' \ @@ -256,4 +238,16 @@ model_group_alias: Optional[Dict[str, Union[str, RouterModelGroupAliasItem]]] = class RouterModelGroupAliasItem(TypedDict): model: str hidden: bool # if 'True', don't return on `/v1/models`, `/v1/model/info`, `/v1/model_group/info` -``` \ No newline at end of file +``` + +### When You'll See Load Balancing in Action + +**Immediate Effects:** + +- Different deployments serve subsequent requests (visible in logs) +- Better response times during high traffic + +**Observable Benefits:** +- **Higher throughput**: More requests handled simultaneously across deployments +- **Improved reliability**: If one deployment fails, traffic automatically routes to healthy ones +- **Better resource utilization**: Load spread evenly across all available deployments diff --git a/docs/my-website/docs/proxy/prod.md b/docs/my-website/docs/proxy/prod.md index fb2acf230c1..a45474f39e8 100644 --- a/docs/my-website/docs/proxy/prod.md +++ b/docs/my-website/docs/proxy/prod.md @@ -90,7 +90,7 @@ Recommended to do this for prod: ```yaml router_settings: - routing_strategy: usage-based-routing-v2 + routing_strategy: simple-shuffle # (default) - recommended for best performance # redis_url: "os.environ/REDIS_URL" redis_host: os.environ/REDIS_HOST redis_port: os.environ/REDIS_PORT @@ -105,6 +105,9 @@ litellm_settings: password: os.environ/REDIS_PASSWORD ``` +> **WARNING** +**Usage-based routing is not recommended for production due to performance impacts.** Use `simple-shuffle` (default) for optimal performance in high-traffic scenarios. + ## 5. Disable 'load_dotenv' Set `export LITELLM_MODE="PRODUCTION"` diff --git a/docs/my-website/docs/proxy/prometheus.md b/docs/my-website/docs/proxy/prometheus.md index dc7030949bd..8bbf737540d 100644 --- a/docs/my-website/docs/proxy/prometheus.md +++ b/docs/my-website/docs/proxy/prometheus.md @@ -63,7 +63,7 @@ Use this for for tracking per [user, key, team, etc.](virtual_keys) | Metric Name | Description | |----------------------|--------------------------------------| -| `litellm_spend_metric` | Total Spend, per `"user", "key", "model", "team", "end-user"` | +| `litellm_spend_metric` | Total Spend, per `"end_user", "hashed_api_key", "api_key_alias", "model", "team", "team_alias", "user"` | | `litellm_total_tokens_metric` | input + output tokens per `"end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "model"` | | `litellm_input_tokens_metric` | input tokens per `"end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "model"` | | `litellm_output_tokens_metric` | output tokens per `"end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "model"` | @@ -73,9 +73,9 @@ Use this for for tracking per [user, key, team, etc.](virtual_keys) | Metric Name | Description | |----------------------|--------------------------------------| -| `litellm_team_max_budget_metric` | Max Budget for Team Labels: `"team_id", "team_alias"`| -| `litellm_remaining_team_budget_metric` | Remaining Budget for Team (A team created on LiteLLM) Labels: `"team_id", "team_alias"`| -| `litellm_team_budget_remaining_hours_metric` | Hours before the team budget is reset Labels: `"team_id", "team_alias"`| +| `litellm_team_max_budget_metric` | Max Budget for Team Labels: `"team", "team_alias"`| +| `litellm_remaining_team_budget_metric` | Remaining Budget for Team (A team created on LiteLLM) Labels: `"team", "team_alias"`| +| `litellm_team_budget_remaining_hours_metric` | Hours before the team budget is reset Labels: `"team", "team_alias"`| ### Virtual Key - Budget @@ -119,8 +119,8 @@ Use this to track overall LiteLLM Proxy usage. | Metric Name | Description | |----------------------|--------------------------------------| -| `litellm_proxy_failed_requests_metric` | Total number of failed responses from proxy - the client did not get a success response from litellm proxy. Labels: `"end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "exception_status", "exception_class"` | -| `litellm_proxy_total_requests_metric` | Total number of requests made to the proxy server - track number of client side requests. Labels: `"end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "status_code"` | +| `litellm_proxy_failed_requests_metric` | Total number of failed responses from proxy - the client did not get a success response from litellm proxy. Labels: `"end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "exception_status", "exception_class", "route"` | +| `litellm_proxy_total_requests_metric` | Total number of requests made to the proxy server - track number of client side requests. Labels: `"end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "status_code", "user_email", "route"` | ## LLM Provider Metrics @@ -155,7 +155,7 @@ Use this for LLM API Error monitoring and tracking remaining rate limits and tok | Metric Name | Description | |----------------------|--------------------------------------| | `litellm_remaining_requests_metric` | Track `x-ratelimit-remaining-requests` returned from LLM API Deployment. Labels: `"model_group", "api_provider", "api_base", "litellm_model_name", "hashed_api_key", "api_key_alias"` | -| `litellm_remaining_tokens` | Track `x-ratelimit-remaining-tokens` return from LLM API Deployment. Labels: `"model_group", "api_provider", "api_base", "litellm_model_name", "hashed_api_key", "api_key_alias"` | +| `litellm_remaining_tokens_metric` | Track `x-ratelimit-remaining-tokens` return from LLM API Deployment. Labels: `"model_group", "api_provider", "api_base", "litellm_model_name", "hashed_api_key", "api_key_alias"` | ### Deployment State | Metric Name | Description | @@ -167,16 +167,22 @@ Use this for LLM API Error monitoring and tracking remaining rate limits and tok | Metric Name | Description | |----------------------|--------------------------------------| -| `litellm_deployment_cooled_down` | Number of times a deployment has been cooled down by LiteLLM load balancing logic. Labels: `"litellm_model_name", "model_id", "api_base", "api_provider", "exception_status"` | +| `litellm_deployment_cooled_down` | Number of times a deployment has been cooled down by LiteLLM load balancing logic. Labels: `"litellm_model_name", "model_id", "api_base", "api_provider"` | | `litellm_deployment_successful_fallbacks` | Number of successful fallback requests from primary model -> fallback model. Labels: `"requested_model", "fallback_model", "hashed_api_key", "api_key_alias", "team", "team_alias", "exception_status", "exception_class"` | | `litellm_deployment_failed_fallbacks` | Number of failed fallback requests from primary model -> fallback model. Labels: `"requested_model", "fallback_model", "hashed_api_key", "api_key_alias", "team", "team_alias", "exception_status", "exception_class"` | +## Request Counting Metrics + +| Metric Name | Description | +|----------------------|--------------------------------------| +| `litellm_requests_metric` | Total number of requests tracked per endpoint. Labels: `"end_user", "hashed_api_key", "api_key_alias", "model", "team", "team_alias", "user", "user_email"` | + ## Request Latency Metrics | Metric Name | Description | |----------------------|--------------------------------------| | `litellm_request_total_latency_metric` | Total latency (seconds) for a request to LiteLLM Proxy Server - tracked for labels "end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "model" | -| `litellm_overhead_latency_metric` | Latency overhead (seconds) added by LiteLLM processing - tracked for labels "end_user", "hashed_api_key", "api_key_alias", "requested_model", "team", "team_alias", "user", "model" | +| `litellm_overhead_latency_metric` | Latency overhead (seconds) added by LiteLLM processing - tracked for labels "model_group", "api_provider", "api_base", "litellm_model_name", "hashed_api_key", "api_key_alias" | | `litellm_llm_api_latency_metric` | Latency (seconds) for just the LLM API call - tracked for labels "model", "hashed_api_key", "api_key_alias", "team", "team_alias", "requested_model", "end_user", "user" | | `litellm_llm_api_time_to_first_token_metric` | Time to first token for LLM API call - tracked for labels `model`, `hashed_api_key`, `api_key_alias`, `team`, `team_alias` [Note: only emitted for streaming requests] | @@ -486,7 +492,6 @@ Here is a screenshot of the metrics you can monitor with the LiteLLM Grafana Das | Metric Name | Description | |----------------------|--------------------------------------| | `litellm_llm_api_failed_requests_metric` | **deprecated** use `litellm_proxy_failed_requests_metric` | -| `litellm_requests_metric` | **deprecated** use `litellm_proxy_total_requests_metric` | diff --git a/docs/my-website/docs/proxy/request_headers.md b/docs/my-website/docs/proxy/request_headers.md index 246d917d00c..eea66e5fa93 100644 --- a/docs/my-website/docs/proxy/request_headers.md +++ b/docs/my-website/docs/proxy/request_headers.md @@ -6,12 +6,16 @@ Special headers that are supported by LiteLLM. `x-litellm-timeout` Optional[float]: The timeout for the request in seconds. +`x-litellm-stream-timeout` Optional[float]: The timeout for getting the first chunk of the response in seconds (only applies for streaming requests). [Demo Video](https://www.loom.com/share/8da67e4845ce431a98c901d4e45db0e5) + `x-litellm-enable-message-redaction`: Optional[bool]: Don't log the message content to logging integrations. Just track spend. [Learn More](./logging#redact-messages-response-content) `x-litellm-tags`: Optional[str]: A comma separated list (e.g. `tag1,tag2,tag3`) of tags to use for [tag-based routing](./tag_routing) **OR** [spend-tracking](./enterprise.md#tracking-spend-for-custom-tags). `x-litellm-num-retries`: Optional[int]: The number of retries for the request. +`x-litellm-spend-logs-metadata`: Optional[str]: JSON string containing custom metadata to include in spend logs. Example: `{"user_id": "12345", "project_id": "proj_abc", "request_type": "chat_completion"}`. [Learn More](../proxy/enterprise#tracking-spend-with-custom-metadata) + ## Anthropic Headers `anthropic-version` Optional[str]: The version of the Anthropic API to use. diff --git a/docs/my-website/docs/proxy/tag_routing.md b/docs/my-website/docs/proxy/tag_routing.md index 23715e77f81..838b2a09d76 100644 --- a/docs/my-website/docs/proxy/tag_routing.md +++ b/docs/my-website/docs/proxy/tag_routing.md @@ -5,6 +5,12 @@ This is useful for - Implementing free / paid tiers for users - Controlling model access per team, example Team A can access gpt-4 deployment A, Team B can access gpt-4 deployment B (LLM Access Control For Teams ) +:::info +## See here for spend tags +- [Track spend per tag](cost_tracking#-custom-tags) +- [Setup Budgets per Virtual Key, Team](users) +::: + ## Quick Start ### 1. Define tags on config.yaml @@ -324,7 +330,4 @@ Here's how to set up and use team-based tag routing using curl commands: By following these steps and using these curl commands, you can implement and test team-based tag routing in your LiteLLM Proxy setup, ensuring that different teams are routed to the appropriate models or deployments based on their assigned tags. -## Other Tag Based Features -- [Track spend per tag](cost_tracking#-custom-tags) -- [Setup Budgets per Virtual Key, Team](users) diff --git a/docs/my-website/docs/proxy/timeout.md b/docs/my-website/docs/proxy/timeout.md index 85428ae53e2..52cb160cf76 100644 --- a/docs/my-website/docs/proxy/timeout.md +++ b/docs/my-website/docs/proxy/timeout.md @@ -38,9 +38,15 @@ $ litellm --config /path/to/config.yaml -### Custom Timeouts, Stream Timeouts - Per Model -For each model you can set `timeout` & `stream_timeout` under `litellm_params` +### Custom Timeouts & Stream Timeouts (Per Model) +For each model, you can set `timeout` and `stream_timeout` under `litellm_params`: + +- **`timeout`** → maximum time for the *complete response*. + Use this to cap long-running completions. + +- **`stream_timeout`** → maximum time to wait for the *first chunk* (i.e., first token) in a streaming response. + Use this to abort “hanging” providers (e.g., Bedrock slow start) and retry another model. diff --git a/docs/my-website/docs/proxy/user_management_heirarchy.md b/docs/my-website/docs/proxy/user_management_heirarchy.md index 3565c9d257d..cb5cc0dd7a2 100644 --- a/docs/my-website/docs/proxy/user_management_heirarchy.md +++ b/docs/my-website/docs/proxy/user_management_heirarchy.md @@ -9,5 +9,5 @@ LiteLLM supports a hierarchy of users, teams, organizations, and budgets. - Organizations can have multiple teams. [API Reference](https://litellm-api.up.railway.app/#/organization%20management) - Teams can have multiple users. [API Reference](https://litellm-api.up.railway.app/#/team%20management) -- Users can have multiple keys. [API Reference](https://litellm-api.up.railway.app/#/budget%20management) +- Users can have multiple keys, and be on multiple teams. [API Reference](https://litellm-api.up.railway.app/#/budget%20management) - Keys can belong to either a team or a user. [API Reference](https://litellm-api.up.railway.app/#/end-user%20management) diff --git a/docs/my-website/docs/proxy/veo_video_generation.md b/docs/my-website/docs/proxy/veo_video_generation.md new file mode 100644 index 00000000000..14c263bf847 --- /dev/null +++ b/docs/my-website/docs/proxy/veo_video_generation.md @@ -0,0 +1,163 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Veo Video Generation with Google AI Studio + +Generate videos using Google's Veo model through LiteLLM's pass-through endpoints. + +## Quick Start + +LiteLLM allows you to use Google AI Studio's Veo video generation API through pass-through routes with zero configuration. + +### 1. Add Google AI Studio API Key to your environment + +```bash +export GEMINI_API_KEY="your_google_ai_studio_api_key" +``` + +### 2. Start LiteLLM Proxy + +```bash +litellm + +# RUNNING on http://0.0.0.0:4000 +``` + +### 3. Generate Video + + + + +```python +import requests +import time +import json + +# Configuration +BASE_URL = "http://localhost:4000/gemini/v1beta" +API_KEY = "anything" # Use "anything" as the key + +headers = { + "x-goog-api-key": API_KEY, + "Content-Type": "application/json" +} + +# Step 1: Initiate video generation +def generate_video(prompt): + url = f"{BASE_URL}/models/veo-3.0-generate-preview:predictLongRunning" + payload = { + "instances": [{ + "prompt": prompt + }] + } + + response = requests.post(url, headers=headers, json=payload) + response.raise_for_status() + + data = response.json() + return data.get("name") # Operation name + +# Step 2: Poll for completion +def wait_for_completion(operation_name): + operation_url = f"{BASE_URL}/{operation_name}" + + while True: + response = requests.get(operation_url, headers=headers) + response.raise_for_status() + + data = response.json() + + if data.get("done", False): + # Extract video URI + video_uri = data["response"]["generateVideoResponse"]["generatedSamples"][0]["video"]["uri"] + return video_uri + + time.sleep(10) # Wait 10 seconds before next poll + +# Step 3: Download video +def download_video(video_uri, filename="generated_video.mp4"): + # Replace Google URL with LiteLLM proxy URL + litellm_url = video_uri.replace( + "https://generativelanguage.googleapis.com/v1beta", + BASE_URL + ) + + response = requests.get(litellm_url, headers=headers, stream=True) + response.raise_for_status() + + with open(filename, 'wb') as f: + for chunk in response.iter_content(chunk_size=8192): + if chunk: + f.write(chunk) + + return filename + +# Complete workflow +prompt = "A cat playing with a ball of yarn in a sunny garden" + +print("Generating video...") +operation_name = generate_video(prompt) + +print("Waiting for completion...") +video_uri = wait_for_completion(operation_name) + +print("Downloading video...") +filename = download_video(video_uri) + +print(f"Video saved as: {filename}") +``` + + + + + +```bash +# Step 1: Initiate video generation +curl -X POST "http://localhost:4000/gemini/v1beta/models/veo-3.0-generate-preview:predictLongRunning" \ + -H "x-goog-api-key: anything" \ + -H "Content-Type: application/json" \ + -d '{ + "instances": [{ + "prompt": "A cat playing with a ball of yarn in a sunny garden" + }] + }' + +# Response will include operation name: +# {"name": "operations/generate_12345"} + +# Step 2: Poll for completion +curl -X GET "http://localhost:4000/gemini/v1beta/operations/generate_12345" \ + -H "x-goog-api-key: anything" + +# Step 3: Download video (when done=true) +curl -X GET "http://localhost:4000/gemini/v1beta/files/VIDEO_ID:download?alt=media" \ + -H "x-goog-api-key: anything" \ + --output generated_video.mp4 +``` + + + + +## Complete Example + +For a full working example with error handling and logging, see our [Veo Video Generation Cookbook](https://github.com/BerriAI/litellm/blob/main/cookbook/veo_video_generation.py). + +## How It Works + +1. **Video Generation Request**: Send a prompt to Veo's `predictLongRunning` endpoint +2. **Operation Polling**: Monitor the long-running operation until completion +3. **File Download**: Download the generated video through LiteLLM's pass-through with automatic redirect handling + +LiteLLM handles: +- ✅ Authentication with Google AI Studio +- ✅ Request routing and proxying +- ✅ Automatic redirect handling for file downloads + +## Configuration Options + +### Environment Variables + +```bash +export GEMINI_API_KEY="your_google_ai_studio_api_key" +``` + diff --git a/docs/my-website/docs/reasoning_content.md b/docs/my-website/docs/reasoning_content.md index f9cab01639d..12db17325d4 100644 --- a/docs/my-website/docs/reasoning_content.md +++ b/docs/my-website/docs/reasoning_content.md @@ -12,7 +12,7 @@ Requires LiteLLM v1.63.0+ Supported Providers: - Deepseek (`deepseek/`) - Anthropic API (`anthropic/`) -- Bedrock (Anthropic + Deepseek) (`bedrock/`) +- Bedrock (Anthropic + Deepseek + GPT-OSS) (`bedrock/`) - Vertex AI (Anthropic) (`vertexai/`) - OpenRouter (`openrouter/`) - XAI (`xai/`) @@ -20,6 +20,7 @@ Supported Providers: - Vertex AI (`vertex_ai/`) - Perplexity (`perplexity/`) - Mistral AI (Magistral models) (`mistral/`) +- Groq (`groq/`) LiteLLM will standardize the `reasoning_content` in the response and `thinking_blocks` in the assistant message. diff --git a/docs/my-website/docs/routing.md b/docs/my-website/docs/routing.md index fbb069895d8..971427806ed 100644 --- a/docs/my-website/docs/routing.md +++ b/docs/my-website/docs/routing.md @@ -154,11 +154,153 @@ curl -X POST 'http://0.0.0.0:4000/chat/completions' \ ## Advanced - Routing Strategies ⭐️ #### Routing Strategies - Weighted Pick, Rate Limit Aware, Least Busy, Latency Based, Cost Based -Router provides 4 strategies for routing your calls across multiple deployments: +Router provides multiple strategies for routing your calls across multiple deployments. **We recommend using `simple-shuffle` (default) for best performance in production.** + + +**Default and Recommended for Production** - Best performance with minimal latency overhead. + +Picks a deployment based on the provided **Requests per minute (rpm) or Tokens per minute (tpm)** + +If `rpm` or `tpm` is not provided, it randomly picks a deployment + +You can also set a `weight` param, to specify which model should get picked when. + + + + +##### **LiteLLM Proxy Config.yaml** + +```yaml +model_list: + - model_name: gpt-3.5-turbo + litellm_params: + model: azure/chatgpt-v-2 + api_key: os.environ/AZURE_API_KEY + api_version: os.environ/AZURE_API_VERSION + api_base: os.environ/AZURE_API_BASE + rpm: 900 + - model_name: gpt-3.5-turbo + litellm_params: + model: azure/chatgpt-functioncalling + api_key: os.environ/AZURE_API_KEY + api_version: os.environ/AZURE_API_VERSION + api_base: os.environ/AZURE_API_BASE + rpm: 10 +``` + +##### **Python SDK** + +```python +from litellm import Router +import asyncio + +model_list = [{ # list of model deployments + "model_name": "gpt-3.5-turbo", # model alias + "litellm_params": { # params for litellm completion/embedding call + "model": "azure/chatgpt-v-2", # actual model name + "api_key": os.getenv("AZURE_API_KEY"), + "api_version": os.getenv("AZURE_API_VERSION"), + "api_base": os.getenv("AZURE_API_BASE"), + "rpm": 900, # requests per minute for this API + } +}, { + "model_name": "gpt-3.5-turbo", + "litellm_params": { # params for litellm completion/embedding call + "model": "azure/chatgpt-functioncalling", + "api_key": os.getenv("AZURE_API_KEY"), + "api_version": os.getenv("AZURE_API_VERSION"), + "api_base": os.getenv("AZURE_API_BASE"), + "rpm": 10, + } +},] + +# init router +router = Router(model_list=model_list, routing_strategy="simple-shuffle") +async def router_acompletion(): + response = await router.acompletion( + model="gpt-3.5-turbo", + messages=[{"role": "user", "content": "Hey, how's it going?"}] + ) + print(response) + return response + +asyncio.run(router_acompletion()) +``` + + + + +##### **LiteLLM Proxy Config.yaml** + +```yaml +model_list: + - model_name: gpt-3.5-turbo + litellm_params: + model: azure/chatgpt-v-2 + api_key: os.environ/AZURE_API_KEY + api_version: os.environ/AZURE_API_VERSION + api_base: os.environ/AZURE_API_BASE + weight: 9 + - model_name: gpt-3.5-turbo + litellm_params: + model: azure/chatgpt-functioncalling + api_key: os.environ/AZURE_API_KEY + api_version: os.environ/AZURE_API_VERSION + api_base: os.environ/AZURE_API_BASE + weight: 1 +``` + +##### **Python SDK** + +```python +from litellm import Router +import asyncio + +model_list = [{ + "model_name": "gpt-3.5-turbo", # model alias + "litellm_params": { + "model": "azure/chatgpt-v-2", # actual model name + "api_key": os.getenv("AZURE_API_KEY"), + "api_version": os.getenv("AZURE_API_VERSION"), + "api_base": os.getenv("AZURE_API_BASE"), + "weight": 9, # pick this 90% of the time + } +}, { + "model_name": "gpt-3.5-turbo", + "litellm_params": { + "model": "azure/chatgpt-functioncalling", + "api_key": os.getenv("AZURE_API_KEY"), + "api_version": os.getenv("AZURE_API_VERSION"), + "api_base": os.getenv("AZURE_API_BASE"), + "weight": 1, + } +}] + +# init router +router = Router(model_list=model_list, routing_strategy="simple-shuffle") +async def router_acompletion(): + response = await router.acompletion( + model="gpt-3.5-turbo", + messages=[{"role": "user", "content": "Hey, how's it going?"}] + ) + print(response) + return response + +asyncio.run(router_acompletion()) +``` + + + + + +> [!WARNING] +**Usage-based routing is not recommended for production due to performance impacts.** Use `simple-shuffle` (default) for optimal performance in high-traffic scenarios. Usage-based routing adds significant latency due to Redis operations for tracking usage across deployments. + + **🎉 NEW** This is an async implementation of usage-based-routing. **Filters out deployment if tpm/rpm limit exceeded** - If you pass in the deployment's tpm/rpm limits. @@ -209,7 +351,7 @@ router = Router(model_list=model_list, redis_host=os.environ["REDIS_HOST"], redis_password=os.environ["REDIS_PASSWORD"], redis_port=os.environ["REDIS_PORT"], - routing_strategy="usage-based-routing-v2" # 👈 KEY CHANGE + routing_strategy="simple-shuffle" # 👈 RECOMMENDED - best performance enable_pre_call_checks=True, # enables router rate limits for concurrent calls ) @@ -241,7 +383,7 @@ model_list: rpm: 1000 router_settings: - routing_strategy: usage-based-routing-v2 # 👈 KEY CHANGE + routing_strategy: simple-shuffle # 👈 RECOMMENDED - best performance redis_host: redis_password: redis_port: @@ -365,143 +507,7 @@ router_settings: ``` - -**Default** Picks a deployment based on the provided **Requests per minute (rpm) or Tokens per minute (tpm)** - -If `rpm` or `tpm` is not provided, it randomly picks a deployment - -You can also set a `weight` param, to specify which model should get picked when. - - - - -##### **LiteLLM Proxy Config.yaml** - -```yaml -model_list: - - model_name: gpt-3.5-turbo - litellm_params: - model: azure/chatgpt-v-2 - api_key: os.environ/AZURE_API_KEY - api_version: os.environ/AZURE_API_VERSION - api_base: os.environ/AZURE_API_BASE - rpm: 900 - - model_name: gpt-3.5-turbo - litellm_params: - model: azure/chatgpt-functioncalling - api_key: os.environ/AZURE_API_KEY - api_version: os.environ/AZURE_API_VERSION - api_base: os.environ/AZURE_API_BASE - rpm: 10 -``` - -##### **Python SDK** - -```python -from litellm import Router -import asyncio - -model_list = [{ # list of model deployments - "model_name": "gpt-3.5-turbo", # model alias - "litellm_params": { # params for litellm completion/embedding call - "model": "azure/chatgpt-v-2", # actual model name - "api_key": os.getenv("AZURE_API_KEY"), - "api_version": os.getenv("AZURE_API_VERSION"), - "api_base": os.getenv("AZURE_API_BASE"), - "rpm": 900, # requests per minute for this API - } -}, { - "model_name": "gpt-3.5-turbo", - "litellm_params": { # params for litellm completion/embedding call - "model": "azure/chatgpt-functioncalling", - "api_key": os.getenv("AZURE_API_KEY"), - "api_version": os.getenv("AZURE_API_VERSION"), - "api_base": os.getenv("AZURE_API_BASE"), - "rpm": 10, - } -},] - -# init router -router = Router(model_list=model_list, routing_strategy="simple-shuffle") -async def router_acompletion(): - response = await router.acompletion( - model="gpt-3.5-turbo", - messages=[{"role": "user", "content": "Hey, how's it going?"}] - ) - print(response) - return response - -asyncio.run(router_acompletion()) -``` - - - - -##### **LiteLLM Proxy Config.yaml** - -```yaml -model_list: - - model_name: gpt-3.5-turbo - litellm_params: - model: azure/chatgpt-v-2 - api_key: os.environ/AZURE_API_KEY - api_version: os.environ/AZURE_API_VERSION - api_base: os.environ/AZURE_API_BASE - weight: 9 - - model_name: gpt-3.5-turbo - litellm_params: - model: azure/chatgpt-functioncalling - api_key: os.environ/AZURE_API_KEY - api_version: os.environ/AZURE_API_VERSION - api_base: os.environ/AZURE_API_BASE - weight: 1 -``` - - -##### **Python SDK** - -```python -from litellm import Router -import asyncio - -model_list = [{ - "model_name": "gpt-3.5-turbo", # model alias - "litellm_params": { - "model": "azure/chatgpt-v-2", # actual model name - "api_key": os.getenv("AZURE_API_KEY"), - "api_version": os.getenv("AZURE_API_VERSION"), - "api_base": os.getenv("AZURE_API_BASE"), - "weight": 9, # pick this 90% of the time - } -}, { - "model_name": "gpt-3.5-turbo", - "litellm_params": { - "model": "azure/chatgpt-functioncalling", - "api_key": os.getenv("AZURE_API_KEY"), - "api_version": os.getenv("AZURE_API_VERSION"), - "api_base": os.getenv("AZURE_API_BASE"), - "weight": 1, - } -}] - -# init router -router = Router(model_list=model_list, routing_strategy="simple-shuffle") -async def router_acompletion(): - response = await router.acompletion( - model="gpt-3.5-turbo", - messages=[{"role": "user", "content": "Hey, how's it going?"}] - ) - print(response) - return response - -asyncio.run(router_acompletion()) -``` - - - - - This will route to the deployment with the lowest TPM usage for that minute. diff --git a/docs/my-website/docs/scheduler.md b/docs/my-website/docs/scheduler.md index 2b0a582626c..9b84c374e3b 100644 --- a/docs/my-website/docs/scheduler.md +++ b/docs/my-website/docs/scheduler.md @@ -41,7 +41,7 @@ router = Router( }, ], timeout=2, # timeout request if takes > 2s - routing_strategy="usage-based-routing-v2", + routing_strategy="simple-shuffle", # recommended for best performance polling_interval=0.03 # poll queue every 3ms if no healthy deployments ) diff --git a/docs/my-website/docs/tutorials/claude_responses_api.md b/docs/my-website/docs/tutorials/claude_responses_api.md index 09b352a7663..5000161a520 100644 --- a/docs/my-website/docs/tutorials/claude_responses_api.md +++ b/docs/my-website/docs/tutorials/claude_responses_api.md @@ -12,6 +12,12 @@ This tutorial is based on [Anthropic's official LiteLLM configuration documentat ::: +
+ +### Video Walkthrough + + + ## Prerequisites - [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) installed @@ -83,11 +89,17 @@ curl -X POST http://0.0.0.0:4000/v1/messages \ Configure Claude Code to use LiteLLM's unified endpoint: +Either a virtual key / master key can be used here + ```bash export ANTHROPIC_BASE_URL="http://0.0.0.0:4000" export ANTHROPIC_AUTH_TOKEN="$LITELLM_MASTER_KEY" ``` +:::tip +LITELLM_MASTER_KEY gives claude access to all proxy models, whereas a virtual key would be limited to the models set in UI +::: + #### Method 2: Provider-specific Pass-through Endpoint Alternatively, use the Anthropic pass-through endpoint: diff --git a/docs/my-website/img/admin_settings_ui_theme.png b/docs/my-website/img/admin_settings_ui_theme.png new file mode 100644 index 00000000000..81e6d761e17 Binary files /dev/null and b/docs/my-website/img/admin_settings_ui_theme.png differ diff --git a/docs/my-website/img/admin_settings_ui_theme_logo.png b/docs/my-website/img/admin_settings_ui_theme_logo.png new file mode 100644 index 00000000000..38f36e61602 Binary files /dev/null and b/docs/my-website/img/admin_settings_ui_theme_logo.png differ diff --git a/docs/my-website/release_notes/v1.74.7/index.md b/docs/my-website/release_notes/v1.74.7/index.md index e3a2ac0aa00..7d7a568e13f 100644 --- a/docs/my-website/release_notes/v1.74.7/index.md +++ b/docs/my-website/release_notes/v1.74.7/index.md @@ -148,7 +148,6 @@ Starting with this release, you can run health endpoints on an isolated process - New provider integration for v0.dev - [PR #12751](https://github.com/BerriAI/litellm/pull/12751), [Get Started](../../docs/providers/v0) - **[OpenAI](../../docs/providers/openai)** - Use OpenAI DeepResearch models with `litellm.completion` (`/chat/completions`) - [PR #12627](https://github.com/BerriAI/litellm/pull/12627) **DOC NEEDED** - - Add `input_fidelity` parameter for OpenAI image generation - [PR #12662](https://github.com/BerriAI/litellm/pull/12662), [Get Started](../../docs/image_generation) - **[Azure OpenAI](../../docs/providers/azure_openai)** - Use Azure OpenAI DeepResearch models with `litellm.completion` (`/chat/completions`) - [PR #12627](https://github.com/BerriAI/litellm/pull/12627) **DOC NEEDED** - Added `response_format` support for openai gpt-4.1 models - [PR #12745](https://github.com/BerriAI/litellm/pull/12745) diff --git a/docs/my-website/release_notes/v1.76.0-stable/index.md b/docs/my-website/release_notes/v1.76.0-stable/index.md new file mode 100644 index 00000000000..660c8cbcf02 --- /dev/null +++ b/docs/my-website/release_notes/v1.76.0-stable/index.md @@ -0,0 +1,189 @@ +--- +title: "[PRE-RELEASE]v1.76.0-stable - RPS Improvements" +slug: "v1-76-0" +date: 2025-08-23T10:00:00 +authors: + - name: Krrish Dholakia + title: CEO, LiteLLM + url: https://www.linkedin.com/in/krish-d/ + image_url: https://pbs.twimg.com/profile_images/1298587542745358340/DZv3Oj-h_400x400.jpg + - 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 + +hide_table_of_contents: false +--- + +import Image from '@theme/IdealImage'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +:::info + +LiteLLM is hiring a **Founding Backend Engineer**, in San Francisco. + +[Apply here](https://www.ycombinator.com/companies/litellm/jobs/6uvoBp3-founding-backend-engineer) if you're interested! +::: + + + + + +## Deploy this version + +:::info + +This release is not live yet. +::: + + +--- + +## New Models / Updated Models + +#### Bugs +- **[OpenAI](../../docs/providers/openai)** + - Gpt-5 chat: clarify does not support function calling [PR #13612](https://github.com/BerriAI/litellm/pull/13612), s/o  @[superpoussin22](https://github.com/superpoussin22) +- **[VertexAI](../../docs/providers/vertex)** + - fix vertexai batch file format by @[thiagosalvatore](https://github.com/thiagosalvatore) in [PR #13576](https://github.com/BerriAI/litellm/pull/13576) +- **[LiteLLM Proxy](../../docs/providers/litellm_proxy)** + - Add support for calling image_edits + image_generations via SDK to Proxy - [PR #13735](https://github.com/BerriAI/litellm/pull/13735) +- **[OpenRouter](../../docs/providers/openrouter)** + - Fix max_output_tokens value for anthropic Claude 4 - [PR #13526](https://github.com/BerriAI/litellm/pull/13526) +- **[Gemini](../../docs/providers/gemini)** + - Fix prompt caching cost calculation - [PR #13742](https://github.com/BerriAI/litellm/pull/13742) +- **[Azure](../../docs/providers/azure)** + - Support `../openai/v1/respones` api base - [PR #13526](https://github.com/BerriAI/litellm/pull/13526) + - Fix azure/gpt-5-chat max_input_tokens - [PR #13660](https://github.com/BerriAI/litellm/pull/13660) +- **[Groq](../../docs/providers/groq)** + - streaming ASCII encoding issue - [PR #13675](https://github.com/BerriAI/litellm/pull/13675) +- **[Baseten](../../docs/providers/baseten)** + - Refactored integration to use new openai-compatible endpoints - [PR #13783](https://github.com/BerriAI/litellm/pull/13783) +- **[Bedrock](../../docs/providers/bedrock)** + - fix application inference profile for pass-through endpoints for bedrock - [PR #13881](https://github.com/BerriAI/litellm/pull/13881) +- **[DataRobot](../../docs/providers/datarobot)** + - Updated URL handling for DataRobot provider URL - [PR #13880](https://github.com/BerriAI/litellm/pull/13880) + +#### Features +- **[Together AI](../../docs/providers/together)** + - Added Qwen3, Deepseek R1 0528 Throughput, GLM 4.5 and GPT-OSS models cost tracking - [PR #13637](https://github.com/BerriAI/litellm/pull/13637), s/o  @[Tasmay-Tibrewal](https://github.com/Tasmay-Tibrewal) +- **[Fireworks AI](../../docs/providers/fireworks_ai)** + - add fireworks_ai/accounts/fireworks/models/deepseek-v3-0324 - [PR #13821](https://github.com/BerriAI/litellm/pull/13821) +- **[VertexAI](../../docs/providers/vertex)** + - Add VertexAI qwen API Service - [PR #13828](https://github.com/BerriAI/litellm/pull/13828) + - Add new VertexAI image models vertex_ai/imagen-4.0-generate-001, vertex_ai/imagen-4.0-ultra-generate-001, vertex_ai/imagen-4.0-fast-generate-001  - [PR #13874](https://github.com/BerriAI/litellm/pull/13874) +- **[Anthropic](../../docs/providers/anthropic)** + - Add long context support w/ cost tracking - [PR #13759](https://github.com/BerriAI/litellm/pull/13759) +- **[DeepInfra](../../docs/providers/deepinfra)** + - Add rerank endpoint support for deepinfra - [PR #13820](https://github.com/BerriAI/litellm/pull/13820) + - Add new models for cost tracking - [PR #13883](https://github.com/BerriAI/litellm/pull/13883), s/o  @[Toy-97](https://github.com/Toy-97) +- **[Bedrock](../../docs/providers/bedrock)** + - Add tool prompt caching on async calls - [PR #13803](https://github.com/BerriAI/litellm/pull/13803), s/o  @[UlookEE](https://github.com/UlookEE) + - role chaining and session name with webauthentication for aws bedrock - [PR #13753](https://github.com/BerriAI/litellm/pull/13753), s/o @[RichardoC](https://github.com/RichardoC) +- **[Ollama](../../docs/providers/ollama)** + - Handle Ollama null response when using tool calling with non-tool trained models - [PR #13902](https://github.com/BerriAI/litellm/pull/13902) +- **[OpenRouter](../../docs/providers/openrouter)** + - Add deepseek/deepseek-chat-v3.1 support - [PR #13897](https://github.com/BerriAI/litellm/pull/13897) +- **[Mistral](../../docs/providers/mistral)** + - Add support for calling mistral files via chat completions - [PR #13866](https://github.com/BerriAI/litellm/pull/13866), s/o  @[jinskjoy](https://github.com/jinskjoy) + - Handle empty assistant content - [PR #13671](https://github.com/BerriAI/litellm/pull/13671) + - Support new ‘thinking’ response block - [PR #13671](https://github.com/BerriAI/litellm/pull/13671) +- **[Databricks](../../docs/providers/databricks)** + - remove deprecated dbrx models (dbrx-instruct, llama 3.1) - [PR #13843](https://github.com/BerriAI/litellm/pull/13843) +- **[AI/ML API](../../docs/providers/ai_ml_api)** + - Image gen api support - [PR #13893](https://github.com/BerriAI/litellm/pull/13893) + + +## LLM API Endpoints +#### Bugs +- **[Responses API](../../docs/response_api)** + - add default api version for openai responses api calls - [PR #13526](https://github.com/BerriAI/litellm/pull/13526) + - support allowed_openai_params - [PR #13671](https://github.com/BerriAI/litellm/pull/13671) + + +## MCP Gateway +#### Bugs +- fix StreamableHTTPSessionManager .run() error - [PR #13666](https://github.com/BerriAI/litellm/pull/13666) + +## Vector Stores +#### Bugs +- **[Bedrock](../../docs/providers/bedrock)** + - Using LiteLLM Managed Credentials for Query - [PR #13787](https://github.com/BerriAI/litellm/pull/13787) + +## Management Endpoints / UI +#### Bugs +- **[Passthrough](../../docs/pass_through/intro)** + - Fix query passthrough deletion - [PR #13622](https://github.com/BerriAI/litellm/pull/13622) + +#### Features +- **Models** + - Add Search Functionality for Public Model Names in Model Dashboard - [PR #13687](https://github.com/BerriAI/litellm/pull/13687) + - Auto-Add `azure/` to deployment Name in UI - [PR #13685](https://github.com/BerriAI/litellm/pull/13685) + - Models page row UI restructure - [PR #13771](https://github.com/BerriAI/litellm/pull/13771) +- **Notifications** + - Add new notifications toast UI everywhere - [PR #13813](https://github.com/BerriAI/litellm/pull/13813) +- **Keys** + - Fix key edit settings after regenerating a key - [PR #13815](https://github.com/BerriAI/litellm/pull/13815) + - Require team_id when creating service account keys - [PR #13873](https://github.com/BerriAI/litellm/pull/13873) + - Filter - show all options on filter option click - [PR #13858](https://github.com/BerriAI/litellm/pull/13858) +- **Usage** + - Fix ‘Cannot read properties of undefined’ exception on user agent activity tab - [PR #13892](https://github.com/BerriAI/litellm/pull/13892) +- **SSO** + - Free SSO usage for up to 5 users - [PR #13843](https://github.com/BerriAI/litellm/pull/13843) + +## Logging / Guardrail Integrations +#### Bugs +- **[Bedrock Guardrails](../../docs/proxy/guardrails/bedrock)** + - Add bedrock api key support - [PR #13835](https://github.com/BerriAI/litellm/pull/13835) +#### Features +- **[Datadog LLM Observability](../../docs/integrations/datadog)** + - Add support for Failure Logging [PR #13726](https://github.com/BerriAI/litellm/pull/13726) + - Add time to first token, litellm overhead, guardrail overhead latency metrics - [PR #13734](https://github.com/BerriAI/litellm/pull/13734) + - Add support for tracing guardrail input/output - [PR #13767](https://github.com/BerriAI/litellm/pull/13767) +- **[Langfuse OTEL](../../docs/integrations/langfuse)** + - Allow using Key/Team Based Logging - [PR #13791](https://github.com/BerriAI/litellm/pull/13791) +- **[AIM](../../docs/integrations/aim)** + - Migrate to new firewall API - [PR #13748](https://github.com/BerriAI/litellm/pull/13748) +- **[OTEL](../../docs/observability/opentelemetry_integration)** + - Add OTEL tracing for actual LLM API call - [PR #13836](https://github.com/BerriAI/litellm/pull/13836) +- **[MLFlow](../../docs/observability/mlflow_integration)** + - Include predicted output in MLflow tracing - [PR #13795](https://github.com/BerriAI/litellm/pull/13795), s/o @TomeHirata  + + +## Performance / Loadbalancing / Reliability improvements +#### Bugs +- **[Cooldowns](../../docs/routing#how-cooldowns-work)** + - don't return raw Azure Exceptions to client (can contain prompt leakage) - [PR #13529](https://github.com/BerriAI/litellm/pull/13529) +- **[Auto-router](../../docs/proxy/auto_routing)** + - Ensures the relevant dependencies for auto router existing on LiteLLM Docker - [PR #13788](https://github.com/BerriAI/litellm/pull/13788) +- **Model Alias** + - Fix calling key with access to model alias - [PR #13830](https://github.com/BerriAI/litellm/pull/13830) + +#### Features +- **[S3 Caching](../../docs/proxy/caching)** + - Use namespace as prefix for s3 cache - [PR #13704](https://github.com/BerriAI/litellm/pull/13704) + - Async S3 Caching support (4x RPS improvement) - [PR #13852](https://github.com/BerriAI/litellm/pull/13852), s/o @[michal-otmianowski](https://github.com/michal-otmianowski) +- **Model Group header forwarding** + - reuse same logic as global header forwarding - [PR #13741](https://github.com/BerriAI/litellm/pull/13741) + - add support for hosted_vllm on UI - [PR #13885](https://github.com/BerriAI/litellm/pull/13885) +- **Performance** + - Improve LiteLLM Python SDK RPS by +200 RPS (braintrust import + aiohttp transport fixes) - [PR #13839](https://github.com/BerriAI/litellm/pull/13839) + - Use O(1) Set lookups for model routing - [PR #13879](https://github.com/BerriAI/litellm/pull/13879) + - Reduce Significant CPU overhead from litellm_logging.py - [PR #13895](https://github.com/BerriAI/litellm/pull/13895) + - Improvements for Async Success Handler (Logging Callbacks) - Approx +130 RPS - [PR #13905](https://github.com/BerriAI/litellm/pull/13905) + + +## General Proxy Improvements +#### Bugs + +- **SDK** + - Fix litellm compatibility with newest release of openAI (>v1.100.0) - [PR #13728](https://github.com/BerriAI/litellm/pull/13728) +- **Helm** + - Add possibility to configure resources for migrations-job - [PR #13617](https://github.com/BerriAI/litellm/pull/13617) + - Ensure Helm chart auto generated master keys follow sk-xxxx format - [PR #13871](https://github.com/BerriAI/litellm/pull/13871) + - Enhance database configuration: add support for optional endpointKey - [PR #13763](https://github.com/BerriAI/litellm/pull/13763) +- **Rate Limits** + - fixing descriptor/response size mismatch on parallel_request_limiter_v3 - [PR #13863](https://github.com/BerriAI/litellm/pull/13863), s/o  @[luizrennocosta](https://github.com/luizrennocosta) +- **Non-root** + - fix permission access on prisma migrate in non-root image - [PR #13848](https://github.com/BerriAI/litellm/pull/13848), s/o @[Ithanil](https://github.com/Ithanil) \ No newline at end of file diff --git a/docs/my-website/release_notes/v1.76.1-stable/index.md b/docs/my-website/release_notes/v1.76.1-stable/index.md new file mode 100644 index 00000000000..4437b7f5799 --- /dev/null +++ b/docs/my-website/release_notes/v1.76.1-stable/index.md @@ -0,0 +1,269 @@ +--- +title: "v1.76.1-stable - Gemini 2.5 Flash Image" +slug: "v1-76-1" +date: 2025-08-30T10:00:00 +authors: + - name: Krrish Dholakia + title: CEO, LiteLLM + url: https://www.linkedin.com/in/krish-d/ + image_url: https://pbs.twimg.com/profile_images/1298587542745358340/DZv3Oj-h_400x400.jpg + - 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 + +hide_table_of_contents: false +--- + +import Image from '@theme/IdealImage'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Deploy this version + + + + +``` showLineNumbers title="docker run litellm" +docker run \ +-e STORE_MODEL_IN_DB=True \ +-p 4000:4000 \ +ghcr.io/berriai/litellm:v1.76.1 +``` + + + + +``` showLineNumbers title="pip install litellm" +pip install litellm==1.76.1 +``` + + + + +--- + +## Key Highlights + +- **Major Performance Improvements** - 6.5x faster LiteLLM Python SDK completion with fastuuid integration. +- **New Model Support** - Gemini 2.5 Flash Image Preview, Grok Code Fast, and GPT Realtime models +- **Enhanced Provider Support** - DeepSeek-v3.1 pricing on Fireworks AI, Vercel AI Gateway, and improved Anthropic/GitHub Copilot integration +- **MCP Improvements** - Better connection testing and SSE MCP tools bug fixes + +## Major Changes +- Added support for using Gemini 2.5 Flash Image Preview with /chat/completions. **🚨 Warning** If you were using `gemini-2.0-flash-exp-image-generation` please follow this migration guide. + [Gemini Image Generation Migration Guide](../../docs/extras/gemini_img_migration) +--- + +## Performance Improvements + +This release includes significant performance optimizations: + +- **6.5x faster LiteLLM Python SDK Completion** - Major performance boost for completion operations - [PR #13990](https://github.com/BerriAI/litellm/pull/13990) +- **fastuuid Integration** - 2.1x faster UUID generation with +80 RPS improvement for /chat/completions and other LLM endpoints - [PR #13992](https://github.com/BerriAI/litellm/pull/13992), [PR #14016](https://github.com/BerriAI/litellm/pull/14016) +- **Optimized Request Logging** - Don't print request params by default for +50 RPS improvement - [PR #14015](https://github.com/BerriAI/litellm/pull/14015) +- **Cache Performance** - 21% speedup in InMemoryCache.evict_cache and 45% speedup in `_is_debugging_on` function - [PR #14012](https://github.com/BerriAI/litellm/pull/14012), [PR #13988](https://github.com/BerriAI/litellm/pull/13988) + +--- + +## New Models / Updated Models + +#### New Model Support + +| Provider | Model | Context Window | Input ($/1M tokens) | Output ($/1M tokens) | Features | +| ----------- | -------------------------------------- | -------------- | ------------------- | -------------------- | -------- | +| Google | `gemini-2.5-flash-image-preview` | 1M | $0.30 | $2.50 | Chat completions + image generation ($0.039/image) | +| X.AI | `xai/grok-code-fast` | 256K | $0.20 | $1.50 | Code generation | +| OpenAI | `gpt-realtime` | 32K | $4.00 | $16.00 | Real-time conversation + audio | +| Vercel AI Gateway | `vercel_ai_gateway/openai/o3` | 200K | $2.00 | $8.00 | Advanced reasoning | +| Vercel AI Gateway | `vercel_ai_gateway/openai/o3-mini` | 200K | $1.10 | $4.40 | Efficient reasoning | +| Vercel AI Gateway | `vercel_ai_gateway/openai/o4-mini` | 200K | $1.10 | $4.40 | Latest mini model | +| DeepInfra | `deepinfra/zai-org/GLM-4.5` | 131K | $0.55 | $2.00 | Chat completions | +| Perplexity | `perplexity/codellama-34b-instruct` | 16K | $0.35 | $1.40 | Code generation | +| Fireworks AI | `fireworks_ai/accounts/fireworks/models/deepseek-v3p1` | 128K | $0.56 | $1.68 | Chat completions | + +**Additional Models Added:** Various other Vercel AI Gateway models were added too. See [models.litellm.ai](https://models.litellm.ai) for the full list. + +#### Features + +- **[Google Gemini](../../docs/providers/gemini)** + - Added support for `gemini-2.5-flash-image-preview` with image return capability - [PR #13979](https://github.com/BerriAI/litellm/pull/13979), [PR #13983](https://github.com/BerriAI/litellm/pull/13983) + - Support for requests with only system prompt - [PR #14010](https://github.com/BerriAI/litellm/pull/14010) + - Fixed invalid model name error for Gemini Imagen models - [PR #13991](https://github.com/BerriAI/litellm/pull/13991) +- **[X.AI](../../docs/providers/xai)** + - Added `xai/grok-code-fast` model family support - [PR #14054](https://github.com/BerriAI/litellm/pull/14054) + - Fixed frequency_penalty parameter for grok-4 models - [PR #14078](https://github.com/BerriAI/litellm/pull/14078) +- **[OpenAI](../../docs/providers/openai)** + - Added support for gpt-realtime models - [PR #14082](https://github.com/BerriAI/litellm/pull/14082) + - Support for reasoning and reasoning_effort parameters by default - [PR #12865](https://github.com/BerriAI/litellm/pull/12865) +- **[Fireworks AI](../../docs/providers/fireworks_ai)** + - Added DeepSeek-v3.1 pricing - [PR #13958](https://github.com/BerriAI/litellm/pull/13958) +- **[DeepInfra](../../docs/providers/deepinfra)** + - Fixed reasoning_effort setting for DeepSeek-V3.1 - [PR #14053](https://github.com/BerriAI/litellm/pull/14053) +- **[GitHub Copilot](../../docs/providers/github_copilot)** + - Added support for thinking and reasoning_effort parameters - [PR #13691](https://github.com/BerriAI/litellm/pull/13691) + - Added image headers support - [PR #13955](https://github.com/BerriAI/litellm/pull/13955) +- **[Anthropic](../../docs/providers/anthropic)** + - Support for custom Anthropic-compatible API endpoints - [PR #13945](https://github.com/BerriAI/litellm/pull/13945) + - Fixed /messages fallback from Anthropic API to Bedrock API - [PR #13946](https://github.com/BerriAI/litellm/pull/13946) +- **[Nebius](../../docs/providers/nebius)** + - Expanded provider models and normalized model IDs - [PR #13965](https://github.com/BerriAI/litellm/pull/13965) +- **[Vertex AI](../../docs/providers/vertex)** + - Fixed Vertex Mistral streaming issues - [PR #13952](https://github.com/BerriAI/litellm/pull/13952) + - Fixed anyOf corner cases for Gemini tool calls - [PR #12797](https://github.com/BerriAI/litellm/pull/12797) +- **[Bedrock](../../docs/providers/bedrock)** + - Fixed structure output issues - [PR #14005](https://github.com/BerriAI/litellm/pull/14005) +- **[OpenRouter](../../docs/providers/openrouter)** + - Added GPT-5 family models pricing - [PR #13536](https://github.com/BerriAI/litellm/pull/13536) + +#### New Provider Support + +- **[Vercel AI Gateway](../../docs/providers/vercel_ai_gateway)** + - New provider support added - [PR #13144](https://github.com/BerriAI/litellm/pull/13144) +- **[DataRobot](../../docs/providers/datarobot)** + - Added provider documentation - [PR #14038](https://github.com/BerriAI/litellm/pull/14038), [PR #14074](https://github.com/BerriAI/litellm/pull/14074) + +--- + +## LLM API Endpoints + +#### Features + +- **[Images API](../../docs/image_generation)** + - Support for multiple images in OpenAI images/edits endpoint - [PR #13916](https://github.com/BerriAI/litellm/pull/13916) + - Allow using dynamic `api_key` for image generation requests - [PR #14007](https://github.com/BerriAI/litellm/pull/14007) +- **[Responses API](../../docs/response_api)** + - Fixed `/responses` endpoint ignoring extra_headers in GitHub Copilot - [PR #13775](https://github.com/BerriAI/litellm/pull/13775) + - Added support for new web_search tool - [PR #14083](https://github.com/BerriAI/litellm/pull/14083) +- **[Azure Passthrough](../../docs/providers/azure/azure)** + - Fixed Azure Passthrough request with streaming - [PR #13831](https://github.com/BerriAI/litellm/pull/13831) + +#### Bugs + +- **General** + - Fixed handling of None metadata in batch requests - [PR #13996](https://github.com/BerriAI/litellm/pull/13996) + - Fixed token_counter with special token input - [PR #13374](https://github.com/BerriAI/litellm/pull/13374) + - Removed incorrect web search support for azure/gpt-4.1 family - [PR #13566](https://github.com/BerriAI/litellm/pull/13566) + +--- + +## [MCP Gateway](../../docs/mcp) + +#### Features + +- **SSE MCP Tools** + - Bug fix for adding SSE MCP tools - improved connection testing when adding MCPs - [PR #14048](https://github.com/BerriAI/litellm/pull/14048) + +[Read More](../../docs/mcp) + +--- + +## Management Endpoints / UI + +#### Features + +- **Team Management** + - Allow setting Team Member RPM/TPM limits when creating a team - [PR #13943](https://github.com/BerriAI/litellm/pull/13943) +- **UI Improvements** + - Fixed Next.js Security Vulnerabilities in UI Dashboard - [PR #14084](https://github.com/BerriAI/litellm/pull/14084) + - Fixed collapsible navbar design - [PR #14075](https://github.com/BerriAI/litellm/pull/14075) + +#### Bugs + +- **Authentication** + - Fixed Virtual keys with llm_api type causing Internal Server Error for /anthropic/* and other LLM passthrough routes - [PR #14046](https://github.com/BerriAI/litellm/pull/14046) + +--- + +## Logging / Guardrail Integrations + +#### Features + +- **[Langfuse OTEL](../../docs/proxy/logging#langfuse)** + - Allow using LANGFUSE_OTEL_HOST for configuring host - [PR #14013](https://github.com/BerriAI/litellm/pull/14013) +- **[Braintrust](../../docs/proxy/logging#braintrust)** + - Added span name metadata feature - [PR #13573](https://github.com/BerriAI/litellm/pull/13573) + - Fixed tests to reference moved attributes in `braintrust_logging` module - [PR #13978](https://github.com/BerriAI/litellm/pull/13978) +- **[OpenMeter](../../docs/proxy/logging#openmeter)** + - Set user from token user_id for OpenMeter integration - [PR #13152](https://github.com/BerriAI/litellm/pull/13152) + +#### New Guardrail Support + +- **[Noma Security](../../docs/proxy/guardrails)** + - Added Noma Security guardrail support - [PR #13572](https://github.com/BerriAI/litellm/pull/13572) +- **[Pangea](../../docs/proxy/guardrails)** + - Updated Pangea Guardrail to support new AIDR endpoint - [PR #13160](https://github.com/BerriAI/litellm/pull/13160) + +--- + +## Performance / Loadbalancing / Reliability improvements + +#### Features + +- **Caching** + - Verify if cache entry has expired prior to serving it to client - [PR #13933](https://github.com/BerriAI/litellm/pull/13933) + - Fixed error saving latency as timedelta on Redis - [PR #14040](https://github.com/BerriAI/litellm/pull/14040) +- **Router** + - Refactored router to choose weights by 'weight', 'rpm', 'tpm' in one loop for simple_shuffle - [PR #13562](https://github.com/BerriAI/litellm/pull/13562) +- **Logging** + - Fixed LoggingWorker graceful shutdown to prevent CancelledError warnings - [PR #14050](https://github.com/BerriAI/litellm/pull/14050) + - Enhanced logging for containers to log on files both with usual format and json format - [PR #13394](https://github.com/BerriAI/litellm/pull/13394) + +#### Bugs + +- **Dependencies** + - Bumped `orjson` version to "3.11.2" - [PR #13969](https://github.com/BerriAI/litellm/pull/13969) + +--- + +## General Proxy Improvements + +#### Features + +- **AWS** + - Add support for AWS assume_role with a session token - [PR #13919](https://github.com/BerriAI/litellm/pull/13919) +- **OCI Provider** + - Added oci_key_file as an optional_parameter - [PR #14036](https://github.com/BerriAI/litellm/pull/14036) +- **Configuration** + - Allow configuration to set threshold before request entry in spend log gets truncated - [PR #14042](https://github.com/BerriAI/litellm/pull/14042) + - Enhanced proxy_config configuration: add support for existing configmap in Helm charts - [PR #14041](https://github.com/BerriAI/litellm/pull/14041) +- **Docker** + - Added back supervisor to non-root image - [PR #13922](https://github.com/BerriAI/litellm/pull/13922) + + +--- + +## New Contributors +* @ArthurRenault made their first contribution in [PR #13922](https://github.com/BerriAI/litellm/pull/13922) +* @stevenmanton made their first contribution in [PR #13919](https://github.com/BerriAI/litellm/pull/13919) +* @uc4w6c made their first contribution in [PR #13914](https://github.com/BerriAI/litellm/pull/13914) +* @nielsbosma made their first contribution in [PR #13573](https://github.com/BerriAI/litellm/pull/13573) +* @Yuki-Imajuku made their first contribution in [PR #13567](https://github.com/BerriAI/litellm/pull/13567) +* @codeflash-ai[bot] made their first contribution in [PR #13988](https://github.com/BerriAI/litellm/pull/13988) +* @ColeFrench made their first contribution in [PR #13978](https://github.com/BerriAI/litellm/pull/13978) +* @dttran-glo made their first contribution in [PR #13969](https://github.com/BerriAI/litellm/pull/13969) +* @manascb1344 made their first contribution in [PR #13965](https://github.com/BerriAI/litellm/pull/13965) +* @DorZion made their first contribution in [PR #13572](https://github.com/BerriAI/litellm/pull/13572) +* @edwardsamuel made their first contribution in [PR #13536](https://github.com/BerriAI/litellm/pull/13536) +* @blahgeek made their first contribution in [PR #13374](https://github.com/BerriAI/litellm/pull/13374) +* @Deviad made their first contribution in [PR #13394](https://github.com/BerriAI/litellm/pull/13394) +* @XSAM made their first contribution in [PR #13775](https://github.com/BerriAI/litellm/pull/13775) +* @KRRT7 made their first contribution in [PR #14012](https://github.com/BerriAI/litellm/pull/14012) +* @ikaadil made their first contribution in [PR #13991](https://github.com/BerriAI/litellm/pull/13991) +* @timelfrink made their first contribution in [PR #13691](https://github.com/BerriAI/litellm/pull/13691) +* @qidu made their first contribution in [PR #13562](https://github.com/BerriAI/litellm/pull/13562) +* @nagyv made their first contribution in [PR #13243](https://github.com/BerriAI/litellm/pull/13243) +* @xywei made their first contribution in [PR #12885](https://github.com/BerriAI/litellm/pull/12885) +* @ericgtkb made their first contribution in [PR #12797](https://github.com/BerriAI/litellm/pull/12797) +* @NoWall57 made their first contribution in [PR #13945](https://github.com/BerriAI/litellm/pull/13945) +* @lmwang9527 made their first contribution in [PR #14050](https://github.com/BerriAI/litellm/pull/14050) +* @WilsonSunBritten made their first contribution in [PR #14042](https://github.com/BerriAI/litellm/pull/14042) +* @Const-antine made their first contribution in [PR #14041](https://github.com/BerriAI/litellm/pull/14041) +* @dmvieira made their first contribution in [PR #14040](https://github.com/BerriAI/litellm/pull/14040) +* @gotsysdba made their first contribution in [PR #14036](https://github.com/BerriAI/litellm/pull/14036) +* @moshemorad made their first contribution in [PR #14005](https://github.com/BerriAI/litellm/pull/14005) +* @joshualipman123 made their first contribution in [PR #13144](https://github.com/BerriAI/litellm/pull/13144) + +--- + +## **[Full Changelog](https://github.com/BerriAI/litellm/compare/v1.76.0-nightly...v1.76.1)** diff --git a/docs/my-website/release_notes/v1.76.3-stable/index.md b/docs/my-website/release_notes/v1.76.3-stable/index.md new file mode 100644 index 00000000000..0f997d6941a --- /dev/null +++ b/docs/my-website/release_notes/v1.76.3-stable/index.md @@ -0,0 +1,282 @@ +--- +title: "v1.76.3-stable - Performance, Video Generation & CloudZero Integration" +slug: "v1-76-3" +date: 2025-09-06T10:00:00 +authors: + - name: Krrish Dholakia + title: CEO, LiteLLM + url: https://www.linkedin.com/in/krish-d/ + image_url: https://pbs.twimg.com/profile_images/1298587542745358340/DZv3Oj-h_400x400.jpg + - 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 + +hide_table_of_contents: false +--- + +import Image from '@theme/IdealImage'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Deploy this version + + + + +``` showLineNumbers title="docker run litellm" +docker run \ +-e STORE_MODEL_IN_DB=True \ +-p 4000:4000 \ +ghcr.io/berriai/litellm:v1.76.3 +``` + + + + +``` showLineNumbers title="pip install litellm" +pip install litellm==1.76.3 +``` + + + + +--- + +## Key Highlights + +- **Major Performance Improvements** +400 RPS when using correct amount of workers + CPU cores combination +- **Video Generation Support** - Added Google AI Studio and Vertex AI Veo Video Generation through LiteLLM Pass through routes +- **CloudZero Integration** - New cost tracking integration for exporting LiteLLM Usage and Spend data to CloudZero. + +## Major Changes +- **Performance Optimization**: LiteLLM Proxy now achieves +400 RPS when using correct amount of CPU cores - [PR #14153](https://github.com/BerriAI/litellm/pull/14153), [PR #14242](https://github.com/BerriAI/litellm/pull/14242) + + By default, LiteLLM will now use `num_workers = os.cpu_count()` to achieve optimal performance. + + **Override Options:** + + Set environment variable: + ```bash + DEFAULT_NUM_WORKERS_LITELLM_PROXY=1 + ``` + + Or start LiteLLM Proxy with: + ```bash + litellm --num_workers 1 + ``` + +- **Security Fix**: Fixed memory_usage_in_mem_cache cache endpoint vulnerability - [PR #14229](https://github.com/BerriAI/litellm/pull/14229) + +--- + +## Performance Improvements + +This release includes significant performance optimizations. On our internal benchmarks we saw 1 instance get +400 RPS when using correct amount of workers + CPU cores combination. + +- **+400 RPS Performance Boost** - LiteLLM Proxy now uses correct amount of CPU cores for optimal performance - [PR #14153](https://github.com/BerriAI/litellm/pull/14153) +- **Default CPU Workers** - Changed DEFAULT_NUM_WORKERS_LITELLM_PROXY default to number of CPUs - [PR #14242](https://github.com/BerriAI/litellm/pull/14242) + + +--- + +## New Models / Updated Models + +#### New Model Support + +| Provider | Model | Context Window | Input ($/1M tokens) | Output ($/1M tokens) | Features | +| ----------- | -------------------------------------- | -------------- | ------------------- | -------------------- | -------- | +| OpenRouter | `openrouter/openai/gpt-4.1` | 1M | $2.00 | $8.00 | Chat completions with vision | +| OpenRouter | `openrouter/openai/gpt-4.1-mini` | 1M | $0.40 | $1.60 | Efficient chat completions | +| OpenRouter | `openrouter/openai/gpt-4.1-nano` | 1M | $0.10 | $0.40 | Ultra-efficient chat | +| Vertex AI | `vertex_ai/openai/gpt-oss-20b-maas` | 131K | $0.075 | $0.30 | Reasoning support | +| Vertex AI | `vertex_ai/openai/gpt-oss-120b-maas` | 131K | $0.15 | $0.60 | Advanced reasoning | +| Gemini | `gemini/veo-3.0-generate-preview` | 1K | - | $0.75/sec | Video generation | +| Gemini | `gemini/veo-3.0-fast-generate-preview` | 1K | - | $0.40/sec | Fast video generation | +| Gemini | `gemini/veo-2.0-generate-001` | 1K | - | $0.35/sec | Video generation | +| Volcengine | `doubao-embedding-large` | 4K | Free | Free | 2048-dim embeddings | +| Together AI | `together_ai/deepseek-ai/DeepSeek-V3.1` | 128K | $0.60 | $1.70 | Reasoning support | + +#### Features + +- **[Google Gemini](../../docs/providers/gemini)** + - Added 'thoughtSignature' support via 'thinking_blocks' - [PR #14122](https://github.com/BerriAI/litellm/pull/14122) + - Added support for reasoning_effort='minimal' for Gemini models - [PR #14262](https://github.com/BerriAI/litellm/pull/14262) +- **[OpenRouter](../../docs/providers/openrouter)** + - Added GPT-4.1 model family - [PR #14101](https://github.com/BerriAI/litellm/pull/14101) +- **[Groq](../../docs/providers/groq)** + - Added support for reasoning_effort parameter - [PR #14207](https://github.com/BerriAI/litellm/pull/14207) +- **[X.AI](../../docs/providers/xai)** + - Fixed XAI cost calculation - [PR #14127](https://github.com/BerriAI/litellm/pull/14127) +- **[Vertex AI](../../docs/providers/vertex)** + - Added support for GPT-OSS models on Vertex AI - [PR #14184](https://github.com/BerriAI/litellm/pull/14184) + - Added additionalProperties to Vertex AI Schema definition - [PR #14252](https://github.com/BerriAI/litellm/pull/14252) +- **[VLLM](../../docs/providers/vllm)** + - Handle output parsing responses API output - [PR #14121](https://github.com/BerriAI/litellm/pull/14121) +- **[Ollama](../../docs/providers/ollama)** + - Added unified 'thinking' param support via `reasoning_content` - [PR #14121](https://github.com/BerriAI/litellm/pull/14121) +- **[Anthropic](../../docs/providers/anthropic)** + - Added supported text field to anthropic citation response - [PR #14126](https://github.com/BerriAI/litellm/pull/14126) +- **[OCI Provider](../../docs/providers/oci)** + - Handle assistant messages with both content and tool_calls - [PR #14171](https://github.com/BerriAI/litellm/pull/14171) +- **[Bedrock](../../docs/providers/bedrock)** + - Fixed structure output - [PR #14130](https://github.com/BerriAI/litellm/pull/14130) + - Added initial support for Bedrock Batches API - [PR #14190](https://github.com/BerriAI/litellm/pull/14190) +- **[Databricks](../../docs/providers/databricks)** + - Added support for anthropic citation API in Databricks - [PR #14077](https://github.com/BerriAI/litellm/pull/14077) + +### Bug Fixes +- **[Google Gemini (Google AI Studio + Vertex AI)](../../docs/providers/gemini)** + - Fixed Gemini 2.5 Pro schema validation with OpenAI-style type arrays in tools - [PR #14154](https://github.com/BerriAI/litellm/pull/14154) + - Fixed Gemini Tool Calling empty enum property - [PR #14155](https://github.com/BerriAI/litellm/pull/14155) + +#### New Provider Support + +- **[Volcengine](../../docs/providers/volcengine)** + - Added Volcengine embedding module with handler and transformation logic - [PR #14028](https://github.com/BerriAI/litellm/pull/14028) + +--- + +## LLM API Endpoints + +#### Features + +- **[Images API](../../docs/image_generation)** + - Added pass through image generation and image editing on OpenAI - [PR #14292](https://github.com/BerriAI/litellm/pull/14292) + - Support extra_body parameter for image generation - [PR #14211](https://github.com/BerriAI/litellm/pull/14211) +- **[Responses API](../../docs/response_api)** + - Fixed response API for reasoning item in input for litellm proxy - [PR #14200](https://github.com/BerriAI/litellm/pull/14200) + - Added structured output for SDK - [PR #14206](https://github.com/BerriAI/litellm/pull/14206) +- **[Bedrock Passthrough](../../docs/pass_through/bedrock)** + - Support AWS_BEDROCK_RUNTIME_ENDPOINT on bedrock passthrough - [PR #14156](https://github.com/BerriAI/litellm/pull/14156) +- **[Google AI Studio Passthrough](../../docs/pass_through/google_ai_studio)** + - Allow using Veo Video Generation through LiteLLM Pass through routes - [PR #14228](https://github.com/BerriAI/litellm/pull/14228) +- **General** + - Added support for safety_identifier parameter in chat.completions.create - [PR #14174](https://github.com/BerriAI/litellm/pull/14174) + - Fixed misclassified 500 error on invalid image_url in /chat/completions request - [PR #14149](https://github.com/BerriAI/litellm/pull/14149) + - Fixed token count error for Gemini CLI - [PR #14133](https://github.com/BerriAI/litellm/pull/14133) + +#### Bugs + +- **General** + - Remove "/" or ":" from model name when being used as h11 header name - [PR #14191](https://github.com/BerriAI/litellm/pull/14191) + - Bug fix for openai.gpt-oss when using reasoning_effort parameter - [PR #14300](https://github.com/BerriAI/litellm/pull/14300) + +--- + +## Spend Tracking, Budgets and Rate Limiting + +### Features + - Added header support for spend_logs_metadata - [PR #14186](https://github.com/BerriAI/litellm/pull/14186) + - Litellm passthrough cost tracking for chat completion - [PR #14256](https://github.com/BerriAI/litellm/pull/14256) + +### Bug Fixes + - Fixed TPM Rate Limit Bug - [PR #14237](https://github.com/BerriAI/litellm/pull/14237) + - Fixed Key Budget not resets at expectable times - [PR #14241](https://github.com/BerriAI/litellm/pull/14241) + + + +## Management Endpoints / UI + +#### Features + +- **UI Improvements** + - Logs page screen size fixed - [PR #14135](https://github.com/BerriAI/litellm/pull/14135) + - Create Organization Tooltip added on Success - [PR #14132](https://github.com/BerriAI/litellm/pull/14132) + - Back to Keys should say Back to Logs - [PR #14134](https://github.com/BerriAI/litellm/pull/14134) + - Add client side pagination on All Models table - [PR #14136](https://github.com/BerriAI/litellm/pull/14136) + - Model Filters UI improvement - [PR #14131](https://github.com/BerriAI/litellm/pull/14131) + - Remove table filter on user info page - [PR #14169](https://github.com/BerriAI/litellm/pull/14169) + - Team name badge added on the User Details - [PR #14003](https://github.com/BerriAI/litellm/pull/14003) + - Fix: Log page parameter passing error - [PR #14193](https://github.com/BerriAI/litellm/pull/14193) +- **Authentication & Authorization** + - Support for ES256/ES384/ES512 and EdDSA JWT verification - [PR #14118](https://github.com/BerriAI/litellm/pull/14118) + - Ensure `team_id` is a required field for generating service account keys - [PR #14270](https://github.com/BerriAI/litellm/pull/14270) + +#### Bugs + +- **General** + - Validate store model in db setting - [PR #14269](https://github.com/BerriAI/litellm/pull/14269) + +--- + +## Logging / Guardrail Integrations + +#### Features + +- **[Datadog](../../docs/proxy/logging#datadog)** + - Ensure `apm_id` is set on DD LLM Observability traces - [PR #14272](https://github.com/BerriAI/litellm/pull/14272) +- **[Braintrust](../../docs/proxy/logging#braintrust)** + - Fix logging when OTEL is enabled - [PR #14122](https://github.com/BerriAI/litellm/pull/14122) +- **[OTEL](../../docs/proxy/logging#otel)** + - Optional Metrics and Logs following semantic conventions - [PR #14179](https://github.com/BerriAI/litellm/pull/14179) +- **[Slack Alerting](../../docs/proxy/alerting)** + - Added alert type to alert message to slack for easier handling - [PR #14176](https://github.com/BerriAI/litellm/pull/14176) + +#### Guardrails + - Added guardrail to the Anthropic API endpoint - [PR #14107](https://github.com/BerriAI/litellm/pull/14107) + +#### New Integration + +- **[CloudZero](../../docs/proxy/cost_tracking)** + - LiteLLM x CloudZero Integration for Cost Tracking - [PR #14296](https://github.com/BerriAI/litellm/pull/14296) + +--- + +## Performance / Loadbalancing / Reliability improvements + +#### Features + +- **Performance** + - LiteLLM Proxy: +400 RPS when using correct amount of CPU cores - [PR #14153](https://github.com/BerriAI/litellm/pull/14153) + - Allow using `x-litellm-stream-timeout` header for stream timeout in requests - [PR #14147](https://github.com/BerriAI/litellm/pull/14147) + - Change DEFAULT_NUM_WORKERS_LITELLM_PROXY default to number CPUs - [PR #14242](https://github.com/BerriAI/litellm/pull/14242) +- **Monitoring** + - Added Prometheus missing metrics - [PR #14139](https://github.com/BerriAI/litellm/pull/14139) +- **Timeout** + - **Stream Timeout Control** - Allow using `x-litellm-stream-timeout` header for stream timeout in requests - [PR #14147](https://github.com/BerriAI/litellm/pull/14147) +- **Routing** + - Fixed x-litellm-tags not routing with Responses API - [PR #14289](https://github.com/BerriAI/litellm/pull/14289) + +#### Bugs + +- **Security** + - Fixed memory_usage_in_mem_cache cache endpoint vulnerability - [PR #14229](https://github.com/BerriAI/litellm/pull/14229) + +--- + +## General Proxy Improvements + +#### Features + +- **SCIM Support** + - Added better SCIM debugging - [PR #14221](https://github.com/BerriAI/litellm/pull/14221) + - Bug fixes for handling SCIM Group Memberships - [PR #14226](https://github.com/BerriAI/litellm/pull/14226) +- **Kubernetes** + - Added optional PodDisruptionBudget for litellm proxy - [PR #14093](https://github.com/BerriAI/litellm/pull/14093) +- **Error Handling** + - Add model to azure error message - [PR #14294](https://github.com/BerriAI/litellm/pull/14294) + +--- + +## New Contributors +* @iabhi4 made their first contribution in [PR #14093](https://github.com/BerriAI/litellm/pull/14093) +* @zainhas made their first contribution in [PR #14087](https://github.com/BerriAI/litellm/pull/14087) +* @LifeDJIK made their first contribution in [PR #14146](https://github.com/BerriAI/litellm/pull/14146) +* @retanoj made their first contribution in [PR #14133](https://github.com/BerriAI/litellm/pull/14133) +* @zhxlp made their first contribution in [PR #14193](https://github.com/BerriAI/litellm/pull/14193) +* @kayoch1n made their first contribution in [PR #14191](https://github.com/BerriAI/litellm/pull/14191) +* @kutsushitaneko made their first contribution in [PR #14171](https://github.com/BerriAI/litellm/pull/14171) +* @mjmendo made their first contribution in [PR #14176](https://github.com/BerriAI/litellm/pull/14176) +* @HarshavardhanK made their first contribution in [PR #14213](https://github.com/BerriAI/litellm/pull/14213) +* @eycjur made their first contribution in [PR #14207](https://github.com/BerriAI/litellm/pull/14207) +* @22mSqRi made their first contribution in [PR #14241](https://github.com/BerriAI/litellm/pull/14241) +* @onlylhf made their first contribution in [PR #14028](https://github.com/BerriAI/litellm/pull/14028) +* @btpemercier made their first contribution in [PR #11319](https://github.com/BerriAI/litellm/pull/11319) +* @tremlin made their first contribution in [PR #14287](https://github.com/BerriAI/litellm/pull/14287) +* @TobiMayr made their first contribution in [PR #14262](https://github.com/BerriAI/litellm/pull/14262) +* @Eitan1112 made their first contribution in [PR #14252](https://github.com/BerriAI/litellm/pull/14252) + +--- + +## **[Full Changelog](https://github.com/BerriAI/litellm/compare/v1.76.1-nightly...v1.76.3-nightly)** diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 6732ab6fdac..dfaa7b2bd96 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -464,6 +464,7 @@ const sidebars = { "providers/replicate", "providers/togetherai", "providers/v0", + "providers/vercel_ai_gateway", "providers/morph", "providers/lambda_ai", "providers/novita", @@ -483,6 +484,7 @@ const sidebars = { "providers/bytez", "providers/heroku", "providers/oci", + "providers/datarobot", ], }, { diff --git a/enterprise/litellm_enterprise/integrations/prometheus.py b/enterprise/litellm_enterprise/integrations/prometheus.py index a2d781fa1c4..efee1a7783e 100644 --- a/enterprise/litellm_enterprise/integrations/prometheus.py +++ b/enterprise/litellm_enterprise/integrations/prometheus.py @@ -95,13 +95,14 @@ class PrometheusLogger(CustomLogger): self.litellm_llm_api_time_to_first_token_metric = self._histogram_factory( "litellm_llm_api_time_to_first_token_metric", "Time to first token for a models LLM API call", - labelnames=[ - "model", - "hashed_api_key", - "api_key_alias", - "team", - "team_alias", - ], + # labelnames=[ + # "model", + # "hashed_api_key", + # "api_key_alias", + # "team", + # "team_alias", + # ], + labelnames=self.get_labels_for_metric("litellm_llm_api_time_to_first_token_metric"), buckets=LATENCY_BUCKETS, ) @@ -109,15 +110,7 @@ class PrometheusLogger(CustomLogger): self.litellm_spend_metric = self._counter_factory( "litellm_spend_metric", "Total spend on LLM requests", - labelnames=[ - "end_user", - "hashed_api_key", - "api_key_alias", - "model", - "team", - "team_alias", - "user", - ], + labelnames=self.get_labels_for_metric("litellm_spend_metric"), ) # Counter for total_output_tokens @@ -243,25 +236,18 @@ class PrometheusLogger(CustomLogger): labelnames=["api_provider"], ) - # Get all keys - _logged_llm_labels = [ - UserAPIKeyLabelNames.v2_LITELLM_MODEL_NAME.value, - UserAPIKeyLabelNames.MODEL_ID.value, - UserAPIKeyLabelNames.API_BASE.value, - UserAPIKeyLabelNames.API_PROVIDER.value, - ] - # Metric for deployment state self.litellm_deployment_state = self._gauge_factory( "litellm_deployment_state", "LLM Deployment Analytics - The state of the deployment: 0 = healthy, 1 = partial outage, 2 = complete outage", - labelnames=_logged_llm_labels, + labelnames=self.get_labels_for_metric("litellm_deployment_state") ) self.litellm_deployment_cooled_down = self._counter_factory( "litellm_deployment_cooled_down", "LLM Deployment Analytics - Number of times a deployment has been cooled down by LiteLLM load balancing logic. exception_status is the status of the exception that caused the deployment to be cooled down", - labelnames=_logged_llm_labels + [EXCEPTION_STATUS], + # labelnames=_logged_llm_labels + [EXCEPTION_STATUS], + labelnames=self.get_labels_for_metric("litellm_deployment_cooled_down") ) self.litellm_deployment_success_responses = self._counter_factory( @@ -327,6 +313,7 @@ class PrometheusLogger(CustomLogger): documentation="deprecated - use litellm_proxy_total_requests_metric. Total number of LLM calls to litellm - track total per API Key, team, user", labelnames=self.get_labels_for_metric("litellm_requests_metric"), ) + except Exception as e: print_verbose(f"Got exception on init prometheus client {str(e)}") raise e diff --git a/idna-3.10-py3-none-any.whl b/idna-3.10-py3-none-any.whl new file mode 100644 index 00000000000..52759bdd237 Binary files /dev/null and b/idna-3.10-py3-none-any.whl differ diff --git a/litellm/__init__.py b/litellm/__init__.py index 1908f1ee9f5..f6be2bc6f00 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -67,6 +67,7 @@ from litellm.constants import ( bedrock_embedding_models, known_tokenizer_config, BEDROCK_INVOKE_PROVIDERS_LITERAL, + BEDROCK_CONVERSE_MODELS, DEFAULT_MAX_TOKENS, DEFAULT_SOFT_BUDGET, DEFAULT_ALLOWED_FAILS, @@ -145,8 +146,11 @@ _custom_logger_compatible_callbacks_literal = Literal[ "aws_sqs", "vector_store_pre_call_hook", "dotprompt", + "cloudzero", ] -configured_cold_storage_logger: Optional[_custom_logger_compatible_callbacks_literal] = None +configured_cold_storage_logger: Optional[ + _custom_logger_compatible_callbacks_literal +] = None logged_real_time_event_types: Optional[Union[List[str], Literal["*"]]] = None _known_custom_logger_compatible_callbacks: List = list( get_args(_custom_logger_compatible_callbacks_literal) @@ -226,6 +230,7 @@ vertex_location: Optional[str] = None predibase_tenant_id: Optional[str] = None togetherai_api_key: Optional[str] = None cloudflare_api_key: Optional[str] = None +vercel_ai_gateway_key: Optional[str] = None baseten_key: Optional[str] = None llama_api_key: Optional[str] = None aleph_alpha_key: Optional[str] = None @@ -432,43 +437,10 @@ organization = None project = None config_path = None vertex_ai_safety_settings: Optional[dict] = None -BEDROCK_CONVERSE_MODELS = [ - "openai.gpt-oss-20b-1:0", - "openai.gpt-oss-120b-1:0", - "anthropic.claude-opus-4-1-20250805-v1:0", - "anthropic.claude-opus-4-20250514-v1:0", - "anthropic.claude-sonnet-4-20250514-v1:0", - "anthropic.claude-3-7-sonnet-20250219-v1:0", - "anthropic.claude-3-5-haiku-20241022-v1:0", - "anthropic.claude-3-5-sonnet-20241022-v2:0", - "anthropic.claude-3-5-sonnet-20240620-v1:0", - "anthropic.claude-3-opus-20240229-v1:0", - "anthropic.claude-3-sonnet-20240229-v1:0", - "anthropic.claude-3-haiku-20240307-v1:0", - "anthropic.claude-v2", - "anthropic.claude-v2:1", - "anthropic.claude-v1", - "anthropic.claude-instant-v1", - "ai21.jamba-instruct-v1:0", - "ai21.jamba-1-5-mini-v1:0", - "ai21.jamba-1-5-large-v1:0", - "meta.llama3-70b-instruct-v1:0", - "meta.llama3-8b-instruct-v1:0", - "meta.llama3-1-8b-instruct-v1:0", - "meta.llama3-1-70b-instruct-v1:0", - "meta.llama3-1-405b-instruct-v1:0", - "meta.llama3-70b-instruct-v1:0", - "mistral.mistral-large-2407-v1:0", - "mistral.mistral-large-2402-v1:0", - "mistral.mistral-small-2402-v1:0", - "meta.llama3-2-1b-instruct-v1:0", - "meta.llama3-2-3b-instruct-v1:0", - "meta.llama3-2-11b-instruct-v1:0", - "meta.llama3-2-90b-instruct-v1:0", -] ####### COMPLETION MODELS ################### -from typing import Set +from typing import Set + open_ai_chat_completion_models: Set = set() open_ai_text_completion_models: Set = set() cohere_models: Set = set() @@ -483,6 +455,7 @@ vertex_vision_models: Set = set() vertex_chat_models: Set = set() vertex_code_chat_models: Set = set() vertex_ai_image_models: Set = set() +vertex_ai_video_models: Set = set() vertex_text_models: Set = set() vertex_code_text_models: Set = set() vertex_embedding_models: Set = set() @@ -491,6 +464,7 @@ vertex_llama3_models: Set = set() vertex_deepseek_models: Set = set() vertex_ai_ai21_models: Set = set() vertex_mistral_models: Set = set() +vertex_openai_models: Set = set() ai21_models: Set = set() ai21_chat_models: Set = set() nlp_cloud_models: Set = set() @@ -544,6 +518,8 @@ hyperbolic_models: Set = set() recraft_models: Set = set() cometapi_models: Set = set() oci_models: Set = set() +vercel_ai_gateway_models: Set = set() +volcengine_models: Set = set() def is_bedrock_pricing_only_model(key: str) -> bool: @@ -601,6 +577,8 @@ def add_known_models(): empower_models.add(key) elif value.get("litellm_provider") == "openrouter": openrouter_models.add(key) + elif value.get("litellm_provider") == "vercel_ai_gateway": + vercel_ai_gateway_models.add(key) elif value.get("litellm_provider") == "datarobot": datarobot_models.add(key) elif value.get("litellm_provider") == "vertex_ai-text-models": @@ -635,6 +613,12 @@ def add_known_models(): elif value.get("litellm_provider") == "vertex_ai-image-models": key = key.replace("vertex_ai/", "") vertex_ai_image_models.add(key) + elif value.get("litellm_provider") == "vertex_ai-video-models": + key = key.replace("vertex_ai/", "") + vertex_ai_video_models.add(key) + elif value.get("litellm_provider") == "vertex_ai-openai_models": + key = key.replace("vertex_ai/", "") + vertex_openai_models.add(key) elif value.get("litellm_provider") == "ai21": if value.get("mode") == "chat": ai21_chat_models.add(key) @@ -748,6 +732,8 @@ def add_known_models(): cometapi_models.add(key) elif value.get("litellm_provider") == "oci": oci_models.add(key) + elif value.get("litellm_provider") == "volcengine": + volcengine_models.add(key) add_known_models() @@ -840,6 +826,8 @@ model_list = list( | cometapi_models | oci_models | heroku_models + | vercel_ai_gateway_models + | volcengine_models ) model_list_set = set(model_list) @@ -858,8 +846,14 @@ models_by_provider: dict = { "together_ai": together_ai_models, "baseten": baseten_models, "openrouter": openrouter_models, + "vercel_ai_gateway": vercel_ai_gateway_models, "datarobot": datarobot_models, - "vertex_ai": vertex_chat_models | vertex_text_models | vertex_anthropic_models | vertex_vision_models | vertex_language_models | vertex_deepseek_models, + "vertex_ai": vertex_chat_models + | vertex_text_models + | vertex_anthropic_models + | vertex_vision_models + | vertex_language_models + | vertex_deepseek_models, "ai21": ai21_models, "bedrock": bedrock_models | bedrock_converse_models, "petals": petals_models, @@ -914,6 +908,7 @@ models_by_provider: dict = { "recraft": recraft_models, "cometapi": cometapi_models, "oci": oci_models, + "volcengine": volcengine_models, } # mapping for those models which have larger equivalents @@ -1157,7 +1152,9 @@ 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.voyage.embedding.transformation_contextual import VoyageContextualEmbeddingConfig +from .llms.voyage.embedding.transformation_contextual import ( + VoyageContextualEmbeddingConfig, +) from .llms.infinity.embedding.transformation import InfinityEmbeddingConfig from .llms.azure_ai.chat.transformation import AzureAIStudioConfig from .llms.mistral.chat.transformation import MistralConfig @@ -1221,7 +1218,9 @@ from .llms.jina_ai.embedding.transformation import JinaAIEmbeddingConfig from .llms.xai.chat.transformation import XAIChatConfig from .llms.xai.common_utils import XAIModelInfo from .llms.aiml.chat.transformation import AIMLChatConfig -from .llms.volcengine import VolcEngineConfig +from .llms.volcengine.chat.transformation import ( + VolcEngineChatConfig as VolcEngineConfig, +) from .llms.codestral.completion.transformation import CodestralTextCompletionConfig from .llms.azure.azure import ( AzureOpenAIError, @@ -1254,6 +1253,7 @@ from .llms.oci.chat.transformation import OCIChatConfig from .llms.morph.chat.transformation import MorphChatConfig from .llms.lambda_ai.chat.transformation import LambdaAIChatConfig from .llms.hyperbolic.chat.transformation import HyperbolicChatConfig +from .llms.vercel_ai_gateway.chat.transformation import VercelAIGatewayConfig from .main import * # type: ignore from .integrations import * from .llms.custom_httpx.async_client_cleanup import close_litellm_async_clients @@ -1261,6 +1261,7 @@ from .exceptions import ( AuthenticationError, InvalidRequestError, BadRequestError, + ImageFetchError, NotFoundError, RateLimitError, ServiceUnavailableError, @@ -1285,7 +1286,6 @@ from .router import Router from .assistants.main import * from .batches.main import * from .images.main import * -from .vector_stores import * from .batch_completion.main import * # type: ignore from .rerank_api.main import * from .llms.anthropic.experimental_pass_through.messages.handler import * diff --git a/litellm/batches/main.py b/litellm/batches/main.py index 3ea0f95157f..0d250779da3 100644 --- a/litellm/batches/main.py +++ b/litellm/batches/main.py @@ -14,13 +14,15 @@ import asyncio import contextvars import os from functools import partial -from typing import Any, Coroutine, Dict, Literal, Optional, Union +from typing import Any, Coroutine, Dict, Literal, Optional, Union, cast import httpx import litellm from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj from litellm.llms.azure.batches.handler import AzureBatchesAPI +from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler +from litellm.llms.custom_httpx.llm_http_handler import BaseLLMHTTPHandler from litellm.llms.openai.openai import OpenAIBatchesAPI from litellm.llms.vertex_ai.batches.handler import VertexAIBatchPrediction from litellm.secret_managers.main import get_secret_str @@ -31,13 +33,19 @@ from litellm.types.llms.openai import ( RetrieveBatchRequest, ) from litellm.types.router import GenericLiteLLMParams -from litellm.types.utils import LiteLLMBatch -from litellm.utils import client, get_litellm_params, supports_httpx_timeout +from litellm.types.utils import LiteLLMBatch, LlmProviders +from litellm.utils import ( + ProviderConfigManager, + client, + get_litellm_params, + supports_httpx_timeout, +) ####### ENVIRONMENT VARIABLES ################### openai_batches_instance = OpenAIBatchesAPI() azure_batches_instance = AzureBatchesAPI() vertex_ai_batches_instance = VertexAIBatchPrediction(gcs_bucket_name="") +base_llm_http_handler = BaseLLMHTTPHandler() ################################################# @@ -46,7 +54,7 @@ async def acreate_batch( completion_window: Literal["24h"], endpoint: Literal["/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, - custom_llm_provider: Literal["openai", "azure", "vertex_ai"] = "openai", + custom_llm_provider: Literal["openai", "azure", "vertex_ai", "bedrock"] = "openai", metadata: Optional[Dict[str, str]] = None, extra_headers: Optional[Dict[str, str]] = None, extra_body: Optional[Dict[str, str]] = None, @@ -94,7 +102,7 @@ def create_batch( completion_window: Literal["24h"], endpoint: Literal["/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, - custom_llm_provider: Literal["openai", "azure", "vertex_ai"] = "openai", + custom_llm_provider: Literal["openai", "azure", "vertex_ai", "bedrock"] = "openai", metadata: Optional[Dict[str, str]] = None, extra_headers: Optional[Dict[str, str]] = None, extra_body: Optional[Dict[str, str]] = None, @@ -111,8 +119,8 @@ def create_batch( proxy_server_request = kwargs.get("proxy_server_request", None) model_info = kwargs.get("model_info", None) _is_async = kwargs.pop("acreate_batch", False) is True - litellm_params = get_litellm_params(**kwargs) - litellm_logging_obj: LiteLLMLoggingObj = kwargs.get("litellm_logging_obj", None) + litellm_params = dict(GenericLiteLLMParams(**kwargs)) + litellm_logging_obj: LiteLLMLoggingObj = cast(LiteLLMLoggingObj, kwargs.get("litellm_logging_obj", None)) ### TIMEOUT LOGIC ### timeout = optional_params.timeout or kwargs.get("request_timeout", 600) or 600 litellm_logging_obj.update_environment_variables( @@ -142,6 +150,7 @@ def create_batch( timeout = float(timeout) # type: ignore elif timeout is None: timeout = 600.0 + _create_batch_request = CreateBatchRequest( completion_window=completion_window, @@ -151,6 +160,27 @@ def create_batch( extra_headers=extra_headers, extra_body=extra_body, ) + provider_config = ProviderConfigManager.get_provider_batches_config( + model="", + provider=LlmProviders(custom_llm_provider), + ) + if provider_config is not None: + response = base_llm_http_handler.create_batch( + provider_config=provider_config, + litellm_params=litellm_params, + create_batch_data=_create_batch_request, + headers=extra_headers or {}, + api_base=optional_params.api_base, + api_key=optional_params.api_key, + logging_obj=litellm_logging_obj, + _is_async=_is_async, + client=client + if client is not None + and isinstance(client, (HTTPHandler, AsyncHTTPHandler)) + else None, + timeout=timeout, + ) + return response api_base: Optional[str] = None if custom_llm_provider == "openai": # for deepinfra/perplexity/anyscale/groq we check in get_llm_provider and pass in the api base from there @@ -322,20 +352,21 @@ def retrieve_batch( """ try: optional_params = GenericLiteLLMParams(**kwargs) - litellm_logging_obj: LiteLLMLoggingObj = kwargs.get("litellm_logging_obj", None) + litellm_logging_obj: Optional[LiteLLMLoggingObj] = kwargs.get("litellm_logging_obj", None) ### TIMEOUT LOGIC ### timeout = optional_params.timeout or kwargs.get("request_timeout", 600) or 600 litellm_params = get_litellm_params( custom_llm_provider=custom_llm_provider, **kwargs, ) - litellm_logging_obj.update_environment_variables( - model=None, - user=None, - optional_params=optional_params.model_dump(), - litellm_params=litellm_params, - custom_llm_provider=custom_llm_provider, - ) + if litellm_logging_obj is not None: + litellm_logging_obj.update_environment_variables( + model=None, + user=None, + optional_params=optional_params.model_dump(), + litellm_params=litellm_params, + custom_llm_provider=custom_llm_provider, + ) if ( timeout is not None diff --git a/litellm/constants.py b/litellm/constants.py index 86f9f4fedc1..75c25d9ea9e 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -14,6 +14,9 @@ DEFAULT_S3_BATCH_SIZE = int(os.getenv("DEFAULT_S3_BATCH_SIZE", 512)) DEFAULT_SQS_FLUSH_INTERVAL_SECONDS = int( os.getenv("DEFAULT_SQS_FLUSH_INTERVAL_SECONDS", 10) ) +DEFAULT_NUM_WORKERS_LITELLM_PROXY = int( + os.getenv("DEFAULT_NUM_WORKERS_LITELLM_PROXY", os.cpu_count() or 4) +) DEFAULT_SQS_BATCH_SIZE = int(os.getenv("DEFAULT_SQS_BATCH_SIZE", 512)) SQS_SEND_MESSAGE_ACTION = "SendMessage" SQS_API_VERSION = "2012-11-05" @@ -48,6 +51,23 @@ SINGLE_DEPLOYMENT_TRAFFIC_FAILURE_THRESHOLD = int( DEFAULT_REASONING_EFFORT_DISABLE_THINKING_BUDGET = int( os.getenv("DEFAULT_REASONING_EFFORT_DISABLE_THINKING_BUDGET", 0) ) + +# Gemini model-specific minimal thinking budget constants +DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH = int( + os.getenv("DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH", 1) +) +DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_PRO = int( + os.getenv("DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_PRO", 128) +) +DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH_LITE = int( + os.getenv("DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH_LITE", 512) +) + +# Generic fallback for unknown models +DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET = int( + os.getenv("DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET", 128) +) + DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET = int( os.getenv("DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET", 1024) ) @@ -157,6 +177,7 @@ NON_LLM_CONNECTION_TIMEOUT = int( os.getenv("NON_LLM_CONNECTION_TIMEOUT", 15) ) # timeout for adjacent services (e.g. jwt auth) MAX_EXCEPTION_MESSAGE_LENGTH = int(os.getenv("MAX_EXCEPTION_MESSAGE_LENGTH", 2000)) +MAX_STRING_LENGTH_PROMPT_IN_DB = int(os.getenv("MAX_STRING_LENGTH_PROMPT_IN_DB", 1000)) BEDROCK_MAX_POLICY_SIZE = int(os.getenv("BEDROCK_MAX_POLICY_SIZE", 75)) REPLICATE_POLLING_DELAY_SECONDS = float( os.getenv("REPLICATE_POLLING_DELAY_SECONDS", 0.5) @@ -289,6 +310,7 @@ LITELLM_CHAT_PROVIDERS = [ "oci", "morph", "lambda_ai", + "vercel_ai_gateway", ] LITELLM_EMBEDDING_PROVIDERS_SUPPORTING_INPUT_ARRAY_OF_TOKENS = [ @@ -393,6 +415,7 @@ DEFAULT_CHAT_COMPLETION_PARAM_VALUES = { "reasoning_effort": None, "thinking": None, "web_search_options": None, + "safety_identifier": None, } openai_compatible_endpoints: List = [ @@ -421,6 +444,7 @@ openai_compatible_endpoints: List = [ "https://api.morphllm.com/v1", "https://api.lambda.ai/v1", "https://api.hyperbolic.xyz/v1", + "https://ai-gateway.vercel.sh/v1", ] @@ -463,6 +487,7 @@ openai_compatible_providers: List = [ "morph", "lambda_ai", "hyperbolic", + "vercel_ai_gateway", "aiml", ] openai_text_completion_compatible_providers: List = ( @@ -487,227 +512,247 @@ _openai_like_providers: List = [ "watsonx", ] # private helper. similar to openai but require some custom auth / endpoint handling, so can't use the openai sdk # well supported replicate llms -replicate_models: set = set([ - # llama replicate supported LLMs - "replicate/llama-2-70b-chat:2796ee9483c3fd7aa2e171d38f4ca12251a30609463dcfd4cd76703f22e96cdf", - "a16z-infra/llama-2-13b-chat:2a7f981751ec7fdf87b5b91ad4db53683a98082e9ff7bfd12c8cd5ea85980a52", - "meta/codellama-13b:1c914d844307b0588599b8393480a3ba917b660c7e9dfae681542b5325f228db", - # Vicuna - "replicate/vicuna-13b:6282abe6a492de4145d7bb601023762212f9ddbbe78278bd6771c8b3b2f2a13b", - "joehoover/instructblip-vicuna13b:c4c54e3c8c97cd50c2d2fec9be3b6065563ccf7d43787fb99f84151b867178fe", - # Flan T-5 - "daanelson/flan-t5-large:ce962b3f6792a57074a601d3979db5839697add2e4e02696b3ced4c022d4767f", - # Others - "replicate/dolly-v2-12b:ef0e1aefc61f8e096ebe4db6b2bacc297daf2ef6899f0f7e001ec445893500e5", - "replit/replit-code-v1-3b:b84f4c074b807211cd75e3e8b1589b6399052125b4c27106e43d47189e8415ad", -]) +replicate_models: set = set( + [ + # llama replicate supported LLMs + "replicate/llama-2-70b-chat:2796ee9483c3fd7aa2e171d38f4ca12251a30609463dcfd4cd76703f22e96cdf", + "a16z-infra/llama-2-13b-chat:2a7f981751ec7fdf87b5b91ad4db53683a98082e9ff7bfd12c8cd5ea85980a52", + "meta/codellama-13b:1c914d844307b0588599b8393480a3ba917b660c7e9dfae681542b5325f228db", + # Vicuna + "replicate/vicuna-13b:6282abe6a492de4145d7bb601023762212f9ddbbe78278bd6771c8b3b2f2a13b", + "joehoover/instructblip-vicuna13b:c4c54e3c8c97cd50c2d2fec9be3b6065563ccf7d43787fb99f84151b867178fe", + # Flan T-5 + "daanelson/flan-t5-large:ce962b3f6792a57074a601d3979db5839697add2e4e02696b3ced4c022d4767f", + # Others + "replicate/dolly-v2-12b:ef0e1aefc61f8e096ebe4db6b2bacc297daf2ef6899f0f7e001ec445893500e5", + "replit/replit-code-v1-3b:b84f4c074b807211cd75e3e8b1589b6399052125b4c27106e43d47189e8415ad", + ] +) -clarifai_models: set = set([ - "clarifai/meta.Llama-3.Llama-3-8B-Instruct", - "clarifai/gcp.generate.gemma-1_1-7b-it", - "clarifai/mistralai.completion.mixtral-8x22B", - "clarifai/cohere.generate.command-r-plus", - "clarifai/databricks.drbx.dbrx-instruct", - "clarifai/mistralai.completion.mistral-large", - "clarifai/mistralai.completion.mistral-medium", - "clarifai/mistralai.completion.mistral-small", - "clarifai/mistralai.completion.mixtral-8x7B-Instruct-v0_1", - "clarifai/gcp.generate.gemma-2b-it", - "clarifai/gcp.generate.gemma-7b-it", - "clarifai/deci.decilm.deciLM-7B-instruct", - "clarifai/mistralai.completion.mistral-7B-Instruct", - "clarifai/gcp.generate.gemini-pro", - "clarifai/anthropic.completion.claude-v1", - "clarifai/anthropic.completion.claude-instant-1_2", - "clarifai/anthropic.completion.claude-instant", - "clarifai/anthropic.completion.claude-v2", - "clarifai/anthropic.completion.claude-2_1", - "clarifai/meta.Llama-2.codeLlama-70b-Python", - "clarifai/meta.Llama-2.codeLlama-70b-Instruct", - "clarifai/openai.completion.gpt-3_5-turbo-instruct", - "clarifai/meta.Llama-2.llama2-7b-chat", - "clarifai/meta.Llama-2.llama2-13b-chat", - "clarifai/meta.Llama-2.llama2-70b-chat", - "clarifai/openai.chat-completion.gpt-4-turbo", - "clarifai/microsoft.text-generation.phi-2", - "clarifai/meta.Llama-2.llama2-7b-chat-vllm", - "clarifai/upstage.solar.solar-10_7b-instruct", - "clarifai/openchat.openchat.openchat-3_5-1210", - "clarifai/togethercomputer.stripedHyena.stripedHyena-Nous-7B", - "clarifai/gcp.generate.text-bison", - "clarifai/meta.Llama-2.llamaGuard-7b", - "clarifai/fblgit.una-cybertron.una-cybertron-7b-v2", - "clarifai/openai.chat-completion.GPT-4", - "clarifai/openai.chat-completion.GPT-3_5-turbo", - "clarifai/ai21.complete.Jurassic2-Grande", - "clarifai/ai21.complete.Jurassic2-Grande-Instruct", - "clarifai/ai21.complete.Jurassic2-Jumbo-Instruct", - "clarifai/ai21.complete.Jurassic2-Jumbo", - "clarifai/ai21.complete.Jurassic2-Large", - "clarifai/cohere.generate.cohere-generate-command", - "clarifai/wizardlm.generate.wizardCoder-Python-34B", - "clarifai/wizardlm.generate.wizardLM-70B", - "clarifai/tiiuae.falcon.falcon-40b-instruct", - "clarifai/togethercomputer.RedPajama.RedPajama-INCITE-7B-Chat", - "clarifai/gcp.generate.code-gecko", - "clarifai/gcp.generate.code-bison", - "clarifai/mistralai.completion.mistral-7B-OpenOrca", - "clarifai/mistralai.completion.openHermes-2-mistral-7B", - "clarifai/wizardlm.generate.wizardLM-13B", - "clarifai/huggingface-research.zephyr.zephyr-7B-alpha", - "clarifai/wizardlm.generate.wizardCoder-15B", - "clarifai/microsoft.text-generation.phi-1_5", - "clarifai/databricks.Dolly-v2.dolly-v2-12b", - "clarifai/bigcode.code.StarCoder", - "clarifai/salesforce.xgen.xgen-7b-8k-instruct", - "clarifai/mosaicml.mpt.mpt-7b-instruct", - "clarifai/anthropic.completion.claude-3-opus", - "clarifai/anthropic.completion.claude-3-sonnet", - "clarifai/gcp.generate.gemini-1_5-pro", - "clarifai/gcp.generate.imagen-2", - "clarifai/salesforce.blip.general-english-image-caption-blip-2", -]) +clarifai_models: set = set( + [ + "clarifai/meta.Llama-3.Llama-3-8B-Instruct", + "clarifai/gcp.generate.gemma-1_1-7b-it", + "clarifai/mistralai.completion.mixtral-8x22B", + "clarifai/cohere.generate.command-r-plus", + "clarifai/databricks.drbx.dbrx-instruct", + "clarifai/mistralai.completion.mistral-large", + "clarifai/mistralai.completion.mistral-medium", + "clarifai/mistralai.completion.mistral-small", + "clarifai/mistralai.completion.mixtral-8x7B-Instruct-v0_1", + "clarifai/gcp.generate.gemma-2b-it", + "clarifai/gcp.generate.gemma-7b-it", + "clarifai/deci.decilm.deciLM-7B-instruct", + "clarifai/mistralai.completion.mistral-7B-Instruct", + "clarifai/gcp.generate.gemini-pro", + "clarifai/anthropic.completion.claude-v1", + "clarifai/anthropic.completion.claude-instant-1_2", + "clarifai/anthropic.completion.claude-instant", + "clarifai/anthropic.completion.claude-v2", + "clarifai/anthropic.completion.claude-2_1", + "clarifai/meta.Llama-2.codeLlama-70b-Python", + "clarifai/meta.Llama-2.codeLlama-70b-Instruct", + "clarifai/openai.completion.gpt-3_5-turbo-instruct", + "clarifai/meta.Llama-2.llama2-7b-chat", + "clarifai/meta.Llama-2.llama2-13b-chat", + "clarifai/meta.Llama-2.llama2-70b-chat", + "clarifai/openai.chat-completion.gpt-4-turbo", + "clarifai/microsoft.text-generation.phi-2", + "clarifai/meta.Llama-2.llama2-7b-chat-vllm", + "clarifai/upstage.solar.solar-10_7b-instruct", + "clarifai/openchat.openchat.openchat-3_5-1210", + "clarifai/togethercomputer.stripedHyena.stripedHyena-Nous-7B", + "clarifai/gcp.generate.text-bison", + "clarifai/meta.Llama-2.llamaGuard-7b", + "clarifai/fblgit.una-cybertron.una-cybertron-7b-v2", + "clarifai/openai.chat-completion.GPT-4", + "clarifai/openai.chat-completion.GPT-3_5-turbo", + "clarifai/ai21.complete.Jurassic2-Grande", + "clarifai/ai21.complete.Jurassic2-Grande-Instruct", + "clarifai/ai21.complete.Jurassic2-Jumbo-Instruct", + "clarifai/ai21.complete.Jurassic2-Jumbo", + "clarifai/ai21.complete.Jurassic2-Large", + "clarifai/cohere.generate.cohere-generate-command", + "clarifai/wizardlm.generate.wizardCoder-Python-34B", + "clarifai/wizardlm.generate.wizardLM-70B", + "clarifai/tiiuae.falcon.falcon-40b-instruct", + "clarifai/togethercomputer.RedPajama.RedPajama-INCITE-7B-Chat", + "clarifai/gcp.generate.code-gecko", + "clarifai/gcp.generate.code-bison", + "clarifai/mistralai.completion.mistral-7B-OpenOrca", + "clarifai/mistralai.completion.openHermes-2-mistral-7B", + "clarifai/wizardlm.generate.wizardLM-13B", + "clarifai/huggingface-research.zephyr.zephyr-7B-alpha", + "clarifai/wizardlm.generate.wizardCoder-15B", + "clarifai/microsoft.text-generation.phi-1_5", + "clarifai/databricks.Dolly-v2.dolly-v2-12b", + "clarifai/bigcode.code.StarCoder", + "clarifai/salesforce.xgen.xgen-7b-8k-instruct", + "clarifai/mosaicml.mpt.mpt-7b-instruct", + "clarifai/anthropic.completion.claude-3-opus", + "clarifai/anthropic.completion.claude-3-sonnet", + "clarifai/gcp.generate.gemini-1_5-pro", + "clarifai/gcp.generate.imagen-2", + "clarifai/salesforce.blip.general-english-image-caption-blip-2", + ] +) -huggingface_models: set = set([ - "meta-llama/Llama-2-7b-hf", - "meta-llama/Llama-2-7b-chat-hf", - "meta-llama/Llama-2-13b-hf", - "meta-llama/Llama-2-13b-chat-hf", - "meta-llama/Llama-2-70b-hf", - "meta-llama/Llama-2-70b-chat-hf", - "meta-llama/Llama-2-7b", - "meta-llama/Llama-2-7b-chat", - "meta-llama/Llama-2-13b", - "meta-llama/Llama-2-13b-chat", - "meta-llama/Llama-2-70b", - "meta-llama/Llama-2-70b-chat", -]) # these have been tested on extensively. But by default all text2text-generation and text-generation models are supported by liteLLM. - https://docs.litellm.ai/docs/providers -empower_models = set([ - "empower/empower-functions", - "empower/empower-functions-small", -]) +huggingface_models: set = set( + [ + "meta-llama/Llama-2-7b-hf", + "meta-llama/Llama-2-7b-chat-hf", + "meta-llama/Llama-2-13b-hf", + "meta-llama/Llama-2-13b-chat-hf", + "meta-llama/Llama-2-70b-hf", + "meta-llama/Llama-2-70b-chat-hf", + "meta-llama/Llama-2-7b", + "meta-llama/Llama-2-7b-chat", + "meta-llama/Llama-2-13b", + "meta-llama/Llama-2-13b-chat", + "meta-llama/Llama-2-70b", + "meta-llama/Llama-2-70b-chat", + ] +) # these have been tested on extensively. But by default all text2text-generation and text-generation models are supported by liteLLM. - https://docs.litellm.ai/docs/providers +empower_models = set( + [ + "empower/empower-functions", + "empower/empower-functions-small", + ] +) -together_ai_models: set = set([ - # llama llms - chat - "togethercomputer/llama-2-70b-chat", - # llama llms - language / instruct - "togethercomputer/llama-2-70b", - "togethercomputer/LLaMA-2-7B-32K", - "togethercomputer/Llama-2-7B-32K-Instruct", - "togethercomputer/llama-2-7b", - # falcon llms - "togethercomputer/falcon-40b-instruct", - "togethercomputer/falcon-7b-instruct", - # alpaca - "togethercomputer/alpaca-7b", - # chat llms - "HuggingFaceH4/starchat-alpha", - # code llms - "togethercomputer/CodeLlama-34b", - "togethercomputer/CodeLlama-34b-Instruct", - "togethercomputer/CodeLlama-34b-Python", - "defog/sqlcoder", - "NumbersStation/nsql-llama-2-7B", - "WizardLM/WizardCoder-15B-V1.0", - "WizardLM/WizardCoder-Python-34B-V1.0", - # language llms - "NousResearch/Nous-Hermes-Llama2-13b", - "Austism/chronos-hermes-13b", - "upstage/SOLAR-0-70b-16bit", - "WizardLM/WizardLM-70B-V1.0", -]) - # supports all together ai models, just pass in the model id e.g. completion(model="together_computer/replit_code_3b",...) +together_ai_models: set = set( + [ + # llama llms - chat + "togethercomputer/llama-2-70b-chat", + # llama llms - language / instruct + "togethercomputer/llama-2-70b", + "togethercomputer/LLaMA-2-7B-32K", + "togethercomputer/Llama-2-7B-32K-Instruct", + "togethercomputer/llama-2-7b", + # falcon llms + "togethercomputer/falcon-40b-instruct", + "togethercomputer/falcon-7b-instruct", + # alpaca + "togethercomputer/alpaca-7b", + # chat llms + "HuggingFaceH4/starchat-alpha", + # code llms + "togethercomputer/CodeLlama-34b", + "togethercomputer/CodeLlama-34b-Instruct", + "togethercomputer/CodeLlama-34b-Python", + "defog/sqlcoder", + "NumbersStation/nsql-llama-2-7B", + "WizardLM/WizardCoder-15B-V1.0", + "WizardLM/WizardCoder-Python-34B-V1.0", + # language llms + "NousResearch/Nous-Hermes-Llama2-13b", + "Austism/chronos-hermes-13b", + "upstage/SOLAR-0-70b-16bit", + "WizardLM/WizardLM-70B-V1.0", + ] +) +# supports all together ai models, just pass in the model id e.g. completion(model="together_computer/replit_code_3b",...) -baseten_models: set = set([ - "qvv0xeq", - "q841o8w", - "31dxrj3", -]) # FALCON 7B # WizardLM # Mosaic ML +baseten_models: set = set( + [ + "qvv0xeq", + "q841o8w", + "31dxrj3", + ] +) # FALCON 7B # WizardLM # Mosaic ML -featherless_ai_models: set = set([ - "featherless-ai/Qwerky-72B", - "featherless-ai/Qwerky-QwQ-32B", - "Qwen/Qwen2.5-72B-Instruct", - "all-hands/openhands-lm-32b-v0.1", - "Qwen/Qwen2.5-Coder-32B-Instruct", - "deepseek-ai/DeepSeek-V3-0324", - "mistralai/Mistral-Small-24B-Instruct-2501", - "mistralai/Mistral-Nemo-Instruct-2407", - "ProdeusUnity/Stellar-Odyssey-12b-v0.0", -]) +featherless_ai_models: set = set( + [ + "featherless-ai/Qwerky-72B", + "featherless-ai/Qwerky-QwQ-32B", + "Qwen/Qwen2.5-72B-Instruct", + "all-hands/openhands-lm-32b-v0.1", + "Qwen/Qwen2.5-Coder-32B-Instruct", + "deepseek-ai/DeepSeek-V3-0324", + "mistralai/Mistral-Small-24B-Instruct-2501", + "mistralai/Mistral-Nemo-Instruct-2407", + "ProdeusUnity/Stellar-Odyssey-12b-v0.0", + ] +) -nebius_models: set = set([ - # deepseek models - "deepseek-ai/DeepSeek-R1-0528", - "deepseek-ai/DeepSeek-V3-0324", - "deepseek-ai/DeepSeek-V3", - "deepseek-ai/DeepSeek-R1", - "deepseek-ai/DeepSeek-R1-Distill-Llama-70B", - # google models - "google/gemma-2-2b-it", - "google/gemma-2-9b-it-fast", - # llama models - "meta-llama/Llama-3.3-70B-Instruct", - "meta-llama/Meta-Llama-3.1-70B-Instruct", - "meta-llama/Meta-Llama-3.1-8B-Instruct", - "meta-llama/Meta-Llama-3.1-405B-Instruct", - "NousResearch/Hermes-3-Llama-405B", - # microsoft models - "microsoft/phi-4", - # mistral models - "mistralai/Mistral-Nemo-Instruct-2407", - "mistralai/Devstral-Small-2505", - # moonshot models - "moonshotai/Kimi-K2-Instruct", - # nvidia models - "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1", - "nvidia/Llama-3_3-Nemotron-Super-49B-v1", - # openai models - "openai/gpt-oss-120b", - "openai/gpt-oss-20b", - # qwen models - "Qwen/Qwen3-Coder-480B-A35B-Instruct", - "Qwen/Qwen3-235B-A22B-Instruct-2507", - "Qwen/Qwen3-235B-A22B", - "Qwen/Qwen3-30B-A3B", - "Qwen/Qwen3-32B", - "Qwen/Qwen3-14B", - "Qwen/Qwen3-4B-fast", - "Qwen/Qwen2.5-Coder-7B", - "Qwen/Qwen2.5-Coder-32B-Instruct", - "Qwen/Qwen2.5-72B-Instruct", - "Qwen/QwQ-32B", - "Qwen/Qwen3-30B-A3B-Thinking-2507", - "Qwen/Qwen3-30B-A3B-Instruct-2507", - # zai models - "zai-org/GLM-4.5", - "zai-org/GLM-4.5-Air", - # other models - "aaditya/Llama3-OpenBioLLM-70B", - "ProdeusUnity/Stellar-Odyssey-12b-v0.0", - "all-hands/openhands-lm-32b-v0.1", -]) +nebius_models: set = set( + [ + # deepseek models + "deepseek-ai/DeepSeek-R1-0528", + "deepseek-ai/DeepSeek-V3-0324", + "deepseek-ai/DeepSeek-V3", + "deepseek-ai/DeepSeek-R1", + "deepseek-ai/DeepSeek-R1-Distill-Llama-70B", + # google models + "google/gemma-2-2b-it", + "google/gemma-2-9b-it-fast", + # llama models + "meta-llama/Llama-3.3-70B-Instruct", + "meta-llama/Meta-Llama-3.1-70B-Instruct", + "meta-llama/Meta-Llama-3.1-8B-Instruct", + "meta-llama/Meta-Llama-3.1-405B-Instruct", + "NousResearch/Hermes-3-Llama-405B", + # microsoft models + "microsoft/phi-4", + # mistral models + "mistralai/Mistral-Nemo-Instruct-2407", + "mistralai/Devstral-Small-2505", + # moonshot models + "moonshotai/Kimi-K2-Instruct", + # nvidia models + "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1", + "nvidia/Llama-3_3-Nemotron-Super-49B-v1", + # openai models + "openai/gpt-oss-120b", + "openai/gpt-oss-20b", + # qwen models + "Qwen/Qwen3-Coder-480B-A35B-Instruct", + "Qwen/Qwen3-235B-A22B-Instruct-2507", + "Qwen/Qwen3-235B-A22B", + "Qwen/Qwen3-30B-A3B", + "Qwen/Qwen3-32B", + "Qwen/Qwen3-14B", + "Qwen/Qwen3-4B-fast", + "Qwen/Qwen2.5-Coder-7B", + "Qwen/Qwen2.5-Coder-32B-Instruct", + "Qwen/Qwen2.5-72B-Instruct", + "Qwen/QwQ-32B", + "Qwen/Qwen3-30B-A3B-Thinking-2507", + "Qwen/Qwen3-30B-A3B-Instruct-2507", + # zai models + "zai-org/GLM-4.5", + "zai-org/GLM-4.5-Air", + # other models + "aaditya/Llama3-OpenBioLLM-70B", + "ProdeusUnity/Stellar-Odyssey-12b-v0.0", + "all-hands/openhands-lm-32b-v0.1", + ] +) -dashscope_models: set = set([ - "qwen-turbo", - "qwen-plus", - "qwen-max", - "qwen-turbo-latest", - "qwen-plus-latest", - "qwen-max-latest", - "qwq-32b", - "qwen3-235b-a22b", - "qwen3-32b", - "qwen3-30b-a3b", -]) +dashscope_models: set = set( + [ + "qwen-turbo", + "qwen-plus", + "qwen-max", + "qwen-turbo-latest", + "qwen-plus-latest", + "qwen-max-latest", + "qwq-32b", + "qwen3-235b-a22b", + "qwen3-32b", + "qwen3-30b-a3b", + ] +) -nebius_embedding_models: set = set([ - "BAAI/bge-en-icl", - "BAAI/bge-multilingual-gemma2", - "intfloat/e5-mistral-7b-instruct", -]) +nebius_embedding_models: set = set( + [ + "BAAI/bge-en-icl", + "BAAI/bge-multilingual-gemma2", + "intfloat/e5-mistral-7b-instruct", + ] +) BEDROCK_INVOKE_PROVIDERS_LITERAL = Literal[ "cohere", @@ -721,21 +766,61 @@ BEDROCK_INVOKE_PROVIDERS_LITERAL = Literal[ "deepseek_r1", ] +BEDROCK_CONVERSE_MODELS = [ + "openai.gpt-oss-20b-1:0", + "openai.gpt-oss-120b-1:0", + "anthropic.claude-opus-4-1-20250805-v1:0", + "anthropic.claude-opus-4-20250514-v1:0", + "anthropic.claude-sonnet-4-20250514-v1:0", + "anthropic.claude-3-7-sonnet-20250219-v1:0", + "anthropic.claude-3-5-haiku-20241022-v1:0", + "anthropic.claude-3-5-sonnet-20241022-v2:0", + "anthropic.claude-3-5-sonnet-20240620-v1:0", + "anthropic.claude-3-opus-20240229-v1:0", + "anthropic.claude-3-sonnet-20240229-v1:0", + "anthropic.claude-3-haiku-20240307-v1:0", + "anthropic.claude-v2", + "anthropic.claude-v2:1", + "anthropic.claude-v1", + "anthropic.claude-instant-v1", + "ai21.jamba-instruct-v1:0", + "ai21.jamba-1-5-mini-v1:0", + "ai21.jamba-1-5-large-v1:0", + "meta.llama3-70b-instruct-v1:0", + "meta.llama3-8b-instruct-v1:0", + "meta.llama3-1-8b-instruct-v1:0", + "meta.llama3-1-70b-instruct-v1:0", + "meta.llama3-1-405b-instruct-v1:0", + "meta.llama3-70b-instruct-v1:0", + "mistral.mistral-large-2407-v1:0", + "mistral.mistral-large-2402-v1:0", + "mistral.mistral-small-2402-v1:0", + "meta.llama3-2-1b-instruct-v1:0", + "meta.llama3-2-3b-instruct-v1:0", + "meta.llama3-2-11b-instruct-v1:0", + "meta.llama3-2-90b-instruct-v1:0", +] + + open_ai_embedding_models: set = set(["text-embedding-ada-002"]) -cohere_embedding_models: set = set([ - "embed-v4.0", - "embed-english-v3.0", - "embed-english-light-v3.0", - "embed-multilingual-v3.0", - "embed-english-v2.0", - "embed-english-light-v2.0", - "embed-multilingual-v2.0", -]) -bedrock_embedding_models: set = set([ - "amazon.titan-embed-text-v1", - "cohere.embed-english-v3", - "cohere.embed-multilingual-v3", -]) +cohere_embedding_models: set = set( + [ + "embed-v4.0", + "embed-english-v3.0", + "embed-english-light-v3.0", + "embed-multilingual-v3.0", + "embed-english-v2.0", + "embed-english-light-v2.0", + "embed-multilingual-v2.0", + ] +) +bedrock_embedding_models: set = set( + [ + "amazon.titan-embed-text-v1", + "cohere.embed-english-v3", + "cohere.embed-multilingual-v3", + ] +) known_tokenizer_config = { "mistralai/Mistral-7B-Instruct-v0.1": { @@ -806,6 +891,9 @@ AZURE_STORAGE_MSFT_VERSION = "2019-07-07" PROMETHEUS_BUDGET_METRICS_REFRESH_INTERVAL_MINUTES = int( os.getenv("PROMETHEUS_BUDGET_METRICS_REFRESH_INTERVAL_MINUTES", 5) ) +CLOUDZERO_EXPORT_INTERVAL_MINUTES = int( + os.getenv("CLOUDZERO_EXPORT_INTERVAL_MINUTES", 60) +) MCP_TOOL_NAME_PREFIX = "mcp_tool" MAXIMUM_TRACEBACK_LINES_TO_LOG = int(os.getenv("MAXIMUM_TRACEBACK_LINES_TO_LOG", 100)) @@ -860,6 +948,8 @@ LITELLM_CLI_SESSION_TOKEN_PREFIX = "litellm-session-token" ########################### DB CRON JOB NAMES ########################### DB_SPEND_UPDATE_JOB_NAME = "db_spend_update_job" PROMETHEUS_EMIT_BUDGET_METRICS_JOB_NAME = "prometheus_emit_budget_metrics" +CLOUDZERO_EXPORT_USAGE_DATA_JOB_NAME = "cloudzero_export_usage_data" +CLOUDZERO_MAX_FETCHED_DATA_RECORDS = int(os.getenv("CLOUDZERO_MAX_FETCHED_DATA_RECORDS", 50000)) SPEND_LOG_CLEANUP_JOB_NAME = "spend_log_cleanup" SPEND_LOG_RUN_LOOPS = int(os.getenv("SPEND_LOG_RUN_LOOPS", 500)) SPEND_LOG_CLEANUP_BATCH_SIZE = int(os.getenv("SPEND_LOG_CLEANUP_BATCH_SIZE", 1000)) diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index 6c6a09cd73e..01f3e2472f8 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -57,6 +57,7 @@ from litellm.llms.vertex_ai.cost_calculator import ( cost_per_token as google_cost_per_token, ) from litellm.llms.vertex_ai.cost_calculator import cost_router as google_cost_router +from litellm.llms.xai.cost_calculator import cost_per_token as xai_cost_per_token from litellm.responses.utils import ResponseAPILoggingUtils from litellm.types.llms.openai import ( HttpxBinaryResponseContent, @@ -341,6 +342,8 @@ def cost_per_token( # noqa: PLR0915 return deepseek_cost_per_token(model=model, usage=usage_block) elif custom_llm_provider == "perplexity": return perplexity_cost_per_token(model=model, usage=usage_block) + elif custom_llm_provider == "xai": + return xai_cost_per_token(model=model, usage=usage_block) else: model_info = _cached_get_model_info_helper( model=model, custom_llm_provider=custom_llm_provider @@ -675,9 +678,9 @@ def completion_cost( # noqa: PLR0915 or isinstance(completion_response, dict) ): # tts returns a custom class if isinstance(completion_response, dict): - usage_obj: Optional[Union[dict, Usage]] = ( - completion_response.get("usage", {}) - ) + usage_obj: Optional[ + Union[dict, Usage] + ] = completion_response.get("usage", {}) else: usage_obj = getattr(completion_response, "usage", {}) if isinstance(usage_obj, BaseModel) and not _is_known_usage_objects( @@ -1279,7 +1282,9 @@ class BaseTokenUsageProcessor: not hasattr(combined, "completion_tokens_details") or not combined.completion_tokens_details ): - combined.completion_tokens_details = CompletionTokensDetailsWrapper() + combined.completion_tokens_details = ( + CompletionTokensDetailsWrapper() + ) # Check what keys exist in the model's completion_tokens_details for attr in usage.completion_tokens_details.model_fields: diff --git a/litellm/exceptions.py b/litellm/exceptions.py index 153230518cc..77fb9c1faef 100644 --- a/litellm/exceptions.py +++ b/litellm/exceptions.py @@ -153,6 +153,29 @@ class BadRequestError(openai.BadRequestError): # type: ignore _message += f", LiteLLM Max Retries: {self.max_retries}" return _message +class ImageFetchError(BadRequestError): + def __init__( + self, + message, + model=None, + llm_provider=None, + response: Optional[httpx.Response] = None, + litellm_debug_info: Optional[str] = None, + max_retries: Optional[int] = None, + num_retries: Optional[int] = None, + body: Optional[dict] = None, + ): + super().__init__( + message=message, + model=model, + llm_provider=llm_provider, + response=response, + litellm_debug_info=litellm_debug_info, + max_retries=max_retries, + num_retries=num_retries, + body=body, + ) + class UnprocessableEntityError(openai.UnprocessableEntityError): # type: ignore def __init__( diff --git a/litellm/files/main.py b/litellm/files/main.py index 5d0dc05771a..299e52895bf 100644 --- a/litellm/files/main.py +++ b/litellm/files/main.py @@ -50,7 +50,7 @@ vertex_ai_files_instance = VertexAIFilesHandler() async def acreate_file( file: FileTypes, purpose: Literal["assistants", "batch", "fine-tune"], - custom_llm_provider: Literal["openai", "azure", "vertex_ai"] = "openai", + custom_llm_provider: Literal["openai", "azure", "vertex_ai", "bedrock"] = "openai", extra_headers: Optional[Dict[str, str]] = None, extra_body: Optional[Dict[str, str]] = None, **kwargs, @@ -94,7 +94,7 @@ async def acreate_file( def create_file( file: FileTypes, purpose: Literal["assistants", "batch", "fine-tune"], - custom_llm_provider: Optional[Literal["openai", "azure", "vertex_ai"]] = None, + custom_llm_provider: Optional[Literal["openai", "azure", "vertex_ai", "bedrock"]] = None, extra_headers: Optional[Dict[str, str]] = None, extra_body: Optional[Dict[str, str]] = None, **kwargs, @@ -109,7 +109,7 @@ def create_file( try: _is_async = kwargs.pop("acreate_file", False) is True optional_params = GenericLiteLLMParams(**kwargs) - litellm_params_dict = get_litellm_params(**kwargs) + litellm_params_dict = dict(**kwargs) logging_obj = cast( Optional[LiteLLMLoggingObj], kwargs.get("litellm_logging_obj") ) diff --git a/litellm/google_genai/adapters/handler.py b/litellm/google_genai/adapters/handler.py index 1f575f27591..dcf707ebd51 100644 --- a/litellm/google_genai/adapters/handler.py +++ b/litellm/google_genai/adapters/handler.py @@ -37,6 +37,10 @@ class GenerateContentToCompletionHandler: completion_kwargs: Dict[str, Any] = dict(completion_request) + # feed metadata for custom callback + if extra_kwargs is not None and "metadata" in extra_kwargs: + completion_kwargs["metadata"] = extra_kwargs["metadata"] + if stream: completion_kwargs["stream"] = stream diff --git a/litellm/images/main.py b/litellm/images/main.py index 4993a48c724..2a8b62bce24 100644 --- a/litellm/images/main.py +++ b/litellm/images/main.py @@ -90,12 +90,12 @@ async def aimage_generation(*args, **kwargs) -> ImageResponse: response = init_response elif asyncio.iscoroutine(init_response): response = await init_response # type: ignore - + if response is None: raise ValueError( "Unable to get Image Response. Please pass a valid llm_provider." ) - + return response except Exception as e: custom_llm_provider = custom_llm_provider or "openai" @@ -108,6 +108,8 @@ async def aimage_generation(*args, **kwargs) -> ImageResponse: ) +# fmt: off + # Overload for when aimg_generation=True (returns Coroutine) @overload def image_generation( @@ -119,7 +121,6 @@ def image_generation( size: Optional[str] = None, style: Optional[str] = None, user: Optional[str] = None, - input_fidelity: Optional[str] = None, timeout=600, # default to 10 minutes api_key: Optional[str] = None, api_base: Optional[str] = None, @@ -128,10 +129,11 @@ def image_generation( *, aimg_generation: Literal[True], **kwargs, -) -> Coroutine[Any, Any, ImageResponse]: +) -> Coroutine[Any, Any, ImageResponse]: ... + # Overload for when aimg_generation=False or not specified (returns ImageResponse) @overload def image_generation( @@ -143,7 +145,6 @@ def image_generation( size: Optional[str] = None, style: Optional[str] = None, user: Optional[str] = None, - input_fidelity: Optional[str] = None, timeout=600, # default to 10 minutes api_key: Optional[str] = None, api_base: Optional[str] = None, @@ -152,9 +153,11 @@ def image_generation( *, aimg_generation: Literal[False] = False, **kwargs, -) -> ImageResponse: +) -> ImageResponse: ... +# fmt: on + @client def image_generation( # noqa: PLR0915 @@ -166,7 +169,6 @@ def image_generation( # noqa: PLR0915 size: Optional[str] = None, style: Optional[str] = None, user: Optional[str] = None, - input_fidelity: Optional[str] = None, timeout=600, # default to 10 minutes api_key: Optional[str] = None, api_base: Optional[str] = None, @@ -174,9 +176,9 @@ def image_generation( # noqa: PLR0915 custom_llm_provider=None, **kwargs, ) -> Union[ - ImageResponse, - Coroutine[Any, Any, ImageResponse], - ]: + ImageResponse, + Coroutine[Any, Any, ImageResponse], +]: """ Maps the https://api.openai.com/v1/images/generations endpoint. @@ -227,7 +229,6 @@ def image_generation( # noqa: PLR0915 "quality", "size", "style", - "input_fidelity", ] litellm_params = all_litellm_params default_params = openai_params + litellm_params @@ -255,7 +256,6 @@ def image_generation( # noqa: PLR0915 size=size, style=style, user=user, - input_fidelity=input_fidelity, custom_llm_provider=custom_llm_provider, provider_config=image_generation_config, **non_default_params, @@ -344,8 +344,10 @@ def image_generation( # noqa: PLR0915 litellm.LlmProviders.GEMINI, ): if image_generation_config is None: - raise ValueError(f"image generation config is not supported for {custom_llm_provider}") - + raise ValueError( + f"image generation config is not supported for {custom_llm_provider}" + ) + return llm_http_handler.image_generation_handler( api_key=api_key, model=model, @@ -360,6 +362,7 @@ def image_generation( # noqa: PLR0915 ) elif custom_llm_provider == "azure_ai": from litellm.llms.azure_ai.common_utils import AzureFoundryModelInfo + api_base = AzureFoundryModelInfo.get_api_base(api_base) api_key = AzureFoundryModelInfo.get_api_key(api_key) if extra_headers is not None: @@ -420,7 +423,7 @@ def image_generation( # noqa: PLR0915 aimg_generation=aimg_generation, client=client, api_base=api_base, - api_key=api_key + api_key=api_key, ) elif custom_llm_provider == "vertex_ai": vertex_ai_project = ( @@ -705,7 +708,7 @@ def image_edit( litellm_call_id: Optional[str] = kwargs.get("litellm_call_id", None) _is_async = kwargs.pop("async_call", False) is True - #add images / or return a single image + # add images / or return a single image images = image if isinstance(image, list) else [image] # get llm provider logic @@ -716,11 +719,11 @@ def image_edit( ) # get provider config - image_edit_provider_config: Optional[ - BaseImageEditConfig - ] = ProviderConfigManager.get_provider_image_edit_config( - model=model, - provider=litellm.LlmProviders(custom_llm_provider), + image_edit_provider_config: Optional[BaseImageEditConfig] = ( + ProviderConfigManager.get_provider_image_edit_config( + model=model, + provider=litellm.LlmProviders(custom_llm_provider), + ) ) if image_edit_provider_config is None: diff --git a/litellm/integrations/SlackAlerting/slack_alerting.py b/litellm/integrations/SlackAlerting/slack_alerting.py index 41db4a551bd..7da38e193b6 100644 --- a/litellm/integrations/SlackAlerting/slack_alerting.py +++ b/litellm/integrations/SlackAlerting/slack_alerting.py @@ -805,9 +805,9 @@ class SlackAlerting(CustomBatchLogger): ### UNIQUE CACHE KEY ### cache_key = provider + region_name - outage_value: Optional[ProviderRegionOutageModel] = ( - await self.internal_usage_cache.async_get_cache(key=cache_key) - ) + outage_value: Optional[ + ProviderRegionOutageModel + ] = await self.internal_usage_cache.async_get_cache(key=cache_key) if ( getattr(exception, "status_code", None) is None @@ -1367,12 +1367,13 @@ Model Info: # Get the current timestamp current_time = datetime.now().strftime("%H:%M:%S") _proxy_base_url = os.getenv("PROXY_BASE_URL", None) + # Use .name if it's an enum, otherwise use as is + alert_type_name = getattr(alert_type, 'name', alert_type) + alert_type_formatted = f"Alert type: `{alert_type_name}`" if alert_type == "daily_reports" or alert_type == "new_model_added": - formatted_message = message + formatted_message = alert_type_formatted + message else: - formatted_message = ( - f"Level: `{level}`\nTimestamp: `{current_time}`\n\nMessage: {message}" - ) + formatted_message = f"{alert_type_formatted}\nLevel: `{level}`\nTimestamp: `{current_time}`\n\nMessage: {message}" if kwargs: for key, value in kwargs.items(): @@ -1388,9 +1389,9 @@ Model Info: self.alert_to_webhook_url is not None and alert_type in self.alert_to_webhook_url ): - slack_webhook_url: Optional[Union[str, List[str]]] = ( - self.alert_to_webhook_url[alert_type] - ) + slack_webhook_url: Optional[ + Union[str, List[str]] + ] = self.alert_to_webhook_url[alert_type] elif self.default_webhook_url is not None: slack_webhook_url = self.default_webhook_url else: diff --git a/litellm/integrations/braintrust_logging.py b/litellm/integrations/braintrust_logging.py index 531da933fcc..5bc6afb6dbc 100644 --- a/litellm/integrations/braintrust_logging.py +++ b/litellm/integrations/braintrust_logging.py @@ -1,13 +1,11 @@ # What is this? ## Log success + failure events to Braintrust -import copy import os from datetime import datetime from typing import Dict, Optional import httpx -from pydantic import BaseModel import litellm from litellm import verbose_logger @@ -24,7 +22,6 @@ API_BASE = "https://api.braintrustdata.com/v1" def get_utc_datetime(): import datetime as dt - from datetime import datetime if hasattr(dt, "UTC"): return datetime.now(dt.UTC) # type: ignore @@ -45,9 +42,9 @@ class BraintrustLogger(CustomLogger): "Authorization": "Bearer " + self.api_key, "Content-Type": "application/json", } - self._project_id_cache: Dict[ - str, str - ] = {} # Cache mapping project names to IDs + self._project_id_cache: Dict[str, str] = ( + {} + ) # Cache mapping project names to IDs self.global_braintrust_http_handler = get_async_httpx_client( llm_provider=httpxSpecialProvider.LoggingCallback ) @@ -108,43 +105,6 @@ class BraintrustLogger(CustomLogger): except httpx.HTTPStatusError as e: raise Exception(f"Failed to register project: {e.response.text}") - @staticmethod - def add_metadata_from_header(litellm_params: dict, metadata: dict) -> dict: - """ - Adds metadata from proxy request headers to Braintrust logging if keys start with "braintrust_" - and overwrites litellm_params.metadata if already included. - - For example if you want to append your trace to an existing `trace_id` via header, send - `headers: { ..., langfuse_existing_trace_id: your-existing-trace-id }` via proxy request. - """ - if litellm_params is None: - return metadata - - if litellm_params.get("proxy_server_request") is None: - return metadata - - if metadata is None: - metadata = {} - - proxy_headers = ( - litellm_params.get("proxy_server_request", {}).get("headers", {}) or {} - ) - - for metadata_param_key in proxy_headers: - if metadata_param_key.startswith("braintrust"): - trace_param_key = metadata_param_key.replace("braintrust", "", 1) - if trace_param_key in metadata: - verbose_logger.warning( - f"Overwriting Braintrust `{trace_param_key}` from request header" - ) - else: - verbose_logger.debug( - f"Found Braintrust `{trace_param_key}` in request header" - ) - metadata[trace_param_key] = proxy_headers.get(metadata_param_key) - - return metadata - async def create_default_project_and_experiment(self): project = await self.global_braintrust_http_handler.post( f"{self.api_base}/project", headers=self.headers, json={"name": "litellm"} @@ -169,7 +129,9 @@ class BraintrustLogger(CustomLogger): verbose_logger.debug("REACHES BRAINTRUST SUCCESS") try: litellm_call_id = kwargs.get("litellm_call_id") + standard_logging_object = kwargs.get("standard_logging_object", {}) prompt = {"messages": kwargs.get("messages")} + output = None choices = [] if response_obj is not None and ( @@ -192,33 +154,13 @@ class BraintrustLogger(CustomLogger): ): output = response_obj["data"] - litellm_params = kwargs.get("litellm_params", {}) - metadata = ( - litellm_params.get("metadata", {}) or {} - ) # if litellm_params['metadata'] == None - metadata = self.add_metadata_from_header(litellm_params, metadata) - clean_metadata = {} - try: - metadata = copy.deepcopy( - metadata - ) # Avoid modifying the original metadata - except Exception: - new_metadata = {} - for key, value in metadata.items(): - if ( - isinstance(value, list) - or isinstance(value, dict) - or isinstance(value, str) - or isinstance(value, int) - or isinstance(value, float) - ): - new_metadata[key] = copy.deepcopy(value) - metadata = new_metadata + litellm_params = kwargs.get("litellm_params", {}) or {} + dynamic_metadata = litellm_params.get("metadata", {}) or {} # Get project_id from metadata or create default if needed - project_id = metadata.get("project_id") + project_id = dynamic_metadata.get("project_id") if project_id is None: - project_name = metadata.get("project_name") + project_name = dynamic_metadata.get("project_name") project_id = ( self.get_project_id_sync(project_name) if project_name else None ) @@ -229,8 +171,9 @@ class BraintrustLogger(CustomLogger): project_id = self.default_project_id tags = [] - if isinstance(metadata, dict): - for key, value in metadata.items(): + + if isinstance(dynamic_metadata, dict): + for key, value in dynamic_metadata.items(): # generate langfuse tags - Default Tags sent to Langfuse from LiteLLM Proxy if ( litellm.langfuse_default_tags is not None @@ -239,25 +182,12 @@ class BraintrustLogger(CustomLogger): ): tags.append(f"{key}:{value}") - # clean litellm metadata before logging - if key in [ - "headers", - "endpoint", - "caching_groups", - "previous_models", - ]: - continue - else: - clean_metadata[key] = value + if ( + isinstance(value, str) and key not in standard_logging_object + ): # support logging dynamic metadata to braintrust + standard_logging_object[key] = value cost = kwargs.get("response_cost", None) - if cost is not None: - clean_metadata["litellm_response_cost"] = cost - - # metadata.model is required for braintrust to calculate the "Estimated cost" metric - litellm_model = kwargs.get("model", None) - if litellm_model is not None: - clean_metadata["model"] = litellm_model metrics: Optional[dict] = None usage_obj = getattr(response_obj, "usage", None) @@ -275,12 +205,12 @@ class BraintrustLogger(CustomLogger): } # Allow metadata override for span name - span_name = metadata.get("span_name", "Chat Completion") - + span_name = dynamic_metadata.get("span_name", "Chat Completion") + request_data = { "id": litellm_call_id, "input": prompt["messages"], - "metadata": clean_metadata, + "metadata": standard_logging_object, "tags": tags, "span_attributes": {"name": span_name, "type": "llm"}, } @@ -312,6 +242,7 @@ class BraintrustLogger(CustomLogger): verbose_logger.debug("REACHES BRAINTRUST SUCCESS") try: litellm_call_id = kwargs.get("litellm_call_id") + standard_logging_object = kwargs.get("standard_logging_object", {}) prompt = {"messages": kwargs.get("messages")} output = None choices = [] @@ -336,32 +267,12 @@ class BraintrustLogger(CustomLogger): output = response_obj["data"] litellm_params = kwargs.get("litellm_params", {}) - metadata = ( - litellm_params.get("metadata", {}) or {} - ) # if litellm_params['metadata'] == None - metadata = self.add_metadata_from_header(litellm_params, metadata) - clean_metadata = {} - new_metadata = {} - for key, value in metadata.items(): - if ( - isinstance(value, list) - or isinstance(value, str) - or isinstance(value, int) - or isinstance(value, float) - ): - new_metadata[key] = value - elif isinstance(value, BaseModel): - new_metadata[key] = value.model_dump_json() - elif isinstance(value, dict): - for k, v in value.items(): - if isinstance(v, datetime): - value[k] = v.isoformat() - new_metadata[key] = value + dynamic_metadata = litellm_params.get("metadata", {}) or {} # Get project_id from metadata or create default if needed - project_id = metadata.get("project_id") + project_id = dynamic_metadata.get("project_id") if project_id is None: - project_name = metadata.get("project_name") + project_name = dynamic_metadata.get("project_name") project_id = ( await self.get_project_id_async(project_name) if project_name @@ -374,8 +285,9 @@ class BraintrustLogger(CustomLogger): project_id = self.default_project_id tags = [] - if isinstance(metadata, dict): - for key, value in metadata.items(): + + if isinstance(dynamic_metadata, dict): + for key, value in dynamic_metadata.items(): # generate langfuse tags - Default Tags sent to Langfuse from LiteLLM Proxy if ( litellm.langfuse_default_tags is not None @@ -384,25 +296,12 @@ class BraintrustLogger(CustomLogger): ): tags.append(f"{key}:{value}") - # clean litellm metadata before logging - if key in [ - "headers", - "endpoint", - "caching_groups", - "previous_models", - ]: - continue - else: - clean_metadata[key] = value + if ( + isinstance(value, str) and key not in standard_logging_object + ): # support logging dynamic metadata to braintrust + standard_logging_object[key] = value cost = kwargs.get("response_cost", None) - if cost is not None: - clean_metadata["litellm_response_cost"] = cost - - # metadata.model is required for braintrust to calculate the "Estimated cost" metric - litellm_model = kwargs.get("model", None) - if litellm_model is not None: - clean_metadata["model"] = litellm_model metrics: Optional[dict] = None usage_obj = getattr(response_obj, "usage", None) @@ -430,13 +329,13 @@ class BraintrustLogger(CustomLogger): ) # Allow metadata override for span name - span_name = metadata.get("span_name", "Chat Completion") - + span_name = dynamic_metadata.get("span_name", "Chat Completion") + request_data = { "id": litellm_call_id, "input": prompt["messages"], "output": output, - "metadata": clean_metadata, + "metadata": standard_logging_object, "tags": tags, "span_attributes": {"name": span_name, "type": "llm"}, } diff --git a/litellm/integrations/cloudzero/cloudzero.py b/litellm/integrations/cloudzero/cloudzero.py index 85aa1679732..ab4ec234bf0 100644 --- a/litellm/integrations/cloudzero/cloudzero.py +++ b/litellm/integrations/cloudzero/cloudzero.py @@ -1,14 +1,15 @@ -import asyncio import os -from datetime import datetime, timedelta -from typing import Optional +from datetime import datetime +from typing import TYPE_CHECKING, Any, List, Optional, cast +import litellm from litellm._logging import verbose_logger from litellm.integrations.custom_logger import CustomLogger -from .cz_stream_api import CloudZeroStreamer -from .database import LiteLLMDatabase -from .transform import CBFTransformer +if TYPE_CHECKING: + from apscheduler.schedulers.asyncio import AsyncIOScheduler +else: + AsyncIOScheduler = Any class CloudZeroLogger(CustomLogger): @@ -29,20 +30,80 @@ class CloudZeroLogger(CustomLogger): self.api_key = api_key or os.getenv("CLOUDZERO_API_KEY") self.connection_id = connection_id or os.getenv("CLOUDZERO_CONNECTION_ID") self.timezone = timezone or os.getenv("CLOUDZERO_TIMEZONE", "UTC") + verbose_logger.debug(f"CloudZero Logger initialized with connection ID: {self.connection_id}, timezone: {self.timezone}") - async def export_usage_data(self, target_hour: datetime, limit: Optional[int] = 1000, operation: str = "replace_hourly"): + async def initialize_cloudzero_export_job(self): """ - Exports the usage data for a specific hour to CloudZero. + Handler for initializing CloudZero export job. - - Reads spend logs from the DB for the specified hour + Runs when CloudZero logger starts up. + + - If redis cache is available, we use the pod lock manager to acquire a lock and export the data. + - Ensures only one pod exports the data at a time. + - If redis cache is not available, we export the data directly. + """ + from litellm.constants import ( + CLOUDZERO_EXPORT_USAGE_DATA_JOB_NAME, + ) + from litellm.proxy.proxy_server import proxy_logging_obj + pod_lock_manager = proxy_logging_obj.db_spend_update_writer.pod_lock_manager + + # if using redis, ensure only one pod exports the data at a time + if pod_lock_manager and pod_lock_manager.redis_cache: + if await pod_lock_manager.acquire_lock( + cronjob_id=CLOUDZERO_EXPORT_USAGE_DATA_JOB_NAME + ): + try: + await self._hourly_usage_data_export() + finally: + await pod_lock_manager.release_lock( + cronjob_id=CLOUDZERO_EXPORT_USAGE_DATA_JOB_NAME + ) + else: + # if not using redis, export the data directly + await self._hourly_usage_data_export() + + async def _hourly_usage_data_export(self): + """ + Exports the hourly usage data to CloudZero. + + Start time: 1 hour ago + End time: current time + """ + from datetime import timedelta, timezone + + from litellm.constants import CLOUDZERO_MAX_FETCHED_DATA_RECORDS + current_time_utc = datetime.now(timezone.utc) + one_hour_ago_utc = current_time_utc - timedelta(hours=1) + await self.export_usage_data( + limit=CLOUDZERO_MAX_FETCHED_DATA_RECORDS, + operation="replace_hourly", + start_time_utc=one_hour_ago_utc, + end_time_utc=current_time_utc + ) + + + async def export_usage_data( + self, + limit: Optional[int] = None, + operation: str = "replace_hourly", + start_time_utc: Optional[datetime] = None, + end_time_utc: Optional[datetime] = None + ): + """ + Exports the usage data to CloudZero. + + - Reads data from the DB - Transforms the data to the CloudZero format - Sends the data to CloudZero Args: - target_hour: The specific hour to export data for - limit: Optional limit on number of records to export (default: 1000) + limit: Optional limit on number of records to export operation: CloudZero operation type ("replace_hourly" or "sum") """ + from litellm.integrations.cloudzero.cz_stream_api import CloudZeroStreamer + from litellm.integrations.cloudzero.database import LiteLLMDatabase + from litellm.integrations.cloudzero.transform import CBFTransformer try: verbose_logger.debug("CloudZero Logger: Starting usage data export") @@ -52,11 +113,27 @@ class CloudZeroLogger(CustomLogger): "CloudZero configuration missing. Please set CLOUDZERO_API_KEY and CLOUDZERO_CONNECTION_ID environment variables." ) - # Fetch and transform data using helper - cbf_data = await self._fetch_cbf_data_for_hour(target_hour, limit) + # Initialize database connection and load data + database = LiteLLMDatabase() + verbose_logger.debug("CloudZero Logger: Loading usage data from database") + data = await database.get_usage_data( + limit=limit, + start_time_utc=start_time_utc, + end_time_utc=end_time_utc + ) + + if data.is_empty(): + verbose_logger.info("CloudZero Logger: No usage data found to export") + return + + verbose_logger.debug(f"CloudZero Logger: Processing {len(data)} records") + + # Transform data to CloudZero CBF format + transformer = CBFTransformer() + cbf_data = transformer.transform(data) if cbf_data.is_empty(): - verbose_logger.info("CloudZero Logger: No usage data found to export") + verbose_logger.warning("CloudZero Logger: No valid data after transformation") return # Send data to CloudZero @@ -75,60 +152,86 @@ class CloudZeroLogger(CustomLogger): verbose_logger.error(f"CloudZero Logger: Error exporting usage data: {str(e)}") raise - async def _fetch_cbf_data_for_hour(self, target_hour: datetime, limit: Optional[int] = 1000): + async def dry_run_export_usage_data(self, limit: Optional[int] = 10000): """ - Helper method to fetch usage data for a specific hour and transform it to CloudZero CBF format. + Returns the data that would be exported to CloudZero without actually sending it. Args: - target_hour: The specific hour to fetch data for - limit: Optional limit on number of records to fetch (default: 1000) + limit: Limit number of records to display (default: 10000) Returns: - CBF formatted data ready for CloudZero ingestion - """ - # Initialize database connection and load data - database = LiteLLMDatabase() - verbose_logger.debug(f"CloudZero Logger: Loading spend logs for hour {target_hour}") - data = await database.get_usage_data_for_hour(target_hour=target_hour, limit=limit) - - if data.is_empty(): - verbose_logger.info("CloudZero Logger: No usage data found for the specified hour") - return data # Return empty data - - verbose_logger.debug(f"CloudZero Logger: Processing {len(data)} records") - - # Transform data to CloudZero CBF format - transformer = CBFTransformer() - cbf_data = transformer.transform(data) - - if cbf_data.is_empty(): - verbose_logger.warning("CloudZero Logger: No valid data after transformation") - - return cbf_data - - async def dry_run_export_usage_data(self, target_hour: datetime, limit: Optional[int] = 1000): - """ - Only prints the spend logs data for a specific hour that would be exported to CloudZero. - - Args: - target_hour: The specific hour to export data for - limit: Limit number of records to display (default: 1000) + dict: Contains usage_data, cbf_data, and summary statistics """ + from litellm.integrations.cloudzero.database import LiteLLMDatabase + from litellm.integrations.cloudzero.transform import CBFTransformer try: verbose_logger.debug("CloudZero Logger: Starting dry run export") - # Fetch and transform data using helper - cbf_data = await self._fetch_cbf_data_for_hour(target_hour, limit) + # Initialize database connection and load data + database = LiteLLMDatabase() + verbose_logger.debug("CloudZero Logger: Loading usage data for dry run") + data = await database.get_usage_data(limit=limit) + + if data.is_empty(): + verbose_logger.warning("CloudZero Dry Run: No usage data found") + return { + "usage_data": [], + "cbf_data": [], + "summary": { + "total_records": 0, + "total_cost": 0, + "total_tokens": 0, + "unique_accounts": 0, + "unique_services": 0 + } + } + + verbose_logger.debug(f"CloudZero Dry Run: Processing {len(data)} records...") + + # Convert usage data to dict format for response + usage_data_sample = data.head(50).to_dicts() # Return first 50 rows + + # Transform data to CloudZero CBF format + transformer = CBFTransformer() + cbf_data = transformer.transform(data) if cbf_data.is_empty(): - verbose_logger.warning("CloudZero Dry Run: No usage data found") - return + verbose_logger.warning("CloudZero Dry Run: No valid data after transformation") + return { + "usage_data": usage_data_sample, + "cbf_data": [], + "summary": { + "total_records": len(usage_data_sample), + "total_cost": sum(row.get('spend', 0) for row in usage_data_sample), + "total_tokens": sum(row.get('prompt_tokens', 0) + row.get('completion_tokens', 0) for row in usage_data_sample), + "unique_accounts": 0, + "unique_services": 0 + } + } - # Display the transformed data on screen - self._display_cbf_data_on_screen(cbf_data) + # Convert CBF data to dict format for response + cbf_data_dict = cbf_data.to_dicts() + + # Calculate summary statistics + total_cost = sum(record.get('cost/cost', 0) for record in cbf_data_dict) + unique_accounts = len(set(record.get('resource/account', '') for record in cbf_data_dict if record.get('resource/account'))) + unique_services = len(set(record.get('resource/service', '') for record in cbf_data_dict if record.get('resource/service'))) + total_tokens = sum(record.get('usage/amount', 0) for record in cbf_data_dict) verbose_logger.info(f"CloudZero Logger: Dry run completed for {len(cbf_data)} records") + return { + "usage_data": usage_data_sample, + "cbf_data": cbf_data_dict, + "summary": { + "total_records": len(cbf_data_dict), + "total_cost": total_cost, + "total_tokens": total_tokens, + "unique_accounts": unique_accounts, + "unique_services": unique_services + } + } + except Exception as e: verbose_logger.error(f"CloudZero Logger: Error in dry run export: {str(e)}") verbose_logger.error(f"CloudZero Dry Run Error: {str(e)}") @@ -155,6 +258,11 @@ class CloudZeroLogger(CustomLogger): cbf_table = Table(show_header=True, header_style="bold cyan", box=SIMPLE, padding=(0, 1)) cbf_table.add_column("time/usage_start", style="blue", no_wrap=False) cbf_table.add_column("cost/cost", style="green", justify="right", no_wrap=False) + cbf_table.add_column("entity_type", style="magenta", justify="right", no_wrap=False) + cbf_table.add_column("entity_id", style="magenta", justify="right", no_wrap=False) + cbf_table.add_column("team_id", style="cyan", no_wrap=False) + cbf_table.add_column("team_alias", style="cyan", no_wrap=False) + cbf_table.add_column("api_key_alias", style="yellow", no_wrap=False) cbf_table.add_column("usage/amount", style="yellow", justify="right", no_wrap=False) cbf_table.add_column("resource/id", style="magenta", no_wrap=False) cbf_table.add_column("resource/service", style="cyan", no_wrap=False) @@ -170,10 +278,20 @@ class CloudZeroLogger(CustomLogger): resource_service = str(record.get('resource/service', 'N/A')) resource_account = str(record.get('resource/account', 'N/A')) resource_region = str(record.get('resource/region', 'N/A')) + entity_type = str(record.get('entity_type', 'N/A')) + entity_id = str(record.get('entity_id', 'N/A')) + team_id = str(record.get('resource/tag:team_id', 'N/A')) + team_alias = str(record.get('resource/tag:team_alias', 'N/A')) + api_key_alias = str(record.get('resource/tag:api_key_alias', 'N/A')) cbf_table.add_row( time_usage_start, cost_cost, + entity_type, + entity_id, + team_id, + team_alias, + api_key_alias, usage_amount, resource_id, resource_service, @@ -199,55 +317,33 @@ class CloudZeroLogger(CustomLogger): console.print(f" Unique Services: {unique_services}") console.print("\n[dim]💡 This is the CloudZero CBF format ready for AnyCost ingestion[/dim]") + + @staticmethod + async def init_cloudzero_background_job(scheduler: AsyncIOScheduler): + """ + Initialize the CloudZero background job. - async def init_background_job(self, redis_cache=None): + Starts the background job that exports the usage data to CloudZero every hour. """ - Initialize a background job that exports usage data every hour. - Uses PodLockManager to ensure only one instance runs the export at a time. + from litellm.constants import CLOUDZERO_EXPORT_INTERVAL_MINUTES + from litellm.integrations.custom_logger import CustomLogger - Args: - redis_cache: Redis cache instance for pod locking - """ - from litellm.proxy.db.db_transaction_queue.pod_lock_manager import ( - PodLockManager, + + prometheus_loggers: List[CustomLogger] = ( + litellm.logging_callback_manager.get_custom_loggers_for_type( + callback_type=CloudZeroLogger + ) ) - - lock_manager = PodLockManager(redis_cache=redis_cache) - cronjob_id = "cloudzero_hourly_export" - - async def hourly_export_task(): - while True: - try: - # Calculate the previous completed hour - now = datetime.utcnow() - target_hour = now.replace(minute=0, second=0, microsecond=0) - # Export data for the previous hour to ensure all data is available - target_hour = target_hour - timedelta(hours=1) - - # Try to acquire lock - lock_acquired = await lock_manager.acquire_lock(cronjob_id) - - if lock_acquired: - try: - verbose_logger.info(f"CloudZero Background Job: Starting export for hour {target_hour}") - await self.export_usage_data(target_hour) - verbose_logger.info(f"CloudZero Background Job: Completed export for hour {target_hour}") - finally: - # Always release the lock - await lock_manager.release_lock(cronjob_id) - else: - verbose_logger.debug("CloudZero Background Job: Another instance is already running the export") - - # Wait until the next hour - next_hour = (datetime.utcnow() + timedelta(hours=1)).replace(minute=0, second=0, microsecond=0) - sleep_seconds = (next_hour - datetime.utcnow()).total_seconds() - await asyncio.sleep(sleep_seconds) - - except Exception as e: - verbose_logger.error(f"CloudZero Background Job: Error in hourly export task: {str(e)}") - # Sleep for 5 minutes before retrying on error - await asyncio.sleep(300) - - # Start the background task - asyncio.create_task(hourly_export_task()) - verbose_logger.debug("CloudZero Background Job: Initialized hourly export task") \ No newline at end of file + # we need to get the initialized prometheus logger instance(s) and call logger.initialize_remaining_budget_metrics() on them + verbose_logger.debug("found %s cloudzero loggers", len(prometheus_loggers)) + if len(prometheus_loggers) > 0: + cloudzero_logger = cast(CloudZeroLogger, prometheus_loggers[0]) + verbose_logger.debug( + "Initializing remaining budget metrics as a cron job executing every %s minutes" + % CLOUDZERO_EXPORT_INTERVAL_MINUTES + ) + scheduler.add_job( + cloudzero_logger.initialize_cloudzero_export_job, + "interval", + minutes=CLOUDZERO_EXPORT_INTERVAL_MINUTES + ) \ No newline at end of file diff --git a/litellm/integrations/cloudzero/cz_resource_names.py b/litellm/integrations/cloudzero/cz_resource_names.py index 44147f9c210..f1098d20381 100644 --- a/litellm/integrations/cloudzero/cz_resource_names.py +++ b/litellm/integrations/cloudzero/cz_resource_names.py @@ -17,11 +17,16 @@ """CloudZero Resource Names (CZRN) generation and validation for LiteLLM resources.""" import re +from enum import Enum from typing import Any, cast import litellm +class CZEntityType(str, Enum): + TEAM = "team" + + class CZRNGenerator: """Generate CloudZero Resource Names (CZRNs) for LiteLLM resources.""" @@ -49,8 +54,8 @@ class CZRNGenerator: region = 'cross-region' # Use the actual entity_id (team_id or user_id) as the owner account - entity_id = row.get('entity_id', 'unknown') - owner_account_id = self._normalize_component(entity_id) + team_id = row.get('team_id', 'unknown') + owner_account_id = self._normalize_component(team_id) resource_type = 'llm-usage' diff --git a/litellm/integrations/cloudzero/database.py b/litellm/integrations/cloudzero/database.py index 6d12c5cfbd9..71b4125ed75 100644 --- a/litellm/integrations/cloudzero/database.py +++ b/litellm/integrations/cloudzero/database.py @@ -12,14 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# CHANGELOG: 2025-07-23 - Added support for using LiteLLM_SpendLogs table for CBF mapping (ishaan-jaff) # CHANGELOG: 2025-01-19 - Refactored to use daily spend tables for proper CBF mapping (erik.peterson) # CHANGELOG: 2025-01-19 - Migrated from pandas to polars for database operations (erik.peterson) # CHANGELOG: 2025-01-19 - Initial database module for LiteLLM data extraction (erik.peterson) """Database connection and data extraction for LiteLLM.""" -from datetime import datetime, timedelta +from datetime import datetime from typing import Any, Dict, Optional import polars as pl @@ -37,61 +36,88 @@ class LiteLLMDatabase: ) return prisma_client - async def get_usage_data_for_hour(self, target_hour: datetime, limit: Optional[int] = 1000) -> pl.DataFrame: - """Retrieve spend logs for a specific hour from LiteLLM_SpendLogs table with batching.""" + async def get_usage_data( + self, + limit: Optional[int] = None, + start_time_utc: Optional[datetime] = None, + end_time_utc: Optional[datetime] = None + ) -> pl.DataFrame: + """Retrieve usage data from LiteLLM daily user spend table.""" client = self._ensure_prisma_client() - # Calculate hour range - hour_start = target_hour.replace(minute=0, second=0, microsecond=0) - hour_end = hour_start + timedelta(hours=1) + # Build WHERE clause for time filtering + where_conditions = [] + if start_time_utc: + where_conditions.append(f"dus.created_at >= '{start_time_utc.isoformat()}'") + if end_time_utc: + where_conditions.append(f"dus.created_at <= '{end_time_utc.isoformat()}'") - # Convert datetime objects to ISO format strings for PostgreSQL compatibility - hour_start_str = hour_start.isoformat() - hour_end_str = hour_end.isoformat() + where_clause = "" + if where_conditions: + where_clause = "WHERE " + " AND ".join(where_conditions) - # Query to get spend logs for the specific hour - query = """ - SELECT * - FROM "LiteLLM_SpendLogs" - WHERE "startTime" >= $1::timestamp - AND "startTime" < $2::timestamp - ORDER BY "startTime" ASC + # Query to get user spend data with team information + query = f""" + SELECT + dus.id, + dus.date, + dus.user_id, + dus.api_key, + dus.model, + dus.model_group, + dus.custom_llm_provider, + dus.prompt_tokens, + dus.completion_tokens, + dus.spend, + dus.api_requests, + dus.successful_requests, + dus.failed_requests, + dus.cache_creation_input_tokens, + dus.cache_read_input_tokens, + dus.created_at, + dus.updated_at, + vt.team_id, + vt.key_alias as api_key_alias, + tt.team_alias + FROM "LiteLLM_DailyUserSpend" dus + LEFT JOIN "LiteLLM_VerificationToken" vt ON dus.api_key = vt.token + LEFT JOIN "LiteLLM_TeamTable" tt ON vt.team_id = tt.team_id + {where_clause} + ORDER BY dus.date DESC, dus.created_at DESC """ if limit: query += f" LIMIT {limit}" try: - db_response = await client.db.query_raw(query, hour_start_str, hour_end_str) - # Convert the response to polars DataFrame - return pl.DataFrame(db_response) if db_response else pl.DataFrame() + db_response = await client.db.query_raw(query) + # Convert the response to polars DataFrame with full schema inference + # This prevents schema mismatch errors when data types vary across rows + return pl.DataFrame(db_response, infer_schema_length=None) except Exception as e: - raise Exception(f"Error retrieving spend logs for hour {target_hour}: {str(e)}") - + raise Exception(f"Error retrieving usage data: {str(e)}") async def get_table_info(self) -> Dict[str, Any]: - """Get information about the LiteLLM_SpendLogs table.""" + """Get information about the daily user spend table.""" client = self._ensure_prisma_client() try: - # Get row count from SpendLogs table - spend_logs_count = await self._get_table_row_count('LiteLLM_SpendLogs') + # Get row count from user spend table + user_count = await self._get_table_row_count('LiteLLM_DailyUserSpend') - # Get column structure from spend logs table + # Get column structure from user spend table query = """ SELECT column_name, data_type, is_nullable FROM information_schema.columns - WHERE table_name = 'LiteLLM_SpendLogs' + WHERE table_name = 'LiteLLM_DailyUserSpend' ORDER BY ordinal_position; """ columns_response = await client.db.query_raw(query) return { 'columns': columns_response, - 'row_count': spend_logs_count, - 'table_breakdown': { - 'spend_logs': spend_logs_count - } + 'row_count': user_count, + 'table_name': 'LiteLLM_DailyUserSpend' } except Exception as e: raise Exception(f"Error getting table info: {str(e)}") diff --git a/litellm/integrations/cloudzero/transform.py b/litellm/integrations/cloudzero/transform.py index 7091ea26b95..e0263295388 100644 --- a/litellm/integrations/cloudzero/transform.py +++ b/litellm/integrations/cloudzero/transform.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# CHANGELOG: 2025-01-19 - Updated CBF transformation for LiteLLM_SpendLogs with hourly aggregation and team_id focus (ishaan-jaff) +# CHANGELOG: 2025-01-19 - Updated CBF transformation for daily spend tables and proper CloudZero mapping (erik.peterson) # CHANGELOG: 2025-01-19 - Migrated from pandas to polars for data transformation (erik.peterson) # CHANGELOG: 2025-01-19 - Initial CBF transformation module (erik.peterson) @@ -24,7 +24,7 @@ from typing import Any, Optional import polars as pl from ...types.integrations.cloudzero import CBFRecord -from .cz_resource_names import CZRNGenerator +from .cz_resource_names import CZEntityType, CZRNGenerator class CBFTransformer: @@ -35,160 +35,99 @@ class CBFTransformer: self.czrn_generator = CZRNGenerator() def transform(self, data: pl.DataFrame) -> pl.DataFrame: - """Transform LiteLLM SpendLogs data to hourly aggregated CBF format.""" + """Transform LiteLLM data to CBF format, dropping records with zero successful_requests or invalid CZRNs.""" if data.is_empty(): return pl.DataFrame() - # Filter out records with zero spend or invalid team_id + # Filter out records with zero successful_requests first original_count = len(data) - filtered_data = data.filter( - (pl.col('spend') > 0) & - (pl.col('team_id').is_not_null()) & - (pl.col('team_id') != "") - ) - filtered_count = len(filtered_data) - zero_spend_dropped = original_count - filtered_count + if 'successful_requests' in data.columns: + filtered_data = data.filter(pl.col('successful_requests') > 0) + zero_requests_dropped = original_count - len(filtered_data) + else: + filtered_data = data + zero_requests_dropped = 0 - if filtered_data.is_empty(): - from rich.console import Console - console = Console() - console.print(f"[yellow]⚠️ Dropped all {original_count:,} records due to zero spend or missing team_id[/yellow]") - return pl.DataFrame() - - # Aggregate data to hourly level - hourly_aggregated = self._aggregate_to_hourly(filtered_data) - - # Transform aggregated data to CBF format cbf_data = [] czrn_dropped_count = 0 - - for row in hourly_aggregated.iter_rows(named=True): + filtered_count = len(filtered_data) + + for row in filtered_data.iter_rows(named=True): try: cbf_record = self._create_cbf_record(row) + # Only include the record if CZRN generation was successful cbf_data.append(cbf_record) except Exception: # Skip records that fail CZRN generation czrn_dropped_count += 1 continue - # Print summary of transformations + # Print summary of dropped records if any from rich.console import Console console = Console() - if zero_spend_dropped > 0: - console.print(f"[yellow]⚠️ Dropped {zero_spend_dropped:,} of {original_count:,} records with zero spend or missing team_id[/yellow]") + if zero_requests_dropped > 0: + console.print(f"[yellow]⚠️ Dropped {zero_requests_dropped:,} of {original_count:,} records with zero successful_requests[/yellow]") if czrn_dropped_count > 0: - console.print(f"[yellow]⚠️ Dropped {czrn_dropped_count:,} of {len(hourly_aggregated):,} aggregated records due to invalid CZRNs[/yellow]") + console.print(f"[yellow]⚠️ Dropped {czrn_dropped_count:,} of {filtered_count:,} filtered records due to invalid CZRNs[/yellow]") if len(cbf_data) > 0: - console.print(f"[green]✓ Successfully transformed {len(cbf_data):,} hourly aggregated records[/green]") + console.print(f"[green]✓ Successfully transformed {len(cbf_data):,} records[/green]") return pl.DataFrame(cbf_data) - def _aggregate_to_hourly(self, data: pl.DataFrame) -> pl.DataFrame: - """Aggregate spend logs to hourly level by team_id, key_name, model, and tags.""" - - # Extract hour from startTime, skip tags and metadata for now - data_with_hour = data.with_columns([ - pl.col('startTime').str.to_datetime().dt.truncate('1h').alias('usage_hour'), - pl.lit([]).cast(pl.List(pl.String)).alias('parsed_tags'), # Empty tags list for now - pl.lit("").alias('key_name') # Empty key name for now - ]) - - # Skip tag explosion for now - just add a null tag column - all_data = data_with_hour.with_columns([ - pl.lit(None, dtype=pl.String).alias('tag') - ]) - - # Group by hour, team_id, key_name, model, provider, and tag - aggregated = all_data.group_by([ - 'usage_hour', - 'team_id', - 'key_name', - 'model', - 'model_group', - 'custom_llm_provider', - 'tag' - ]).agg([ - pl.col('spend').sum().alias('total_spend'), - pl.col('total_tokens').sum().alias('total_tokens'), - pl.col('prompt_tokens').sum().alias('total_prompt_tokens'), - pl.col('completion_tokens').sum().alias('total_completion_tokens'), - pl.col('request_id').count().alias('request_count'), - pl.col('api_key').first().alias('api_key_sample'), # Keep one for reference - pl.col('status').filter(pl.col('status') == 'success').count().alias('successful_requests'), - pl.col('status').filter(pl.col('status') != 'success').count().alias('failed_requests') - ]) - return aggregated - - def _create_cbf_record(self, row: dict[str, Any]) -> CBFRecord: - """Create a single CBF record from aggregated hourly spend data.""" + """Create a single CBF record from LiteLLM daily spend row.""" - # Helper function to extract scalar values from polars data - def extract_scalar(value): - if hasattr(value, 'item') and not isinstance(value, (str, int, float, bool)): - return value.item() if value is not None else None - return value + # Parse date (daily spend tables use date strings like '2025-04-19') + usage_date = self._parse_date(row.get('date')) - # Use the aggregated hour as usage time - usage_time = self._parse_datetime(extract_scalar(row.get('usage_hour'))) - - # Use team_id as the primary entity_id - entity_id = str(extract_scalar(row.get('team_id', ''))) - key_name = str(extract_scalar(row.get('key_name', ''))) - model = str(extract_scalar(row.get('model', ''))) - model_group = str(extract_scalar(row.get('model_group', ''))) - provider = str(extract_scalar(row.get('custom_llm_provider', ''))) - tag = extract_scalar(row.get('tag')) - - # Calculate aggregated metrics - total_spend = float(extract_scalar(row.get('total_spend', 0.0)) or 0.0) - total_tokens = int(extract_scalar(row.get('total_tokens', 0)) or 0) - total_prompt_tokens = int(extract_scalar(row.get('total_prompt_tokens', 0)) or 0) - total_completion_tokens = int(extract_scalar(row.get('total_completion_tokens', 0)) or 0) - request_count = int(extract_scalar(row.get('request_count', 0)) or 0) - successful_requests = int(extract_scalar(row.get('successful_requests', 0)) or 0) - failed_requests = int(extract_scalar(row.get('failed_requests', 0)) or 0) + # Calculate total tokens + prompt_tokens = int(row.get('prompt_tokens', 0)) + completion_tokens = int(row.get('completion_tokens', 0)) + total_tokens = prompt_tokens + completion_tokens # Create CloudZero Resource Name (CZRN) as resource_id - # Create a mock row for CZRN generation with team_id as entity_id - czrn_row = { - 'entity_id': entity_id, - 'entity_type': 'team', - 'model': model, - 'custom_llm_provider': provider, - 'api_key': str(extract_scalar(row.get('api_key_sample', ''))) - } - resource_id = self.czrn_generator.create_from_litellm_data(czrn_row) + resource_id = self.czrn_generator.create_from_litellm_data(row) - # Build dimensions for CloudZero tracking - dimensions = { - 'entity_type': 'team', - 'entity_id': entity_id, - 'key_name': key_name, - 'model': model, - 'model_group': model_group, - 'provider': provider, - 'request_count': str(request_count), - 'successful_requests': str(successful_requests), - 'failed_requests': str(failed_requests), - } + # Build dimensions for CloudZero + model = str(row.get('model', '')) + api_key_hash = str(row.get('api_key', ''))[:8] # First 8 chars for identification - # Add tag if present - if tag is not None and str(tag) not in ['', 'null', 'None']: - dimensions['tag'] = str(tag) + # Handle team information with fallbacks + team_id = row.get('team_id') + team_alias = row.get('team_alias') + + # Use team_alias if available, otherwise team_id, otherwise fallback to 'unknown' + entity_id = str(team_alias) if team_alias else (str(team_id) if team_id else 'unknown') + + dimensions = { + 'entity_type': CZEntityType.TEAM.value, + 'entity_id': entity_id, + 'team_id': str(team_id) if team_id else 'unknown', + 'team_alias': str(team_alias) if team_alias else 'unknown', + 'model': model, + 'model_group': str(row.get('model_group', '')), + 'provider': str(row.get('custom_llm_provider', '')), + 'api_key_prefix': api_key_hash, + 'api_key_alias': str(row.get('api_key_alias', '')), + 'api_requests': str(row.get('api_requests', 0)), + 'successful_requests': str(row.get('successful_requests', 0)), + 'failed_requests': str(row.get('failed_requests', 0)), + 'cache_creation_tokens': str(row.get('cache_creation_input_tokens', 0)), + 'cache_read_tokens': str(row.get('cache_read_input_tokens', 0)), + } # Extract CZRN components to populate corresponding CBF columns czrn_components = self.czrn_generator.extract_components(resource_id) - service_type, provider_czrn, region, owner_account_id, resource_type, cloud_local_id = czrn_components + service_type, provider, region, owner_account_id, resource_type, cloud_local_id = czrn_components # CloudZero CBF format with proper column names cbf_record = { # Required CBF fields - 'time/usage_start': usage_time.isoformat() if usage_time else None, # Required: ISO-formatted UTC datetime - 'cost/cost': total_spend, # Required: billed cost + 'time/usage_start': usage_date.isoformat() if usage_date else None, # Required: ISO-formatted UTC datetime + 'cost/cost': float(row.get('spend', 0.0)), # Required: billed cost 'resource/id': resource_id, # Required when resource tags are present # Usage metrics for token consumption @@ -206,41 +145,42 @@ class CBFTransformer: } # Add CZRN components that don't have direct CBF column mappings as resource tags - cbf_record['resource/tag:provider'] = provider_czrn # CZRN provider component + cbf_record['resource/tag:provider'] = provider # CZRN provider component cbf_record['resource/tag:model'] = cloud_local_id # CZRN cloud-local-id component (model) - + # Add resource tags for all dimensions (using resource/tag: format) for key, value in dimensions.items(): - # Ensure value is a scalar and not empty - if hasattr(value, 'item') and not isinstance(value, str): - value = value.item() if value is not None else None - if value is not None and str(value) not in ['', 'N/A', 'None', 'null']: # Only add non-empty tags + if value and value != 'N/A' and value != 'unknown': # Only add meaningful tags cbf_record[f'resource/tag:{key}'] = str(value) # Add token breakdown as resource tags for analysis - if total_prompt_tokens > 0: - cbf_record['resource/tag:prompt_tokens'] = str(total_prompt_tokens) - if total_completion_tokens > 0: - cbf_record['resource/tag:completion_tokens'] = str(total_completion_tokens) + if prompt_tokens > 0: + cbf_record['resource/tag:prompt_tokens'] = str(prompt_tokens) + if completion_tokens > 0: + cbf_record['resource/tag:completion_tokens'] = str(completion_tokens) if total_tokens > 0: cbf_record['resource/tag:total_tokens'] = str(total_tokens) return CBFRecord(cbf_record) - def _parse_datetime(self, datetime_obj) -> Optional[datetime]: - """Parse datetime object to ensure proper format.""" - if datetime_obj is None: + def _parse_date(self, date_str) -> Optional[datetime]: + """Parse date string from daily spend tables (e.g., '2025-04-19').""" + if date_str is None: return None - if isinstance(datetime_obj, datetime): - return datetime_obj + if isinstance(date_str, datetime): + return date_str - if isinstance(datetime_obj, str): + if isinstance(date_str, str): try: - # Try to parse ISO format - return pl.Series([datetime_obj]).str.to_datetime().item() + # Parse date string and set to midnight UTC for daily aggregation + return pl.Series([date_str]).str.to_datetime("%Y-%m-%d").item() except Exception: - return None + try: + # Fallback: try ISO format parsing + return pl.Series([date_str]).str.to_datetime().item() + except Exception: + return None return None diff --git a/litellm/integrations/custom_guardrail.py b/litellm/integrations/custom_guardrail.py index 501185b207e..1ca45f907e1 100644 --- a/litellm/integrations/custom_guardrail.py +++ b/litellm/integrations/custom_guardrail.py @@ -119,11 +119,8 @@ class CustomGuardrail(CustomLogger): """ if "guardrails" in data: return data["guardrails"] - metadata = data.get("metadata") or {} - requested_guardrails = metadata.get("guardrails") or [] - if requested_guardrails: - return requested_guardrails - return requested_guardrails + metadata = data.get("litellm_metadata") or data.get("metadata", {}) + return metadata.get("guardrails") or [] def _guardrail_is_in_requested_guardrails( self, diff --git a/litellm/integrations/datadog/datadog_llm_obs.py b/litellm/integrations/datadog/datadog_llm_obs.py index 4f9c6409770..200f2f283de 100644 --- a/litellm/integrations/datadog/datadog_llm_obs.py +++ b/litellm/integrations/datadog/datadog_llm_obs.py @@ -19,6 +19,7 @@ import litellm from litellm._logging import verbose_logger from litellm.integrations.custom_batch_logger import CustomBatchLogger from litellm.integrations.datadog.datadog import DataDogLogger +from litellm.litellm_core_utils.dd_tracing import tracer from litellm.litellm_core_utils.prompt_templates.common_utils import ( handle_any_messages_to_chat_completion_str_messages_conversion, ) @@ -216,7 +217,7 @@ class DataDogLLMObsLogger(DataDogLogger, CustomBatchLogger): time_to_first_token=self._get_time_to_first_token_seconds(standard_logging_payload), ) - return LLMObsPayload( + payload: LLMObsPayload = LLMObsPayload( parent_id=metadata.get("parent_id", "undefined"), trace_id=standard_logging_payload.get("trace_id", str(uuid.uuid4())), span_id=metadata.get("span_id", str(uuid.uuid4())), @@ -230,6 +231,26 @@ class DataDogLLMObsLogger(DataDogLogger, CustomBatchLogger): self._get_datadog_tags(standard_logging_object=standard_logging_payload) ], ) + + apm_trace_id = self._get_apm_trace_id() + if apm_trace_id is not None: + payload["apm_id"] = apm_trace_id + + return payload + + def _get_apm_trace_id(self) -> Optional[str]: + """Retrieve the current APM trace ID if available.""" + try: + current_span_fn = getattr(tracer, "current_span", None) + if callable(current_span_fn): + current_span = current_span_fn() + if current_span is not None: + trace_id = getattr(current_span, "trace_id", None) + if trace_id is not None: + return str(trace_id) + except Exception: + pass + return None def _assemble_error_info(self, standard_logging_payload: StandardLoggingPayload) -> Optional[DDLLMObsError]: """ diff --git a/litellm/integrations/openmeter.py b/litellm/integrations/openmeter.py index 19010daf831..b8fb64ec287 100644 --- a/litellm/integrations/openmeter.py +++ b/litellm/integrations/openmeter.py @@ -66,8 +66,18 @@ class OpenMeterLogger(CustomLogger): } user_param = kwargs.get("user", None) # end-user passed in via 'user' param + + # If no user provided directly, try to get it from token user_id if user_param is None: - raise Exception("OpenMeter: user is required") + # Check if user_id is available from the API key metadata + litellm_params = kwargs.get("litellm_params", {}) + metadata = litellm_params.get("metadata", {}) + user_api_key_user_id = metadata.get("user_api_key_user_id", None) + + if user_api_key_user_id is not None: + user_param = user_api_key_user_id + else: + raise Exception("OpenMeter: user is required") # Ensure subject is always a string for OpenMeter API subject = str(user_param) diff --git a/litellm/integrations/opentelemetry.py b/litellm/integrations/opentelemetry.py index 22ab3092901..e6f265ded58 100644 --- a/litellm/integrations/opentelemetry.py +++ b/litellm/integrations/opentelemetry.py @@ -15,6 +15,8 @@ from litellm.types.utils import ( StandardLoggingPayload, ) +# OpenTelemetry imports moved to individual functions to avoid import errors when not installed + if TYPE_CHECKING: from opentelemetry.sdk.trace.export import SpanExporter as _SpanExporter from opentelemetry.trace import Context as _Context @@ -41,6 +43,8 @@ else: Context = Any LITELLM_TRACER_NAME = os.getenv("OTEL_TRACER_NAME", "litellm") +LITELLM_METER_NAME = os.getenv("LITELLM_METER_NAME", "litellm") +LITELLM_LOGGER_NAME = os.getenv("LITELLM_LOGGER_NAME", "litellm") # Remove the hardcoded LITELLM_RESOURCE dictionary - we'll create it properly later RAW_REQUEST_SPAN_NAME = "raw_gen_ai_request" LITELLM_REQUEST_SPAN_NAME = "litellm_request" @@ -83,6 +87,8 @@ class OpenTelemetryConfig: exporter: Union[str, SpanExporter] = "console" endpoint: Optional[str] = None headers: Optional[str] = None + enable_metrics: bool = False + enable_events: bool = False @classmethod def from_env(cls): @@ -104,6 +110,14 @@ class OpenTelemetryConfig: headers = os.getenv( "OTEL_EXPORTER_OTLP_HEADERS", os.getenv("OTEL_HEADERS") ) # example: OTEL_HEADERS=x-honeycomb-team=B85YgLm96***" + enable_metrics: bool = ( + os.getenv("LITELLM_OTEL_INTEGRATION_ENABLE_METRICS", "false").lower() + == "true" + ) + enable_events: bool = ( + os.getenv("LITELLM_OTEL_INTEGRATION_ENABLE_EVENTS", "false").lower() + == "true" + ) if exporter == "in_memory": return cls(exporter=InMemorySpanExporter()) @@ -111,6 +125,8 @@ class OpenTelemetryConfig: exporter=exporter, endpoint=endpoint, headers=headers, # example: OTEL_HEADERS=x-honeycomb-team=B85YgLm96***" + enable_metrics=enable_metrics, + enable_events=enable_events, ) @@ -119,27 +135,22 @@ class OpenTelemetry(CustomLogger): self, config: Optional[OpenTelemetryConfig] = None, callback_name: Optional[str] = None, + # injection points for testing + tracer_provider: Optional[Any] = None, + logger_provider: Optional[Any] = None, + meter_provider: Optional[Any] = None, **kwargs, ): - from opentelemetry import trace - from opentelemetry.sdk.trace import TracerProvider - from opentelemetry.trace import SpanKind if config is None: config = OpenTelemetryConfig.from_env() self.config = config + self.callback_name = callback_name self.OTEL_EXPORTER = self.config.exporter self.OTEL_ENDPOINT = self.config.endpoint self.OTEL_HEADERS = self.config.headers - provider = TracerProvider(resource=_get_litellm_resource()) - provider.add_span_processor(self._get_span_processor()) - self.callback_name = callback_name - - trace.set_tracer_provider(provider) - self.tracer = trace.get_tracer(LITELLM_TRACER_NAME) - - self.span_kind = SpanKind + self._init_tracing(tracer_provider) _debug_otel = str(os.getenv("DEBUG_OTEL", "False")).lower() @@ -156,6 +167,8 @@ class OpenTelemetry(CustomLogger): # init CustomLogger params super().__init__(**kwargs) + self._init_metrics(meter_provider) + self._init_logs(logger_provider) self._init_otel_logger_on_litellm_proxy() def _init_otel_logger_on_litellm_proxy(self): @@ -178,14 +191,109 @@ class OpenTelemetry(CustomLogger): litellm.service_callback.append("otel") setattr(proxy_server, "open_telemetry_logger", self) + def _init_tracing(self, tracer_provider): + from opentelemetry import trace + from opentelemetry.sdk.trace import TracerProvider + from opentelemetry.trace import SpanKind + + # use provided tracer or create a new one + if tracer_provider is None: + tracer_provider = TracerProvider(resource=_get_litellm_resource()) + # Only add OTLP span processor if we created the tracer provider ourselves + tracer_provider.add_span_processor(self._get_span_processor()) + + # register global provider and grab our tracer + trace.set_tracer_provider(tracer_provider) + self.tracer = trace.get_tracer(LITELLM_TRACER_NAME) + self.span_kind = SpanKind + + def _init_metrics(self, meter_provider): + if not self.config.enable_metrics: + self._operation_duration_histogram = None + self._token_usage_histogram = None + self._cost_histogram = None + return + + from opentelemetry import metrics + from opentelemetry.sdk.metrics import Histogram, MeterProvider + + # Only create OTLP infrastructure if no custom meter provider is provided + if meter_provider is None: + from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import ( + OTLPMetricExporter, + ) + from opentelemetry.sdk.metrics.export import ( + AggregationTemporality, + PeriodicExportingMetricReader, + ) + + _metric_exporter = OTLPMetricExporter( + endpoint=self.config.endpoint, + headers=OpenTelemetry._get_headers_dictionary(self.config.headers), + preferred_temporality={Histogram: AggregationTemporality.DELTA}, + ) + _metric_reader = PeriodicExportingMetricReader( + _metric_exporter, export_interval_millis=10000 + ) + + meter_provider = MeterProvider( + metric_readers=[_metric_reader], resource=_get_litellm_resource() + ) + meter = meter_provider.get_meter(__name__) + else: + # Use the provided meter provider as-is, without creating additional OTLP infrastructure + meter = meter_provider.get_meter(__name__) + + metrics.set_meter_provider(meter_provider) + + self._operation_duration_histogram = meter.create_histogram( + name="gen_ai.client.operation.duration", # Replace with semconv constant in otel 1.38 + description="GenAI operation duration", + unit="s", + ) + self._token_usage_histogram = meter.create_histogram( + name="gen_ai.client.token.usage", # Replace with semconv constant in otel 1.38 + description="GenAI token usage", + unit="{token}", + ) + self._cost_histogram = meter.create_histogram( + name="gen_ai.client.token.cost", + description="GenAI request cost", + unit="USD", + ) + + def _init_logs(self, logger_provider): + # nothing to do if events disabled + if not self.config.enable_events: + return + + from opentelemetry._logs import set_logger_provider + from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter + from opentelemetry.sdk._logs import LoggerProvider as OTLoggerProvider + from opentelemetry.sdk._logs.export import BatchLogRecordProcessor + + # set up log pipeline + if logger_provider is None: + logger_provider = OTLoggerProvider() + # Only add OTLP exporter if we created the logger provider ourselves + logger_provider.add_log_record_processor( + BatchLogRecordProcessor( + OTLPLogExporter( + endpoint=self.config.endpoint, + headers=self._get_headers_dictionary(self.config.headers), + ) + ) + ) + set_logger_provider(logger_provider) + def log_success_event(self, kwargs, response_obj, start_time, end_time): - self._handle_sucess(kwargs, response_obj, start_time, end_time) + self._handle_success(kwargs, response_obj, start_time, end_time) def log_failure_event(self, kwargs, response_obj, start_time, end_time): self._handle_failure(kwargs, response_obj, start_time, end_time) async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): - self._handle_sucess(kwargs, response_obj, start_time, end_time) + self._handle_success(kwargs, response_obj, start_time, end_time) async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time): self._handle_failure(kwargs, response_obj, start_time, end_time) @@ -372,9 +480,9 @@ class OpenTelemetry(CustomLogger): def _get_dynamic_otel_headers_from_kwargs(self, kwargs) -> Optional[dict]: """Extract dynamic headers from kwargs if available.""" - standard_callback_dynamic_params: Optional[StandardCallbackDynamicParams] = ( - kwargs.get("standard_callback_dynamic_params") - ) + standard_callback_dynamic_params: Optional[ + StandardCallbackDynamicParams + ] = kwargs.get("standard_callback_dynamic_params") if not standard_callback_dynamic_params: return None @@ -414,50 +522,185 @@ class OpenTelemetry(CustomLogger): # End of Team/Key Based Logging Control Flow ######################################################### - def _handle_sucess(self, kwargs, response_obj, start_time, end_time): - from opentelemetry import trace - from opentelemetry.trace import Status, StatusCode + def _handle_success(self, kwargs, response_obj, start_time, end_time): verbose_logger.debug( "OpenTelemetry Logger: Logging kwargs: %s, OTEL config settings=%s", kwargs, self.config, ) + ctx, parent_span = self._get_span_context(kwargs) + + # 1. Primary span + span = self._start_primary_span(kwargs, response_obj, start_time, end_time, ctx) + + # 2. Raw‐request sub-span (if enabled) + self._maybe_log_raw_request(kwargs, response_obj, start_time, end_time, span) + + # 3. Guardrail span + self._create_guardrail_span(kwargs=kwargs, context=ctx) + + # 4. Metrics & cost recording + self._record_metrics(kwargs, response_obj, start_time, end_time) + + # 5. Semantic logs. + if self.config.enable_events: + self._emit_semantic_logs(kwargs, response_obj, span) + + # 6. End parent span + if parent_span is not None: + parent_span.end(end_time=self._to_ns(datetime.now())) + + def _start_primary_span(self, kwargs, response_obj, start_time, end_time, context): + from opentelemetry.trace import Status, StatusCode - _parent_context, parent_otel_span = self._get_span_context(kwargs) - # Span 1: Request sent to litellm SDK otel_tracer: Tracer = self.get_tracer_to_use_for_request(kwargs) span = otel_tracer.start_span( name=self._get_span_name(kwargs), start_time=self._to_ns(start_time), - context=_parent_context, + context=context, ) span.set_status(Status(StatusCode.OK)) self.set_attributes(span, kwargs, response_obj) + span.end(end_time=self._to_ns(end_time)) + return span - if litellm.turn_off_message_logging is True: - pass - elif self.message_logging is not True: - pass - else: - # Span 2: Raw Request / Response to LLM - raw_request_span = otel_tracer.start_span( - name=RAW_REQUEST_SPAN_NAME, - start_time=self._to_ns(start_time), - context=trace.set_span_in_context(span), + def _maybe_log_raw_request( + self, kwargs, response_obj, start_time, end_time, parent_span + ): + from opentelemetry import trace + from opentelemetry.trace import Status, StatusCode + + # only log raw LLM request/response if message_logging is on and not globally turned off + if litellm.turn_off_message_logging or not self.message_logging: + return + + otel_tracer: Tracer = self.get_tracer_to_use_for_request(kwargs) + raw_span = otel_tracer.start_span( + name=RAW_REQUEST_SPAN_NAME, + start_time=self._to_ns(start_time), + context=trace.set_span_in_context(parent_span), + ) + raw_span.set_status(Status(StatusCode.OK)) + self.set_raw_request_attributes(raw_span, kwargs, response_obj) + raw_span.end(end_time=self._to_ns(end_time)) + + def _record_metrics(self, kwargs, response_obj, start_time, end_time): + duration_s = (end_time - start_time).total_seconds() + params = kwargs.get("litellm_params") or {} + provider = params.get("custom_llm_provider", "Unknown") + + common_attrs = { + "gen_ai.operation.name": "chat", + "gen_ai.system": provider, + "gen_ai.request.model": kwargs.get("model"), + "gen_ai.framework": "litellm", + } + + std_log = kwargs.get("standard_logging_object") + md = getattr(std_log, "metadata", None) or (std_log or {}).get("metadata", {}) + for key in [ + "user_api_key_hash", + "user_api_key_alias", + "user_api_key_team_id", + "user_api_key_org_id", + "user_api_key_user_id", + "user_api_key_team_alias", + "user_api_key_user_email", + "spend_logs_metadata", + "requester_ip_address", + "requester_metadata", + "user_api_key_end_user_id", + "prompt_management_metadata", + "applied_guardrails", + "mcp_tool_call_metadata", + "vector_store_request_metadata", + ]: + if md.get(key) is not None: + common_attrs[f"metadata.{key}"] = str(md[key]) + + if self._operation_duration_histogram: + self._operation_duration_histogram.record( + duration_s, attributes=common_attrs + ) + if ( + response_obj + and (usage := response_obj.get("usage")) + and self._token_usage_histogram + ): + in_attrs = {**common_attrs, "gen_ai.token.type": "input"} + out_attrs = {**common_attrs, "gen_ai.token.type": "completion"} + self._token_usage_histogram.record( + usage.get("prompt_tokens", 0), attributes=in_attrs + ) + self._token_usage_histogram.record( + usage.get("completion_tokens", 0), attributes=out_attrs + ) + + cost = kwargs.get("response_cost") + if self._cost_histogram and cost: + self._cost_histogram.record(cost, attributes=common_attrs) + + def _emit_semantic_logs(self, kwargs, response_obj, span: Span): + if not self.config.enable_events: + return + + from opentelemetry._logs import get_logger, LogRecord + otel_logger = get_logger(LITELLM_LOGGER_NAME) + + parent_ctx = span.get_span_context() + provider = (kwargs.get("litellm_params") or {}).get( + "custom_llm_provider", "Unknown" + ) + + # per-message events + for msg in kwargs.get("messages", []): + role = msg.get("role", "user") + attrs = {"event_name": "gen_ai.content.prompt", "gen_ai.system": provider} + if role == "tool" and msg.get("id"): + attrs["id"] = msg["id"] + if self.message_logging and msg.get("content"): + attrs["gen_ai.prompt"] = msg["content"] + + otel_logger.emit( + LogRecord( + attributes=attrs, + body=msg.copy(), + trace_id=parent_ctx.trace_id, + span_id=parent_ctx.span_id, + trace_flags=parent_ctx.trace_flags, + ) ) - raw_request_span.set_status(Status(StatusCode.OK)) - self.set_raw_request_attributes(raw_request_span, kwargs, response_obj) - raw_request_span.end(end_time=self._to_ns(end_time)) + # per-choice events + for idx, choice in enumerate(response_obj.get("choices", [])): + attrs = { + "event_name": "gen_ai.content.completion", + "gen_ai.system": provider, + "index": idx, + "finish_reason": choice.get("finish_reason"), + } + body_msg = choice.get("message", {}) + if self.message_logging and body_msg.get("content"): + attrs["message.content"] = body_msg["content"] + body = { + "index": idx, + "finish_reason": choice.get("finish_reason"), + "message": {"role": body_msg.get("role", "assistant")}, + } + if self.message_logging and body_msg.get("content"): + body["message"]["content"] = body_msg["content"] - span.end(end_time=self._to_ns(end_time)) + otel_logger.emit( + LogRecord( + attributes=attrs, + body=body, + trace_id=parent_ctx.trace_id, + span_id=parent_ctx.span_id, + trace_flags=parent_ctx.trace_flags, + ) + ) - # Create span for guardrail information - self._create_guardrail_span(kwargs=kwargs, context=_parent_context) - - if parent_otel_span is not None: - parent_otel_span.end(end_time=self._to_ns(datetime.now())) def _create_guardrail_span( self, kwargs: Optional[dict], context: Optional[Context] diff --git a/litellm/integrations/vector_store_integrations/vector_store_pre_call_hook.py b/litellm/integrations/vector_store_integrations/vector_store_pre_call_hook.py index 59c378f8204..8ef160dd783 100644 --- a/litellm/integrations/vector_store_integrations/vector_store_pre_call_hook.py +++ b/litellm/integrations/vector_store_integrations/vector_store_pre_call_hook.py @@ -8,6 +8,7 @@ It searches the vector store for relevant context and appends it to the messages from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, cast import litellm +import litellm.vector_stores from litellm._logging import verbose_logger from litellm.integrations.custom_logger import CustomLogger from litellm.types.llms.openai import AllMessageValues, ChatCompletionUserMessage @@ -192,4 +193,4 @@ class VectorStorePreCallHook(CustomLogger): modified_messages.insert(-1, cast(AllMessageValues, context_message)) return modified_messages - return messages \ No newline at end of file + return messages diff --git a/litellm/litellm_core_utils/custom_logger_registry.py b/litellm/litellm_core_utils/custom_logger_registry.py index fd82ecdf2b2..af51fe9ab79 100644 --- a/litellm/litellm_core_utils/custom_logger_registry.py +++ b/litellm/litellm_core_utils/custom_logger_registry.py @@ -38,6 +38,7 @@ try: from litellm_enterprise.integrations.prometheus import PrometheusLogger except Exception: PrometheusLogger = None +from litellm.integrations.cloudzero.cloudzero import CloudZeroLogger from litellm.integrations.dotprompt import DotpromptManager from litellm.integrations.s3_v2 import S3Logger from litellm.integrations.sqs import SQSLogger @@ -86,6 +87,7 @@ class CustomLoggerRegistry: "dynamic_rate_limiter": _PROXY_DynamicRateLimitHandler, "vector_store_pre_call_hook": VectorStorePreCallHook, "dotprompt": DotpromptManager, + "cloudzero": CloudZeroLogger, } try: diff --git a/litellm/litellm_core_utils/duration_parser.py b/litellm/litellm_core_utils/duration_parser.py index 08f1d4c82d0..08e5323c30c 100644 --- a/litellm/litellm_core_utils/duration_parser.py +++ b/litellm/litellm_core_utils/duration_parser.py @@ -1,7 +1,7 @@ """ Helper utilities for parsing durations - 1s, 1d, 10d, 30d, 1mo, 2mo -duration_in_seconds is used in diff parts of the code base, example +duration_in_seconds is used in diff parts of the code base, example - Router - Provider budget routing - Proxy - Key, Team Generation """ @@ -192,6 +192,10 @@ def _handle_day_reset( current_time: datetime, base_midnight: datetime, value: int, timezone: timezone ) -> datetime: """Handle day-based reset times.""" + # Handle zero value - immediate expiration + if value == 0: + return current_time + if value == 1: # Daily reset at midnight return base_midnight + timedelta(days=1) elif value == 7: # Weekly reset on Monday at midnight @@ -234,6 +238,10 @@ def _handle_hour_reset( current_time: datetime, base_midnight: datetime, value: int ) -> datetime: """Handle hour-based reset times.""" + # Handle zero value - immediate expiration + if value == 0: + return current_time + current_hour = current_time.hour current_minute = current_time.minute current_second = current_time.second @@ -266,6 +274,10 @@ def _handle_minute_reset( current_time: datetime, base_midnight: datetime, value: int ) -> datetime: """Handle minute-based reset times.""" + # Handle zero value - immediate expiration + if value == 0: + return current_time + current_hour = current_time.hour current_minute = current_time.minute current_second = current_time.second @@ -306,6 +318,10 @@ def _handle_second_reset( current_time: datetime, base_midnight: datetime, value: int ) -> datetime: """Handle second-based reset times.""" + # Handle zero value - immediate expiration + if value == 0: + return current_time + current_hour = current_time.hour current_minute = current_time.minute current_second = current_time.second diff --git a/litellm/litellm_core_utils/get_llm_provider_logic.py b/litellm/litellm_core_utils/get_llm_provider_logic.py index 22fea27b812..d5009fb0ca6 100644 --- a/litellm/litellm_core_utils/get_llm_provider_logic.py +++ b/litellm/litellm_core_utils/get_llm_provider_logic.py @@ -249,6 +249,9 @@ def get_llm_provider( # noqa: PLR0915 elif endpoint == "https://api.hyperbolic.xyz/v1": custom_llm_provider = "hyperbolic" dynamic_api_key = get_secret_str("HYPERBOLIC_API_KEY") + elif endpoint == "https://ai-gateway.vercel.sh/v1": + custom_llm_provider = "vercel_ai_gateway" + dynamic_api_key = get_secret_str("VERCEL_AI_GATEWAY_API_KEY") if api_base is not None and not isinstance(api_base, str): raise Exception( @@ -317,6 +320,7 @@ def get_llm_provider( # noqa: PLR0915 or model in litellm.vertex_embedding_models or model in litellm.vertex_vision_models or model in litellm.vertex_ai_image_models + or model in litellm.vertex_ai_video_models ): custom_llm_provider = "vertex_ai" ## ai21 @@ -751,6 +755,13 @@ def _get_openai_compatible_provider_info( # noqa: PLR0915 ) = litellm.HyperbolicChatConfig()._get_openai_compatible_provider_info( api_base, api_key ) + elif custom_llm_provider == "vercel_ai_gateway": + ( + api_base, + dynamic_api_key, + ) = litellm.VercelAIGatewayConfig()._get_openai_compatible_provider_info( + api_base, api_key + ) elif custom_llm_provider == "aiml": ( api_base, diff --git a/litellm/litellm_core_utils/get_supported_openai_params.py b/litellm/litellm_core_utils/get_supported_openai_params.py index cf39411f663..86535943762 100644 --- a/litellm/litellm_core_utils/get_supported_openai_params.py +++ b/litellm/litellm_core_utils/get_supported_openai_params.py @@ -131,6 +131,8 @@ def get_supported_openai_params( # noqa: PLR0915 return litellm.AzureOpenAIConfig().get_supported_openai_params(model=model) elif custom_llm_provider == "openrouter": return litellm.OpenrouterConfig().get_supported_openai_params(model=model) + elif custom_llm_provider == "vercel_ai_gateway": + return litellm.VercelAIGatewayConfig().get_supported_openai_params(model=model) elif custom_llm_provider == "mistral" or custom_llm_provider == "codestral": # mistal and codestral api have the exact same params if request_type == "chat_completion": diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 7bc7702684d..0b152e0dda3 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -1164,7 +1164,6 @@ class Logging(LiteLLMLoggingBaseClass): used for consistent cost calculation across response headers + logging integrations. """ - if isinstance(result, BaseModel) and hasattr(result, "_hidden_params"): hidden_params = getattr(result, "_hidden_params", {}) if ( @@ -3361,7 +3360,14 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 galileo_logger = GalileoObserve() _in_memory_loggers.append(galileo_logger) return galileo_logger # type: ignore - + elif logging_integration == "cloudzero": + from litellm.integrations.cloudzero.cloudzero import CloudZeroLogger + for callback in _in_memory_loggers: + if isinstance(callback, CloudZeroLogger): + return callback # type: ignore + cloudzero_logger = CloudZeroLogger() + _in_memory_loggers.append(cloudzero_logger) + return cloudzero_logger # type: ignore elif logging_integration == "deepeval": for callback in _in_memory_loggers: if isinstance(callback, DeepEvalLogger): @@ -3581,6 +3587,11 @@ def get_custom_logger_compatible_class( # noqa: PLR0915 for callback in _in_memory_loggers: if isinstance(callback, GalileoObserve): return callback + elif logging_integration == "cloudzero": + from litellm.integrations.cloudzero.cloudzero import CloudZeroLogger + for callback in _in_memory_loggers: + if isinstance(callback, CloudZeroLogger): + return callback elif logging_integration == "deepeval": for callback in _in_memory_loggers: if isinstance(callback, DeepEvalLogger): diff --git a/litellm/litellm_core_utils/llm_cost_calc/tool_call_cost_tracking.py b/litellm/litellm_core_utils/llm_cost_calc/tool_call_cost_tracking.py index 75bb699292e..21ff44ab082 100644 --- a/litellm/litellm_core_utils/llm_cost_calc/tool_call_cost_tracking.py +++ b/litellm/litellm_core_utils/llm_cost_calc/tool_call_cost_tracking.py @@ -580,7 +580,9 @@ class StandardBuiltInToolCostTracking: return WebSearchOptions(**kwargs.get("web_search_options", {})) tools = StandardBuiltInToolCostTracking._get_tools_from_kwargs( - kwargs, "web_search_preview" + kwargs=kwargs, tool_type="web_search_preview" + ) or StandardBuiltInToolCostTracking._get_tools_from_kwargs( + kwargs=kwargs, tool_type="web_search" ) if tools: # Look for web search tool in the tools array @@ -612,6 +614,8 @@ class StandardBuiltInToolCostTracking: def _is_web_search_tool_call(tool: Dict) -> bool: if tool.get("type", None) == "web_search_preview": return True + if tool.get("type", None) == "web_search": + return True if "search_context_size" in tool: return True return False 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 54adef9c958..8dc3061460a 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 @@ -43,13 +43,13 @@ from .get_headers import get_response_headers def _safe_convert_created_field(created_value) -> int: """ Safely convert a 'created' field value to an integer. - - Some providers (like SambaNova) return the 'created' field as a float + + Some providers (like SambaNova) return the 'created' field as a float (Unix timestamp with fractional seconds), but LiteLLM expects an integer. - + Args: created_value: The value from response_object["created"] - + Returns: int: Unix timestamp as integer """ @@ -161,7 +161,9 @@ async def convert_to_streaming_response_async(response_object: Optional[dict] = model_response_object.id = response_object["id"] if "created" in response_object: - model_response_object.created = _safe_convert_created_field(response_object["created"]) + model_response_object.created = _safe_convert_created_field( + response_object["created"] + ) if "system_fingerprint" in response_object: model_response_object.system_fingerprint = response_object["system_fingerprint"] @@ -209,7 +211,9 @@ def convert_to_streaming_response(response_object: Optional[dict] = None): model_response_object.id = response_object["id"] if "created" in response_object: - model_response_object.created = _safe_convert_created_field(response_object["created"]) + model_response_object.created = _safe_convert_created_field( + response_object["created"] + ) if "system_fingerprint" in response_object: model_response_object.system_fingerprint = response_object["system_fingerprint"] @@ -557,9 +561,9 @@ def convert_to_model_response_object( # noqa: PLR0915 provider_specific_fields["thinking_blocks"] = thinking_blocks if reasoning_content: - provider_specific_fields[ - "reasoning_content" - ] = reasoning_content + provider_specific_fields["reasoning_content"] = ( + reasoning_content + ) message = Message( content=content, @@ -571,6 +575,7 @@ def convert_to_model_response_object( # noqa: PLR0915 reasoning_content=reasoning_content, thinking_blocks=thinking_blocks, annotations=choice["message"].get("annotations", None), + images=choice["message"].get("images", None), ) finish_reason = choice.get("finish_reason", None) if finish_reason is None: @@ -606,7 +611,9 @@ def convert_to_model_response_object( # noqa: PLR0915 usage_object = litellm.Usage(**response_object["usage"]) setattr(model_response_object, "usage", usage_object) if "created" in response_object: - model_response_object.created = _safe_convert_created_field(response_object["created"]) + model_response_object.created = _safe_convert_created_field( + response_object["created"] + ) if "id" in response_object: model_response_object.id = response_object["id"] or str(uuid.uuid4()) diff --git a/litellm/litellm_core_utils/logging_worker.py b/litellm/litellm_core_utils/logging_worker.py index faf8413bd57..3f83719dd32 100644 --- a/litellm/litellm_core_utils/logging_worker.py +++ b/litellm/litellm_core_utils/logging_worker.py @@ -57,9 +57,10 @@ class LoggingWorker: finally: self._queue.task_done() - except asyncio.CancelledError as e: - verbose_logger.exception(f"LoggingWorker cancelled: {e}") - pass + except asyncio.CancelledError: + verbose_logger.debug("LoggingWorker cancelled during shutdown") + # Attempt to clear remaining items to prevent "never awaited" warnings + await self.clear_queue() def enqueue(self, coroutine: Coroutine) -> None: """ diff --git a/litellm/litellm_core_utils/prompt_templates/image_handling.py b/litellm/litellm_core_utils/prompt_templates/image_handling.py index a9ff14d6c82..4fa10e42111 100644 --- a/litellm/litellm_core_utils/prompt_templates/image_handling.py +++ b/litellm/litellm_core_utils/prompt_templates/image_handling.py @@ -17,7 +17,7 @@ in_memory_cache = InMemoryCache(max_size_in_memory=MAX_IMGS_IN_MEMORY) def _process_image_response(response: Response, url: str) -> str: if response.status_code != 200: - raise Exception( + raise litellm.ImageFetchError( f"Error: Unable to fetch image from URL. Status code: {response.status_code}, url={url}" ) @@ -57,9 +57,11 @@ async def async_convert_url_to_base64(url: str) -> str: try: response = await client.get(url, follow_redirects=True) return _process_image_response(response, url) + except litellm.ImageFetchError: + raise except Exception: pass - raise Exception( + raise litellm.ImageFetchError( f"Error: Unable to fetch image from URL after 3 attempts. url={url}" ) @@ -74,10 +76,11 @@ def convert_url_to_base64(url: str) -> str: try: response = client.get(url, follow_redirects=True) return _process_image_response(response, url) + except litellm.ImageFetchError: + raise except Exception as e: verbose_logger.exception(e) - # print(e) pass - raise Exception( - f"Error: Unable to fetch image from URL after 3 attempts. url={url}" + raise litellm.ImageFetchError( + f"Error: Unable to fetch image from URL after 3 attempts. url={url}", ) diff --git a/litellm/litellm_core_utils/safe_json_dumps.py b/litellm/litellm_core_utils/safe_json_dumps.py index 7ad0038ecb2..c714e36b5f9 100644 --- a/litellm/litellm_core_utils/safe_json_dumps.py +++ b/litellm/litellm_core_utils/safe_json_dumps.py @@ -1,5 +1,6 @@ import json from typing import Any, Union + from litellm.constants import DEFAULT_MAX_RECURSE_DEPTH diff --git a/litellm/litellm_core_utils/streaming_handler.py b/litellm/litellm_core_utils/streaming_handler.py index 01b2609d31d..2203cac11d0 100644 --- a/litellm/litellm_core_utils/streaming_handler.py +++ b/litellm/litellm_core_utils/streaming_handler.py @@ -20,9 +20,7 @@ from litellm.litellm_core_utils.redact_messages import LiteLLMLoggingObject from litellm.litellm_core_utils.thread_pool_executor import executor from litellm.types.llms.openai import ChatCompletionChunk from litellm.types.router import GenericLiteLLMParams -from litellm.types.utils import ( - Delta, -) +from litellm.types.utils import Delta from litellm.types.utils import GenericStreamingChunk as GChunk from litellm.types.utils import ( ModelResponse, @@ -39,7 +37,7 @@ from .rules import Rules # Constants for special delta attribute names AUDIO_ATTRIBUTE = "audio" -IMAGE_ATTRIBUTE = "image" +IMAGE_ATTRIBUTE = "images" TOOL_CALLS_ATTRIBUTE = "tool_calls" FUNCTION_CALL_ATTRIBUTE = "function_call" @@ -780,24 +778,35 @@ class CustomStreamWrapper: """ if len(model_response.choices) == 0: return False - + delta = model_response.choices[0].delta - + # Check for tool_calls or function_call - if getattr(delta, TOOL_CALLS_ATTRIBUTE, None) is not None or getattr(delta, FUNCTION_CALL_ATTRIBUTE, None) is not None: + if ( + getattr(delta, TOOL_CALLS_ATTRIBUTE, None) is not None + or getattr(delta, FUNCTION_CALL_ATTRIBUTE, None) is not None + ): return True - + # Check for audio - if hasattr(delta, AUDIO_ATTRIBUTE) and getattr(delta, AUDIO_ATTRIBUTE, None) is not None: + if ( + hasattr(delta, AUDIO_ATTRIBUTE) + and getattr(delta, AUDIO_ATTRIBUTE, None) is not None + ): return True - + # Check for image - if hasattr(delta, IMAGE_ATTRIBUTE) and getattr(delta, IMAGE_ATTRIBUTE, None) is not None: + if ( + hasattr(delta, IMAGE_ATTRIBUTE) + and getattr(delta, IMAGE_ATTRIBUTE, None) is not None + ): return True - + return False - def _handle_special_delta_content(self, model_response: ModelResponseStream) -> ModelResponseStream: + def _handle_special_delta_content( + self, model_response: ModelResponseStream + ) -> ModelResponseStream: """ Handle special delta content types by stripping role and returning the response. """ @@ -809,7 +818,9 @@ class CustomStreamWrapper: """ return delta is not None and getattr(delta, attribute_name, None) is not None - def _copy_delta_attribute(self, source_delta, target_delta, attribute_name: str) -> None: + def _copy_delta_attribute( + self, source_delta, target_delta, attribute_name: str + ) -> None: """ Copy a specific attribute from source delta to target delta. """ @@ -825,14 +836,18 @@ class CustomStreamWrapper: return True return False - def _handle_special_delta_attributes(self, delta, model_response: "ModelResponseStream") -> None: + def _handle_special_delta_attributes( + self, delta, model_response: "ModelResponseStream" + ) -> None: """ Handle special delta attributes (audio, image) by copying them to model_response. """ special_attributes = [AUDIO_ATTRIBUTE, IMAGE_ATTRIBUTE] for attribute in special_attributes: if self._has_special_delta_attribute(delta, attribute): - self._copy_delta_attribute(delta, model_response.choices[0].delta, attribute) + self._copy_delta_attribute( + delta, model_response.choices[0].delta, attribute + ) def return_processed_chunk_logic( # noqa self, diff --git a/litellm/llms/base_llm/__init__.py b/litellm/llms/base_llm/__init__.py index 187c985fd67..665e242969c 100644 --- a/litellm/llms/base_llm/__init__.py +++ b/litellm/llms/base_llm/__init__.py @@ -1,5 +1,6 @@ from .anthropic_messages.transformation import BaseAnthropicMessagesConfig from .audio_transcription.transformation import BaseAudioTranscriptionConfig +from .batches.transformation import BaseBatchesConfig from .chat.transformation import BaseConfig from .embedding.transformation import BaseEmbeddingConfig from .image_edit.transformation import BaseImageEditConfig @@ -12,4 +13,5 @@ __all__ = [ "BaseAnthropicMessagesConfig", "BaseEmbeddingConfig", "BaseImageEditConfig", + "BaseBatchesConfig", ] diff --git a/litellm/llms/base_llm/batches/transformation.py b/litellm/llms/base_llm/batches/transformation.py new file mode 100644 index 00000000000..1d3e54fae67 --- /dev/null +++ b/litellm/llms/base_llm/batches/transformation.py @@ -0,0 +1,176 @@ +import types +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union + +import httpx +from httpx import Headers + +from litellm.types.llms.openai import ( + AllMessageValues, + CreateBatchRequest, +) +from litellm.types.utils import LiteLLMBatch, LlmProviders + +if TYPE_CHECKING: + from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj + + from ..chat.transformation import BaseLLMException as _BaseLLMException + + LiteLLMLoggingObj = _LiteLLMLoggingObj + BaseLLMException = _BaseLLMException +else: + LiteLLMLoggingObj = Any + BaseLLMException = Any + + +class BaseBatchesConfig(ABC): + """ + Abstract base class for batch processing configurations across different LLM providers. + + This class defines the interface that all provider-specific batch configurations + must implement to work with LiteLLM's unified batch processing system. + """ + + def __init__(self): + pass + + @property + @abstractmethod + def custom_llm_provider(self) -> LlmProviders: + """Return the LLM provider type for this configuration.""" + pass + + @classmethod + def get_config(cls): + """Get configuration dictionary for this class.""" + return { + k: v + for k, v in cls.__dict__.items() + if not k.startswith("__") + and not k.startswith("_abc") + and not isinstance( + v, + ( + types.FunctionType, + types.BuiltinFunctionType, + classmethod, + staticmethod, + ), + ) + and v is not None + } + + @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: + """ + Validate and prepare environment-specific headers and parameters. + + Args: + headers: HTTP headers dictionary + model: Model name + messages: List of messages + optional_params: Optional parameters + litellm_params: LiteLLM parameters + api_key: API key + api_base: API base URL + + Returns: + Updated headers dictionary + """ + pass + + @abstractmethod + def get_complete_batch_url( + self, + api_base: Optional[str], + api_key: Optional[str], + model: str, + optional_params: Dict, + litellm_params: Dict, + data: CreateBatchRequest, + ) -> str: + """ + Get the complete URL for batch creation request. + + Args: + api_base: Base API URL + api_key: API key + model: Model name + optional_params: Optional parameters + litellm_params: LiteLLM parameters + data: Batch creation request data + + Returns: + Complete URL for the batch request + """ + pass + + @abstractmethod + def transform_create_batch_request( + self, + model: str, + create_batch_data: CreateBatchRequest, + optional_params: dict, + litellm_params: dict, + ) -> Union[bytes, str, Dict[str, Any]]: + """ + Transform the batch creation request to provider-specific format. + + Args: + model: Model name + create_batch_data: Batch creation request data + optional_params: Optional parameters + litellm_params: LiteLLM parameters + + Returns: + Transformed request data + """ + pass + + @abstractmethod + def transform_create_batch_response( + self, + model: Optional[str], + raw_response: httpx.Response, + logging_obj: LiteLLMLoggingObj, + litellm_params: dict, + ) -> LiteLLMBatch: + """ + Transform provider-specific batch response to LiteLLM format. + + Args: + model: Model name + raw_response: Raw HTTP response + logging_obj: Logging object + litellm_params: LiteLLM parameters + + Returns: + LiteLLM batch object + """ + pass + + @abstractmethod + def get_error_class( + self, error_message: str, status_code: int, headers: Union[Dict, Headers] + ) -> "BaseLLMException": + """ + Get the appropriate error class for this provider. + + Args: + error_message: Error message + status_code: HTTP status code + headers: Response headers + + Returns: + Provider-specific exception class + """ + pass diff --git a/litellm/llms/base_llm/files/transformation.py b/litellm/llms/base_llm/files/transformation.py index 5c37a8b7547..35b76479cdc 100644 --- a/litellm/llms/base_llm/files/transformation.py +++ b/litellm/llms/base_llm/files/transformation.py @@ -35,6 +35,16 @@ class BaseFilesConfig(BaseConfig): def custom_llm_provider(self) -> LlmProviders: pass + @property + def file_upload_http_method(self) -> str: + """ + HTTP method to use for file uploads. + Override this in provider configs if they need different methods. + Default is POST (used by most providers like OpenAI, Anthropic). + S3-based providers like Bedrock should return "PUT". + """ + return "POST" + @abstractmethod def get_supported_openai_params( self, model: str diff --git a/litellm/llms/base_llm/passthrough/transformation.py b/litellm/llms/base_llm/passthrough/transformation.py index 60d89c1610f..f925e6819dc 100644 --- a/litellm/llms/base_llm/passthrough/transformation.py +++ b/litellm/llms/base_llm/passthrough/transformation.py @@ -31,30 +31,26 @@ class BasePassthroughConfig(BaseLLMModelInfo): Args: endpoint: str - the endpoint to add to the url base_target_url: str - the base url to add the endpoint to - request_query_params: dict - the query params to add to the url + request_query_params: Optional[dict] - the query params to add to the url Returns: - str - the formatted url + httpx.URL - the formatted url """ from urllib.parse import urlencode import httpx - encoded_endpoint = httpx.URL(endpoint).path + base = base_target_url.rstrip('/') + endpoint = endpoint.lstrip('/') + full_url = f"{base}/{endpoint}" - # Ensure endpoint starts with '/' for proper URL construction - if not encoded_endpoint.startswith("/"): - encoded_endpoint = "/" + encoded_endpoint - - # Construct the full target URL using httpx - base_url = httpx.URL(base_target_url) - updated_url = base_url.copy_with(path=encoded_endpoint) + url = httpx.URL(full_url) if request_query_params: - # Create a new URL with the merged query params - updated_url = updated_url.copy_with( + url = url.copy_with( query=urlencode(request_query_params).encode("ascii") ) - return updated_url + + return url @abstractmethod def get_complete_url( diff --git a/litellm/llms/bedrock/batches/transformation.py b/litellm/llms/bedrock/batches/transformation.py new file mode 100644 index 00000000000..ce580ebc624 --- /dev/null +++ b/litellm/llms/bedrock/batches/transformation.py @@ -0,0 +1,254 @@ +import os +import time +from typing import Any, Dict, List, Literal, Optional, Union, cast + +from httpx import Headers, Response + +from litellm.llms.base_llm.batches.transformation import BaseBatchesConfig +from litellm.llms.base_llm.chat.transformation import BaseLLMException +from litellm.types.llms.bedrock import ( + BedrockBatchJobStatus, + BedrockCreateBatchRequest, + BedrockCreateBatchResponse, + BedrockInputDataConfig, + BedrockOutputDataConfig, + BedrockS3InputDataConfig, + BedrockS3OutputDataConfig, +) +from litellm.types.llms.openai import ( + AllMessageValues, + CreateBatchRequest, +) +from litellm.types.utils import LiteLLMBatch, LlmProviders + +from ..base_aws_llm import BaseAWSLLM +from ..common_utils import CommonBatchFilesUtils + + +class BedrockBatchesConfig(BaseAWSLLM, BaseBatchesConfig): + """ + Config for Bedrock Batches - handles batch job creation and management for Bedrock + """ + + def __init__(self): + super().__init__() + self.common_utils = CommonBatchFilesUtils() + + @property + def custom_llm_provider(self) -> LlmProviders: + return LlmProviders.BEDROCK + + 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: + """ + Validate and prepare environment for Bedrock batch requests. + AWS credentials are handled by BaseAWSLLM. + """ + # Add any Bedrock-specific headers if needed + return headers + + def get_complete_batch_url( + self, + api_base: Optional[str], + api_key: Optional[str], + model: str, + optional_params: Dict, + litellm_params: Dict, + data: CreateBatchRequest, + ) -> str: + """ + Get the complete URL for Bedrock batch creation. + Bedrock batch jobs are created via the model invocation job API. + """ + aws_region_name = self._get_aws_region_name(optional_params, model) + + # Bedrock model invocation job endpoint + # Format: https://bedrock.{region}.amazonaws.com/model-invocation-job + bedrock_endpoint = f"https://bedrock.{aws_region_name}.amazonaws.com/model-invocation-job" + + return bedrock_endpoint + + + + + + + + def transform_create_batch_request( + self, + model: str, + create_batch_data: CreateBatchRequest, + optional_params: dict, + litellm_params: dict, + ) -> Dict[str, Any]: + """ + Transform the batch creation request to Bedrock format. + + Bedrock batch inference requires: + - modelId: The Bedrock model ID + - jobName: Unique name for the batch job + - inputDataConfig: Configuration for input data (S3 location) + - outputDataConfig: Configuration for output data (S3 location) + - roleArn: IAM role ARN for the batch job + """ + # Get required parameters + input_file_id = create_batch_data.get("input_file_id") + if not input_file_id: + raise ValueError("input_file_id is required for Bedrock batch creation") + + # Extract S3 information from file ID using common utility + input_bucket, input_key = self.common_utils.parse_s3_uri(input_file_id) + + # Get output S3 configuration + output_bucket = litellm_params.get("s3_output_bucket_name") or os.getenv("AWS_S3_OUTPUT_BUCKET_NAME") + if not output_bucket: + # Use same bucket as input if no output bucket specified + output_bucket = input_bucket + + # Get IAM role ARN + role_arn = ( + litellm_params.get("aws_batch_role_arn") + or optional_params.get("aws_batch_role_arn") + or os.getenv("AWS_BATCH_ROLE_ARN") + ) + if not role_arn: + raise ValueError( + "AWS IAM role ARN is required for Bedrock batch jobs. " + "Set 'aws_batch_role_arn' in litellm_params or AWS_BATCH_ROLE_ARN env var" + ) + + # Get the actual Bedrock model ID using common utility + bedrock_model_id = self.common_utils.extract_model_from_s3_file_path(input_file_id, optional_params) + + if not bedrock_model_id: + raise ValueError("Could not determine Bedrock model ID. Ensure the model is specified in the input file or passed as a parameter.") + + # Generate job name with the correct model ID using common utility + job_name = self.common_utils.generate_unique_job_name(bedrock_model_id, prefix="litellm") + output_key = f"litellm-batch-outputs/{job_name}/" + + # Build input data config + input_data_config: BedrockInputDataConfig = { + "s3InputDataConfig": BedrockS3InputDataConfig( + s3Uri=f"s3://{input_bucket}/{input_key}" + ) + } + + # Build output data config + output_data_config: BedrockOutputDataConfig = { + "s3OutputDataConfig": BedrockS3OutputDataConfig( + s3Uri=f"s3://{output_bucket}/{output_key}" + ) + } + + # Create Bedrock batch request with proper typing + bedrock_request: BedrockCreateBatchRequest = { + "modelId": bedrock_model_id, + "jobName": job_name, + "inputDataConfig": input_data_config, + "outputDataConfig": output_data_config, + "roleArn": role_arn + } + + # Add optional parameters if provided + completion_window = create_batch_data.get("completion_window") + if completion_window: + # Map OpenAI completion window to Bedrock timeout + # OpenAI uses "24h", Bedrock expects timeout in hours + if completion_window == "24h": + bedrock_request["timeoutDurationInHours"] = 24 + + # For Bedrock, we need to return a pre-signed request with AWS auth headers + # Use common utility for AWS signing + endpoint_url = f"https://bedrock.{self._get_aws_region_name(optional_params, model)}.amazonaws.com/model-invocation-job" + signed_headers, signed_data = self.common_utils.sign_aws_request( + service_name="bedrock", + data=bedrock_request, + endpoint_url=endpoint_url, + optional_params=optional_params, + method="POST" + ) + + # Return a pre-signed request format that the HTTP handler can use + return { + "method": "POST", + "url": endpoint_url, + "headers": signed_headers, + "data": signed_data.decode('utf-8') + } + + def transform_create_batch_response( + self, + model: Optional[str], + raw_response: Response, + logging_obj: Any, + litellm_params: dict, + ) -> LiteLLMBatch: + """ + Transform Bedrock batch creation response to LiteLLM format. + """ + try: + response_data: BedrockCreateBatchResponse = raw_response.json() + except Exception as e: + raise ValueError(f"Failed to parse Bedrock batch response: {e}") + + # Extract information from typed Bedrock response + job_arn = response_data.get("jobArn", "") + status: BedrockBatchJobStatus = response_data.get("status", "Submitted") + + # Map Bedrock status to OpenAI-compatible status + status_mapping: Dict[BedrockBatchJobStatus, str] = { + "Submitted": "validating", + "InProgress": "in_progress", + "Completed": "completed", + "Failed": "failed", + "Stopping": "cancelling", + "Stopped": "cancelled" + } + + openai_status = cast(Literal["validating", "failed", "in_progress", "finalizing", "completed", "expired", "cancelling", "cancelled"], status_mapping.get(status, "validating")) + + # Get original request data from litellm_params if available + original_request = litellm_params.get("original_batch_request", {}) + + # Create LiteLLM batch object + return LiteLLMBatch( + id=job_arn, # Use ARN as the batch ID + object="batch", + endpoint=original_request.get("endpoint", "/v1/chat/completions"), + errors=None, + input_file_id=original_request.get("input_file_id", ""), + completion_window=original_request.get("completion_window", "24h"), + status=openai_status, + output_file_id=None, # Will be populated when job completes + error_file_id=None, + created_at=int(time.time()), + in_progress_at=int(time.time()) if status == "InProgress" else None, + expires_at=None, + finalizing_at=None, + completed_at=None, + failed_at=None, + expired_at=None, + cancelling_at=None, + cancelled_at=None, + request_counts=None, + metadata=original_request.get("metadata", {}), + ) + + def get_error_class( + self, error_message: str, status_code: int, headers: Union[Dict, Headers] + ) -> BaseLLMException: + """ + Get Bedrock-specific error class using common utility. + """ + return self.common_utils.get_error_class(error_message, status_code, headers) + + diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index b93ca94bed4..fda9220ff7d 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -10,6 +10,8 @@ from typing import List, Literal, Optional, Tuple, Union, cast, overload import httpx import litellm +from litellm._logging import verbose_logger +from litellm.constants import RESPONSE_FORMAT_TOOL_NAME from litellm.litellm_core_utils.core_helpers import map_finish_reason from litellm.litellm_core_utils.litellm_logging import Logging from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import ( @@ -48,14 +50,19 @@ from litellm.types.utils import ( ) from litellm.utils import add_dummy_tool, has_tool_call_blocks, supports_reasoning -from ..common_utils import BedrockError, BedrockModelInfo, get_bedrock_tool_name, get_anthropic_beta_from_headers +from ..common_utils import ( + BedrockError, + BedrockModelInfo, + get_anthropic_beta_from_headers, + get_bedrock_tool_name, +) # Computer use tool prefixes supported by Bedrock BEDROCK_COMPUTER_USE_TOOLS = [ "computer_use_preview", "computer_", "bash_", - "text_editor_" + "text_editor_", ] @@ -163,7 +170,9 @@ class AmazonConverseConfig(BaseConfig): # only anthropic and mistral support tool choice config. otherwise (E.g. cohere) will fail the call - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html supported_params.append("tool_choice") - if ( + if "gpt-oss" in model: + supported_params.append("reasoning_effort") + elif ( "claude-3-7" in model or "claude-sonnet-4" in model or "claude-opus-4" in model @@ -233,7 +242,7 @@ class AmazonConverseConfig(BaseConfig): """Check if computer use tools are being used in the request.""" if tools is None: return False - + for tool in tools: if "type" in tool: tool_type = tool["type"] @@ -247,17 +256,17 @@ class AmazonConverseConfig(BaseConfig): ) -> List[dict]: """Transform computer use tools to Bedrock format.""" transformed_tools: List[dict] = [] - + for tool in computer_use_tools: tool_type = tool.get("type", "") - + # Check if this is a computer use tool with the startswith method is_computer_use_tool = False for computer_use_prefix in BEDROCK_COMPUTER_USE_TOOLS: if tool_type.startswith(computer_use_prefix): is_computer_use_tool = True break - + transformed_tool: dict = {} if is_computer_use_tool: if tool_type.startswith("computer_") and "function" in tool: @@ -266,7 +275,7 @@ class AmazonConverseConfig(BaseConfig): transformed_tool = { "type": tool_type, "name": func.get("name", "computer"), - **func.get("parameters", {}) + **func.get("parameters", {}), } else: # Direct tools - just need to ensure name is present @@ -279,27 +288,29 @@ class AmazonConverseConfig(BaseConfig): else: # Pass through other tools as-is transformed_tool = dict(tool) - + transformed_tools.append(transformed_tool) - + return transformed_tools def _separate_computer_use_tools( self, tools: List[OpenAIChatCompletionToolParam], model: str - ) -> Tuple[List[OpenAIChatCompletionToolParam], List[OpenAIChatCompletionToolParam]]: + ) -> Tuple[ + List[OpenAIChatCompletionToolParam], List[OpenAIChatCompletionToolParam] + ]: """ Separate computer use tools from regular function tools. - + Args: tools: List of tools to separate model: The model name to check if it supports computer use - + Returns: Tuple of (computer_use_tools, regular_tools) """ computer_use_tools = [] regular_tools = [] - + for tool in tools: if "type" in tool: tool_type = tool["type"] @@ -314,15 +325,12 @@ class AmazonConverseConfig(BaseConfig): regular_tools.append(tool) else: regular_tools.append(tool) - + return computer_use_tools, regular_tools - - def _create_json_tool_call_for_response_format( self, json_schema: Optional[dict] = None, - schema_name: str = "json_tool_call", description: Optional[str] = None, ) -> ChatCompletionToolParam: """ @@ -344,10 +352,12 @@ class AmazonConverseConfig(BaseConfig): "properties": {}, } else: + # Use the schema as-is for Bedrock + # Bedrock requires the tool schema to be of type "object" and doesn't need unwrapping _input_schema = json_schema tool_param_function_chunk = ChatCompletionToolParamFunctionChunk( - name=schema_name, parameters=_input_schema + name=RESPONSE_FORMAT_TOOL_NAME, parameters=_input_schema ) if description: tool_param_function_chunk["description"] = description @@ -386,56 +396,9 @@ class AmazonConverseConfig(BaseConfig): for param, value in non_default_params.items(): if param == "response_format" and isinstance(value, dict): - ignore_response_format_types = ["text"] - if value["type"] in ignore_response_format_types: # value is a no-op - continue - - json_schema: Optional[dict] = None - schema_name: str = "" - description: Optional[str] = None - if "response_schema" in value: - json_schema = value["response_schema"] - schema_name = "json_tool_call" - elif "json_schema" in value: - json_schema = value["json_schema"]["schema"] - schema_name = value["json_schema"]["name"] - description = value["json_schema"].get("description") - - if "type" in value and value["type"] == "text": - continue - - """ - Follow similar approach to anthropic - translate to a single tool call. - - When using tools in this way: - https://docs.anthropic.com/en/docs/build-with-claude/tool-use#json-mode - - You usually want to provide a single tool - - You should set tool_choice (see Forcing tool use) to instruct the model to explicitly use that tool - - Remember that the model will pass the input to the tool, so the name of the tool and description should be from the model’s perspective. - """ - _tool = self._create_json_tool_call_for_response_format( - json_schema=json_schema, - schema_name=schema_name if schema_name != "" else "json_tool_call", - description=description, + optional_params = self._translate_response_format_param( + value=value, model=model, optional_params=optional_params, non_default_params=non_default_params, is_thinking_enabled=is_thinking_enabled ) - optional_params = self._add_tools_to_optional_params( - optional_params=optional_params, tools=[_tool] - ) - - if ( - litellm.utils.supports_tool_choice( - model=model, custom_llm_provider=self.custom_llm_provider - ) - and not is_thinking_enabled - ): - - optional_params["tool_choice"] = ToolChoiceValuesBlock( - tool=SpecificToolChoiceBlock( - name=schema_name if schema_name != "" else "json_tool_call" - ) - ) - optional_params["json_mode"] = True - if non_default_params.get("stream", False) is True: - optional_params["fake_stream"] = True if param == "max_tokens" or param == "max_completion_tokens": optional_params["maxTokens"] = value if param == "stream": @@ -466,14 +429,82 @@ class AmazonConverseConfig(BaseConfig): if param == "thinking": optional_params["thinking"] = value elif param == "reasoning_effort" and isinstance(value, str): - optional_params["thinking"] = AnthropicConfig._map_reasoning_effort( - value - ) + if "gpt-oss" in model: + # GPT-OSS models: keep reasoning_effort as-is + # It will be passed through to additionalModelRequestFields + optional_params["reasoning_effort"] = value + else: + # Anthropic and other models: convert to thinking parameter + optional_params["thinking"] = AnthropicConfig._map_reasoning_effort( + value + ) - self.update_optional_params_with_thinking_tokens( - non_default_params=non_default_params, optional_params=optional_params + # Only update thinking tokens for non-GPT-OSS models + if "gpt-oss" not in model: + self.update_optional_params_with_thinking_tokens( + non_default_params=non_default_params, optional_params=optional_params + ) + + return optional_params + + def _translate_response_format_param( + self, + value: dict, + model: str, + optional_params: dict, + non_default_params: dict, + is_thinking_enabled: bool, + ) -> dict: + """ + Handles translation of response_format parameter to Bedrock format. + + Returns `optional_params` with the translated response_format parameter. + """ + ignore_response_format_types = ["text"] + if value["type"] in ignore_response_format_types: # value is a no-op + return optional_params + + json_schema: Optional[dict] = None + description: Optional[str] = None + if "response_schema" in value: + json_schema = value["response_schema"] + elif "json_schema" in value: + json_schema = value["json_schema"]["schema"] + description = value["json_schema"].get("description") + + if "type" in value and value["type"] == "text": + return optional_params + + """ + Follow similar approach to anthropic - translate to a single tool call. + + When using tools in this way: - https://docs.anthropic.com/en/docs/build-with-claude/tool-use#json-mode + - You usually want to provide a single tool + - You should set tool_choice (see Forcing tool use) to instruct the model to explicitly use that tool + - Remember that the model will pass the input to the tool, so the name of the tool and description should be from the model’s perspective. + """ + _tool = self._create_json_tool_call_for_response_format( + json_schema=json_schema, + description=description, + ) + optional_params = self._add_tools_to_optional_params( + optional_params=optional_params, tools=[_tool] ) + if ( + litellm.utils.supports_tool_choice( + model=model, custom_llm_provider=self.custom_llm_provider + ) + and not is_thinking_enabled + ): + + optional_params["tool_choice"] = ToolChoiceValuesBlock( + tool=SpecificToolChoiceBlock(name=RESPONSE_FORMAT_TOOL_NAME) + ) + optional_params["json_mode"] = True + if non_default_params.get("stream", False) is True: + optional_params["fake_stream"] = True + return optional_params def update_optional_params_with_thinking_tokens( @@ -597,7 +628,6 @@ class AmazonConverseConfig(BaseConfig): return {} - def _transform_request_helper( self, model: str, @@ -653,36 +683,38 @@ class AmazonConverseConfig(BaseConfig): ) original_tools = inference_params.pop("tools", []) - + # Initialize bedrock_tools bedrock_tools: List[ToolBlock] = [] - + # Collect anthropic_beta values from user headers anthropic_beta_list = [] if headers: user_betas = get_anthropic_beta_from_headers(headers) anthropic_beta_list.extend(user_betas) - + # Only separate tools if computer use tools are actually present if original_tools and self.is_computer_use_tool_used(original_tools, model): # Separate computer use tools from regular function tools computer_use_tools, regular_tools = self._separate_computer_use_tools( original_tools, model ) - + # Process regular function tools using existing logic bedrock_tools = _bedrock_tools_pt(regular_tools) - + # Add computer use tools and anthropic_beta if needed (only when computer use tools are present) if computer_use_tools: anthropic_beta_list.append("computer-use-2024-10-22") # Transform computer use tools to proper Bedrock format - transformed_computer_tools = self._transform_computer_use_tools(computer_use_tools) + transformed_computer_tools = self._transform_computer_use_tools( + computer_use_tools + ) additional_request_params["tools"] = transformed_computer_tools else: # No computer use tools, process all tools as regular tools bedrock_tools = _bedrock_tools_pt(original_tools) - + # Set anthropic_beta in additional_request_params if we have any beta features if anthropic_beta_list: # Remove duplicates while preserving order @@ -693,7 +725,7 @@ class AmazonConverseConfig(BaseConfig): unique_betas.append(beta) seen.add(beta) additional_request_params["anthropic_beta"] = unique_betas - + bedrock_tool_config: Optional[ToolConfigBlock] = None if len(bedrock_tools) > 0: tool_choice_values: ToolChoiceValuesBlock = inference_params.pop( @@ -1119,10 +1151,37 @@ class AmazonConverseConfig(BaseConfig): self._transform_thinking_blocks(reasoningContentBlocks) ) chat_completion_message["content"] = content_str - if json_mode is True and tools is not None and len(tools) == 1: - # to support 'json_schema' logic on bedrock models + if ( + json_mode is True + and tools is not None + and len(tools) == 1 + and tools[0]["function"].get("name") == RESPONSE_FORMAT_TOOL_NAME + ): + verbose_logger.debug( + "Processing JSON tool call response for response_format" + ) json_mode_content_str: Optional[str] = tools[0]["function"].get("arguments") if json_mode_content_str is not None: + import json + + # Bedrock returns the response wrapped in a "properties" object + # We need to extract the actual content from this wrapper + try: + + response_data = json.loads(json_mode_content_str) + + # If Bedrock wrapped the response in "properties", extract the content + if ( + isinstance(response_data, dict) + and "properties" in response_data + and len(response_data) == 1 + ): + response_data = response_data["properties"] + json_mode_content_str = json.dumps(response_data) + except json.JSONDecodeError: + # If parsing fails, use the original response + pass + chat_completion_message["content"] = json_mode_content_str else: chat_completion_message["tool_calls"] = tools @@ -1182,7 +1241,6 @@ class AmazonConverseConfig(BaseConfig): if api_key: headers["Authorization"] = f"Bearer {api_key}" return headers - def should_fake_stream( self, diff --git a/litellm/llms/bedrock/common_utils.py b/litellm/llms/bedrock/common_utils.py index c76fc0a80c3..831a6da93b3 100644 --- a/litellm/llms/bedrock/common_utils.py +++ b/litellm/llms/bedrock/common_utils.py @@ -6,6 +6,9 @@ import json import os from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Union +if TYPE_CHECKING: + from litellm.types.llms.bedrock import BedrockCreateBatchRequest + import httpx import litellm @@ -608,3 +611,218 @@ def get_anthropic_beta_from_headers(headers: dict) -> List[str]: # Split comma-separated values and strip whitespace return [beta.strip() for beta in anthropic_beta_header.split(",")] + + +class CommonBatchFilesUtils: + """ + Common utilities for Bedrock batch and file operations. + Provides shared functionality to reduce code duplication between batches and files. + """ + + def __init__(self): + # Import here to avoid circular imports + from .base_aws_llm import BaseAWSLLM + self._base_aws = BaseAWSLLM() + + def get_bedrock_model_id_from_litellm_model(self, model: str) -> str: + """ + Extract the actual Bedrock model ID from LiteLLM model name. + + Args: + model: LiteLLM model name (e.g., "bedrock/anthropic.claude-3-sonnet-20240229-v1:0") + + Returns: + Bedrock model ID (e.g., "anthropic.claude-3-sonnet-20240229-v1:0") + """ + if model.startswith("bedrock/"): + return model[8:] # Remove "bedrock/" prefix + return model + + def parse_s3_uri(self, s3_uri: str) -> tuple: + """ + Parse S3 URI into bucket and key components. + + Args: + s3_uri: S3 URI (e.g., "s3://bucket/key/path") + + Returns: + Tuple of (bucket, key) + + Raises: + ValueError: If URI format is invalid + """ + if not s3_uri.startswith("s3://"): + raise ValueError(f"Invalid S3 URI format: {s3_uri}") + + s3_parts = s3_uri[5:].split("/", 1) # Remove "s3://" and split on first "/" + if len(s3_parts) != 2: + raise ValueError(f"Invalid S3 URI format: {s3_uri}") + + return s3_parts[0], s3_parts[1] # bucket, key + + def extract_model_from_s3_file_path(self, s3_uri: str, optional_params: dict) -> str: + """ + Extract model ID from S3 file path. + + The Bedrock file transformation creates S3 objects with the model name embedded: + Format: s3://bucket/litellm-bedrock-files-{model}-{uuid}.jsonl + """ + # Check if model is provided in optional_params first + if "model" in optional_params and optional_params["model"]: + return self.get_bedrock_model_id_from_litellm_model(optional_params["model"]) + + # Extract model from S3 URI path + # Expected format: s3://bucket/litellm-bedrock-files-{model}-{uuid}.jsonl + try: + bucket, object_key = self.parse_s3_uri(s3_uri) + + # Extract model from object key if it follows our naming pattern + if object_key.startswith("litellm-bedrock-files-"): + # Remove prefix and suffix to get model part + model_part = object_key[22:] # Remove "litellm-bedrock-files-" + # Find the last dash before the UUID + parts = model_part.split("-") + if len(parts) > 1: + # Reconstruct model name (everything except the last UUID part and .jsonl) + model_name = "-".join(parts[:-1]) + if model_name.endswith(".jsonl"): + model_name = model_name[:-6] # Remove .jsonl + return model_name + except Exception: + pass + + # Fallback to default model + return "anthropic.claude-3-5-sonnet-20240620-v1:0" + + def sign_aws_request( + self, + service_name: str, + data: Union[str, dict, "BedrockCreateBatchRequest"], + endpoint_url: str, + optional_params: dict, + method: str = "POST", + ) -> tuple: + """ + Sign AWS request using Signature Version 4. + + Args: + service_name: AWS service name ("bedrock" or "s3") + data: Request data (string or dict) + endpoint_url: Full endpoint URL + optional_params: Optional parameters containing AWS credentials + method: HTTP method (default: POST) + + Returns: + Tuple of (signed_headers, signed_data) + """ + try: + from botocore.auth import SigV4Auth + from botocore.awsrequest import AWSRequest + except ImportError: + raise ImportError("Missing boto3 to call bedrock. Run 'pip install boto3'.") + + # Get AWS credentials using existing methods + aws_region_name = self._base_aws._get_aws_region_name( + optional_params=optional_params, model="" + ) + credentials = self._base_aws.get_credentials( + aws_access_key_id=optional_params.get("aws_access_key_id"), + aws_secret_access_key=optional_params.get("aws_secret_access_key"), + aws_session_token=optional_params.get("aws_session_token"), + aws_region_name=aws_region_name, + aws_session_name=optional_params.get("aws_session_name"), + aws_profile_name=optional_params.get("aws_profile_name"), + aws_role_name=optional_params.get("aws_role_name"), + aws_web_identity_token=optional_params.get("aws_web_identity_token"), + aws_sts_endpoint=optional_params.get("aws_sts_endpoint"), + ) + + # Prepare the request data + if isinstance(data, dict): + import json + request_data = json.dumps(data) + else: + request_data = data + + # Prepare headers + headers = {"Content-Type": "application/json"} + + # Create AWS request and sign it + sigv4 = SigV4Auth(credentials, service_name, aws_region_name) + request = AWSRequest( + method=method.upper(), url=endpoint_url, data=request_data, headers=headers + ) + sigv4.add_auth(request) + prepped = request.prepare() + + return dict(prepped.headers), request_data.encode('utf-8') if isinstance(request_data, str) else request_data + + def generate_unique_job_name(self, model: str, prefix: str = "litellm") -> str: + """ + Generate a unique job name for AWS services. + AWS services often have length limits, so this creates a concise name. + + Args: + model: Model name to include in the job name + prefix: Prefix for the job name + + Returns: + Unique job name (≤ 63 characters for Bedrock compatibility) + """ + import fastuuid as uuid + unique_id = str(uuid.uuid4())[:8] + # Format: {prefix}-batch-{model}-{uuid} + # Example: litellm-batch-claude-266c398e + job_name = f"{prefix}-batch-{unique_id}" + + return job_name + + def get_s3_bucket_and_key_from_config( + self, + litellm_params: dict, + optional_params: dict, + bucket_env_var: str = "AWS_S3_BUCKET_NAME", + key_prefix: str = "litellm" + ) -> tuple: + """ + Get S3 bucket and generate a unique key from configuration. + + Args: + litellm_params: LiteLLM parameters + optional_params: Optional parameters + bucket_env_var: Environment variable name for bucket + key_prefix: Prefix for the S3 key + + Returns: + Tuple of (bucket_name, object_key) + """ + import time + import uuid + + # Get bucket name + bucket_name = ( + litellm_params.get("s3_bucket_name") + or optional_params.get("s3_bucket_name") + or os.getenv(bucket_env_var) + ) + if not bucket_name: + raise ValueError(f"S3 bucket name is required. Set 's3_bucket_name' parameter or {bucket_env_var} env var") + + # Generate unique object key + timestamp = int(time.time()) + unique_id = str(uuid.uuid4())[:8] + object_key = f"{key_prefix}-{timestamp}-{unique_id}" + + return bucket_name, object_key + + def get_error_class( + self, error_message: str, status_code: int, headers: Union[Dict, httpx.Headers] + ) -> BaseLLMException: + """ + Get Bedrock-specific error class. + """ + return BedrockError( + status_code=status_code, + message=error_message, + headers=headers + ) diff --git a/litellm/llms/bedrock/files/transformation.py b/litellm/llms/bedrock/files/transformation.py new file mode 100644 index 00000000000..83bbad7e1e8 --- /dev/null +++ b/litellm/llms/bedrock/files/transformation.py @@ -0,0 +1,607 @@ +import json +import os +import time +import uuid +from typing import Any, Dict, List, Optional, Tuple, Union + +from httpx import Headers, Response + +from litellm.litellm_core_utils.prompt_templates.common_utils import extract_file_data +from litellm.llms.base_llm.chat.transformation import BaseLLMException +from litellm.llms.base_llm.files.transformation import ( + BaseFilesConfig, + LiteLLMLoggingObj, +) +from litellm.types.llms.openai import ( + AllMessageValues, + CreateFileRequest, + FileTypes, + OpenAICreateFileRequestOptionalParams, + OpenAIFileObject, + PathLike, +) +from litellm.types.utils import ExtractedFileData, LlmProviders + +from ..base_aws_llm import BaseAWSLLM +from ..common_utils import BedrockError + + +class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig): + """ + Config for Bedrock Files - handles S3 uploads for Bedrock batch processing + """ + + def __init__(self): + self.jsonl_transformation = BedrockJsonlFilesTransformation() + super().__init__() + + @property + def custom_llm_provider(self) -> LlmProviders: + return LlmProviders.BEDROCK + + @property + def file_upload_http_method(self) -> str: + """ + Bedrock files are uploaded to S3, which requires PUT requests + """ + return "PUT" + + 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: + # No additional headers needed for S3 uploads - AWS credentials handled by BaseAWSLLM + return headers + + + + def _get_content_from_openai_file(self, openai_file_content: FileTypes) -> str: + """ + Helper to extract content from various OpenAI file types and return as string. + + Handles: + - Direct content (str, bytes, IO[bytes]) + - Tuple formats: (filename, content, [content_type], [headers]) + - PathLike objects + """ + content: Union[str, bytes] = b"" + # Extract file content from tuple if necessary + if isinstance(openai_file_content, tuple): + # Take the second element which is always the file content + file_content = openai_file_content[1] + else: + file_content = openai_file_content + + # Handle different file content types + if isinstance(file_content, str): + # String content can be used directly + content = file_content + elif isinstance(file_content, bytes): + # Bytes content can be decoded + content = file_content + elif isinstance(file_content, PathLike): # PathLike + with open(str(file_content), "rb") as f: + content = f.read() + elif hasattr(file_content, "read"): # IO[bytes] + # File-like objects need to be read + content = file_content.read() + + # Ensure content is string + if isinstance(content, bytes): + content = content.decode("utf-8") + + return content + + def _get_s3_object_name_from_batch_jsonl( + self, + openai_jsonl_content: List[Dict[str, Any]], + ) -> str: + """ + Gets a unique S3 object name for the Bedrock batch processing job + + named as: litellm-bedrock-files/{model}/{uuid} + """ + _model = openai_jsonl_content[0].get("body", {}).get("model", "") + # Remove bedrock/ prefix if present + if _model.startswith("bedrock/"): + _model = _model[8:] + object_name = f"litellm-bedrock-files-{_model}-{uuid.uuid4()}.jsonl" + return object_name + + def get_object_name( + self, extracted_file_data: ExtractedFileData, purpose: str + ) -> str: + """ + Get the object name for the request + """ + extracted_file_data_content = extracted_file_data.get("content") + + if extracted_file_data_content is None: + raise ValueError("file content is required") + + if purpose == "batch": + ## 1. If jsonl, check if there's a model name + file_content = self._get_content_from_openai_file( + extracted_file_data_content + ) + + # Split into lines and parse each line as JSON + openai_jsonl_content = [ + json.loads(line) for line in file_content.splitlines() if line.strip() + ] + if len(openai_jsonl_content) > 0: + return self._get_s3_object_name_from_batch_jsonl(openai_jsonl_content) + + ## 2. If not jsonl, return the filename + filename = extracted_file_data.get("filename") + if filename: + return filename + ## 3. If no file name, return timestamp + return str(int(time.time())) + + def get_complete_file_url( + self, + api_base: Optional[str], + api_key: Optional[str], + model: str, + optional_params: Dict, + litellm_params: Dict, + data: CreateFileRequest, + ) -> str: + """ + Get the complete S3 URL for the file upload request + """ + bucket_name = litellm_params.get("s3_bucket_name") or os.getenv("AWS_S3_BUCKET_NAME") + if not bucket_name: + raise ValueError("S3 bucket_name is required. Set 's3_bucket_name' in litellm_params or AWS_S3_BUCKET_NAME env var") + + aws_region_name = self._get_aws_region_name(optional_params, model) + + file_data = data.get("file") + purpose = data.get("purpose") + if file_data is None: + raise ValueError("file is required") + if purpose is None: + raise ValueError("purpose is required") + extracted_file_data = extract_file_data(file_data) + object_name = self.get_object_name(extracted_file_data, purpose) + + # S3 endpoint URL format + s3_endpoint_url = optional_params.get("s3_endpoint_url") or f"https://s3.{aws_region_name}.amazonaws.com" + + return f"{s3_endpoint_url}/{bucket_name}/{object_name}" + + def get_supported_openai_params( + self, model: str + ) -> List[OpenAICreateFileRequestOptionalParams]: + return [] + + def map_openai_params( + self, + non_default_params: dict, + optional_params: dict, + model: str, + drop_params: bool, + ) -> dict: + return optional_params + + def _get_bedrock_provider_from_model(self, model: str) -> Optional[str]: + """ + Extract provider from Bedrock model name + """ + if model.startswith("anthropic."): + return "anthropic" + elif model.startswith("cohere."): + return "cohere" + elif model.startswith("meta.") or model.startswith("llama"): + return "meta" + elif model.startswith("mistral."): + return "mistral" + elif model.startswith("ai21."): + return "ai21" + elif model.startswith("amazon."): + return "amazon" + else: + return None + + def _map_openai_to_bedrock_params( + self, + openai_request_body: Dict[str, Any], + provider: Optional[str] = None, + ) -> Dict[str, Any]: + """ + Transform OpenAI request body to Bedrock-compatible modelInput parameters using existing transformation logic + """ + _model = openai_request_body.get("model", "") + messages = openai_request_body.get("messages", []) + + # Use existing Anthropic transformation logic for Anthropic models + if provider == "anthropic": + from litellm.llms.bedrock.chat.invoke_transformations.anthropic_claude3_transformation import ( + AmazonAnthropicClaudeConfig, + ) + + anthropic_config = AmazonAnthropicClaudeConfig() + + # Extract optional params (everything except model and messages) + optional_params = {k: v for k, v in openai_request_body.items() if k not in ["model", "messages"]} + + # Transform using existing Anthropic logic + bedrock_params = anthropic_config.transform_request( + model=_model, + messages=messages, + optional_params=optional_params, + litellm_params={}, + headers={} + ) + + return bedrock_params + else: + # For other providers, use basic mapping + bedrock_params = { + "messages": messages, + **{k: v for k, v in openai_request_body.items() if k not in ["model", "messages"]} + } + return bedrock_params + + def _transform_openai_jsonl_content_to_bedrock_jsonl_content( + self, openai_jsonl_content: List[Dict[str, Any]] + ) -> List[Dict[str, Any]]: + """ + Transforms OpenAI JSONL content to Bedrock batch format + + Bedrock batch format: { "recordId": "alphanumeric string", "modelInput": {JSON body} } + Example: + { + "recordId": "CALL0000001", + "modelInput": { + "anthropic_version": "bedrock-2023-05-31", + "max_tokens": 1024, + "messages": [ + { + "role": "user", + "content": [{"type": "text", "text": "Hello"}] + } + ] + } + } + """ + + bedrock_jsonl_content = [] + for idx, _openai_jsonl_content in enumerate(openai_jsonl_content): + # Extract the request body from OpenAI format + openai_body = _openai_jsonl_content.get("body", {}) + model = openai_body.get("model", "") + + # Determine provider from model name + provider = self._get_bedrock_provider_from_model(model) + + # Transform to Bedrock modelInput format + model_input = self._map_openai_to_bedrock_params( + openai_request_body=openai_body, + provider=provider + ) + + # Create Bedrock batch record + record_id = _openai_jsonl_content.get("custom_id", f"CALL{str(idx).zfill(7)}") + bedrock_record = { + "recordId": record_id, + "modelInput": model_input + } + + bedrock_jsonl_content.append(bedrock_record) + return bedrock_jsonl_content + + def transform_create_file_request( + self, + model: str, + create_file_data: CreateFileRequest, + optional_params: dict, + litellm_params: dict, + ) -> Union[bytes, str, dict]: + """ + Transform file request and return a pre-signed request for S3. + This keeps the HTTP handler clean by doing all the signing here. + """ + file_data = create_file_data.get("file") + if file_data is None: + raise ValueError("file is required") + extracted_file_data = extract_file_data(file_data) + extracted_file_data_content = extracted_file_data.get("content") + + # Get and transform the file content + if ( + create_file_data.get("purpose") == "batch" + and extracted_file_data.get("content_type") == "application/jsonl" + and extracted_file_data_content is not None + ): + ## Transform JSONL content to Bedrock format + original_file_content = self._get_content_from_openai_file( + extracted_file_data_content + ) + openai_jsonl_content = [ + json.loads(line) for line in original_file_content.splitlines() if line.strip() + ] + bedrock_jsonl_content = ( + self._transform_openai_jsonl_content_to_bedrock_jsonl_content( + openai_jsonl_content + ) + ) + file_content = "\n".join(json.dumps(item) for item in bedrock_jsonl_content) + elif isinstance(extracted_file_data_content, bytes): + file_content = extracted_file_data_content.decode('utf-8') + elif isinstance(extracted_file_data_content, str): + file_content = extracted_file_data_content + else: + raise ValueError("Unsupported file content type") + + # Get the S3 URL for upload + api_base = self.get_complete_file_url( + api_base=None, + api_key=None, + model=model, + optional_params=optional_params, + litellm_params=litellm_params, + data=create_file_data, + ) + + # Sign the request and return a pre-signed request object + signed_headers, signed_body = self._sign_s3_request( + content=file_content, + api_base=api_base, + optional_params=optional_params, + ) + + # Return a dict that tells the HTTP handler exactly what to do + return { + "method": "PUT", + "url": api_base, + "headers": signed_headers, + "data": signed_body or file_content, + } + + def _sign_s3_request( + self, + content: str, + api_base: str, + optional_params: dict, + ) -> Tuple[dict, str]: + """ + Sign S3 PUT request using the same proven logic as S3Logger. + Reuses the exact pattern from litellm/integrations/s3_v2.py + """ + try: + import hashlib + + import requests + from botocore.auth import SigV4Auth + from botocore.awsrequest import AWSRequest + except ImportError: + raise ImportError("Missing boto3 to call bedrock. Run 'pip install boto3'.") + + # Get AWS credentials using existing methods + aws_region_name = self._get_aws_region_name( + optional_params=optional_params, model="" + ) + credentials = self.get_credentials( + aws_access_key_id=optional_params.get("aws_access_key_id"), + aws_secret_access_key=optional_params.get("aws_secret_access_key"), + aws_session_token=optional_params.get("aws_session_token"), + aws_region_name=aws_region_name, + aws_session_name=optional_params.get("aws_session_name"), + aws_profile_name=optional_params.get("aws_profile_name"), + aws_role_name=optional_params.get("aws_role_name"), + aws_web_identity_token=optional_params.get("aws_web_identity_token"), + aws_sts_endpoint=optional_params.get("aws_sts_endpoint"), + ) + + # Calculate SHA256 hash of the content (REQUIRED for S3) + content_hash = hashlib.sha256(content.encode("utf-8")).hexdigest() + + # Prepare headers with required S3 headers (same as s3_v2.py) + request_headers = { + "Content-Type": "application/json", # JSONL files are JSON content + "x-amz-content-sha256": content_hash, # REQUIRED by S3 + "Content-Language": "en", + "Cache-Control": "private, immutable, max-age=31536000, s-maxage=0", + } + + # Use requests.Request to prepare the request (same pattern as s3_v2.py) + req = requests.Request("PUT", api_base, data=content, headers=request_headers) + prepped = req.prepare() + + # Sign the request with S3 service + aws_request = AWSRequest( + method=prepped.method, + url=prepped.url, + data=prepped.body, + headers=prepped.headers, + ) + + # Get region name for non-LLM API calls (same as s3_v2.py) + signing_region = self.get_aws_region_name_for_non_llm_api_calls( + aws_region_name=aws_region_name + ) + + SigV4Auth(credentials, "s3", signing_region).add_auth(aws_request) + + # Return signed headers and body + signed_body = aws_request.body + if isinstance(signed_body, bytes): + signed_body = signed_body.decode('utf-8') + elif signed_body is None: + signed_body = content # Fallback to original content + + return dict(aws_request.headers), signed_body + + def transform_create_file_response( + self, + model: Optional[str], + raw_response: Response, + logging_obj: LiteLLMLoggingObj, + litellm_params: dict, + ) -> OpenAIFileObject: + """ + Transform S3 File upload response into OpenAI-style FileObject + """ + # For S3 uploads, we typically get an ETag and other metadata + response_headers = raw_response.headers + + # Extract S3 object information from the response + # S3 PUT object returns ETag and other metadata in headers + content_length = response_headers.get("Content-Length", "0") + + # Extract bucket and key from the request URL or litellm_params + bucket_name = litellm_params.get("s3_bucket_name") or os.getenv("AWS_S3_BUCKET_NAME") + + # Generate file ID in S3 format + object_key = getattr(logging_obj, 'object_key', None) or f"file-{int(time.time())}" + file_id = f"s3://{bucket_name}/{object_key}" + + # Extract filename from object key + filename = object_key.split("/")[-1] if "/" in object_key else object_key + + return OpenAIFileObject( + purpose="batch", # Default purpose for Bedrock files + id=file_id, + filename=filename, + created_at=int(time.time()), # Current timestamp + status="uploaded", + bytes=int(content_length) if content_length.isdigit() else 0, + object="file", + ) + + def get_error_class( + self, error_message: str, status_code: int, headers: Union[Dict, Headers] + ) -> BaseLLMException: + return BedrockError( + status_code=status_code, message=error_message, headers=headers + ) + + +class BedrockJsonlFilesTransformation: + """ + Transforms OpenAI /v1/files/* requests to Bedrock S3 file uploads for batch processing + """ + + def transform_openai_file_content_to_bedrock_file_content( + self, openai_file_content: Optional[FileTypes] = None + ) -> Tuple[str, str]: + """ + Transforms OpenAI FileContentRequest to Bedrock S3 file format + """ + + if openai_file_content is None: + raise ValueError("contents of file are None") + # Read the content of the file + file_content = self._get_content_from_openai_file(openai_file_content) + + # Split into lines and parse each line as JSON + openai_jsonl_content = [ + json.loads(line) for line in file_content.splitlines() if line.strip() + ] + bedrock_jsonl_content = ( + self._transform_openai_jsonl_content_to_bedrock_jsonl_content( + openai_jsonl_content + ) + ) + bedrock_jsonl_string = "\n".join( + json.dumps(item) for item in bedrock_jsonl_content + ) + object_name = self._get_s3_object_name( + openai_jsonl_content=openai_jsonl_content + ) + return bedrock_jsonl_string, object_name + + def _transform_openai_jsonl_content_to_bedrock_jsonl_content( + self, openai_jsonl_content: List[Dict[str, Any]] + ): + """ + Delegate to the main BedrockFilesConfig transformation method + """ + config = BedrockFilesConfig() + return config._transform_openai_jsonl_content_to_bedrock_jsonl_content(openai_jsonl_content) + + def _get_s3_object_name( + self, + openai_jsonl_content: List[Dict[str, Any]], + ) -> str: + """ + Gets a unique S3 object name for the Bedrock batch processing job + + named as: litellm-bedrock-files-{model}-{uuid} + """ + _model = openai_jsonl_content[0].get("body", {}).get("model", "") + # Remove bedrock/ prefix if present + if _model.startswith("bedrock/"): + _model = _model[8:] + object_name = f"litellm-bedrock-files-{_model}-{uuid.uuid4()}.jsonl" + return object_name + + + + def _get_content_from_openai_file(self, openai_file_content: FileTypes) -> str: + """ + Helper to extract content from various OpenAI file types and return as string. + + Handles: + - Direct content (str, bytes, IO[bytes]) + - Tuple formats: (filename, content, [content_type], [headers]) + - PathLike objects + """ + content: Union[str, bytes] = b"" + # Extract file content from tuple if necessary + if isinstance(openai_file_content, tuple): + # Take the second element which is always the file content + file_content = openai_file_content[1] + else: + file_content = openai_file_content + + # Handle different file content types + if isinstance(file_content, str): + # String content can be used directly + content = file_content + elif isinstance(file_content, bytes): + # Bytes content can be decoded + content = file_content + elif isinstance(file_content, PathLike): # PathLike + with open(str(file_content), "rb") as f: + content = f.read() + elif hasattr(file_content, "read"): # IO[bytes] + # File-like objects need to be read + content = file_content.read() + + # Ensure content is string + if isinstance(content, bytes): + content = content.decode("utf-8") + + return content + + def transform_s3_bucket_response_to_openai_file_object( + self, create_file_data: CreateFileRequest, s3_upload_response: Dict[str, Any] + ) -> OpenAIFileObject: + """ + Transforms S3 Bucket upload file response to OpenAI FileObject + """ + # S3 response typically contains ETag, key, etc. + object_key = s3_upload_response.get("Key", "") + bucket_name = s3_upload_response.get("Bucket", "") + + # Extract filename from object key + filename = object_key.split("/")[-1] if "/" in object_key else object_key + + return OpenAIFileObject( + purpose=create_file_data.get("purpose", "batch"), + id=f"s3://{bucket_name}/{object_key}", + filename=filename, + created_at=int(time.time()), # Current timestamp + status="uploaded", + bytes=s3_upload_response.get("ContentLength", 0), + object="file", + ) diff --git a/litellm/llms/bedrock/passthrough/transformation.py b/litellm/llms/bedrock/passthrough/transformation.py index d7221ff4b7a..5791bfb8013 100644 --- a/litellm/llms/bedrock/passthrough/transformation.py +++ b/litellm/llms/bedrock/passthrough/transformation.py @@ -41,9 +41,15 @@ class BedrockPassthroughConfig( model_id=None, ) - api_base = f"https://bedrock-runtime.{aws_region_name}.amazonaws.com" + aws_bedrock_runtime_endpoint = optional_params.get("aws_bedrock_runtime_endpoint") + endpoint_url, _ = self.get_runtime_endpoint( + api_base=api_base, + aws_bedrock_runtime_endpoint=aws_bedrock_runtime_endpoint, + aws_region_name=aws_region_name, + endpoint_type="runtime", + ) - return self.format_url(endpoint, api_base, request_query_params or {}), api_base + return self.format_url(endpoint, endpoint_url, request_query_params or {}), endpoint_url def sign_request( self, diff --git a/litellm/llms/custom_httpx/http_handler.py b/litellm/llms/custom_httpx/http_handler.py index 4d8781fff2a..36b543086f5 100644 --- a/litellm/llms/custom_httpx/http_handler.py +++ b/litellm/llms/custom_httpx/http_handler.py @@ -212,6 +212,7 @@ class AsyncHTTPHandler: verify=ssl_config, cert=cert, headers=headers, + follow_redirects=True, ) async def close(self): @@ -687,6 +688,7 @@ class HTTPHandler: verify=ssl_config, cert=cert, headers=headers, + follow_redirects=True, ) else: self.client = client diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index 2faea53901c..13133a56aad 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -28,6 +28,7 @@ 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.batches.transformation import BaseBatchesConfig 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 @@ -58,6 +59,7 @@ from litellm.types.llms.anthropic_messages.anthropic_response import ( AnthropicMessagesResponse, ) from litellm.types.llms.openai import ( + CreateBatchRequest, CreateFileRequest, OpenAIFileObject, ResponseInputParam, @@ -66,7 +68,12 @@ from litellm.types.llms.openai import ( 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.types.utils import ( + EmbeddingResponse, + FileTypes, + LiteLLMBatch, + TranscriptionResponse, +) from litellm.types.vector_stores import ( VectorStoreCreateOptionalRequestParams, VectorStoreCreateResponse, @@ -2212,15 +2219,38 @@ class BaseLLMHTTPHandler: else: sync_httpx_client = client - if isinstance(transformed_request, str) or isinstance( - transformed_request, bytes - ): - upload_response = sync_httpx_client.post( - url=api_base, - headers=headers, - data=transformed_request, + if isinstance(transformed_request, dict) and "method" in transformed_request: + # Handle pre-signed requests (e.g., from Bedrock S3 uploads) + upload_response = getattr(sync_httpx_client, transformed_request["method"].lower())( + url=transformed_request["url"], + headers=transformed_request["headers"], + data=transformed_request["data"], timeout=timeout, ) + elif isinstance(transformed_request, str) or isinstance( + transformed_request, bytes + ): + # Handle traditional file uploads + # Ensure transformed_request is a string for httpx compatibility + if isinstance(transformed_request, bytes): + transformed_request = transformed_request.decode('utf-8') + + # Use the HTTP method specified by the provider config + http_method = provider_config.file_upload_http_method.upper() + if http_method == "PUT": + upload_response = sync_httpx_client.put( + url=api_base, + headers=headers, + data=transformed_request, + timeout=timeout, + ) + else: # Default to POST + upload_response = sync_httpx_client.post( + url=api_base, + headers=headers, + data=transformed_request, + timeout=timeout, + ) else: try: # Step 1: Initial request to get upload URL @@ -2280,16 +2310,52 @@ class BaseLLMHTTPHandler: ) else: async_httpx_client = client + + ######################################################### + # Debug Logging + ######################################################### + logging_obj.pre_call( + input="", + api_key="", + additional_args={ + "complete_input_dict": transformed_request, + "api_base": api_base, + "headers": headers, + }, + ) - if isinstance(transformed_request, str) or isinstance( - transformed_request, bytes - ): - upload_response = await async_httpx_client.post( - url=api_base, - headers=headers, - data=transformed_request, + if isinstance(transformed_request, dict) and "method" in transformed_request: + # Handle pre-signed requests (e.g., from Bedrock S3 uploads) + upload_response = await getattr(async_httpx_client, transformed_request["method"].lower())( + url=transformed_request["url"], + headers=transformed_request["headers"], + data=transformed_request["data"], timeout=timeout, ) + elif isinstance(transformed_request, str) or isinstance( + transformed_request, bytes + ): + # Handle traditional file uploads + # Ensure transformed_request is a string for httpx compatibility + if isinstance(transformed_request, bytes): + transformed_request = transformed_request.decode('utf-8') + + # Use the HTTP method specified by the provider config + http_method = provider_config.file_upload_http_method.upper() + if http_method == "PUT": + upload_response = await async_httpx_client.put( + url=api_base, + headers=headers, + data=transformed_request, + timeout=timeout, + ) + else: # Default to POST + upload_response = await async_httpx_client.post( + url=api_base, + headers=headers, + data=transformed_request, + timeout=timeout, + ) else: try: # Step 1: Initial request to get upload URL @@ -2330,6 +2396,188 @@ class BaseLLMHTTPHandler: litellm_params=litellm_params, ) + def create_batch( + self, + create_batch_data: "CreateBatchRequest", + litellm_params: dict, + provider_config: "BaseBatchesConfig", + headers: dict, + api_base: Optional[str], + api_key: Optional[str], + logging_obj: "LiteLLMLoggingObj", + _is_async: bool = False, + client: Optional[Union["HTTPHandler", "AsyncHTTPHandler"]] = None, + timeout: Optional[Union[float, httpx.Timeout]] = None, + ) -> Union["LiteLLMBatch", Coroutine[Any, Any, "LiteLLMBatch"]]: + """ + Creates a batch using provider-specific batch creation process + """ + # get config from model, custom llm provider + headers = provider_config.validate_environment( + api_key=api_key, + headers=headers, + model="", + messages=[], + optional_params={}, + litellm_params=litellm_params, + ) + + api_base = provider_config.get_complete_batch_url( + api_base=api_base, + api_key=api_key, + model="", + optional_params={}, + litellm_params=litellm_params, + data=create_batch_data, + ) + if api_base is None: + raise ValueError("api_base is required for create_batch") + + # Get the transformed request data + transformed_request = provider_config.transform_create_batch_request( + model="", + create_batch_data=create_batch_data, + litellm_params=litellm_params, + optional_params={}, + ) + + if _is_async: + return self.async_create_batch( + transformed_request=transformed_request, + litellm_params=litellm_params, + provider_config=provider_config, + headers=headers, + api_base=api_base, + logging_obj=logging_obj, + client=client, + timeout=timeout, + create_batch_data=create_batch_data, + ) + + if client is None or not isinstance(client, HTTPHandler): + sync_httpx_client = _get_httpx_client() + else: + sync_httpx_client = client + + try: + if isinstance(transformed_request, dict) and "method" in transformed_request: + # Handle pre-signed requests (e.g., from Bedrock with AWS auth) + batch_response = getattr(sync_httpx_client, transformed_request["method"].lower())( + url=transformed_request["url"], + headers=transformed_request["headers"], + data=transformed_request["data"], + timeout=timeout, + ) + elif isinstance(transformed_request, dict): + # For other providers that use JSON requests + batch_response = sync_httpx_client.post( + url=api_base, + headers={**headers, "Content-Type": "application/json"}, + json=transformed_request, + timeout=timeout, + ) + else: + # Handle other request types if needed + batch_response = sync_httpx_client.post( + url=api_base, + headers=headers, + data=transformed_request, + timeout=timeout, + ) + except Exception as e: + verbose_logger.exception(f"Error creating batch: {e}") + raise self._handle_error( + e=e, + provider_config=provider_config, + ) + + # Store original request for response transformation + litellm_params_with_request = {**litellm_params, "original_batch_request": create_batch_data} + + return provider_config.transform_create_batch_response( + model=None, + raw_response=batch_response, + logging_obj=logging_obj, + litellm_params=litellm_params_with_request, + ) + + async def async_create_batch( + self, + transformed_request: Union[bytes, str, dict], + litellm_params: dict, + provider_config: "BaseBatchesConfig", + headers: dict, + api_base: str, + logging_obj: "LiteLLMLoggingObj", + client: Optional[Union["HTTPHandler", "AsyncHTTPHandler"]] = None, + timeout: Optional[Union[float, httpx.Timeout]] = None, + create_batch_data: Optional["CreateBatchRequest"] = None, + ): + """ + Async version of create_batch + """ + if client is None or not isinstance(client, AsyncHTTPHandler): + async_httpx_client = get_async_httpx_client( + llm_provider=provider_config.custom_llm_provider + ) + else: + async_httpx_client = client + + ######################################################### + # Debug Logging + ######################################################### + logging_obj.pre_call( + input="", + api_key="", + additional_args={ + "complete_input_dict": transformed_request, + "api_base": api_base, + "headers": headers, + }, + ) + + try: + if isinstance(transformed_request, dict) and "method" in transformed_request: + # Handle pre-signed requests (e.g., from Bedrock with AWS auth) + batch_response = await getattr(async_httpx_client, transformed_request["method"].lower())( + url=transformed_request["url"], + headers=transformed_request["headers"], + data=transformed_request["data"], + timeout=timeout, + ) + elif isinstance(transformed_request, dict): + # For other providers that use JSON requests + batch_response = await async_httpx_client.post( + url=api_base, + headers={**headers, "Content-Type": "application/json"}, + json=transformed_request, + timeout=timeout, + ) + else: + # Handle other request types if needed + batch_response = await async_httpx_client.post( + url=api_base, + headers=headers, + data=transformed_request, + timeout=timeout, + ) + except Exception as e: + verbose_logger.exception(f"Error creating batch: {e}") + raise self._handle_error( + e=e, + provider_config=provider_config, + ) + + # Store original request for response transformation (for async version) + litellm_params_with_request = {**litellm_params, "original_batch_request": create_batch_data or {}} + + return provider_config.transform_create_batch_response( + model=None, + raw_response=batch_response, + logging_obj=logging_obj, + litellm_params=litellm_params_with_request, + ) + def list_files(self): """ Lists all files @@ -2381,6 +2629,7 @@ class BaseLLMHTTPHandler: BaseVectorStoreConfig, BaseGoogleGenAIGenerateContentConfig, BaseAnthropicMessagesConfig, + BaseBatchesConfig, "BasePassthroughConfig", ], ): diff --git a/litellm/llms/databricks/chat/transformation.py b/litellm/llms/databricks/chat/transformation.py index 908419f7193..d3df5bbf361 100644 --- a/litellm/llms/databricks/chat/transformation.py +++ b/litellm/llms/databricks/chat/transformation.py @@ -26,7 +26,6 @@ from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response impo _should_convert_tool_call_to_json_mode, ) from litellm.litellm_core_utils.prompt_templates.common_utils import ( - handle_messages_with_content_list_to_str_conversion, strip_name_from_messages, ) from litellm.llms.base_llm.base_model_iterator import BaseModelResponseIterator @@ -301,7 +300,6 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig): ) -> Union[List[AllMessageValues], Coroutine[Any, Any, List[AllMessageValues]]]: """ Databricks does not support: - - content in list format. - 'name' in user message. """ new_messages = [] @@ -311,7 +309,6 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig): else: _message = message new_messages.append(_message) - new_messages = handle_messages_with_content_list_to_str_conversion(new_messages) new_messages = strip_name_from_messages(new_messages) if is_async: @@ -379,6 +376,25 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig): thinking_blocks.append(thinking_block) return reasoning_content, thinking_blocks + @staticmethod + def extract_citations( + content: Optional[AllDatabricksContentValues], + ) -> Optional[List[Any]]: + if content is None: + return None + citations = [] + if isinstance(content, list): + for item in content: + text = item.get("text", None) + if citations_item := item.get("citations"): + citations.append( + [ + {**citation, "supported_text": text} + for citation in citations_item + ] + ) + return citations or None + def _transform_dbrx_choices( self, choices: List[DatabricksChoice], json_mode: Optional[bool] = None ) -> List[Choices]: @@ -427,12 +443,19 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig): choice["message"].get("content") ) + citations = DatabricksConfig.extract_citations( + choice["message"].get("content") + ) + translated_message = Message( role="assistant", content=content_str, reasoning_content=reasoning_content, thinking_blocks=thinking_blocks, tool_calls=choice["message"].get("tool_calls"), + provider_specific_fields={"citations": citations} + if citations is not None + else None, ) if finish_reason is None: @@ -561,6 +584,17 @@ class DatabricksChatResponseIterator(BaseModelResponseIterator): for _tc in tool_calls: if _tc.get("function", {}).get("arguments") == "{}": _tc["function"]["arguments"] = "" # avoid invalid json + if isinstance(choice["delta"]["content"], list) and ( + content := choice["delta"]["content"] + ): + if citations := content[0].get("citations"): + # TODO: Databricks delta does not include supported text or chunk type. + # Add either here once Databricks supports it to enable citation linkage. + choice["delta"].setdefault("provider_specific_fields", {})[ + "citation" + ] = citations[ + 0 + ] # Databricks Content item always has citation as a list of list # extract the content str content_str = DatabricksConfig.extract_content_str( choice["delta"].get("content") diff --git a/litellm/llms/deepinfra/chat/transformation.py b/litellm/llms/deepinfra/chat/transformation.py index 0d446d39b92..09cdabcdd82 100644 --- a/litellm/llms/deepinfra/chat/transformation.py +++ b/litellm/llms/deepinfra/chat/transformation.py @@ -12,6 +12,9 @@ class DeepInfraConfig(OpenAIGPTConfig): The class `DeepInfra` provides configuration for the DeepInfra's Chat Completions API interface. Below are the parameters: """ + @property + def custom_llm_provider(self) -> Optional[str]: + return "deepinfra" frequency_penalty: Optional[int] = None function_call: Optional[Union[str, dict]] = None @@ -53,7 +56,7 @@ class DeepInfraConfig(OpenAIGPTConfig): return super().get_config() def get_supported_openai_params(self, model: str): - return [ + supported_openai_params = [ "stream", "frequency_penalty", "function_call", @@ -68,9 +71,16 @@ class DeepInfraConfig(OpenAIGPTConfig): "top_p", "response_format", "tools", - "tool_choice", + "tool_choice" ] + if litellm.supports_reasoning( + model=model, + custom_llm_provider=self.custom_llm_provider, + ): + supported_openai_params.append("reasoning_effort") + return supported_openai_params + def map_openai_params( self, non_default_params: dict, diff --git a/litellm/llms/groq/chat/transformation.py b/litellm/llms/groq/chat/transformation.py index 86fa323f9e3..165301efb5c 100644 --- a/litellm/llms/groq/chat/transformation.py +++ b/litellm/llms/groq/chat/transformation.py @@ -6,6 +6,8 @@ from typing import Any, Coroutine, List, Literal, Optional, Tuple, Union, cast, import httpx from pydantic import BaseModel +import litellm +from litellm._logging import verbose_logger from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj from litellm.secret_managers.main import get_secret_str from litellm.types.llms.openai import ( @@ -55,6 +57,10 @@ class GroqChatConfig(OpenAILikeChatConfig): if key != "self" and value is not None: setattr(self.__class__, key, value) + @property + def custom_llm_provider(self) -> Optional[str]: + return "groq" + @classmethod def get_config(cls): return super().get_config() @@ -65,6 +71,15 @@ class GroqChatConfig(OpenAILikeChatConfig): base_params.remove("max_retries") except ValueError: pass + + try: + if litellm.supports_reasoning( + model=model, custom_llm_provider=self.custom_llm_provider + ): + base_params.append("reasoning_effort") + except Exception as e: + verbose_logger.debug(f"Error checking if model supports reasoning: {e}") + return base_params @overload diff --git a/litellm/llms/oci/chat/transformation.py b/litellm/llms/oci/chat/transformation.py index 3e05473630d..3be373ca5e5 100644 --- a/litellm/llms/oci/chat/transformation.py +++ b/litellm/llms/oci/chat/transformation.py @@ -92,6 +92,22 @@ def load_private_key_from_str(key_str: str): return key +def load_private_key_from_file(file_path: str): + """Loads a private key from a file path""" + try: + with open(file_path, "r", encoding="utf-8") as f: + key_str = f.read().strip() + except FileNotFoundError: + raise FileNotFoundError(f"Private key file not found: {file_path}") + except OSError as e: + raise OSError(f"Failed to read private key file '{file_path}': {e}") from e + + if not key_str: + raise ValueError(f"Private key file is empty: {file_path}") + + return load_private_key_from_str(key_str) + + def get_vendor_from_model(model: str) -> OCIVendors: """ Extracts the vendor from the model name. @@ -237,10 +253,17 @@ class OCIChatConfig(BaseConfig): oci_fingerprint = optional_params.get("oci_fingerprint") oci_tenancy = optional_params.get("oci_tenancy") oci_key = optional_params.get("oci_key") + oci_key_file = optional_params.get("oci_key_file") - if not oci_user or not oci_fingerprint or not oci_tenancy or not oci_key: + if ( + not oci_user + or not oci_fingerprint + or not oci_tenancy + or not (oci_key or oci_key_file) + ): raise Exception( - "Missing one of the following parameters: oci_user, oci_fingerprint, oci_tenancy, oci_key" + "Missing required parameters: oci_user, oci_fingerprint, oci_tenancy, " + "and at least one of oci_key or oci_key_file." ) method = str(optional_params.get("method", "POST")).upper() @@ -283,7 +306,17 @@ class OCIChatConfig(BaseConfig): "Please install it with: pip install cryptography" ) from e - private_key = load_private_key_from_str(oci_key) + private_key = ( + load_private_key_from_str(oci_key) + if oci_key + else load_private_key_from_file(oci_key_file) if oci_key_file else None + ) + + if private_key is None: + raise Exception( + "Private key is required for OCI authentication. Please provide either oci_key or oci_key_file." + ) + signature = private_key.sign( signing_string.encode("utf-8"), padding.PKCS1v15(), @@ -334,17 +367,19 @@ class OCIChatConfig(BaseConfig): oci_fingerprint = optional_params.get("oci_fingerprint") oci_tenancy = optional_params.get("oci_tenancy") oci_key = optional_params.get("oci_key") + oci_key_file = optional_params.get("oci_key_file") oci_compartment_id = optional_params.get("oci_compartment_id") if ( not oci_user or not oci_fingerprint or not oci_tenancy - or not oci_key + or not (oci_key or oci_key_file) or not oci_compartment_id ): raise Exception( - "Missing one of the following parameters: oci_user, oci_fingerprint, oci_tenancy, oci_key, oci_compartment_id" + "Missing required parameters: oci_user, oci_fingerprint, oci_tenancy, " + "and at least one of oci_key or oci_key_file." ) if not api_base: @@ -737,7 +772,14 @@ def adapt_messages_to_generic_oci_standard( tool_calls = message.get("tool_calls") tool_call_id = message.get("tool_call_id") - if role in ["system", "user", "assistant"] and content is not None: + if role == "assistant" and tool_calls is not None: + if not isinstance(tool_calls, list): + raise Exception("Prop `tool_calls` must be a list of tool calls") + new_messages.append( + adapt_messages_to_generic_oci_standard_tool_call(role, tool_calls) + ) + + elif role in ["system", "user", "assistant"] and content is not None: if not isinstance(content, (str, list)): raise Exception( "Prop `content` must be a string or a list of content items" @@ -746,13 +788,6 @@ def adapt_messages_to_generic_oci_standard( adapt_messages_to_generic_oci_standard_content_message(role, content) ) - elif role == "assistant" and tool_calls is not None: - if not isinstance(tool_calls, list): - raise Exception("Prop `tool_calls` must be a list of tool calls") - new_messages.append( - adapt_messages_to_generic_oci_standard_tool_call(role, tool_calls) - ) - elif role == "tool": if not isinstance(tool_call_id, str): raise Exception("Prop `tool_call_id` is required and must be a string") diff --git a/litellm/llms/ollama/chat/transformation.py b/litellm/llms/ollama/chat/transformation.py index d4ce4052a7e..ee0d3acef70 100644 --- a/litellm/llms/ollama/chat/transformation.py +++ b/litellm/llms/ollama/chat/transformation.py @@ -137,6 +137,7 @@ class OllamaChatConfig(BaseConfig): "tool_choice", "functions", "response_format", + "reasoning_effort", ] def map_openai_params( @@ -175,6 +176,8 @@ class OllamaChatConfig(BaseConfig): if value.get("json_schema") and value["json_schema"].get("schema"): optional_params["format"] = value["json_schema"]["schema"] ### FUNCTION CALLING LOGIC ### + if param == "reasoning_effort" and value is not None: + optional_params["think"] = True if param == "tools": ## CHECK IF MODEL SUPPORTS TOOL CALLING ## try: @@ -212,9 +215,9 @@ class OllamaChatConfig(BaseConfig): litellm.add_function_to_prompt = ( True # so that main.py adds the function call to the prompt ) - optional_params[ - "functions_unsupported_model" - ] = non_default_params.get("functions") + optional_params["functions_unsupported_model"] = ( + non_default_params.get("functions") + ) non_default_params.pop("tool_choice", None) # causes ollama requests to hang non_default_params.pop("functions", None) # causes ollama requests to hang return optional_params @@ -229,6 +232,8 @@ class OllamaChatConfig(BaseConfig): api_key: Optional[str] = None, api_base: Optional[str] = None, ) -> dict: + if api_key is not None and "Authorization" not in headers: + headers["Authorization"] = f"Bearer {api_key}" return headers def get_complete_url( @@ -346,11 +351,31 @@ class OllamaChatConfig(BaseConfig): ## RESPONSE OBJECT model_response.choices[0].finish_reason = "stop" + response_json_message = response_json.get("message") + if response_json_message is not None: + if "thinking" in response_json_message: + # remap 'thinking' to 'reasoning_content' + response_json_message["reasoning_content"] = response_json_message[ + "thinking" + ] + del response_json_message["thinking"] + elif response_json_message.get("content") is not None: + # parse reasoning content from content + from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import ( + _parse_content_for_reasoning, + ) + + reasoning_content, content = _parse_content_for_reasoning( + response_json_message["content"] + ) + response_json_message["reasoning_content"] = reasoning_content + response_json_message["content"] = content + if ( request_data.get("format", "") == "json" and litellm_params.get("function_name") is not None ): - function_call = json.loads(response_json["message"]["content"]) + function_call = json.loads(response_json_message["content"]) message = litellm.Message( content=None, tool_calls=[ @@ -367,11 +392,13 @@ class OllamaChatConfig(BaseConfig): "type": "function", } ], + reasoning_content=response_json_message.get("reasoning_content"), ) model_response.choices[0].message = message # type: ignore model_response.choices[0].finish_reason = "tool_calls" else: - _message = litellm.Message(**response_json["message"]) + + _message = litellm.Message(**response_json_message) model_response.choices[0].message = _message # type: ignore model_response.created = int(time.time()) model_response.model = "ollama_chat/" + model @@ -412,6 +439,9 @@ class OllamaChatConfig(BaseConfig): class OllamaChatCompletionResponseIterator(BaseModelResponseIterator): + started_reasoning_content: bool = False + finished_reasoning_content: bool = False + def _is_function_call_complete(self, function_args: Union[str, dict]) -> bool: if isinstance(function_args, dict): return True @@ -465,8 +495,38 @@ class OllamaChatCompletionResponseIterator(BaseModelResponseIterator): if is_function_call_complete: tool_call["id"] = str(uuid.uuid4()) + # PROCESS REASONING CONTENT + reasoning_content: Optional[str] = None + content: Optional[str] = None + if chunk["message"].get("thinking") is not None: + if self.started_reasoning_content is False: + reasoning_content = chunk["message"].get("thinking") + self.started_reasoning_content = True + elif self.finished_reasoning_content is False: + reasoning_content = chunk["message"].get("thinking") + self.finished_reasoning_content = True + elif chunk["message"].get("content") is not None: + message_content = chunk["message"].get("content") + if "" in message_content: + message_content = message_content.replace("", "") + + self.started_reasoning_content = True + + if "" in message_content and self.started_reasoning_content: + message_content = message_content.replace("", "") + self.finished_reasoning_content = True + + if ( + self.started_reasoning_content + and not self.finished_reasoning_content + ): + reasoning_content = message_content + else: + content = message_content + delta = Delta( - content=chunk["message"].get("content", ""), + content=content, + reasoning_content=reasoning_content, tool_calls=tool_calls, ) diff --git a/litellm/llms/ollama/common_utils.py b/litellm/llms/ollama/common_utils.py index daff7a12065..166ceee27fc 100644 --- a/litellm/llms/ollama/common_utils.py +++ b/litellm/llms/ollama/common_utils.py @@ -57,8 +57,20 @@ class OllamaModelInfo(BaseLLMModelInfo): """ @staticmethod - def get_api_key(api_key=None) -> None: - return None # Ollama does not use an API key by default + def get_api_key(api_key=None) -> Optional[str]: + """Get API key from environment variables or litellm configuration""" + import os + + import litellm + from litellm.secret_managers.main import get_secret_str + + return ( + os.environ.get("OLLAMA_API_KEY") + or litellm.api_key + or litellm.openai_key + or get_secret_str("OLLAMA_API_KEY") + ) + @staticmethod def get_api_base(api_base: Optional[str] = None) -> str: @@ -73,9 +85,12 @@ class OllamaModelInfo(BaseLLMModelInfo): """ base = self.get_api_base(api_base) + api_key = self.get_api_key() + headers = { "Authorization": f"Bearer {api_key}" } if api_key else {} + names: set[str] = set() try: - resp = httpx.get(f"{base}/api/tags") + resp = httpx.get(f"{base}/api/tags", headers=headers) resp.raise_for_status() data = resp.json() # Expecting a dict with a 'models' list diff --git a/litellm/llms/ollama/completion/transformation.py b/litellm/llms/ollama/completion/transformation.py index 4f7be507cc2..71bcf0bb3f7 100644 --- a/litellm/llms/ollama/completion/transformation.py +++ b/litellm/llms/ollama/completion/transformation.py @@ -19,13 +19,13 @@ from litellm.llms.base_llm.chat.transformation import BaseConfig, BaseLLMExcepti from litellm.secret_managers.main import get_secret_str from litellm.types.llms.openai import AllMessageValues, ChatCompletionUsageBlock from litellm.types.utils import ( + Delta, GenericStreamingChunk, ModelInfoBase, ModelResponse, ModelResponseStream, ProviderField, StreamingChoices, - Delta, ) from ..common_utils import OllamaError, _convert_image @@ -92,9 +92,9 @@ class OllamaConfig(BaseConfig): repeat_penalty: Optional[float] = None temperature: Optional[float] = None seed: Optional[int] = None - stop: Optional[ - list - ] = None # stop is a list based on this - https://github.com/ollama/ollama/pull/442 + stop: Optional[list] = ( + None # stop is a list based on this - https://github.com/ollama/ollama/pull/442 + ) tfs_z: Optional[float] = None num_predict: Optional[int] = None top_k: Optional[int] = None @@ -154,6 +154,7 @@ class OllamaConfig(BaseConfig): "stop", "response_format", "max_completion_tokens", + "reasoning_effort", ] def map_openai_params( @@ -166,19 +167,21 @@ class OllamaConfig(BaseConfig): for param, value in non_default_params.items(): if param == "max_tokens" or param == "max_completion_tokens": optional_params["num_predict"] = value - if param == "stream": + elif param == "stream": optional_params["stream"] = value - if param == "temperature": + elif param == "temperature": optional_params["temperature"] = value - if param == "seed": + elif param == "seed": optional_params["seed"] = value - if param == "top_p": + elif param == "top_p": optional_params["top_p"] = value - if param == "frequency_penalty": + elif param == "frequency_penalty": optional_params["frequency_penalty"] = value - if param == "stop": + elif param == "stop": optional_params["stop"] = value - if param == "response_format" and isinstance(value, dict): + elif param == "reasoning_effort" and value is not None: + optional_params["think"] = True + elif param == "response_format" and isinstance(value, dict): if value["type"] == "json_object": optional_params["format"] = "json" elif value["type"] == "json_schema": @@ -201,6 +204,21 @@ class OllamaConfig(BaseConfig): return v return None + @staticmethod + def get_api_key() -> Optional[str]: + """Get API key from environment variables or litellm configuration""" + import os + + import litellm + from litellm.secret_managers.main import get_secret_str + + return ( + os.environ.get("OLLAMA_API_KEY") + or litellm.api_key + or litellm.openai_key + or get_secret_str("OLLAMA_API_KEY") + ) + def get_model_info(self, model: str) -> ModelInfoBase: """ curl http://localhost:11434/api/show -d '{ @@ -210,11 +228,14 @@ class OllamaConfig(BaseConfig): if model.startswith("ollama/") or model.startswith("ollama_chat/"): model = model.split("/", 1)[1] api_base = get_secret_str("OLLAMA_API_BASE") or "http://localhost:11434" + api_key = self.get_api_key() + headers = { "Authorization": f"Bearer {api_key}" } if api_key else {} try: response = litellm.module_level_client.post( url=f"{api_base}/api/show", json={"name": model}, + headers=headers, ) except Exception as e: raise Exception( @@ -258,12 +279,17 @@ class OllamaConfig(BaseConfig): api_key: Optional[str] = None, json_mode: Optional[bool] = None, ) -> ModelResponse: + from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import ( + _parse_content_for_reasoning, + ) + response_json = raw_response.json() ## RESPONSE OBJECT model_response.choices[0].finish_reason = "stop" if request_data.get("format", "") == "json": # Check if response field exists and is not empty before parsing JSON response_text = response_json.get("response", "") + if not response_text or not response_text.strip(): # Handle empty response gracefully - set empty content message = litellm.Message(content="") @@ -288,7 +314,9 @@ class OllamaConfig(BaseConfig): "id": f"call_{str(uuid.uuid4())}", "function": { "name": function_call["name"], - "arguments": json.dumps(function_call["arguments"]), + "arguments": json.dumps( + function_call["arguments"] + ), }, "type": "function", } @@ -305,11 +333,28 @@ class OllamaConfig(BaseConfig): model_response.choices[0].finish_reason = "stop" except json.JSONDecodeError: # If JSON parsing fails, treat as regular text response - message = litellm.Message(content=response_text) + ## output parse reasoning content from response_text + reasoning_content: Optional[str] = None + content: Optional[str] = None + if response_text is not None: + reasoning_content, content = _parse_content_for_reasoning( + response_text + ) + message = litellm.Message( + content=content, reasoning_content=reasoning_content + ) model_response.choices[0].message = message # type: ignore model_response.choices[0].finish_reason = "stop" else: - model_response.choices[0].message.content = response_json["response"] # type: ignore + response_text = response_json.get("response", "") + content = None + reasoning_content = None + if response_text is not None and isinstance(response_text, str): + reasoning_content, content = _parse_content_for_reasoning(response_text) + else: + content = response_text # type: ignore + model_response.choices[0].message.content = content # type: ignore + model_response.choices[0].message.reasoning_content = reasoning_content # type: ignore model_response.created = int(time.time()) model_response.model = "ollama/" + model _prompt = request_data.get("prompt", "") @@ -434,12 +479,21 @@ class OllamaConfig(BaseConfig): class OllamaTextCompletionResponseIterator(BaseModelResponseIterator): + def __init__( + self, streaming_response, sync_stream: bool, json_mode: Optional[bool] = False + ): + super().__init__(streaming_response, sync_stream, json_mode) + self.started_reasoning_content: bool = False + self.finished_reasoning_content: bool = False + def _handle_string_chunk( self, str_line: str ) -> Union[GenericStreamingChunk, ModelResponseStream]: return self.chunk_parser(json.loads(str_line)) - def chunk_parser(self, chunk: dict) -> Union[GenericStreamingChunk, ModelResponseStream]: + def chunk_parser( + self, chunk: dict + ) -> Union[GenericStreamingChunk, ModelResponseStream]: try: if "error" in chunk: raise Exception(f"Ollama Error - {chunk}") @@ -469,12 +523,42 @@ class OllamaTextCompletionResponseIterator(BaseModelResponseIterator): ) elif chunk["response"]: text = chunk["response"] - return GenericStreamingChunk( - text=text, - is_finished=is_finished, - finish_reason="stop", + reasoning_content: Optional[str] = None + content: Optional[str] = None + if text is not None: + if "" in text: + text = text.replace("", "") + self.started_reasoning_content = True + elif "" in text: + text = text.replace("", "") + self.finished_reasoning_content = True + + if ( + self.started_reasoning_content + and not self.finished_reasoning_content + ): + reasoning_content = text + else: + content = text + + return ModelResponseStream( + choices=[ + StreamingChoices( + index=0, + delta=Delta( + reasoning_content=reasoning_content, content=content + ), + ) + ], + finish_reason=finish_reason, usage=None, ) + # return GenericStreamingChunk( + # text=text, + # is_finished=is_finished, + # finish_reason="stop", + # usage=None, + # ) elif "thinking" in chunk and not chunk["response"]: # Return reasoning content as ModelResponseStream so UIs can render it thinking_content = chunk.get("thinking") or "" diff --git a/litellm/llms/openai/chat/gpt_5_transformation.py b/litellm/llms/openai/chat/gpt_5_transformation.py index 9a8bb74d447..3902304a3b4 100644 --- a/litellm/llms/openai/chat/gpt_5_transformation.py +++ b/litellm/llms/openai/chat/gpt_5_transformation.py @@ -28,7 +28,18 @@ class OpenAIGPT5Config(OpenAIGPTConfig): base_gpt_series_params.extend(gpt_5_only_params) if not supports_tool_choice(model=model): base_gpt_series_params.remove("tool_choice") - return base_gpt_series_params + + non_supported_params = [ + "logprobs", + "top_p", + "presence_penalty", + "frequency_penalty", + "top_logprobs", + ] + + return [ + param for param in base_gpt_series_params if param not in non_supported_params + ] def map_openai_params( self, diff --git a/litellm/llms/openai/chat/gpt_transformation.py b/litellm/llms/openai/chat/gpt_transformation.py index be0ca3a7086..204916e3a48 100644 --- a/litellm/llms/openai/chat/gpt_transformation.py +++ b/litellm/llms/openai/chat/gpt_transformation.py @@ -158,6 +158,7 @@ class OpenAIGPTConfig(BaseLLMModelInfo, BaseConfig): "parallel_tool_calls", "audio", "web_search_options", + "safety_identifier", ] # works across all models model_specific_params = [] diff --git a/litellm/llms/openai/image_generation/gpt_transformation.py b/litellm/llms/openai/image_generation/gpt_transformation.py index 150cffba21c..1cee13784e7 100644 --- a/litellm/llms/openai/image_generation/gpt_transformation.py +++ b/litellm/llms/openai/image_generation/gpt_transformation.py @@ -16,7 +16,6 @@ class GPTImageGenerationConfig(BaseImageGenerationConfig): ) -> List[OpenAIImageGenerationOptionalParams]: return [ "background", - "input_fidelity", "moderation", "n", "output_compression", diff --git a/litellm/llms/openai/responses/transformation.py b/litellm/llms/openai/responses/transformation.py index e70cadddaf7..392d47f9822 100644 --- a/litellm/llms/openai/responses/transformation.py +++ b/litellm/llms/openai/responses/transformation.py @@ -1,6 +1,15 @@ -from typing import TYPE_CHECKING, Any, Dict, Optional, Union, cast, get_type_hints +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Optional, + Union, + cast, + get_type_hints, +) import httpx +from openai.types.responses import ResponseReasoningItem from pydantic import BaseModel import litellm @@ -92,12 +101,67 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): # if it's pydantic, convert to dict if isinstance(item, BaseModel): validated_input.append(item.model_dump(exclude_none=True)) + elif isinstance(item, dict): + # Handle reasoning items specifically to filter out status=None + verbose_logger.debug(f"Handling reasoning item: {item}") + if item.get("type") == "reasoning": + # Type assertion since we know it's a dict at this point + dict_item = cast(Dict[str, Any], item) + filtered_item = self._handle_reasoning_item(dict_item) + else: + # For other dict items, just pass through + filtered_item = cast(Dict[str, Any], item) + validated_input.append(filtered_item) else: validated_input.append(item) - return validated_input + return validated_input # type: ignore # Input is expected to be either str or List, no single BaseModel expected return input + def _handle_reasoning_item(self, item: Dict[str, Any]) -> Dict[str, Any]: + """ + Handle reasoning items specifically to filter out status=None using OpenAI's model. + Issue: https://github.com/BerriAI/litellm/issues/13484 + OpenAI API does not accept ReasoningItem(status=None), so we need to: + 1. Check if the item is a reasoning type + 2. Create a ResponseReasoningItem object with the item data + 3. Convert it back to dict with exclude_none=True to filter None values + """ + verbose_logger.debug(f"Handling reasoning item: {item}") + if item.get("type") == "reasoning": + try: + # Ensure required fields are present for ResponseReasoningItem + item_data = dict(item) + if "id" not in item_data: + item_data["id"] = f"reasoning_{hash(str(item_data))}" + if "summary" not in item_data: + item_data["summary"] = ( + item_data.get("reasoning_content", "")[:100] + "..." + if len(item_data.get("reasoning_content", "")) > 100 + else item_data.get("reasoning_content", "") + ) + + # Create ResponseReasoningItem object from the item data + reasoning_item = ResponseReasoningItem(**item_data) + + # Convert back to dict with exclude_none=True to exclude None fields + dict_reasoning_item = reasoning_item.model_dump(exclude_none=True) + + return dict_reasoning_item + except Exception as e: + verbose_logger.debug( + f"Failed to create ResponseReasoningItem, falling back to manual filtering: {e}" + ) + # Fallback: manually filter out known None fields + filtered_item = { + k: v + for k, v in item.items() + if v is not None + or k not in {"status", "content", "encrypted_content"} + } + return filtered_item + return item + def transform_response_api_response( self, model: str, diff --git a/litellm/llms/vercel_ai_gateway/chat/transformation.py b/litellm/llms/vercel_ai_gateway/chat/transformation.py new file mode 100644 index 00000000000..13a88377489 --- /dev/null +++ b/litellm/llms/vercel_ai_gateway/chat/transformation.py @@ -0,0 +1,112 @@ +""" +Support for OpenAI's `/v1/chat/completions` endpoint. + +Calls done in OpenAI/openai.py as Vercel AI Gateway is openai-compatible. + +Docs: https://vercel.com/docs/ai-gateway +""" + +from typing import List, Optional, Tuple, Union + +import httpx + +from litellm.llms.base_llm.chat.transformation import BaseLLMException +from litellm.types.llms.openai import AllMessageValues +from litellm.secret_managers.main import get_secret_str +import litellm + +from ...openai.chat.gpt_transformation import OpenAIGPTConfig +from ..common_utils import VercelAIGatewayException + + +class VercelAIGatewayConfig(OpenAIGPTConfig): + @property + def custom_llm_provider(self) -> Optional[str]: + return "vercel_ai_gateway" + + def get_supported_openai_params(self, model: str) -> list: + base_params = super().get_supported_openai_params(model) + if "extra_body" not in base_params: + base_params.append("extra_body") + return base_params + + def _get_openai_compatible_provider_info( + self, api_base: Optional[str], api_key: Optional[str] + ) -> Tuple[Optional[str], Optional[str]]: + + api_base = ( + api_base + or get_secret_str("VERCEL_AI_GATEWAY_API_BASE") + or "https://ai-gateway.vercel.sh/v1" + ) + user_api_key = ( + api_key + or get_secret_str("VERCEL_AI_GATEWAY_API_KEY") + or get_secret_str("VERCEL_OIDC_TOKEN") + ) + return api_base, user_api_key + + def map_openai_params( + self, + non_default_params: dict, + optional_params: dict, + model: str, + drop_params: bool, + ) -> dict: + mapped_openai_params = super().map_openai_params( + non_default_params, optional_params, model, drop_params + ) + + # Vercel AI Gateway-only parameters + extra_body = {} + provider_options = non_default_params.pop("providerOptions", None) + + if provider_options is not None: + extra_body["providerOptions"] = provider_options + + mapped_openai_params["extra_body"] = extra_body # openai client supports `extra_body` param + return mapped_openai_params + + def transform_request( + self, + model: str, + messages: List[AllMessageValues], + optional_params: dict, + litellm_params: dict, + headers: dict, + ) -> dict: + """ + Transform the overall request to be sent to the API. + + Returns: + dict: The transformed request. Sent as the body of the API call. + """ + return super().transform_request( + model, messages, optional_params, litellm_params, headers + ) + + def get_error_class( + self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers] + ) -> BaseLLMException: + return VercelAIGatewayException( + message=error_message, + status_code=status_code, + headers=headers, + ) + + def get_models( + self, api_key: Optional[str] = None, api_base: Optional[str] = None + ) -> List[str]: + api_base, _ = self._get_openai_compatible_provider_info(api_base, api_key) + + if api_base is None: + api_base = "https://ai-gateway.vercel.sh/v1" + + models_url = f"{api_base}/models" + response = litellm.module_level_client.get(url=models_url) + + if response.status_code != 200: + raise Exception(f"Failed to get models: {response.text}") + + models = response.json()["data"] + return [model["id"] for model in models] diff --git a/litellm/llms/vercel_ai_gateway/common_utils.py b/litellm/llms/vercel_ai_gateway/common_utils.py new file mode 100644 index 00000000000..93e792be05e --- /dev/null +++ b/litellm/llms/vercel_ai_gateway/common_utils.py @@ -0,0 +1,5 @@ +from litellm.llms.base_llm.chat.transformation import BaseLLMException + + +class VercelAIGatewayException(BaseLLMException): + pass diff --git a/litellm/llms/vertex_ai/common_utils.py b/litellm/llms/vertex_ai/common_utils.py index 4931631d75d..8588c3efa27 100644 --- a/litellm/llms/vertex_ai/common_utils.py +++ b/litellm/llms/vertex_ai/common_utils.py @@ -187,6 +187,25 @@ def _check_text_in_content(parts: List[PartType]) -> bool: return has_text_param +def _fix_enum_empty_strings(schema, depth=0): + """Fix empty strings in enum values by replacing them with None. Gemini doesn't accept empty strings in enums.""" + if depth > DEFAULT_MAX_RECURSE_DEPTH: + raise ValueError(f"Max depth of {DEFAULT_MAX_RECURSE_DEPTH} exceeded while processing schema.") + + if "enum" in schema and isinstance(schema["enum"], list): + schema["enum"] = [None if value == "" else value for value in schema["enum"]] + + # Reuse existing recursion pattern from convert_anyof_null_to_nullable + properties = schema.get("properties", None) + if properties is not None: + for _, value in properties.items(): + _fix_enum_empty_strings(value, depth=depth + 1) + + items = schema.get("items", None) + if items is not None: + _fix_enum_empty_strings(items, depth=depth + 1) + + 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 @@ -215,6 +234,11 @@ def _build_vertex_schema(parameters: dict, add_property_ordering: bool = False): # * https://github.com/pydantic/pydantic/discussions/4872 convert_anyof_null_to_nullable(parameters) + _convert_schema_types(parameters) + + # Handle empty strings in enum values - Gemini doesn't accept empty strings in enums + _fix_enum_empty_strings(parameters) + # Handle empty items objects process_items(parameters) add_object_type(parameters) @@ -254,9 +278,7 @@ def _filter_anyof_fields(schema_dict: Dict[str, Any]) -> Dict[str, Any]: item["title"] = title if description: item["description"] = description - return {"anyOf": any_of} - else: - return schema_dict + return {"anyOf": any_of} return schema_dict @@ -441,6 +463,47 @@ def _convert_vertex_datetime_to_openai_datetime(vertex_datetime: str) -> int: return int(dt.timestamp()) +def _convert_schema_types(schema, depth=0): + """ + Convert type arrays and lowercase types for Vertex AI compatibility. + + Transforms OpenAI-style schemas to Vertex AI format by converting type arrays + like ["string", "number"] to anyOf format and converting all types to uppercase. + """ + 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 not isinstance(schema, dict): + return + + + # Handle type field + if "type" in schema: + type_val = schema["type"] + if isinstance(type_val, list) and len(type_val) > 1: + # Convert ["string", "number"] -> {"anyOf": [{"type": "STRING"}, {"type": "NUMBER"}]} + schema["anyOf"] = [{"type": t} for t in type_val if isinstance(t, str)] + schema.pop("type") + elif isinstance(type_val, list) and len(type_val) == 1: + schema["type"] = type_val[0] + elif isinstance(type_val, str): + schema["type"] = type_val + + # Recursively process nested properties, items, and anyOf + for key in ["properties", "items", "anyOf"]: + if key in schema: + value = schema[key] + if key == "properties" and isinstance(value, dict): + for prop_schema in value.values(): + _convert_schema_types(prop_schema, depth + 1) + elif key == "items": + _convert_schema_types(value, depth + 1) + elif key == "anyOf" and isinstance(value, list): + for anyof_schema in value: + _convert_schema_types(anyof_schema, depth + 1) + def get_vertex_project_id_from_url(url: str) -> Optional[str]: """ Get the vertex project id from the url diff --git a/litellm/llms/vertex_ai/gemini/transformation.py b/litellm/llms/vertex_ai/gemini/transformation.py index 8ab212e2558..267ca61ef5d 100644 --- a/litellm/llms/vertex_ai/gemini/transformation.py +++ b/litellm/llms/vertex_ai/gemini/transformation.py @@ -105,6 +105,64 @@ def _process_gemini_image(image_url: str, format: Optional[str] = None) -> PartT raise e +def _snake_to_camel(snake_str: str) -> str: + """Convert snake_case to camelCase""" + components = snake_str.split("_") + return components[0] + "".join(x.capitalize() for x in components[1:]) + + +def _camel_to_snake(camel_str: str) -> str: + """Convert camelCase to snake_case""" + import re + + return re.sub(r"(? Optional[str]: + """ + Get the equivalent key from available keys, checking both camelCase and snake_case variants + """ + if key in available_keys: + return key + + # Try camelCase version + camel_key = _snake_to_camel(key) + if camel_key in available_keys: + return camel_key + + # Try snake_case version + snake_key = _camel_to_snake(key) + if snake_key in available_keys: + return snake_key + + return None + + +def check_if_part_exists_in_parts( + parts: List[PartType], part: PartType, excluded_keys: List[str] = [] +) -> bool: + """ + Check if a part exists in a list of parts + Handles both camelCase and snake_case key variations (e.g., function_call vs functionCall) + """ + keys_to_compare = set(part.keys()) - set(excluded_keys) + for p in parts: + p_keys = set(p.keys()) + # Check if all keys in part have equivalent values in p + match_found = True + for key in keys_to_compare: + equivalent_key = _get_equivalent_key(key, p_keys) + if equivalent_key is None or p.get(equivalent_key, None) != part.get( + key, None + ): + match_found = False + break + + if match_found: + return True + return False + + def _gemini_convert_messages_with_history( # noqa: PLR0915 messages: List[AllMessageValues], ) -> List[ContentType]: @@ -236,10 +294,33 @@ def _gemini_convert_messages_with_history( # noqa: PLR0915 assistant_msg = ChatCompletionAssistantMessage(**msg_dict) # type: ignore _message_content = assistant_msg.get("content", None) reasoning_content = assistant_msg.get("reasoning_content", None) + thinking_blocks = assistant_msg.get("thinking_blocks") if reasoning_content is not None: assistant_content.append( PartType(thought=True, text=reasoning_content) ) + if thinking_blocks is not None: + for block in thinking_blocks: + block_thinking_str = block.get("thinking") + block_signature = block.get("signature") + if ( + block_thinking_str is not None + and block_signature is not None + ): + try: + assistant_content.append( + PartType( + thoughtSignature=block_signature, + **json.loads(block_thinking_str), + ) + ) + except Exception: + assistant_content.append( + PartType( + thoughtSignature=block_signature, + text=block_thinking_str, + ) + ) if _message_content is not None and isinstance(_message_content, list): _parts = [] for element in _message_content: @@ -262,9 +343,17 @@ def _gemini_convert_messages_with_history( # noqa: PLR0915 assistant_msg.get("tool_calls", []) is not None or assistant_msg.get("function_call") is not None ): # support assistant tool invoke conversion - assistant_content.extend( - convert_to_gemini_tool_call_invoke(assistant_msg) + gemini_tool_call_parts = convert_to_gemini_tool_call_invoke( + assistant_msg ) + ## check if gemini_tool_call already exists in assistant_content + for gemini_tool_call_part in gemini_tool_call_parts: + if not check_if_part_exists_in_parts( + assistant_content, + gemini_tool_call_part, + excluded_keys=["thoughtSignature"], + ): + assistant_content.append(gemini_tool_call_part) last_message_with_tool_calls = assistant_msg msg_i += 1 @@ -476,6 +565,7 @@ async def async_transform_request_body( optional_params=optional_params, ) + def _default_user_message_when_system_message_passed() -> ChatCompletionUserMessage: """ Returns a default user message when a "system" message is passed in gemini fails. @@ -484,6 +574,7 @@ def _default_user_message_when_system_message_passed() -> ChatCompletionUserMess """ return ChatCompletionUserMessage(content=".", role="user") + def _transform_system_message( supports_system_message: bool, messages: List[AllMessageValues] ) -> Tuple[Optional[SystemInstructions], List[AllMessageValues]]: 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 923e140a262..9376b28cbec 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 @@ -30,6 +30,10 @@ from litellm.constants import ( DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET, DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET, DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH, + DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_PRO, + DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH_LITE, ) from litellm.llms.base_llm.chat.transformation import BaseConfig, BaseLLMException from litellm.llms.custom_httpx.http_handler import ( @@ -43,9 +47,11 @@ from litellm.types.llms.gemini import BidiGenerateContentServerMessage from litellm.types.llms.openai import ( AllMessageValues, ChatCompletionResponseMessage, + ChatCompletionThinkingBlock, ChatCompletionToolCallChunk, ChatCompletionToolCallFunctionChunk, ChatCompletionToolParamFunctionChunk, + ImageURLListItem, ImageURLObject, OpenAIChatCompletionFinishReason, ) @@ -421,8 +427,25 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): @staticmethod def _map_reasoning_effort_to_thinking_budget( reasoning_effort: str, + model: Optional[str] = None, ) -> GeminiThinkingConfig: - if reasoning_effort == "low": + if reasoning_effort == "minimal": + # Use model-specific minimum thinking budget or fallback + # Check for exact matches first, then partial matches + if model and "gemini-2.5-flash-lite" in model.lower(): + budget = DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH_LITE + elif model and "gemini-2.5-pro" in model.lower(): + budget = DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_PRO + elif model and "gemini-2.5-flash" in model.lower(): + budget = DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET_GEMINI_2_5_FLASH + else: + budget = DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET + + return { + "thinkingBudget": budget, + "includeThoughts": True, + } + elif reasoning_effort == "low": return { "thinkingBudget": DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET, "includeThoughts": True, @@ -463,7 +486,6 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): params["includeThoughts"] = True if thinking_budget is not None and isinstance(thinking_budget, int): params["thinkingBudget"] = thinking_budget - return params def map_response_modalities(self, value: list) -> list: @@ -600,7 +622,9 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): optional_params["seed"] = value elif param == "reasoning_effort" and isinstance(value, str): optional_params["thinkingConfig"] = ( - VertexGeminiConfig._map_reasoning_effort_to_thinking_budget(value) + VertexGeminiConfig._map_reasoning_effort_to_thinking_budget( + value, model + ) ) elif param == "thinking": optional_params["thinkingConfig"] = ( @@ -793,11 +817,30 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): content_str += _content_str return content_str, reasoning_content_str - + + def _extract_thinking_blocks_from_parts( + self, parts: List[HttpxPartType] + ) -> List[ChatCompletionThinkingBlock]: + """Extract thinking blocks from parts if present""" + thinking_blocks: List[ChatCompletionThinkingBlock] = [] + for part in parts: + if "thoughtSignature" in part: + part_copy = part.copy() + part_copy.pop("thoughtSignature") + thinking_blocks.append( + ChatCompletionThinkingBlock( + type="thinking", + thinking=json.dumps(part_copy), + signature=part["thoughtSignature"], + ) + ) + return thinking_blocks + def _extract_image_response_from_parts( self, parts: List[HttpxPartType] - ) -> Optional[ImageURLObject]: + ) -> Optional[List[ImageURLListItem]]: """Extract image response from parts if present""" + images: List[ImageURLListItem] = [] for part in parts: if "inlineData" in part: mime_type = part["inlineData"]["mimeType"] @@ -805,11 +848,14 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): if mime_type.startswith("image/"): # Convert base64 data to data URI format data_uri = f"data:{mime_type};base64,{data}" - return ImageURLObject( - url=data_uri, - detail="auto" + images.append( + ImageURLListItem( + image_url=ImageURLObject(url=data_uri, detail="auto"), + index=0, + type="image_url", + ) ) - return None + return images def _extract_audio_response_from_parts( self, parts: List[HttpxPartType] @@ -1128,7 +1174,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): elif web_search_queries: web_search_requests = len(grounding_metadata) return web_search_requests - + @staticmethod def _create_streaming_choice( chat_completion_message: ChatCompletionResponseMessage, @@ -1137,7 +1183,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): tools: Optional[List[ChatCompletionToolCallChunk]], functions: Optional[ChatCompletionToolCallFunctionChunk], chat_completion_logprobs: Optional[ChoiceLogprobs], - image_response: Optional[ImageURLObject], + image_response: Optional[List[ImageURLListItem]], ) -> StreamingChoices: """ Helper method to create a streaming choice object for Vertex AI @@ -1152,11 +1198,9 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): index=candidate.get("index", idx), delta=Delta( content=chat_completion_message.get("content"), - reasoning_content=chat_completion_message.get( - "reasoning_content" - ), + reasoning_content=chat_completion_message.get("reasoning_content"), tool_calls=tools, - image=image_response, + images=image_response, function_call=functions, ), logprobs=chat_completion_logprobs, @@ -1165,13 +1209,15 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): return choice @staticmethod - def _extract_candidate_metadata(candidate: Candidates) -> Tuple[List[dict], List[dict], List, List]: + def _extract_candidate_metadata( + candidate: Candidates, + ) -> Tuple[List[dict], List[dict], List, List]: """ Extract metadata from a single candidate response. - + Returns: grounding_metadata: List[dict] - url_context_metadata: List[dict] + url_context_metadata: List[dict] safety_ratings: List citation_metadata: List """ @@ -1179,7 +1225,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): url_context_metadata: List[dict] = [] safety_ratings: List = [] citation_metadata: List = [] - + if "groundingMetadata" in candidate: if isinstance(candidate["groundingMetadata"], list): grounding_metadata.extend(candidate["groundingMetadata"]) # type: ignore @@ -1195,8 +1241,13 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): if "urlContextMetadata" in candidate: # Add URL context metadata to grounding metadata url_context_metadata.append(cast(dict, candidate["urlContextMetadata"])) - - return grounding_metadata, url_context_metadata, safety_ratings, citation_metadata + + return ( + grounding_metadata, + url_context_metadata, + safety_ratings, + citation_metadata, + ) @staticmethod def _process_candidates( @@ -1220,7 +1271,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): grounding_metadata: List[dict] = [] url_context_metadata: List[dict] = [] - image_response: Optional[ImageURLObject] = None + image_response: Optional[List[ImageURLListItem]] = None safety_ratings: List = [] citation_metadata: List = [] chat_completion_message: ChatCompletionResponseMessage = {"role": "assistant"} @@ -1228,6 +1279,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): tools: Optional[List[ChatCompletionToolCallChunk]] = [] functions: Optional[ChatCompletionToolCallFunctionChunk] = None cumulative_tool_call_index: int = 0 + thinking_blocks: Optional[List[ChatCompletionThinkingBlock]] = None for idx, candidate in enumerate(_candidates): if "content" not in candidate: @@ -1240,7 +1292,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): candidate_safety_ratings, candidate_citation_metadata, ) = VertexGeminiConfig._extract_candidate_metadata(candidate) - + grounding_metadata.extend(candidate_grounding_metadata) url_context_metadata.extend(candidate_url_context_metadata) safety_ratings.extend(candidate_safety_ratings) @@ -1265,15 +1317,23 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): ) ) + thinking_blocks = ( + VertexGeminiConfig()._extract_thinking_blocks_from_parts( + parts=candidate["content"]["parts"] + ) + ) + if audio_response is not None: cast(Dict[str, Any], chat_completion_message)[ "audio" ] = audio_response chat_completion_message["content"] = None # OpenAI spec - elif image_response is not None: + if image_response is not None: # Handle image response - combine with text content into structured format - cast(Dict[str, Any], chat_completion_message)["image"] = image_response - elif content is not None: + cast(Dict[str, Any], chat_completion_message)[ + "images" + ] = image_response + if content is not None: chat_completion_message["content"] = content if reasoning_content is not None: @@ -1299,15 +1359,18 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): if functions is not None: chat_completion_message["function_call"] = functions + if thinking_blocks is not None: + chat_completion_message["thinking_blocks"] = thinking_blocks # type: ignore + if isinstance(model_response, ModelResponseStream): choice = VertexGeminiConfig._create_streaming_choice( chat_completion_message=chat_completion_message, - candidate=candidate, - idx=idx, - tools=tools, - functions=functions, + candidate=candidate, + idx=idx, + tools=tools, + functions=functions, chat_completion_logprobs=chat_completion_logprobs, - image_response=image_response + image_response=image_response, ) model_response.choices.append(choice) elif isinstance(model_response, ModelResponse): diff --git a/litellm/llms/vertex_ai/vertex_ai_partner_models/gpt_oss/transformation.py b/litellm/llms/vertex_ai/vertex_ai_partner_models/gpt_oss/transformation.py new file mode 100644 index 00000000000..86e36e802ed --- /dev/null +++ b/litellm/llms/vertex_ai/vertex_ai_partner_models/gpt_oss/transformation.py @@ -0,0 +1,27 @@ +import litellm +from litellm.llms.openai.chat.gpt_transformation import OpenAIGPTConfig + + +class VertexAIGPTOSSTransformation(OpenAIGPTConfig): + """ + Transformation for GPT-OSS model from VertexAI + + https://console.cloud.google.com/vertex-ai/publishers/openai/model-garden/gpt-oss-120b-maas?hl=id + """ + def __init__(self): + super().__init__() + + def get_supported_openai_params(self, model: str) -> list: + base_gpt_series_params = super().get_supported_openai_params(model=model) + gpt_oss_only_params = ["reasoning_effort"] + base_gpt_series_params.extend(gpt_oss_only_params) + + ######################################################### + # VertexAI - GPT-OSS does not support tool calls + ######################################################### + if litellm.supports_function_calling(model=model) is False: + TOOL_CALLING_PARAMS_TO_REMOVE = ["tool", "tool_choice", "function_call", "functions"] + base_gpt_series_params = [param for param in base_gpt_series_params if param not in TOOL_CALLING_PARAMS_TO_REMOVE] + + return base_gpt_series_params + diff --git a/litellm/llms/vertex_ai/vertex_ai_partner_models/main.py b/litellm/llms/vertex_ai/vertex_ai_partner_models/main.py index f281cab3b58..ea29970f0aa 100644 --- a/litellm/llms/vertex_ai/vertex_ai_partner_models/main.py +++ b/litellm/llms/vertex_ai/vertex_ai_partner_models/main.py @@ -1,5 +1,6 @@ # What is this? ## API Handler for calling Vertex AI Partner Models +from enum import Enum from typing import Callable, Optional, Union import httpx # type: ignore @@ -27,6 +28,16 @@ class VertexAIError(Exception): self.message ) # Call the base class constructor with the parameters it needs +class PartnerModelPrefixes(str, Enum): + META_PREFIX = "meta/" + DEEPSEEK_PREFIX = "deepseek-ai" + MISTRAL_PREFIX = "mistral" + CODERESTAL_PREFIX = "codestral" + JAMBA_PREFIX = "jamba" + CLAUDE_PREFIX = "claude" + QWEN_PREFIX = "qwen" + GPT_OSS_PREFIX = "openai/gpt-oss-" + class VertexAIPartnerModels(VertexBase): def __init__(self) -> None: @@ -42,13 +53,14 @@ class VertexAIPartnerModels(VertexBase): bool: True if the model string is a Vertex AI Partner Model, False otherwise """ if ( - model.startswith("meta/") - or model.startswith("deepseek-ai") - or model.startswith("mistral") - or model.startswith("codestral") - or model.startswith("jamba") - or model.startswith("claude") - or model.startswith("qwen") + model.startswith(PartnerModelPrefixes.META_PREFIX) + or model.startswith(PartnerModelPrefixes.DEEPSEEK_PREFIX) + or model.startswith(PartnerModelPrefixes.MISTRAL_PREFIX) + or model.startswith(PartnerModelPrefixes.CODERESTAL_PREFIX) + or model.startswith(PartnerModelPrefixes.JAMBA_PREFIX) + or model.startswith(PartnerModelPrefixes.CLAUDE_PREFIX) + or model.startswith(PartnerModelPrefixes.QWEN_PREFIX) + or model.startswith(PartnerModelPrefixes.GPT_OSS_PREFIX) ): return True return False @@ -57,8 +69,9 @@ class VertexAIPartnerModels(VertexBase): def should_use_openai_handler(model: str): OPENAI_LIKE_VERTEX_PROVIDERS = [ "llama", - "deepseek-ai", - "qwen", + PartnerModelPrefixes.DEEPSEEK_PREFIX, + PartnerModelPrefixes.QWEN_PREFIX, + PartnerModelPrefixes.GPT_OSS_PREFIX, ] if any(provider in model for provider in OPENAI_LIKE_VERTEX_PROVIDERS): return True diff --git a/litellm/llms/vertex_ai/vertex_llm_base.py b/litellm/llms/vertex_ai/vertex_llm_base.py index ae43e1fd167..c24f26fffa7 100644 --- a/litellm/llms/vertex_ai/vertex_llm_base.py +++ b/litellm/llms/vertex_ai/vertex_llm_base.py @@ -469,14 +469,28 @@ class VertexBase: raise ValueError("Credentials are None after loading") if _credentials.expired: - verbose_logger.debug( - f"Credentials expired, refreshing for project_id: {project_id}" - ) - self.refresh_auth(_credentials) - self._credentials_project_mapping[credential_cache_key] = ( - _credentials, - credential_project_id, - ) + try: + verbose_logger.debug( + f"Credentials expired, refreshing for project_id: {project_id}" + ) + self.refresh_auth(_credentials) + self._credentials_project_mapping[credential_cache_key] = ( + _credentials, + credential_project_id, + ) + except Exception as e: + # if refresh fails, it's possible the user has re-authenticated via `gcloud auth application-default login` + # in this case, we should try to reload the credentials by clearing the cache and retrying + if "Reauthentication is needed" in str(e): + verbose_logger.debug( + f"Credential refresh failed for project_id: {project_id}. Deleting from cache and retrying." + ) + del self._credentials_project_mapping[credential_cache_key] + return self.get_access_token( + credentials=credentials, + project_id=project_id, + ) + raise e ## VALIDATION STEP if _credentials.token is None or not isinstance(_credentials.token, str): diff --git a/litellm/llms/volcengine/__init__.py b/litellm/llms/volcengine/__init__.py new file mode 100644 index 00000000000..0887937bed5 --- /dev/null +++ b/litellm/llms/volcengine/__init__.py @@ -0,0 +1,24 @@ +""" +Volcengine LLM Provider +Support for Volcengine (ByteDance) chat and embedding models +""" + +from .chat.transformation import VolcEngineChatConfig +from .common_utils import ( + VolcEngineError, + get_volcengine_base_url, + get_volcengine_headers, +) +from .embedding import VolcEngineEmbeddingConfig + +# For backward compatibility, keep the old class name +VolcEngineConfig = VolcEngineChatConfig + +__all__ = [ + "VolcEngineChatConfig", + "VolcEngineConfig", # backward compatibility + "VolcEngineEmbeddingConfig", + "VolcEngineError", + "get_volcengine_base_url", + "get_volcengine_headers", +] diff --git a/litellm/llms/volcengine.py b/litellm/llms/volcengine/chat/transformation.py similarity index 91% rename from litellm/llms/volcengine.py rename to litellm/llms/volcengine/chat/transformation.py index c878aaf933c..216570a1aba 100644 --- a/litellm/llms/volcengine.py +++ b/litellm/llms/volcengine/chat/transformation.py @@ -3,7 +3,7 @@ from typing import Optional, Union from litellm.llms.openai_like.chat.transformation import OpenAILikeChatConfig -class VolcEngineConfig(OpenAILikeChatConfig): +class VolcEngineChatConfig(OpenAILikeChatConfig): frequency_penalty: Optional[int] = None function_call: Optional[Union[str, dict]] = None functions: Optional[list] = None @@ -82,17 +82,19 @@ class VolcEngineConfig(OpenAILikeChatConfig): if "thinking" in optional_params: thinking_value = optional_params.pop("thinking") - + # Handle disabled thinking case - don't add to extra_body if disabled if ( - thinking_value is not None - and isinstance(thinking_value, dict) + thinking_value is not None + and isinstance(thinking_value, dict) and thinking_value.get("type") == "disabled" ): # Skip adding thinking parameter when it's disabled pass else: # Add thinking parameter to extra_body for all other cases - optional_params.setdefault("extra_body", {})["thinking"] = thinking_value + optional_params.setdefault("extra_body", {})[ + "thinking" + ] = thinking_value return optional_params diff --git a/litellm/llms/volcengine/common_utils.py b/litellm/llms/volcengine/common_utils.py new file mode 100644 index 00000000000..0c8d3daebdc --- /dev/null +++ b/litellm/llms/volcengine/common_utils.py @@ -0,0 +1,62 @@ +""" +Common utilities for Volcengine LLM provider +""" + +from typing import Optional + +import httpx + +from litellm.llms.base_llm.chat.transformation import BaseLLMException + + +class VolcEngineError(BaseLLMException): + """ + Custom exception class for Volcengine provider errors. + """ + + def __init__( + self, status_code: int, message: str, headers: Optional[httpx.Headers] = None + ): + self.status_code = status_code + self.message = message + self.headers = headers or httpx.Headers() + super().__init__( + status_code=status_code, message=message, headers=dict(self.headers) + ) + + +def get_volcengine_base_url(api_base: Optional[str] = None) -> str: + """ + Get the base URL for Volcengine API calls. + + Args: + api_base: Optional custom API base URL + + Returns: + The base URL to use for API calls + """ + if api_base: + return api_base + return "https://ark.cn-beijing.volces.com" + + +def get_volcengine_headers(api_key: str, extra_headers: Optional[dict] = None) -> dict: + """ + Get headers for Volcengine API calls. + + Args: + api_key: The API key for authentication + extra_headers: Optional additional headers + + Returns: + Dictionary of headers + """ + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}", + } + + if extra_headers: + headers.update(extra_headers) + + return headers diff --git a/litellm/llms/volcengine/embedding/__init__.py b/litellm/llms/volcengine/embedding/__init__.py new file mode 100644 index 00000000000..7b3efc4f961 --- /dev/null +++ b/litellm/llms/volcengine/embedding/__init__.py @@ -0,0 +1,7 @@ +""" +Volcengine Embedding Module +""" + +from .transformation import VolcEngineEmbeddingConfig + +__all__ = ["VolcEngineEmbeddingConfig"] diff --git a/litellm/llms/volcengine/embedding/transformation.py b/litellm/llms/volcengine/embedding/transformation.py new file mode 100644 index 00000000000..20747b76725 --- /dev/null +++ b/litellm/llms/volcengine/embedding/transformation.py @@ -0,0 +1,211 @@ +""" +Volcengine Embedding Transformation +Transforms OpenAI embedding requests to Volcengine format +""" + +from typing import List, Optional, Union, Dict, Any +import httpx +from litellm.types.llms.openai import AllEmbeddingInputValues, AllMessageValues +from litellm.types.utils import EmbeddingResponse +from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj +from litellm.llms.base_llm.embedding.transformation import BaseEmbeddingConfig +from litellm.llms.base_llm.chat.transformation import BaseLLMException +from ..common_utils import get_volcengine_base_url, get_volcengine_headers + + +class VolcEngineEmbeddingConfig(BaseEmbeddingConfig): + """ + Configuration class for Volcengine embedding models. + Reference: https://ark.cn-beijing.volces.com/api/v3/embeddings + """ + + def __init__( + self, + encoding_format: Optional[str] = None, + ) -> None: + locals_ = locals().copy() + for key, value in locals_.items(): + if key != "self" and value is not None: + setattr(self.__class__, key, value) + + @classmethod + def get_config(cls): + return super().get_config() + + def get_supported_openai_params(self, model: str) -> List[str]: + """ + Get the list of OpenAI parameters supported by Volcengine embedding models. + + Args: + model: The model name + + Returns: + List of supported parameter names + """ + return [ + "encoding_format", + "user", + "extra_headers", + ] + + 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: + """ + Get the complete URL for volcengine embedding API calls. + + Args: + api_base: Optional custom API base URL + api_key: API key (not used for URL construction) + model: Model name (not used for URL construction) + optional_params: Optional parameters (not used for URL construction) + litellm_params: LiteLLM parameters (not used for URL construction) + stream: Stream parameter (not used for URL construction) + + Returns: + Complete URL for the embedding API endpoint + """ + base_url = get_volcengine_base_url(api_base) + # Construct the complete URL with /embeddings endpoint + if base_url.endswith("/api/v3"): + return f"{base_url}/embeddings" + else: + return f"{base_url}/api/v3/embeddings" + + def map_openai_params( + self, + non_default_params: Dict[str, Any], + optional_params: Dict[str, Any], + model: str, + drop_params: bool, + ) -> Dict[str, Any]: + """ + Map OpenAI embedding parameters to Volcengine format. + + Args: + non_default_params: Parameters that are not default values + optional_params: Optional parameters dict to update + model: The model name + drop_params: Whether to drop unsupported parameters + + Returns: + Updated optional_params dict + """ + for param, value in non_default_params.items(): + if param == "encoding_format": + # Volcengine supports: float, base64, null + if value in ["float", "base64", None]: + optional_params["encoding_format"] = value + else: + if not drop_params: + raise ValueError( + f"Unsupported encoding_format: {value}. Volcengine supports: float, base64, null" + ) + elif param == "user": + # Keep user parameter as-is + optional_params["user"] = value + elif param in self.get_supported_openai_params(model): + optional_params[param] = value + elif not drop_params: + raise ValueError(f"Unsupported parameter for Volcengine: {param}") + + return optional_params + + + + def transform_embedding_request( + self, + model: str, + input: AllEmbeddingInputValues, + optional_params: dict, + headers: dict, + ) -> dict: + """Transform embedding request to Volcengine format""" + # Prepare request data (only the JSON body, not the full request) + data = { + "model": model, + "input": input if isinstance(input, list) else [input], + } + + # Add optional parameters from optional_params + if "encoding_format" in optional_params: + encoding_format = optional_params["encoding_format"] + if encoding_format is not None: + data["encoding_format"] = encoding_format + + if "user" in optional_params: + user = optional_params["user"] + if user is not None: + data["user"] = user + + return data + + def transform_embedding_response( + self, + model: str, + raw_response: httpx.Response, + model_response: EmbeddingResponse, + logging_obj: LiteLLMLoggingObj, + api_key: Optional[str], + request_data: dict, + optional_params: dict, + litellm_params: dict, + ) -> EmbeddingResponse: + """Transform Volcengine response to EmbeddingResponse""" + try: + response_json = raw_response.json() + except Exception as e: + raise ValueError(f"Failed to parse Volcengine response as JSON: {str(e)}") + + # Volcengine response format matches OpenAI format closely + # Just need to ensure all required fields are present + transformed_response = { + "object": "list", + "data": response_json.get("data", []), + "model": response_json.get("model", model), + "usage": response_json.get("usage", {}), + } + + # Add id if present + if "id" in response_json: + transformed_response["id"] = response_json["id"] + + # Create EmbeddingResponse from transformed data + return EmbeddingResponse(**transformed_response) + + 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: + """Validate environment and return headers""" + # Get Volcengine headers + if api_key is None: + raise ValueError("api_key is required for Volcengine authentication") + volcengine_headers = get_volcengine_headers(api_key) + return {**headers, **volcengine_headers} + + def get_error_class( + self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers] + ) -> BaseLLMException: + """Get error class for Volcengine errors""" + from ..common_utils import VolcEngineError + # Convert dict to httpx.Headers if needed + if isinstance(headers, dict): + headers = httpx.Headers(headers) + return VolcEngineError( + status_code=status_code, + message=error_message, + headers=headers, + ) diff --git a/litellm/llms/xai/chat/transformation.py b/litellm/llms/xai/chat/transformation.py index 5a488876cd9..78c20ac5731 100644 --- a/litellm/llms/xai/chat/transformation.py +++ b/litellm/llms/xai/chat/transformation.py @@ -31,7 +31,6 @@ class XAIChatConfig(OpenAIGPTConfig): def get_supported_openai_params(self, model: str) -> list: base_openai_params = [ - "frequency_penalty", "logit_bias", "logprobs", "max_tokens", @@ -50,8 +49,22 @@ class XAIChatConfig(OpenAIGPTConfig): "web_search_options", ] # for some reason, grok-3-mini does not support stop tokens + ######################################################### + # stop tokens check + ######################################################### if self._supports_stop_reason(model): base_openai_params.append("stop") + + + ######################################################### + # frequency penalty check + ######################################################### + if self._supports_frequency_penalty(model): + base_openai_params.append("frequency_penalty") + + ######################################################### + # reasoning check + ######################################################### try: if litellm.supports_reasoning( model=model, custom_llm_provider=self.custom_llm_provider @@ -68,6 +81,18 @@ class XAIChatConfig(OpenAIGPTConfig): elif "grok-4" in model: return False return True + + def _supports_frequency_penalty(self, model: str) -> bool: + """ + From manual testing grok-4 does not support `frequency_penalty` + + When sent the model fails from xAI API + """ + if "grok-4" in model: + return False + if "grok-code-fast" in model: + return False + return True def map_openai_params( self, diff --git a/litellm/llms/xai/cost_calculator.py b/litellm/llms/xai/cost_calculator.py new file mode 100644 index 00000000000..62a48080d1c --- /dev/null +++ b/litellm/llms/xai/cost_calculator.py @@ -0,0 +1,54 @@ +""" +Helper util for handling XAI-specific cost calculation +- e.g.: reasoning tokens for grok models +""" + +from typing import Tuple, Union + +from litellm.types.utils import Usage +from litellm.utils import get_model_info + + +def cost_per_token(model: str, usage: Usage) -> Tuple[float, float]: + """ + Calculates the cost per token for a given XAI model, prompt tokens, and completion tokens. + + Input: + - model: str, the model name without provider prefix + - usage: LiteLLM Usage block, containing XAI-specific usage information + + Returns: + Tuple[float, float] - prompt_cost_in_usd, completion_cost_in_usd + """ + ## GET MODEL INFO + model_info = get_model_info(model=model, custom_llm_provider="xai") + + def _safe_float_cast( + value: Union[str, int, float, None, object], default: float = 0.0 + ) -> float: + """Safely cast a value to float with proper type handling for mypy.""" + if value is None: + return default + try: + return float(value) # type: ignore + except (ValueError, TypeError): + return default + + ## CALCULATE INPUT COST + input_cost_per_token = _safe_float_cast(model_info.get("input_cost_per_token")) + prompt_cost: float = (usage.prompt_tokens or 0) * input_cost_per_token + + ## CALCULATE OUTPUT COST + output_cost_per_token = _safe_float_cast(model_info.get("output_cost_per_token")) + + # For XAI models, completion is billed as (visible completion tokens + reasoning tokens) + completion_tokens = int(getattr(usage, "completion_tokens", 0) or 0) + reasoning_tokens = 0 + if hasattr(usage, "completion_tokens_details") and usage.completion_tokens_details: + reasoning_tokens = int( + getattr(usage.completion_tokens_details, "reasoning_tokens", 0) or 0 + ) + + completion_cost = (completion_tokens + reasoning_tokens) * output_cost_per_token + + return prompt_cost, completion_cost diff --git a/litellm/main.py b/litellm/main.py index 8631e98ff1e..703bf34032b 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -358,7 +358,8 @@ async def acompletion( logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, deployment_id=None, - reasoning_effort: Optional[Literal["minimal", "low", "medium", "high"]] = None, + reasoning_effort: Optional[Literal["none", "minimal", "low", "medium", "high", "default"]] = None, + safety_identifier: Optional[str] = None, # set api_base, api_version, api_key base_url: Optional[str] = None, api_version: Optional[str] = None, @@ -495,6 +496,7 @@ async def acompletion( "api_key": api_key, "model_list": model_list, "reasoning_effort": reasoning_effort, + "safety_identifier": safety_identifier, "extra_headers": extra_headers, "acompletion": True, # assuming this is a required parameter "thinking": thinking, @@ -502,7 +504,7 @@ async def acompletion( } if custom_llm_provider is None: _, custom_llm_provider, _, _ = get_llm_provider( - model=model, api_base=completion_kwargs.get("base_url", None) + model=model, custom_llm_provider=custom_llm_provider, api_base=completion_kwargs.get("base_url", None) ) fallbacks = fallbacks or litellm.model_fallbacks @@ -897,7 +899,7 @@ def completion( # type: ignore # noqa: PLR0915 logit_bias: Optional[dict] = None, user: Optional[str] = None, # openai v1.0+ new params - reasoning_effort: Optional[Literal["minimal", "low", "medium", "high"]] = None, + reasoning_effort: Optional[Literal["none", "minimal", "low", "medium", "high", "default"]] = None, response_format: Optional[Union[dict, Type[BaseModel]]] = None, seed: Optional[int] = None, tools: Optional[List] = None, @@ -908,6 +910,7 @@ def completion( # type: ignore # noqa: PLR0915 web_search_options: Optional[OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, + safety_identifier: Optional[str] = None, # soon to be deprecated params by OpenAI functions: Optional[List] = None, function_call: Optional[str] = None, @@ -1245,6 +1248,7 @@ def completion( # type: ignore # noqa: PLR0915 "reasoning_effort": reasoning_effort, "thinking": thinking, "web_search_options": web_search_options, + "safety_identifier": safety_identifier, "allowed_openai_params": kwargs.get("allowed_openai_params"), } optional_params = get_optional_params( @@ -2204,8 +2208,18 @@ def completion( # type: ignore # noqa: PLR0915 or "https://api.anthropic.com/v1/complete" ) - if api_base is not None and not api_base.endswith("/v1/complete"): + # Check if we should disable automatic URL suffix appending + disable_url_suffix = get_secret_bool("LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX") + if ( + api_base is not None + and not disable_url_suffix + and not api_base.endswith("/v1/complete") + ): api_base += "/v1/complete" + elif disable_url_suffix: + verbose_logger.debug( + "LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX is set, skipping /v1/complete suffix" + ) response = base_llm_http_handler.completion( model=model, @@ -2241,8 +2255,18 @@ def completion( # type: ignore # noqa: PLR0915 or "https://api.anthropic.com/v1/messages" ) - if api_base is not None and not api_base.endswith("/v1/messages"): + # Check if we should disable automatic URL suffix appending + disable_url_suffix = get_secret_bool("LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX") + if ( + api_base is not None + and not disable_url_suffix + and not api_base.endswith("/v1/messages") + ): api_base += "/v1/messages" + elif disable_url_suffix: + verbose_logger.debug( + "LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX is set, skipping /v1/messages suffix" + ) response = anthropic_chat_completions.completion( model=model, @@ -2679,6 +2703,70 @@ def completion( # type: ignore # noqa: PLR0915 logging.post_call( input=messages, api_key=openai.api_key, original_response=response ) + elif custom_llm_provider == "vercel_ai_gateway": + api_base = ( + api_base + or litellm.api_base + or get_secret_str("VERCEL_AI_GATEWAY_API_BASE") + or "https://ai-gateway.vercel.sh/v1" + ) + + api_key = ( + api_key + or litellm.api_key + or get_secret("VERCEL_AI_GATEWAY_API_KEY") + ) + + vercel_site_url = get_secret("VERCEL_SITE_URL") or "https://litellm.ai" + vercel_app_name = get_secret("VERCEL_APP_NAME") or "liteLLM" + + vercel_headers = { + "http-referer": vercel_site_url, + "x-title": vercel_app_name, + } + + _headers = headers or litellm.headers + if _headers: + vercel_headers.update(_headers) + + headers = vercel_headers + + ## Load Config + config = litellm.VercelAIGatewayConfig.get_config() + for k, v in config.items(): + if k == "extra_body": + # we use openai 'extra_body' to pass vercel specific params - providerOptions + if "extra_body" in optional_params: + optional_params[k].update(v) + else: + optional_params[k] = v + elif k not in optional_params: + optional_params[k] = v + + data = {"model": model, "messages": messages, **optional_params} + + ## COMPLETION CALL + response = base_llm_http_handler.completion( + model=model, + stream=stream, + messages=messages, + acompletion=acompletion, + api_base=api_base, + model_response=model_response, + optional_params=optional_params, + litellm_params=litellm_params, + custom_llm_provider="vercel_ai_gateway", + 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, + ) + ## LOGGING + logging.post_call( + input=messages, api_key=openai.api_key, original_response=response + ) elif ( custom_llm_provider == "together_ai" or ("togethercomputer" in model) @@ -3614,7 +3702,7 @@ async def aembedding(*args, **kwargs) -> EmbeddingResponse: model = args[0] if len(args) > 0 else kwargs["model"] ### PASS ARGS TO Embedding ### kwargs["aembedding"] = True - custom_llm_provider = None + custom_llm_provider = kwargs.get("custom_llm_provider", None) try: # Use a partial function to pass your keyword arguments func = partial(embedding, *args, **kwargs) @@ -3624,7 +3712,7 @@ async def aembedding(*args, **kwargs) -> EmbeddingResponse: func_with_context = partial(ctx.run, func) _, custom_llm_provider, _, _ = get_llm_provider( - model=model, api_base=kwargs.get("api_base", None) + model=model, custom_llm_provider=custom_llm_provider, api_base=kwargs.get("api_base", None) ) # Await normally @@ -4446,6 +4534,36 @@ def embedding( # noqa: PLR0915 client=client, aembedding=aembedding, ) + elif custom_llm_provider == "volcengine": + volcengine_key = ( + api_key + or litellm.api_key + or get_secret_str("ARK_API_KEY") + or get_secret_str("VOLCENGINE_API_KEY") + ) + if volcengine_key is None: + raise ValueError( + "Missing API key for Volcengine. Set ARK_API_KEY or VOLCENGINE_API_KEY environment variable or pass api_key parameter." + ) + if extra_headers is not None and isinstance(extra_headers, dict): + headers = extra_headers + else: + headers = {} + response = base_llm_http_handler.embedding( + model=model, + input=input, + timeout=timeout, + custom_llm_provider=custom_llm_provider, + logging_obj=logging, + api_base=api_base, + optional_params=optional_params, + litellm_params={}, + model_response=EmbeddingResponse(), + api_key=volcengine_key, + client=client, + aembedding=aembedding, + headers=headers, + ) elif custom_llm_provider in litellm._custom_providers: custom_handler: Optional[CustomLLM] = None for item in litellm.custom_provider_map: diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 4dddc064df8..c8b4cc4b791 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -1479,6 +1479,70 @@ "supports_system_messages": true, "supports_tool_choice": true }, + "gpt-realtime": { + "max_tokens": 4096, + "max_input_tokens": 32000, + "max_output_tokens": 4096, + "input_cost_per_token": 4e-06, + "cache_read_input_token_cost": 0.4e-06, + "output_cost_per_token": 16e-06, + "input_cost_per_audio_token": 32e-06, + "output_cost_per_audio_token": 64e-06, + "cache_creation_input_audio_token_cost": 0.4e-06, + "input_cost_per_image": 5e-06, + "litellm_provider": "openai", + "mode": "chat", + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_audio_input": true, + "supports_audio_output": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supported_endpoints": [ + "/v1/realtime" + ], + "supported_modalities": [ + "text", + "image", + "audio" + ], + "supported_output_modalities": [ + "text", + "audio" + ] + }, + "gpt-realtime-2025-08-28": { + "max_tokens": 4096, + "max_input_tokens": 32000, + "max_output_tokens": 4096, + "input_cost_per_token": 4e-06, + "cache_read_input_token_cost": 0.4e-06, + "output_cost_per_token": 16e-06, + "input_cost_per_audio_token": 32e-06, + "output_cost_per_audio_token": 64e-06, + "cache_creation_input_audio_token_cost": 0.4e-06, + "input_cost_per_image": 5e-06, + "litellm_provider": "openai", + "mode": "chat", + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_audio_input": true, + "supports_audio_output": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supported_endpoints": [ + "/v1/realtime" + ], + "supported_modalities": [ + "text", + "image", + "audio" + ], + "supported_output_modalities": [ + "text", + "audio" + ] + }, "gpt-4o-realtime-preview-2024-10-01": { "max_tokens": 4096, "max_input_tokens": 128000, @@ -5598,6 +5662,48 @@ "supports_tool_choice": true, "supports_web_search": true }, + "xai/grok-code-fast-1": { + "max_tokens": 256000, + "max_input_tokens": 256000, + "max_output_tokens": 256000, + "input_cost_per_token": 0.2e-06, + "output_cost_per_token": 1.5e-06, + "cache_read_input_token_cost": 0.02e-06, + "litellm_provider": "xai", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_reasoning": true, + "source": "https://docs.x.ai/docs/models" + }, + "xai/grok-code-fast": { + "max_tokens": 256000, + "max_input_tokens": 256000, + "max_output_tokens": 256000, + "input_cost_per_token": 0.2e-06, + "output_cost_per_token": 1.5e-06, + "cache_read_input_token_cost": 0.02e-06, + "litellm_provider": "xai", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_reasoning": true, + "source": "https://docs.x.ai/docs/models" + }, + "xai/grok-code-fast-1-0825": { + "max_tokens": 256000, + "max_input_tokens": 256000, + "max_output_tokens": 256000, + "input_cost_per_token": 0.2e-06, + "output_cost_per_token": 1.5e-06, + "cache_read_input_token_cost": 0.02e-06, + "litellm_provider": "xai", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_reasoning": true, + "source": "https://docs.x.ai/docs/models" + }, "xai/grok-4": { "max_tokens": 256000, "max_input_tokens": 256000, @@ -5711,16 +5817,6 @@ "supports_response_schema": true, "supports_tool_choice": true }, - "groq/llama3-8b-8192": { - "max_tokens": 8192, - "max_input_tokens": 8192, - "max_output_tokens": 8192, - "input_cost_per_token": 5e-08, - "output_cost_per_token": 8e-08, - "litellm_provider": "groq", - "mode": "chat", - "supports_tool_choice": true - }, "groq/llama-3.2-1b-preview": { "max_tokens": 8192, "max_input_tokens": 8192, @@ -5801,17 +5897,6 @@ "supports_tool_choice": true, "deprecation_date": "2025-04-14" }, - "groq/llama3-70b-8192": { - "max_tokens": 8192, - "max_input_tokens": 8192, - "max_output_tokens": 8192, - "input_cost_per_token": 5.9e-07, - "output_cost_per_token": 7.9e-07, - "litellm_provider": "groq", - "mode": "chat", - "supports_response_schema": true, - "supports_tool_choice": true - }, "groq/llama-3.1-8b-instant": { "max_tokens": 8192, "max_input_tokens": 128000, @@ -6072,21 +6157,7 @@ "supports_tool_choice": true, "source": "https://inference-docs.cerebras.ai/support/pricing" }, - "cerebras/openai/gpt-oss-20b": { - "max_tokens": 32768, - "max_input_tokens": 131072, - "max_output_tokens": 32768, - "input_cost_per_token": 7e-08, - "output_cost_per_token": 3e-07, - "litellm_provider": "cerebras", - "mode": "chat", - "supports_function_calling": true, - "supports_parallel_function_calling": true, - "supports_response_schema": true, - "supports_reasoning": true, - "supports_tool_choice": true, - "source": "https://inference-docs.cerebras.ai/support/pricing" - }, + "cerebras/openai/gpt-oss-120b": { "max_tokens": 32768, "max_input_tokens": 131072, @@ -7921,12 +7992,11 @@ "max_pdf_size_mb": 30, "input_cost_per_audio_token": 1e-06, "input_cost_per_token": 3e-07, - "output_cost_per_token": 2.5e-06, - "output_cost_per_reasoning_token": 2.5e-06, + "output_cost_per_token": 3e-05, + "output_cost_per_reasoning_token": 3e-05, "output_cost_per_image": 0.039, "litellm_provider": "gemini", "mode": "chat", - "supports_reasoning": true, "supports_system_messages": true, "supports_function_calling": true, "supports_vision": true, @@ -8286,12 +8356,11 @@ "max_pdf_size_mb": 30, "input_cost_per_audio_token": 1e-06, "input_cost_per_token": 3e-07, - "output_cost_per_token": 2.5e-06, - "output_cost_per_reasoning_token": 2.5e-06, + "output_cost_per_token": 3e-05, + "output_cost_per_reasoning_token": 3e-05, "output_cost_per_image": 0.039, "litellm_provider": "vertex_ai-language-models", "mode": "chat", - "supports_reasoning": true, "supports_system_messages": true, "supports_function_calling": true, "supports_vision": true, @@ -9415,6 +9484,48 @@ "source": "https://aistudio.google.com", "supports_tool_choice": true }, + "gemini/veo-3.0-generate-preview": { + "max_tokens": 1024, + "max_input_tokens": 1024, + "output_cost_per_second": 0.75, + "litellm_provider": "gemini", + "mode": "video_generation", + "supported_modalities": [ + "text" + ], + "supported_output_modalities": [ + "video" + ], + "source": "https://ai.google.dev/gemini-api/docs/video" + }, + "gemini/veo-3.0-fast-generate-preview": { + "max_tokens": 1024, + "max_input_tokens": 1024, + "output_cost_per_second": 0.40, + "litellm_provider": "gemini", + "mode": "video_generation", + "supported_modalities": [ + "text" + ], + "supported_output_modalities": [ + "video" + ], + "source": "https://ai.google.dev/gemini-api/docs/video" + }, + "gemini/veo-2.0-generate-001": { + "max_tokens": 1024, + "max_input_tokens": 1024, + "output_cost_per_second": 0.35, + "litellm_provider": "gemini", + "mode": "video_generation", + "supported_modalities": [ + "text" + ], + "supported_output_modalities": [ + "video" + ], + "source": "https://ai.google.dev/gemini-api/docs/video" + }, "vertex_ai/claude-opus-4-1": { "max_tokens": 4096, "max_input_tokens": 200000, @@ -9801,6 +9912,28 @@ "supports_tool_choice": true, "supports_prompt_caching": true }, + "vertex_ai/openai/gpt-oss-20b-maas": { + "max_tokens": 32768, + "max_input_tokens": 131072, + "max_output_tokens": 32768, + "input_cost_per_token": 0.075e-06, + "output_cost_per_token": 0.30e-06, + "litellm_provider": "vertex_ai-openai_models", + "mode": "chat", + "supports_reasoning": true, + "source": "https://console.cloud.google.com/vertex-ai/publishers/openai/model-garden/gpt-oss-120b-maas" + }, + "vertex_ai/openai/gpt-oss-120b-maas": { + "max_tokens": 32768, + "max_input_tokens": 131072, + "max_output_tokens": 32768, + "input_cost_per_token": 0.15e-06, + "output_cost_per_token": 0.60e-06, + "litellm_provider": "vertex_ai-openai_models", + "mode": "chat", + "supports_reasoning": true, + "source": "https://console.cloud.google.com/vertex-ai/publishers/openai/model-garden/gpt-oss-120b-maas" + }, "vertex_ai/qwen/qwen3-coder-480b-a35b-instruct-maas": { "max_tokens": 32768, "max_input_tokens": 262144, @@ -10210,6 +10343,48 @@ "mode": "image_generation", "source": "https://cloud.google.com/vertex-ai/generative-ai/pricing" }, + "vertex_ai/veo-3.0-generate-preview": { + "max_tokens": 1024, + "max_input_tokens": 1024, + "output_cost_per_second": 0.75, + "litellm_provider": "vertex_ai-video-models", + "mode": "video_generation", + "supported_modalities": [ + "text" + ], + "supported_output_modalities": [ + "video" + ], + "source": "https://ai.google.dev/gemini-api/docs/video" + }, + "vertex_ai/veo-3.0-fast-generate-preview": { + "max_tokens": 1024, + "max_input_tokens": 1024, + "output_cost_per_second": 0.40, + "litellm_provider": "vertex_ai-video-models", + "mode": "video_generation", + "supported_modalities": [ + "text" + ], + "supported_output_modalities": [ + "video" + ], + "source": "https://ai.google.dev/gemini-api/docs/video" + }, + "vertex_ai/veo-2.0-generate-001": { + "max_tokens": 1024, + "max_input_tokens": 1024, + "output_cost_per_second": 0.35, + "litellm_provider": "vertex_ai-video-models", + "mode": "video_generation", + "supported_modalities": [ + "text" + ], + "supported_output_modalities": [ + "video" + ], + "source": "https://ai.google.dev/gemini-api/docs/video" + }, "text-embedding-004": { "max_tokens": 2048, "max_input_tokens": 2048, @@ -11887,6 +12062,108 @@ "mode": "chat", "supports_tool_choice": true }, + "openrouter/openai/gpt-4.1": { + "max_tokens": 32768, + "max_input_tokens": 1047576, + "max_output_tokens": 32768, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 8e-06, + "cache_read_input_token_cost": 5e-07, + "litellm_provider": "openrouter", + "mode": "chat", + "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 + }, + "openrouter/openai/gpt-4.1-2025-04-14": { + "max_tokens": 32768, + "max_input_tokens": 1047576, + "max_output_tokens": 32768, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 8e-06, + "cache_read_input_token_cost": 5e-07, + "litellm_provider": "openrouter", + "mode": "chat", + "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 + }, + "openrouter/openai/gpt-4.1-mini": { + "max_tokens": 32768, + "max_input_tokens": 1047576, + "max_output_tokens": 32768, + "input_cost_per_token": 4e-07, + "output_cost_per_token": 1.6e-06, + "cache_read_input_token_cost": 1e-07, + "litellm_provider": "openrouter", + "mode": "chat", + "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 + }, + "openrouter/openai/gpt-4.1-mini-2025-04-14": { + "max_tokens": 32768, + "max_input_tokens": 1047576, + "max_output_tokens": 32768, + "input_cost_per_token": 4e-07, + "output_cost_per_token": 1.6e-06, + "cache_read_input_token_cost": 1e-07, + "litellm_provider": "openrouter", + "mode": "chat", + "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 + }, + "openrouter/openai/gpt-4.1-nano": { + "max_tokens": 32768, + "max_input_tokens": 1047576, + "max_output_tokens": 32768, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 4e-07, + "cache_read_input_token_cost": 2.5e-08, + "litellm_provider": "openrouter", + "mode": "chat", + "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 + }, + "openrouter/openai/gpt-4.1-nano-2025-04-14": { + "max_tokens": 32768, + "max_input_tokens": 1047576, + "max_output_tokens": 32768, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 4e-07, + "cache_read_input_token_cost": 2.5e-08, + "litellm_provider": "openrouter", + "mode": "chat", + "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 + }, "openrouter/openai/gpt-5-mini": { "max_tokens": 128000, "max_input_tokens": 400000, @@ -11941,7 +12218,7 @@ "supported_output_modalities": [ "text" ], - "supports_tool_choice": false, + "supports_tool_choice": true, "supports_reasoning": true }, "openrouter/openai/gpt-oss-20b": { @@ -14866,10 +15143,10 @@ "output_cost_per_token": 6e-06, "max_input_tokens": 262000, "litellm_provider": "together_ai", - "supports_function_calling": false, - "supports_parallel_function_calling": false, + "supports_function_calling": true, + "supports_parallel_function_calling": true, "mode": "chat", - "supports_tool_choice": false, + "supports_tool_choice": true, "source": "https://www.together.ai/models/qwen3-235b-a22b-instruct-2507-fp8" }, "together_ai/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8": { @@ -14877,10 +15154,10 @@ "output_cost_per_token": 2e-06, "max_input_tokens": 256000, "litellm_provider": "together_ai", - "supports_function_calling": false, - "supports_parallel_function_calling": false, + "supports_function_calling": true, + "supports_parallel_function_calling": true, "mode": "chat", - "supports_tool_choice": false, + "supports_tool_choice": true, "source": "https://www.together.ai/models/qwen3-coder-480b-a35b-instruct" }, "together_ai/Qwen/Qwen3-235B-A22B-Thinking-2507": { @@ -14888,10 +15165,10 @@ "output_cost_per_token": 3e-06, "max_input_tokens": 256000, "litellm_provider": "together_ai", - "supports_function_calling": false, - "supports_parallel_function_calling": false, + "supports_function_calling": true, + "supports_parallel_function_calling": true, "mode": "chat", - "supports_tool_choice": false, + "supports_tool_choice": true, "source": "https://www.together.ai/models/qwen3-235b-a22b-thinking-2507" }, "together_ai/Qwen/Qwen3-235B-A22B-fp8-tput": { @@ -14934,10 +15211,10 @@ "output_cost_per_token": 2.19e-06, "max_input_tokens": 128000, "litellm_provider": "together_ai", - "supports_function_calling": false, - "supports_parallel_function_calling": false, + "supports_function_calling": true, + "supports_parallel_function_calling": true, "mode": "chat", - "supports_tool_choice": false, + "supports_tool_choice": true, "source": "https://www.together.ai/models/deepseek-r1-0528-throughput" }, "together_ai/mistralai/Mistral-Small-24B-Instruct-2501": { @@ -14962,9 +15239,9 @@ "output_cost_per_token": 6e-07, "max_input_tokens": 128000, "litellm_provider": "together_ai", - "supports_function_calling": false, - "supports_tool_choice": false, - "supports_parallel_function_calling": false, + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_parallel_function_calling": true, "mode": "chat", "source": "https://www.together.ai/models/gpt-oss-120b" }, @@ -14973,9 +15250,9 @@ "output_cost_per_token": 2e-07, "max_input_tokens": 128000, "litellm_provider": "together_ai", - "supports_function_calling": false, - "supports_tool_choice": false, - "supports_parallel_function_calling": false, + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_parallel_function_calling": true, "mode": "chat", "source": "https://www.together.ai/models/gpt-oss-20b" }, @@ -14984,12 +15261,24 @@ "output_cost_per_token": 1.1e-06, "max_input_tokens": 128000, "litellm_provider": "together_ai", - "supports_function_calling": false, - "supports_tool_choice": false, - "supports_parallel_function_calling": false, + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_parallel_function_calling": true, "mode": "chat", "source": "https://www.together.ai/models/glm-4-5-air" }, + "together_ai/deepseek-ai/DeepSeek-V3.1": { + "input_cost_per_token": 0.6e-06, + "output_cost_per_token": 1.7e-06, + "max_tokens": 128000, + "litellm_provider": "together_ai", + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_reasoning": true, + "mode": "chat", + "supports_tool_choice": true, + "source": "https://www.together.ai/models/deepseek-v3-1" + }, "ollama/codegemma": { "max_tokens": 8192, "max_input_tokens": 8192, @@ -15626,7 +15915,8 @@ "output_cost_per_token": 2.18e-06, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": false + "supports_tool_choice": false, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-R1": { "max_tokens": 163840, @@ -15636,7 +15926,8 @@ "output_cost_per_token": 2.15e-06, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-R1-0528": { "max_tokens": 163840, @@ -15646,7 +15937,8 @@ "output_cost_per_token": 2.15e-06, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-R1-0528-Turbo": { "max_tokens": 32768, @@ -15656,7 +15948,8 @@ "output_cost_per_token": 3e-06, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-R1-Distill-Llama-70B": { "max_tokens": 131072, @@ -15666,7 +15959,8 @@ "output_cost_per_token": 4e-07, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": false + "supports_tool_choice": false, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B": { "max_tokens": 131072, @@ -15676,7 +15970,8 @@ "output_cost_per_token": 1.5e-07, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-R1-Turbo": { "max_tokens": 163840, @@ -15686,7 +15981,8 @@ "output_cost_per_token": 3e-06, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-V3": { "max_tokens": 163840, @@ -15696,7 +15992,8 @@ "output_cost_per_token": 8.9e-07, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-V3-0324": { "max_tokens": 163840, @@ -15706,7 +16003,8 @@ "output_cost_per_token": 8.8e-07, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-V3-0324-Turbo": { "max_tokens": 32768, @@ -15716,7 +16014,8 @@ "output_cost_per_token": 3e-06, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": true + "supports_tool_choice": true, + "supports_reasoning": true }, "deepinfra/deepseek-ai/DeepSeek-V3.1": { "max_tokens": 163840, @@ -15726,7 +16025,8 @@ "output_cost_per_token": 1e-06, "litellm_provider": "deepinfra", "mode": "chat", - "supports_tool_choice": false + "supports_tool_choice": false, + "supports_reasoning": true }, "deepinfra/google/codegemma-7b-it": { "max_tokens": 8192, @@ -19690,6 +19990,848 @@ "supports_system_messages": true, "supports_tool_choice": true }, + "vercel_ai_gateway/alibaba/qwen3-coder": { + "max_tokens": 262144, + "input_cost_per_token": 4e-07, + "output_cost_per_token": 1.6e-06, + "max_output_tokens": 66536, + "max_input_tokens": 262144, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/codestral-embed": { + "max_tokens": 0, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/google/gemini-2.5-pro": { + "max_tokens": 1048576, + "input_cost_per_token": 2.5e-06, + "output_cost_per_token": 1e-05, + "max_output_tokens": 65536, + "max_input_tokens": 1048576, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/deepseek/deepseek-v3": { + "max_tokens": 128000, + "input_cost_per_token": 9e-07, + "output_cost_per_token": 9e-07, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/amazon/nova-lite": { + "max_tokens": 300000, + "input_cost_per_token": 6e-08, + "output_cost_per_token": 2.4e-07, + "max_output_tokens": 8192, + "max_input_tokens": 300000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-4-scout": { + "max_tokens": 131072, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 3e-07, + "max_output_tokens": 8192, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3.2-1b": { + "max_tokens": 128000, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 1e-07, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/mistral-small": { + "max_tokens": 32000, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 3e-07, + "max_output_tokens": 4000, + "max_input_tokens": 32000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/google/gemini-2.5-flash": { + "max_tokens": 1000000, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 2.5e-06, + "max_output_tokens": 65536, + "max_input_tokens": 1000000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/inception/mercury-coder-small": { + "max_tokens": 32000, + "input_cost_per_token": 2.5e-07, + "output_cost_per_token": 1e-06, + "max_output_tokens": 16384, + "max_input_tokens": 32000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/text-embedding-3-small": { + "max_tokens": 0, + "input_cost_per_token": 2e-08, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "embedding" + }, + "vercel_ai_gateway/xai/grok-2-vision": { + "max_tokens": 32768, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 1e-05, + "max_output_tokens": 32768, + "max_input_tokens": 32768, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/xai/grok-2": { + "max_tokens": 131072, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 1e-05, + "max_output_tokens": 4000, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/deepseek/deepseek-r1-distill-llama-70b": { + "max_tokens": 131072, + "input_cost_per_token": 7.5e-07, + "output_cost_per_token": 9.9e-07, + "max_output_tokens": 131072, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3.1-70b": { + "max_tokens": 128000, + "input_cost_per_token": 7.2e-07, + "output_cost_per_token": 7.2e-07, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/xai/grok-3": { + "max_tokens": 131072, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "max_output_tokens": 131072, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/alibaba/qwen-3-235b": { + "max_tokens": 40960, + "input_cost_per_token": 2e-07, + "output_cost_per_token": 6e-07, + "max_output_tokens": 16384, + "max_input_tokens": 40960, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/xai/grok-3-fast": { + "max_tokens": 131072, + "input_cost_per_token": 5e-06, + "output_cost_per_token": 2.5e-05, + "max_output_tokens": 131072, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/vercel/v0-1.5-md": { + "max_tokens": 128000, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "max_output_tokens": 32768, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/o4-mini": { + "max_tokens": 200000, + "input_cost_per_token": 1.1e-06, + "output_cost_per_token": 4.4e-06, + "max_output_tokens": 100000, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 2.75e-07, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/magistral-medium": { + "max_tokens": 128000, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 5e-06, + "max_output_tokens": 64000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/amazon/titan-embed-text-v2": { + "max_tokens": 0, + "input_cost_per_token": 2e-08, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/alibaba/qwen-3-30b": { + "max_tokens": 40960, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 3e-07, + "max_output_tokens": 16384, + "max_input_tokens": 40960, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/zai/glm-4.5-air": { + "max_tokens": 128000, + "input_cost_per_token": 2e-07, + "output_cost_per_token": 1.1e-06, + "max_output_tokens": 96000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/gpt-4-turbo": { + "max_tokens": 128000, + "input_cost_per_token": 1e-05, + "output_cost_per_token": 3e-05, + "max_output_tokens": 4096, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/mistral-large": { + "max_tokens": 32000, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 6e-06, + "max_output_tokens": 4000, + "max_input_tokens": 32000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/perplexity/sonar-pro": { + "max_tokens": 200000, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "max_output_tokens": 8000, + "max_input_tokens": 200000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3.2-90b": { + "max_tokens": 128000, + "input_cost_per_token": 7.2e-07, + "output_cost_per_token": 7.2e-07, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3-8b": { + "max_tokens": 8192, + "input_cost_per_token": 5e-08, + "output_cost_per_token": 8e-08, + "max_output_tokens": 8192, + "max_input_tokens": 8192, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/google/text-embedding-005": { + "max_tokens": 0, + "input_cost_per_token": 2.5e-08, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "embedding" + }, + "vercel_ai_gateway/mistral/pixtral-large": { + "max_tokens": 128000, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 6e-06, + "max_output_tokens": 4000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/anthropic/claude-3.5-sonnet": { + "max_tokens": 200000, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "max_output_tokens": 8192, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 3e-07, + "cache_creation_input_token_cost": 3.75e-06, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/amazon/nova-micro": { + "max_tokens": 128000, + "input_cost_per_token": 3.5e-08, + "output_cost_per_token": 1.4e-07, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/cohere/command-r": { + "max_tokens": 128000, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 6e-07, + "max_output_tokens": 4096, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/morph/morph-v3-large": { + "max_tokens": 32768, + "input_cost_per_token": 9e-07, + "output_cost_per_token": 1.9e-06, + "max_output_tokens": 16384, + "max_input_tokens": 32768, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/mixtral-8x22b-instruct": { + "max_tokens": 65536, + "input_cost_per_token": 1.2e-06, + "output_cost_per_token": 1.2e-06, + "max_output_tokens": 2048, + "max_input_tokens": 65536, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/xai/grok-4": { + "max_tokens": 256000, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "max_output_tokens": 256000, + "max_input_tokens": 256000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3.1-8b": { + "max_tokens": 131000, + "input_cost_per_token": 5e-08, + "output_cost_per_token": 8e-08, + "max_output_tokens": 131072, + "max_input_tokens": 131000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/anthropic/claude-3-opus": { + "max_tokens": 200000, + "input_cost_per_token": 1.5e-05, + "output_cost_per_token": 7.5e-05, + "max_output_tokens": 4096, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 1.5e-06, + "cache_creation_input_token_cost": 1.875e-05, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/zai/glm-4.5": { + "max_tokens": 131072, + "input_cost_per_token": 6e-07, + "output_cost_per_token": 2.2e-06, + "max_output_tokens": 131072, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/gpt-4o": { + "max_tokens": 128000, + "input_cost_per_token": 2.5e-06, + "output_cost_per_token": 1e-05, + "max_output_tokens": 16384, + "max_input_tokens": 128000, + "cache_read_input_token_cost": 1.25e-06, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/o3-mini": { + "max_tokens": 200000, + "input_cost_per_token": 1.1e-06, + "output_cost_per_token": 4.4e-06, + "max_output_tokens": 100000, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 5.5e-07, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/ministral-8b": { + "max_tokens": 128000, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 1e-07, + "max_output_tokens": 4000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/o3": { + "max_tokens": 200000, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 8e-06, + "max_output_tokens": 100000, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 5e-07, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/vercel/v0-1.0-md": { + "max_tokens": 128000, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "max_output_tokens": 32000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/google/text-multilingual-embedding-002": { + "max_tokens": 0, + "input_cost_per_token": 2.5e-08, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "embedding" + }, + "vercel_ai_gateway/amazon/nova-pro": { + "max_tokens": 300000, + "input_cost_per_token": 8e-07, + "output_cost_per_token": 3.2e-06, + "max_output_tokens": 8192, + "max_input_tokens": 300000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/morph/morph-v3-fast": { + "max_tokens": 32768, + "input_cost_per_token": 8e-07, + "output_cost_per_token": 1.2e-06, + "max_output_tokens": 16384, + "max_input_tokens": 32768, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/gpt-3.5-turbo": { + "max_tokens": 16385, + "input_cost_per_token": 5e-07, + "output_cost_per_token": 1.5e-06, + "max_output_tokens": 4096, + "max_input_tokens": 16385, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/codestral": { + "max_tokens": 256000, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 9e-07, + "max_output_tokens": 4000, + "max_input_tokens": 256000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3.2-11b": { + "max_tokens": 128000, + "input_cost_per_token": 1.6e-07, + "output_cost_per_token": 1.6e-07, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3-70b": { + "max_tokens": 8192, + "input_cost_per_token": 5.9e-07, + "output_cost_per_token": 7.9e-07, + "max_output_tokens": 8192, + "max_input_tokens": 8192, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/xai/grok-3-mini-fast": { + "max_tokens": 131072, + "input_cost_per_token": 6e-07, + "output_cost_per_token": 4e-06, + "max_output_tokens": 131072, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/text-embedding-3-large": { + "max_tokens": 0, + "input_cost_per_token": 1.3e-07, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "embedding" + }, + "vercel_ai_gateway/google/gemini-2.0-flash-lite": { + "max_tokens": 1048576, + "input_cost_per_token": 7.5e-08, + "output_cost_per_token": 3e-07, + "max_output_tokens": 8192, + "max_input_tokens": 1048576, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/ministral-3b": { + "max_tokens": 128000, + "input_cost_per_token": 4e-08, + "output_cost_per_token": 4e-08, + "max_output_tokens": 4000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/perplexity/sonar-reasoning-pro": { + "max_tokens": 127000, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 8e-06, + "max_output_tokens": 8000, + "max_input_tokens": 127000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/google/gemini-embedding-001": { + "max_tokens": 0, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "embedding" + }, + "vercel_ai_gateway/anthropic/claude-3-haiku": { + "max_tokens": 200000, + "input_cost_per_token": 2.5e-07, + "output_cost_per_token": 1.25e-06, + "max_output_tokens": 4096, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/o1": { + "max_tokens": 200000, + "input_cost_per_token": 1.5e-05, + "output_cost_per_token": 6e-05, + "max_output_tokens": 100000, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 7.5e-06, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/deepseek/deepseek-r1": { + "max_tokens": 128000, + "input_cost_per_token": 5.5e-07, + "output_cost_per_token": 2.19e-06, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/mistral-embed": { + "max_tokens": 0, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/gpt-4.1-mini": { + "max_tokens": 1047576, + "input_cost_per_token": 4e-07, + "output_cost_per_token": 1.6e-06, + "max_output_tokens": 32768, + "max_input_tokens": 1047576, + "cache_read_input_token_cost": 1e-07, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/gpt-4o-mini": { + "max_tokens": 128000, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 6e-07, + "max_output_tokens": 16384, + "max_input_tokens": 128000, + "cache_read_input_token_cost": 7.5e-08, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/alibaba/qwen-3-14b": { + "max_tokens": 40960, + "input_cost_per_token": 8e-08, + "output_cost_per_token": 2.4e-07, + "max_output_tokens": 16384, + "max_input_tokens": 40960, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/anthropic/claude-4-opus": { + "max_tokens": 200000, + "input_cost_per_token": 1.5e-05, + "output_cost_per_token": 7.5e-05, + "max_output_tokens": 32000, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 1.5e-06, + "cache_creation_input_token_cost": 1.875e-05, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/mistral-saba-24b": { + "max_tokens": 32768, + "input_cost_per_token": 7.9e-07, + "output_cost_per_token": 7.9e-07, + "max_output_tokens": 32768, + "max_input_tokens": 32768, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/perplexity/sonar-reasoning": { + "max_tokens": 127000, + "input_cost_per_token": 1e-06, + "output_cost_per_token": 5e-06, + "max_output_tokens": 8000, + "max_input_tokens": 127000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/anthropic/claude-3.5-haiku": { + "max_tokens": 200000, + "input_cost_per_token": 8e-07, + "output_cost_per_token": 4e-06, + "max_output_tokens": 8192, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 8e-08, + "cache_creation_input_token_cost": 1e-06, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/cohere/command-a": { + "max_tokens": 256000, + "input_cost_per_token": 2.5e-06, + "output_cost_per_token": 1e-05, + "max_output_tokens": 8000, + "max_input_tokens": 256000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/google/gemma-2-9b": { + "max_tokens": 8192, + "input_cost_per_token": 2e-07, + "output_cost_per_token": 2e-07, + "max_output_tokens": 8192, + "max_input_tokens": 8192, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3.2-3b": { + "max_tokens": 128000, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 1.5e-07, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/gpt-4.1-nano": { + "max_tokens": 1047576, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 4e-07, + "max_output_tokens": 32768, + "max_input_tokens": 1047576, + "cache_read_input_token_cost": 2.5e-08, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/anthropic/claude-4-sonnet": { + "max_tokens": 200000, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "max_output_tokens": 64000, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 3e-07, + "cache_creation_input_token_cost": 3.75e-06, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/perplexity/sonar": { + "max_tokens": 127000, + "input_cost_per_token": 1e-06, + "output_cost_per_token": 1e-06, + "max_output_tokens": 8000, + "max_input_tokens": 127000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-4-maverick": { + "max_tokens": 131072, + "input_cost_per_token": 2e-07, + "output_cost_per_token": 6e-07, + "max_output_tokens": 8192, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/text-embedding-ada-002": { + "max_tokens": 0, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "embedding" + }, + "vercel_ai_gateway/xai/grok-3-mini": { + "max_tokens": 131072, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 5e-07, + "max_output_tokens": 131072, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/cohere/embed-v4.0": { + "max_tokens": 0, + "input_cost_per_token": 1.2e-07, + "output_cost_per_token": 0.0, + "max_output_tokens": 0, + "max_input_tokens": 0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/meta/llama-3.3-70b": { + "max_tokens": 128000, + "input_cost_per_token": 7.2e-07, + "output_cost_per_token": 7.2e-07, + "max_output_tokens": 8192, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/cohere/command-r-plus": { + "max_tokens": 128000, + "input_cost_per_token": 2.5e-06, + "output_cost_per_token": 1e-05, + "max_output_tokens": 4096, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/gpt-3.5-turbo-instruct": { + "max_tokens": 8192, + "input_cost_per_token": 1.5e-06, + "output_cost_per_token": 2e-06, + "max_output_tokens": 4096, + "max_input_tokens": 8192, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/devstral-small": { + "max_tokens": 128000, + "input_cost_per_token": 7e-08, + "output_cost_per_token": 2.8e-07, + "max_output_tokens": 128000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/anthropic/claude-3.7-sonnet": { + "max_tokens": 200000, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "max_output_tokens": 64000, + "max_input_tokens": 200000, + "cache_read_input_token_cost": 3e-07, + "cache_creation_input_token_cost": 3.75e-06, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/google/gemini-2.0-flash": { + "max_tokens": 1048576, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 6e-07, + "max_output_tokens": 8192, + "max_input_tokens": 1048576, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/pixtral-12b": { + "max_tokens": 128000, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 1.5e-07, + "max_output_tokens": 4000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/mistral/magistral-small": { + "max_tokens": 128000, + "input_cost_per_token": 5e-07, + "output_cost_per_token": 1.5e-06, + "max_output_tokens": 64000, + "max_input_tokens": 128000, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/moonshotai/kimi-k2": { + "max_tokens": 131072, + "input_cost_per_token": 5.5e-07, + "output_cost_per_token": 2.2e-06, + "max_output_tokens": 16384, + "max_input_tokens": 131072, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/alibaba/qwen-3-32b": { + "max_tokens": 40960, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 3e-07, + "max_output_tokens": 16384, + "max_input_tokens": 40960, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, + "vercel_ai_gateway/openai/gpt-4.1": { + "max_tokens": 1047576, + "input_cost_per_token": 2e-06, + "output_cost_per_token": 8e-06, + "max_output_tokens": 32768, + "max_input_tokens": 1047576, + "cache_read_input_token_cost": 5e-07, + "cache_creation_input_token_cost": 0.0, + "litellm_provider": "vercel_ai_gateway", + "mode": "chat" + }, "oci/meta.llama-4-maverick-17b-128e-instruct-fp8": { "max_tokens": 512000, "max_input_tokens": 512000, @@ -19923,5 +21065,65 @@ "metadata": { "notes": "DALL-E 2 via AI/ML API - Reliable text-to-image generation" } + }, + "doubao-embedding-large": { + "max_tokens": 4096, + "max_input_tokens": 4096, + "output_vector_size": 2048, + "input_cost_per_token": 0.0, + "output_cost_per_token": 0.0, + "litellm_provider": "volcengine", + "mode": "embedding", + "metadata": { + "notes": "Volcengine Doubao embedding model - large version with 2048 dimensions" + } + }, + "doubao-embedding-large-text-250515": { + "max_tokens": 4096, + "max_input_tokens": 4096, + "output_vector_size": 2048, + "input_cost_per_token": 0.0, + "output_cost_per_token": 0.0, + "litellm_provider": "volcengine", + "mode": "embedding", + "metadata": { + "notes": "Volcengine Doubao embedding model - text-250515 version with 2048 dimensions" + } + }, + "doubao-embedding-large-text-240915": { + "max_tokens": 4096, + "max_input_tokens": 4096, + "output_vector_size": 4096, + "input_cost_per_token": 0.0, + "output_cost_per_token": 0.0, + "litellm_provider": "volcengine", + "mode": "embedding", + "metadata": { + "notes": "Volcengine Doubao embedding model - text-240915 version with 4096 dimensions" + } + }, + "doubao-embedding": { + "max_tokens": 4096, + "max_input_tokens": 4096, + "output_vector_size": 2560, + "input_cost_per_token": 0.0, + "output_cost_per_token": 0.0, + "litellm_provider": "volcengine", + "mode": "embedding", + "metadata": { + "notes": "Volcengine Doubao embedding model - standard version with 2560 dimensions" + } + }, + "doubao-embedding-text-240715": { + "max_tokens": 4096, + "max_input_tokens": 4096, + "output_vector_size": 2560, + "input_cost_per_token": 0.0, + "output_cost_per_token": 0.0, + "litellm_provider": "volcengine", + "mode": "embedding", + "metadata": { + "notes": "Volcengine Doubao embedding model - text-240715 version with 2560 dimensions" + } } -} +} \ No newline at end of file diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index 6624eb7e64e..048b25fa35a 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -1,5 +1,5 @@ import importlib -from typing import Optional, Dict +from typing import Dict, List, Optional from fastapi import APIRouter, Depends, Query, Request @@ -21,9 +21,10 @@ router = APIRouter( ) if MCP_AVAILABLE: + from litellm.experimental_mcp_client.client import MCPTool from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( - global_mcp_server_manager, _convert_protocol_version_to_enum, + global_mcp_server_manager, ) from litellm.proxy._experimental.mcp_server.server import ( ListMCPToolsRestAPIResponseObject, @@ -100,7 +101,9 @@ if MCP_AVAILABLE: "message": "Successfully retrieved tools" } """ - from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler + from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import ( + MCPRequestHandler, + ) try: # Extract auth headers from request @@ -172,10 +175,11 @@ if MCP_AVAILABLE: """ REST API to call a specific MCP tool with the provided arguments """ - from litellm.proxy.proxy_server import add_litellm_data_to_request, proxy_config - from litellm.exceptions import BlockedPiiEntityError, GuardrailRaisedException from fastapi import HTTPException + from litellm.exceptions import BlockedPiiEntityError, GuardrailRaisedException + from litellm.proxy.proxy_server import add_litellm_data_to_request, proxy_config + try: data = await request.json() data = await add_litellm_data_to_request( @@ -230,13 +234,19 @@ if MCP_AVAILABLE: from litellm.proxy.management_endpoints.mcp_management_endpoints import ( NewMCPServerRequest, ) - @router.post("/test/connection") - async def test_connection( - request: NewMCPServerRequest, - ): + + async def _execute_with_mcp_client(request: NewMCPServerRequest, operation): """ - Test if we can connect to the provided MCP server before adding it + Common helper to create MCP client, execute operation, and ensure proper cleanup. + + Args: + request: MCP server configuration + operation: Async function that takes a client and returns the operation result + + Returns: + Operation result or error response """ + client = None try: client = global_mcp_server_manager._create_mcp_client( server=MCPServer( @@ -250,12 +260,31 @@ if MCP_AVAILABLE: ), mcp_auth_header=None, ) - - await client.connect() + + return await operation(client) + except Exception as e: - verbose_logger.error(f"Error in test_connection: {e}", exc_info=True) + verbose_logger.error(f"Error in MCP operation: {e}", exc_info=True) return {"status": "error", "message": "An internal error has occurred."} - return {"status": "ok"} + finally: + # Ensure client is properly disconnected before response is sent + if client is not None: + try: + await client.disconnect() + except Exception as e: + verbose_logger.warning(f"Error disconnecting MCP client: {e}") + @router.post("/test/connection") + async def test_connection( + request: NewMCPServerRequest, + ): + """ + Test if we can connect to the provided MCP server before adding it + """ + async def _test_connection_operation(client): + await client.connect() + return {"status": "ok"} + + return await _execute_with_mcp_client(request, _test_connection_operation) @router.post("/test/tools/list") @@ -266,25 +295,13 @@ if MCP_AVAILABLE: """ Preview tools available from MCP server before adding it """ - try: - client = global_mcp_server_manager._create_mcp_client( - server=MCPServer( - server_id=request.server_id or "", - name=request.alias or request.server_name or "", - url=request.url, - transport=request.transport, - spec_version=_convert_protocol_version_to_enum(request.spec_version), - auth_type=request.auth_type, - mcp_info=request.mcp_info, - ), - mcp_auth_header=None, - ) - list_tools_result = await client.list_tools() - except Exception as e: - verbose_logger.error(f"Error in test_tools_list: {e}", exc_info=True) - return {"status": "error", "message": "An internal error has occurred."} - return { - "tools": list_tools_result, - "error": None, - "message": "Successfully retrieved tools" - } + async def _list_tools_operation(client): + list_tools_result: List[MCPTool] = await client.list_tools() + model_dumped_tools: List[dict] = [tool.model_dump() for tool in list_tools_result] + return { + "tools": model_dumped_tools, + "error": None, + "message": "Successfully retrieved tools" + } + + return await _execute_with_mcp_client(request, _list_tools_operation) diff --git a/litellm/proxy/_experimental/out/_next/static/0rzQKhrKTur56aOgaxVrq/_buildManifest.js b/litellm/proxy/_experimental/out/_next/static/0GF-OyXnYlAPMWfyPAZSs/_buildManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/0rzQKhrKTur56aOgaxVrq/_buildManifest.js rename to litellm/proxy/_experimental/out/_next/static/0GF-OyXnYlAPMWfyPAZSs/_buildManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/0rzQKhrKTur56aOgaxVrq/_ssgManifest.js b/litellm/proxy/_experimental/out/_next/static/0GF-OyXnYlAPMWfyPAZSs/_ssgManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/0rzQKhrKTur56aOgaxVrq/_ssgManifest.js rename to litellm/proxy/_experimental/out/_next/static/0GF-OyXnYlAPMWfyPAZSs/_ssgManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/117-a0da667066d322b6.js b/litellm/proxy/_experimental/out/_next/static/chunks/117-6a9f6a591033d4a0.js similarity index 99% rename from litellm/proxy/_experimental/out/_next/static/chunks/117-a0da667066d322b6.js rename to litellm/proxy/_experimental/out/_next/static/chunks/117-6a9f6a591033d4a0.js index 21cf536ca55..54b5be82634 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/117-a0da667066d322b6.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/117-6a9f6a591033d4a0.js @@ -1,2 +1,2 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[117],{65157:function(e,t){"use strict";function n(){return""}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"getDeploymentIdQueryOrEmptyString",{enumerable:!0,get:function(){return n}})},91572:function(){"trimStart"in String.prototype||(String.prototype.trimStart=String.prototype.trimLeft),"trimEnd"in String.prototype||(String.prototype.trimEnd=String.prototype.trimRight),"description"in Symbol.prototype||Object.defineProperty(Symbol.prototype,"description",{configurable:!0,get:function(){var e=/\((.*)\)/.exec(this.toString());return e?e[1]:void 0}}),Array.prototype.flat||(Array.prototype.flat=function(e,t){return t=this.concat.apply([],this),e>1&&t.some(Array.isArray)?t.flat(e-1):t},Array.prototype.flatMap=function(e,t){return this.map(e,t).flat()}),Promise.prototype.finally||(Promise.prototype.finally=function(e){if("function"!=typeof e)return this.then(e,e);var t=this.constructor||Promise;return this.then(function(n){return t.resolve(e()).then(function(){return n})},function(n){return t.resolve(e()).then(function(){throw n})})}),Object.fromEntries||(Object.fromEntries=function(e){return Array.from(e).reduce(function(e,t){return e[t[0]]=t[1],e},{})}),Array.prototype.at||(Array.prototype.at=function(e){var t=Math.trunc(e)||0;if(t<0&&(t+=this.length),!(t<0||t>=this.length))return this[t]}),Object.hasOwn||(Object.hasOwn=function(e,t){if(null==e)throw TypeError("Cannot convert undefined or null to object");return Object.prototype.hasOwnProperty.call(Object(e),t)}),"canParse"in URL||(URL.canParse=function(e,t){try{return new URL(e,t),!0}catch(e){return!1}})},1634:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"addBasePath",{enumerable:!0,get:function(){return u}});let r=n(68498),o=n(33068);function u(e,t){return(0,o.normalizePathTrailingSlash)((0,r.addPathPrefix)(e,""))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},75266:function(e,t){"use strict";function n(e){var t,n;t=self.__next_s,n=()=>{e()},t&&t.length?t.reduce((e,t)=>{let[n,r]=t;return e.then(()=>new Promise((e,t)=>{let o=document.createElement("script");if(r)for(let e in r)"children"!==e&&o.setAttribute(e,r[e]);n?(o.src=n,o.onload=()=>e(),o.onerror=t):r&&(o.innerHTML=r.children,setTimeout(e)),document.head.appendChild(o)}))},Promise.resolve()).catch(e=>{console.error(e)}).then(()=>{n()}):n()}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"appBootstrap",{enumerable:!0,get:function(){return n}}),window.next={version:"14.2.30",appDir:!0},("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},83079:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"callServer",{enumerable:!0,get:function(){return o}});let r=n(12846);async function o(e,t){let n=(0,r.getServerActionDispatcher)();if(!n)throw Error("Invariant: missing action dispatcher.");return new Promise((r,o)=>{n({actionId:e,actionArgs:t,resolve:r,reject:o})})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},92304:function(e,t,n){"use strict";let r,o;Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"hydrate",{enumerable:!0,get:function(){return x}});let u=n(47043),l=n(53099),a=n(57437);n(91572);let i=u._(n(34040)),c=l._(n(2265)),s=n(6671),f=n(48701),d=u._(n(61404)),p=n(83079),h=n(89721),y=n(2103);n(70647);let _=window.console.error;window.console.error=function(){for(var e=arguments.length,t=Array(e),n=0;n{if((0,h.isNextRouterError)(e.error)){e.preventDefault();return}});let v=document,b=new TextEncoder,g=!1,m=!1,R=null;function P(e){if(0===e[0])r=[];else if(1===e[0]){if(!r)throw Error("Unexpected server data: missing bootstrap script.");o?o.enqueue(b.encode(e[1])):r.push(e[1])}else 2===e[0]&&(R=e[1])}let j=function(){o&&!m&&(o.close(),m=!0,r=void 0),g=!0};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",j,!1):j();let O=self.__next_f=self.__next_f||[];O.forEach(P),O.push=P;let S=new ReadableStream({start(e){r&&(r.forEach(t=>{e.enqueue(b.encode(t))}),g&&!m&&(e.close(),m=!0,r=void 0)),o=e}}),E=(0,s.createFromReadableStream)(S,{callServer:p.callServer});function w(){return(0,c.use)(E)}let T=c.default.StrictMode;function M(e){let{children:t}=e;return t}function x(){let e=(0,y.createMutableActionQueue)(),t=(0,a.jsx)(T,{children:(0,a.jsx)(f.HeadManagerContext.Provider,{value:{appDir:!0},children:(0,a.jsx)(y.ActionQueueContext.Provider,{value:e,children:(0,a.jsx)(M,{children:(0,a.jsx)(w,{})})})})}),n=window.__next_root_layout_missing_tags,r=!!(null==n?void 0:n.length),o={onRecoverableError:d.default};"__next_error__"===document.documentElement.id||r?i.default.createRoot(v,o).render(t):c.default.startTransition(()=>i.default.hydrateRoot(v,t,{...o,formState:R}))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},54278:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(19506),(0,n(75266).appBootstrap)(()=>{let{hydrate:e}=n(92304);n(12846),n(4707),e()}),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},19506:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(65157);{let e=n.u;n.u=function(){for(var t=arguments.length,n=Array(t),r=0;r(l(function(){var e;let t=document.getElementsByName(u)[0];if(null==t?void 0:null==(e=t.shadowRoot)?void 0:e.childNodes[0])return t.shadowRoot.childNodes[0];{let e=document.createElement(u);e.style.cssText="position:absolute";let t=document.createElement("div");return t.ariaLive="assertive",t.id="__next-route-announcer__",t.role="alert",t.style.cssText="position:absolute;border:0;height:1px;margin:-1px;padding:0;width:1px;clip:rect(0 0 0 0);overflow:hidden;white-space:nowrap;word-wrap:normal",e.attachShadow({mode:"open"}).appendChild(t),document.body.appendChild(e),t}}()),()=>{let e=document.getElementsByTagName(u)[0];(null==e?void 0:e.isConnected)&&document.body.removeChild(e)}),[]);let[a,i]=(0,r.useState)(""),c=(0,r.useRef)();return(0,r.useEffect)(()=>{let e="";if(document.title)e=document.title;else{let t=document.querySelector("h1");t&&(e=t.innerText||t.textContent||"")}void 0!==c.current&&c.current!==e&&i(e),c.current=e},[t]),n?(0,o.createPortal)(a,n):null}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},6866:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ACTION:function(){return r},FLIGHT_PARAMETERS:function(){return i},NEXT_DID_POSTPONE_HEADER:function(){return s},NEXT_ROUTER_PREFETCH_HEADER:function(){return u},NEXT_ROUTER_STATE_TREE:function(){return o},NEXT_RSC_UNION_QUERY:function(){return c},NEXT_URL:function(){return l},RSC_CONTENT_TYPE_HEADER:function(){return a},RSC_HEADER:function(){return n}});let n="RSC",r="Next-Action",o="Next-Router-State-Tree",u="Next-Router-Prefetch",l="Next-Url",a="text/x-component",i=[[n],[o],[u]],c="_rsc",s="x-nextjs-postponed";("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},12846:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{createEmptyCacheNode:function(){return C},default:function(){return I},getServerActionDispatcher:function(){return E},urlToUrlWithoutFlightMarker:function(){return T}});let r=n(53099),o=n(57437),u=r._(n(2265)),l=n(61956),a=n(24673),i=n(33456),c=n(79060),s=n(47744),f=n(61060),d=n(82952),p=n(86146),h=n(1634),y=n(6495),_=n(4123),v=n(39320),b=n(38137),g=n(6866),m=n(35076),R=n(11283),P=n(84541),j="undefined"==typeof window,O=j?null:new Map,S=null;function E(){return S}let w={};function T(e){let t=new URL(e,location.origin);if(t.searchParams.delete(g.NEXT_RSC_UNION_QUERY),t.pathname.endsWith(".txt")){let{pathname:e}=t,n=e.endsWith("/index.txt")?10:4;t.pathname=e.slice(0,-n)}return t}function M(e){return e.origin!==window.location.origin}function x(e){let{appRouterState:t,sync:n}=e;return(0,u.useInsertionEffect)(()=>{let{tree:e,pushRef:r,canonicalUrl:o}=t,u={...r.preserveCustomHistoryState?window.history.state:{},__NA:!0,__PRIVATE_NEXTJS_INTERNALS_TREE:e};r.pendingPush&&(0,i.createHrefFromUrl)(new URL(window.location.href))!==o?(r.pendingPush=!1,window.history.pushState(u,"",o)):window.history.replaceState(u,"",o),n(t)},[t,n]),null}function C(){return{lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null}}function A(e){null==e&&(e={});let t=window.history.state,n=null==t?void 0:t.__NA;n&&(e.__NA=n);let r=null==t?void 0:t.__PRIVATE_NEXTJS_INTERNALS_TREE;return r&&(e.__PRIVATE_NEXTJS_INTERNALS_TREE=r),e}function N(e){let{headCacheNode:t}=e,n=null!==t?t.head:null,r=null!==t?t.prefetchHead:null,o=null!==r?r:n;return(0,u.useDeferredValue)(n,o)}function D(e){let t,{buildId:n,initialHead:r,initialTree:i,urlParts:f,initialSeedData:g,couldBeIntercepted:E,assetPrefix:T,missingSlots:C}=e,D=(0,u.useMemo)(()=>(0,d.createInitialRouterState)({buildId:n,initialSeedData:g,urlParts:f,initialTree:i,initialParallelRoutes:O,location:j?null:window.location,initialHead:r,couldBeIntercepted:E}),[n,g,f,i,r,E]),[I,U,k]=(0,s.useReducerWithReduxDevtools)(D);(0,u.useEffect)(()=>{O=null},[]);let{canonicalUrl:F}=(0,s.useUnwrapState)(I),{searchParams:L,pathname:H}=(0,u.useMemo)(()=>{let e=new URL(F,"undefined"==typeof window?"http://n":window.location.href);return{searchParams:e.searchParams,pathname:(0,R.hasBasePath)(e.pathname)?(0,m.removeBasePath)(e.pathname):e.pathname}},[F]),$=(0,u.useCallback)(e=>{let{previousTree:t,serverResponse:n}=e;(0,u.startTransition)(()=>{U({type:a.ACTION_SERVER_PATCH,previousTree:t,serverResponse:n})})},[U]),G=(0,u.useCallback)((e,t,n)=>{let r=new URL((0,h.addBasePath)(e),location.href);return U({type:a.ACTION_NAVIGATE,url:r,isExternalUrl:M(r),locationSearch:location.search,shouldScroll:null==n||n,navigateType:t})},[U]);S=(0,u.useCallback)(e=>{(0,u.startTransition)(()=>{U({...e,type:a.ACTION_SERVER_ACTION})})},[U]);let z=(0,u.useMemo)(()=>({back:()=>window.history.back(),forward:()=>window.history.forward(),prefetch:(e,t)=>{let n;if(!(0,p.isBot)(window.navigator.userAgent)){try{n=new URL((0,h.addBasePath)(e),window.location.href)}catch(t){throw Error("Cannot prefetch '"+e+"' because it cannot be converted to a URL.")}M(n)||(0,u.startTransition)(()=>{var e;U({type:a.ACTION_PREFETCH,url:n,kind:null!=(e=null==t?void 0:t.kind)?e:a.PrefetchKind.FULL})})}},replace:(e,t)=>{void 0===t&&(t={}),(0,u.startTransition)(()=>{var n;G(e,"replace",null==(n=t.scroll)||n)})},push:(e,t)=>{void 0===t&&(t={}),(0,u.startTransition)(()=>{var n;G(e,"push",null==(n=t.scroll)||n)})},refresh:()=>{(0,u.startTransition)(()=>{U({type:a.ACTION_REFRESH,origin:window.location.origin})})},fastRefresh:()=>{throw Error("fastRefresh can only be used in development mode. Please use refresh instead.")}}),[U,G]);(0,u.useEffect)(()=>{window.next&&(window.next.router=z)},[z]),(0,u.useEffect)(()=>{function e(e){var t;e.persisted&&(null==(t=window.history.state)?void 0:t.__PRIVATE_NEXTJS_INTERNALS_TREE)&&(w.pendingMpaPath=void 0,U({type:a.ACTION_RESTORE,url:new URL(window.location.href),tree:window.history.state.__PRIVATE_NEXTJS_INTERNALS_TREE}))}return window.addEventListener("pageshow",e),()=>{window.removeEventListener("pageshow",e)}},[U]);let{pushRef:B}=(0,s.useUnwrapState)(I);if(B.mpaNavigation){if(w.pendingMpaPath!==F){let e=window.location;B.pendingPush?e.assign(F):e.replace(F),w.pendingMpaPath=F}(0,u.use)(b.unresolvedThenable)}(0,u.useEffect)(()=>{let e=window.history.pushState.bind(window.history),t=window.history.replaceState.bind(window.history),n=e=>{var t;let n=window.location.href,r=null==(t=window.history.state)?void 0:t.__PRIVATE_NEXTJS_INTERNALS_TREE;(0,u.startTransition)(()=>{U({type:a.ACTION_RESTORE,url:new URL(null!=e?e:n,n),tree:r})})};window.history.pushState=function(t,r,o){return(null==t?void 0:t.__NA)||(null==t?void 0:t._N)||(t=A(t),o&&n(o)),e(t,r,o)},window.history.replaceState=function(e,r,o){return(null==e?void 0:e.__NA)||(null==e?void 0:e._N)||(e=A(e),o&&n(o)),t(e,r,o)};let r=e=>{let{state:t}=e;if(t){if(!t.__NA){window.location.reload();return}(0,u.startTransition)(()=>{U({type:a.ACTION_RESTORE,url:new URL(window.location.href),tree:t.__PRIVATE_NEXTJS_INTERNALS_TREE})})}};return window.addEventListener("popstate",r),()=>{window.history.pushState=e,window.history.replaceState=t,window.removeEventListener("popstate",r)}},[U]);let{cache:W,tree:K,nextUrl:V,focusAndScrollRef:Y}=(0,s.useUnwrapState)(I),X=(0,u.useMemo)(()=>(0,v.findHeadInCache)(W,K[1]),[W,K]),q=(0,u.useMemo)(()=>(function e(t,n){for(let r of(void 0===n&&(n={}),Object.values(t[1]))){let t=r[0],o=Array.isArray(t),u=o?t[1]:t;!u||u.startsWith(P.PAGE_SEGMENT_KEY)||(o&&("c"===t[2]||"oc"===t[2])?n[t[0]]=t[1].split("/"):o&&(n[t[0]]=t[1]),n=e(r,n))}return n})(K),[K]);if(null!==X){let[e,n]=X;t=(0,o.jsx)(N,{headCacheNode:e},n)}else t=null;let J=(0,o.jsxs)(_.RedirectBoundary,{children:[t,W.rsc,(0,o.jsx)(y.AppRouterAnnouncer,{tree:K})]});return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(x,{appRouterState:(0,s.useUnwrapState)(I),sync:k}),(0,o.jsx)(c.PathParamsContext.Provider,{value:q,children:(0,o.jsx)(c.PathnameContext.Provider,{value:H,children:(0,o.jsx)(c.SearchParamsContext.Provider,{value:L,children:(0,o.jsx)(l.GlobalLayoutRouterContext.Provider,{value:{buildId:n,changeByServerResponse:$,tree:K,focusAndScrollRef:Y,nextUrl:V},children:(0,o.jsx)(l.AppRouterContext.Provider,{value:z,children:(0,o.jsx)(l.LayoutRouterContext.Provider,{value:{childNodes:W.parallelRoutes,tree:K,url:F,loading:W.loading},children:J})})})})})})]})}function I(e){let{globalErrorComponent:t,...n}=e;return(0,o.jsx)(f.ErrorBoundary,{errorComponent:t,children:(0,o.jsx)(D,{...n})})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},96149:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"bailoutToClientRendering",{enumerable:!0,get:function(){return u}});let r=n(18993),o=n(51845);function u(e){let t=o.staticGenerationAsyncStorage.getStore();if((null==t||!t.forceStatic)&&(null==t?void 0:t.isStaticGeneration))throw new r.BailoutToCSRError(e)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},19107:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"ClientPageRoot",{enumerable:!0,get:function(){return u}});let r=n(57437),o=n(54535);function u(e){let{Component:t,props:n}=e;return n.searchParams=(0,o.createDynamicallyTrackedSearchParams)(n.searchParams||{}),(0,r.jsx)(t,{...n})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},61060:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ErrorBoundary:function(){return h},ErrorBoundaryHandler:function(){return f},GlobalError:function(){return d},default:function(){return p}});let r=n(47043),o=n(57437),u=r._(n(2265)),l=n(35475),a=n(89721),i=n(51845),c={error:{fontFamily:'system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"',height:"100vh",textAlign:"center",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},text:{fontSize:"14px",fontWeight:400,lineHeight:"28px",margin:"0 8px"}};function s(e){let{error:t}=e,n=i.staticGenerationAsyncStorage.getStore();if((null==n?void 0:n.isRevalidate)||(null==n?void 0:n.isStaticGeneration))throw console.error(t),t;return null}class f extends u.default.Component{static getDerivedStateFromError(e){if((0,a.isNextRouterError)(e))throw e;return{error:e}}static getDerivedStateFromProps(e,t){return e.pathname!==t.previousPathname&&t.error?{error:null,previousPathname:e.pathname}:{error:t.error,previousPathname:e.pathname}}render(){return this.state.error?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(s,{error:this.state.error}),this.props.errorStyles,this.props.errorScripts,(0,o.jsx)(this.props.errorComponent,{error:this.state.error,reset:this.reset})]}):this.props.children}constructor(e){super(e),this.reset=()=>{this.setState({error:null})},this.state={error:null,previousPathname:this.props.pathname}}}function d(e){let{error:t}=e,n=null==t?void 0:t.digest;return(0,o.jsxs)("html",{id:"__next_error__",children:[(0,o.jsx)("head",{}),(0,o.jsxs)("body",{children:[(0,o.jsx)(s,{error:t}),(0,o.jsx)("div",{style:c.error,children:(0,o.jsxs)("div",{children:[(0,o.jsx)("h2",{style:c.text,children:"Application error: a "+(n?"server":"client")+"-side exception has occurred (see the "+(n?"server logs":"browser console")+" for more information)."}),n?(0,o.jsx)("p",{style:c.text,children:"Digest: "+n}):null]})})]})]})}let p=d;function h(e){let{errorComponent:t,errorStyles:n,errorScripts:r,children:u}=e,a=(0,l.usePathname)();return t?(0,o.jsx)(f,{pathname:a,errorComponent:t,errorStyles:n,errorScripts:r,children:u}):(0,o.jsx)(o.Fragment,{children:u})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},46177:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{DynamicServerError:function(){return r},isDynamicServerError:function(){return o}});let n="DYNAMIC_SERVER_USAGE";class r extends Error{constructor(e){super("Dynamic server usage: "+e),this.description=e,this.digest=n}}function o(e){return"object"==typeof e&&null!==e&&"digest"in e&&"string"==typeof e.digest&&e.digest===n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},89721:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"isNextRouterError",{enumerable:!0,get:function(){return u}});let r=n(98200),o=n(88968);function u(e){return e&&e.digest&&((0,o.isRedirectError)(e)||(0,r.isNotFoundError)(e))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},4707:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return S}});let r=n(47043),o=n(53099),u=n(57437),l=o._(n(2265)),a=r._(n(54887)),i=n(61956),c=n(44848),s=n(38137),f=n(61060),d=n(76015),p=n(7092),h=n(4123),y=n(80),_=n(73171),v=n(78505),b=n(28077),g=["bottom","height","left","right","top","width","x","y"];function m(e,t){let n=e.getBoundingClientRect();return n.top>=0&&n.top<=t}class R extends l.default.Component{componentDidMount(){this.handlePotentialScroll()}componentDidUpdate(){this.props.focusAndScrollRef.apply&&this.handlePotentialScroll()}render(){return this.props.children}constructor(...e){super(...e),this.handlePotentialScroll=()=>{let{focusAndScrollRef:e,segmentPath:t}=this.props;if(e.apply){var n;if(0!==e.segmentPaths.length&&!e.segmentPaths.some(e=>t.every((t,n)=>(0,d.matchSegment)(t,e[n]))))return;let r=null,o=e.hashFragment;if(o&&(r="top"===o?document.body:null!=(n=document.getElementById(o))?n:document.getElementsByName(o)[0]),r||(r="undefined"==typeof window?null:a.default.findDOMNode(this)),!(r instanceof Element))return;for(;!(r instanceof HTMLElement)||function(e){if(["sticky","fixed"].includes(getComputedStyle(e).position))return!0;let t=e.getBoundingClientRect();return g.every(e=>0===t[e])}(r);){if(null===r.nextElementSibling)return;r=r.nextElementSibling}e.apply=!1,e.hashFragment=null,e.segmentPaths=[],(0,p.handleSmoothScroll)(()=>{if(o){r.scrollIntoView();return}let e=document.documentElement,t=e.clientHeight;!m(r,t)&&(e.scrollTop=0,m(r,t)||r.scrollIntoView())},{dontForceLayout:!0,onlyHashChange:e.onlyHashChange}),e.onlyHashChange=!1,r.focus()}}}}function P(e){let{segmentPath:t,children:n}=e,r=(0,l.useContext)(i.GlobalLayoutRouterContext);if(!r)throw Error("invariant global layout router not mounted");return(0,u.jsx)(R,{segmentPath:t,focusAndScrollRef:r.focusAndScrollRef,children:n})}function j(e){let{parallelRouterKey:t,url:n,childNodes:r,segmentPath:o,tree:a,cacheKey:f}=e,p=(0,l.useContext)(i.GlobalLayoutRouterContext);if(!p)throw Error("invariant global layout router not mounted");let{buildId:h,changeByServerResponse:y,tree:_}=p,v=r.get(f);if(void 0===v){let e={lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null};v=e,r.set(f,e)}let g=null!==v.prefetchRsc?v.prefetchRsc:v.rsc,m=(0,l.useDeferredValue)(v.rsc,g),R="object"==typeof m&&null!==m&&"function"==typeof m.then?(0,l.use)(m):m;if(!R){let e=v.lazyData;if(null===e){let t=function e(t,n){if(t){let[r,o]=t,u=2===t.length;if((0,d.matchSegment)(n[0],r)&&n[1].hasOwnProperty(o)){if(u){let t=e(void 0,n[1][o]);return[n[0],{...n[1],[o]:[t[0],t[1],t[2],"refetch"]}]}return[n[0],{...n[1],[o]:e(t.slice(2),n[1][o])}]}}return n}(["",...o],_),r=(0,b.hasInterceptionRouteInCurrentTree)(_);v.lazyData=e=(0,c.fetchServerResponse)(new URL(n,location.origin),t,r?p.nextUrl:null,h),v.lazyDataResolved=!1}let t=(0,l.use)(e);v.lazyDataResolved||(setTimeout(()=>{(0,l.startTransition)(()=>{y({previousTree:_,serverResponse:t})})}),v.lazyDataResolved=!0),(0,l.use)(s.unresolvedThenable)}return(0,u.jsx)(i.LayoutRouterContext.Provider,{value:{tree:a[1][t],childNodes:v.parallelRoutes,url:n,loading:v.loading},children:R})}function O(e){let{children:t,hasLoading:n,loading:r,loadingStyles:o,loadingScripts:a}=e;return n?(0,u.jsx)(l.Suspense,{fallback:(0,u.jsxs)(u.Fragment,{children:[o,a,r]}),children:t}):(0,u.jsx)(u.Fragment,{children:t})}function S(e){let{parallelRouterKey:t,segmentPath:n,error:r,errorStyles:o,errorScripts:a,templateStyles:c,templateScripts:s,template:d,notFound:p,notFoundStyles:b}=e,g=(0,l.useContext)(i.LayoutRouterContext);if(!g)throw Error("invariant expected layout router to be mounted");let{childNodes:m,tree:R,url:S,loading:E}=g,w=m.get(t);w||(w=new Map,m.set(t,w));let T=R[1][t][0],M=(0,_.getSegmentValue)(T),x=[T];return(0,u.jsx)(u.Fragment,{children:x.map(e=>{let l=(0,_.getSegmentValue)(e),g=(0,v.createRouterCacheKey)(e);return(0,u.jsxs)(i.TemplateContext.Provider,{value:(0,u.jsx)(P,{segmentPath:n,children:(0,u.jsx)(f.ErrorBoundary,{errorComponent:r,errorStyles:o,errorScripts:a,children:(0,u.jsx)(O,{hasLoading:!!E,loading:null==E?void 0:E[0],loadingStyles:null==E?void 0:E[1],loadingScripts:null==E?void 0:E[2],children:(0,u.jsx)(y.NotFoundBoundary,{notFound:p,notFoundStyles:b,children:(0,u.jsx)(h.RedirectBoundary,{children:(0,u.jsx)(j,{parallelRouterKey:t,url:S,tree:R,childNodes:w,segmentPath:n,cacheKey:g,isActive:M===l})})})})})}),children:[c,s,d]},(0,v.createRouterCacheKey)(e,!0))})})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},76015:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{canSegmentBeOverridden:function(){return u},matchSegment:function(){return o}});let r=n(87417),o=(e,t)=>"string"==typeof e?"string"==typeof t&&e===t:"string"!=typeof t&&e[0]===t[0]&&e[1]===t[1],u=(e,t)=>{var n;return!Array.isArray(e)&&!!Array.isArray(t)&&(null==(n=(0,r.getSegmentParam)(e))?void 0:n.param)===t[0]};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},35475:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ReadonlyURLSearchParams:function(){return i.ReadonlyURLSearchParams},RedirectType:function(){return i.RedirectType},ServerInsertedHTMLContext:function(){return c.ServerInsertedHTMLContext},notFound:function(){return i.notFound},permanentRedirect:function(){return i.permanentRedirect},redirect:function(){return i.redirect},useParams:function(){return p},usePathname:function(){return f},useRouter:function(){return d},useSearchParams:function(){return s},useSelectedLayoutSegment:function(){return y},useSelectedLayoutSegments:function(){return h},useServerInsertedHTML:function(){return c.useServerInsertedHTML}});let r=n(2265),o=n(61956),u=n(79060),l=n(73171),a=n(84541),i=n(52646),c=n(55501);function s(){let e=(0,r.useContext)(u.SearchParamsContext),t=(0,r.useMemo)(()=>e?new i.ReadonlyURLSearchParams(e):null,[e]);if("undefined"==typeof window){let{bailoutToClientRendering:e}=n(96149);e("useSearchParams()")}return t}function f(){return(0,r.useContext)(u.PathnameContext)}function d(){let e=(0,r.useContext)(o.AppRouterContext);if(null===e)throw Error("invariant expected app router to be mounted");return e}function p(){return(0,r.useContext)(u.PathParamsContext)}function h(e){void 0===e&&(e="children");let t=(0,r.useContext)(o.LayoutRouterContext);return t?function e(t,n,r,o){let u;if(void 0===r&&(r=!0),void 0===o&&(o=[]),r)u=t[1][n];else{var i;let e=t[1];u=null!=(i=e.children)?i:Object.values(e)[0]}if(!u)return o;let c=u[0],s=(0,l.getSegmentValue)(c);return!s||s.startsWith(a.PAGE_SEGMENT_KEY)?o:(o.push(s),e(u,n,!1,o))}(t.tree,e):null}function y(e){void 0===e&&(e="children");let t=h(e);if(!t||0===t.length)return null;let n="children"===e?t[0]:t[t.length-1];return n===a.DEFAULT_SEGMENT_KEY?null:n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},52646:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ReadonlyURLSearchParams:function(){return l},RedirectType:function(){return r.RedirectType},notFound:function(){return o.notFound},permanentRedirect:function(){return r.permanentRedirect},redirect:function(){return r.redirect}});let r=n(88968),o=n(98200);class u extends Error{constructor(){super("Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams")}}class l extends URLSearchParams{append(){throw new u}delete(){throw new u}set(){throw new u}sort(){throw new u}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},80:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"NotFoundBoundary",{enumerable:!0,get:function(){return s}});let r=n(53099),o=n(57437),u=r._(n(2265)),l=n(35475),a=n(98200);n(31765);let i=n(61956);class c extends u.default.Component{componentDidCatch(){}static getDerivedStateFromError(e){if((0,a.isNotFoundError)(e))return{notFoundTriggered:!0};throw e}static getDerivedStateFromProps(e,t){return e.pathname!==t.previousPathname&&t.notFoundTriggered?{notFoundTriggered:!1,previousPathname:e.pathname}:{notFoundTriggered:t.notFoundTriggered,previousPathname:e.pathname}}render(){return this.state.notFoundTriggered?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)("meta",{name:"robots",content:"noindex"}),!1,this.props.notFoundStyles,this.props.notFound]}):this.props.children}constructor(e){super(e),this.state={notFoundTriggered:!!e.asNotFound,previousPathname:e.pathname}}}function s(e){let{notFound:t,notFoundStyles:n,asNotFound:r,children:a}=e,s=(0,l.usePathname)(),f=(0,u.useContext)(i.MissingSlotContext);return t?(0,o.jsx)(c,{pathname:s,notFound:t,notFoundStyles:n,asNotFound:r,missingSlots:f,children:a}):(0,o.jsx)(o.Fragment,{children:a})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},98200:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{isNotFoundError:function(){return o},notFound:function(){return r}});let n="NEXT_NOT_FOUND";function r(){let e=Error(n);throw e.digest=n,e}function o(e){return"object"==typeof e&&null!==e&&"digest"in e&&e.digest===n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},29744:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"PromiseQueue",{enumerable:!0,get:function(){return c}});let r=n(2522),o=n(90675);var u=o._("_maxConcurrency"),l=o._("_runningCount"),a=o._("_queue"),i=o._("_processNext");class c{enqueue(e){let t,n;let o=new Promise((e,r)=>{t=e,n=r}),u=async()=>{try{r._(this,l)[l]++;let n=await e();t(n)}catch(e){n(e)}finally{r._(this,l)[l]--,r._(this,i)[i]()}};return r._(this,a)[a].push({promiseFn:o,task:u}),r._(this,i)[i](),o}bump(e){let t=r._(this,a)[a].findIndex(t=>t.promiseFn===e);if(t>-1){let e=r._(this,a)[a].splice(t,1)[0];r._(this,a)[a].unshift(e),r._(this,i)[i](!0)}}constructor(e=5){Object.defineProperty(this,i,{value:s}),Object.defineProperty(this,u,{writable:!0,value:void 0}),Object.defineProperty(this,l,{writable:!0,value:void 0}),Object.defineProperty(this,a,{writable:!0,value:void 0}),r._(this,u)[u]=e,r._(this,l)[l]=0,r._(this,a)[a]=[]}}function s(e){if(void 0===e&&(e=!1),(r._(this,l)[l]0){var t;null==(t=r._(this,a)[a].shift())||t.task()}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},4123:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{RedirectBoundary:function(){return s},RedirectErrorBoundary:function(){return c}});let r=n(53099),o=n(57437),u=r._(n(2265)),l=n(35475),a=n(88968);function i(e){let{redirect:t,reset:n,redirectType:r}=e,o=(0,l.useRouter)();return(0,u.useEffect)(()=>{u.default.startTransition(()=>{r===a.RedirectType.push?o.push(t,{}):o.replace(t,{}),n()})},[t,r,n,o]),null}class c extends u.default.Component{static getDerivedStateFromError(e){if((0,a.isRedirectError)(e))return{redirect:(0,a.getURLFromRedirectError)(e),redirectType:(0,a.getRedirectTypeFromError)(e)};throw e}render(){let{redirect:e,redirectType:t}=this.state;return null!==e&&null!==t?(0,o.jsx)(i,{redirect:e,redirectType:t,reset:()=>this.setState({redirect:null})}):this.props.children}constructor(e){super(e),this.state={redirect:null,redirectType:null}}}function s(e){let{children:t}=e,n=(0,l.useRouter)();return(0,o.jsx)(c,{router:n,children:t})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},5001:function(e,t){"use strict";var n,r;Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"RedirectStatusCode",{enumerable:!0,get:function(){return n}}),(r=n||(n={}))[r.SeeOther=303]="SeeOther",r[r.TemporaryRedirect=307]="TemporaryRedirect",r[r.PermanentRedirect=308]="PermanentRedirect",("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},88968:function(e,t,n){"use strict";var r,o;Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{RedirectType:function(){return r},getRedirectError:function(){return c},getRedirectStatusCodeFromError:function(){return y},getRedirectTypeFromError:function(){return h},getURLFromRedirectError:function(){return p},isRedirectError:function(){return d},permanentRedirect:function(){return f},redirect:function(){return s}});let u=n(20544),l=n(90295),a=n(5001),i="NEXT_REDIRECT";function c(e,t,n){void 0===n&&(n=a.RedirectStatusCode.TemporaryRedirect);let r=Error(i);r.digest=i+";"+t+";"+e+";"+n+";";let o=u.requestAsyncStorage.getStore();return o&&(r.mutableCookies=o.mutableCookies),r}function s(e,t){void 0===t&&(t="replace");let n=l.actionAsyncStorage.getStore();throw c(e,t,(null==n?void 0:n.isAction)?a.RedirectStatusCode.SeeOther:a.RedirectStatusCode.TemporaryRedirect)}function f(e,t){void 0===t&&(t="replace");let n=l.actionAsyncStorage.getStore();throw c(e,t,(null==n?void 0:n.isAction)?a.RedirectStatusCode.SeeOther:a.RedirectStatusCode.PermanentRedirect)}function d(e){if("object"!=typeof e||null===e||!("digest"in e)||"string"!=typeof e.digest)return!1;let[t,n,r,o]=e.digest.split(";",4),u=Number(o);return t===i&&("replace"===n||"push"===n)&&"string"==typeof r&&!isNaN(u)&&u in a.RedirectStatusCode}function p(e){return d(e)?e.digest.split(";",3)[2]:null}function h(e){if(!d(e))throw Error("Not a redirect error");return e.digest.split(";",2)[1]}function y(e){if(!d(e))throw Error("Not a redirect error");return Number(e.digest.split(";",4)[3])}(o=r||(r={})).push="push",o.replace="replace",("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},36423:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return a}});let r=n(53099),o=n(57437),u=r._(n(2265)),l=n(61956);function a(){let e=(0,u.useContext)(l.TemplateContext);return(0,o.jsx)(o.Fragment,{children:e})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},20544:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{getExpectedRequestStore:function(){return o},requestAsyncStorage:function(){return r.requestAsyncStorage}});let r=n(25575);function o(e){let t=r.requestAsyncStorage.getStore();if(t)return t;throw Error("`"+e+"` was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context")}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},22356:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"applyFlightData",{enumerable:!0,get:function(){return u}});let r=n(27420),o=n(92576);function u(e,t,n,u){let[l,a,i]=n.slice(-3);if(null===a)return!1;if(3===n.length){let n=a[2],o=a[3];t.loading=o,t.rsc=n,t.prefetchRsc=null,(0,r.fillLazyItemsTillLeafWithHead)(t,e,l,a,i,u)}else t.rsc=e.rsc,t.prefetchRsc=e.prefetchRsc,t.parallelRoutes=new Map(e.parallelRoutes),t.loading=e.loading,(0,o.fillCacheWithNewSubTreeData)(t,e,n,u);return!0}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},81935:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"applyRouterStatePatchToTree",{enumerable:!0,get:function(){return function e(t,n,r,a){let i;let[c,s,f,d,p]=n;if(1===t.length){let e=l(n,r,t);return(0,u.addRefreshMarkerToActiveParallelSegments)(e,a),e}let[h,y]=t;if(!(0,o.matchSegment)(h,c))return null;if(2===t.length)i=l(s[y],r,t);else if(null===(i=e(t.slice(2),s[y],r,a)))return null;let _=[t[0],{...s,[y]:i},f,d];return p&&(_[4]=!0),(0,u.addRefreshMarkerToActiveParallelSegments)(_,a),_}}});let r=n(84541),o=n(76015),u=n(50232);function l(e,t,n){let[u,a]=e,[i,c]=t;if(i===r.DEFAULT_SEGMENT_KEY&&u!==r.DEFAULT_SEGMENT_KEY)return e;if((0,o.matchSegment)(u,i)){let t={};for(let e in a)void 0!==c[e]?t[e]=l(a[e],c[e],n):t[e]=a[e];for(let e in c)t[e]||(t[e]=c[e]);let r=[u,t];return e[2]&&(r[2]=e[2]),e[3]&&(r[3]=e[3]),e[4]&&(r[4]=e[4]),r}return t}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},65556:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"clearCacheNodeDataForSegmentPath",{enumerable:!0,get:function(){return function e(t,n,o){let u=o.length<=2,[l,a]=o,i=(0,r.createRouterCacheKey)(a),c=n.parallelRoutes.get(l),s=t.parallelRoutes.get(l);s&&s!==c||(s=new Map(c),t.parallelRoutes.set(l,s));let f=null==c?void 0:c.get(i),d=s.get(i);if(u){d&&d.lazyData&&d!==f||s.set(i,{lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null});return}if(!d||!f){d||s.set(i,{lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null});return}return d===f&&(d={lazyData:d.lazyData,rsc:d.rsc,prefetchRsc:d.prefetchRsc,head:d.head,prefetchHead:d.prefetchHead,parallelRoutes:new Map(d.parallelRoutes),lazyDataResolved:d.lazyDataResolved,loading:d.loading},s.set(i,d)),e(d,f,o.slice(2))}}});let r=n(78505);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},5410:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{computeChangedPath:function(){return s},extractPathFromFlightRouterState:function(){return c}});let r=n(91182),o=n(84541),u=n(76015),l=e=>"/"===e[0]?e.slice(1):e,a=e=>"string"==typeof e?"children"===e?"":e:e[1];function i(e){return e.reduce((e,t)=>""===(t=l(t))||(0,o.isGroupSegment)(t)?e:e+"/"+t,"")||"/"}function c(e){var t;let n=Array.isArray(e[0])?e[0][1]:e[0];if(n===o.DEFAULT_SEGMENT_KEY||r.INTERCEPTION_ROUTE_MARKERS.some(e=>n.startsWith(e)))return;if(n.startsWith(o.PAGE_SEGMENT_KEY))return"";let u=[a(n)],l=null!=(t=e[1])?t:{},s=l.children?c(l.children):void 0;if(void 0!==s)u.push(s);else for(let[e,t]of Object.entries(l)){if("children"===e)continue;let n=c(t);void 0!==n&&u.push(n)}return i(u)}function s(e,t){let n=function e(t,n){let[o,l]=t,[i,s]=n,f=a(o),d=a(i);if(r.INTERCEPTION_ROUTE_MARKERS.some(e=>f.startsWith(e)||d.startsWith(e)))return"";if(!(0,u.matchSegment)(o,i)){var p;return null!=(p=c(n))?p:""}for(let t in l)if(s[t]){let n=e(l[t],s[t]);if(null!==n)return a(i)+"/"+n}return null}(e,t);return null==n||"/"===n?n:i(n.split("/"))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},33456:function(e,t){"use strict";function n(e,t){return void 0===t&&(t=!0),e.pathname+e.search+(t?e.hash:"")}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createHrefFromUrl",{enumerable:!0,get:function(){return n}}),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},82952:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createInitialRouterState",{enumerable:!0,get:function(){return c}});let r=n(33456),o=n(27420),u=n(5410),l=n(60305),a=n(24673),i=n(50232);function c(e){var t;let{buildId:n,initialTree:c,initialSeedData:s,urlParts:f,initialParallelRoutes:d,location:p,initialHead:h,couldBeIntercepted:y}=e,_=f.join("/"),v=!p,b={lazyData:null,rsc:s[2],prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:v?new Map:d,lazyDataResolved:!1,loading:s[3]},g=p?(0,r.createHrefFromUrl)(p):_;(0,i.addRefreshMarkerToActiveParallelSegments)(c,g);let m=new Map;(null===d||0===d.size)&&(0,o.fillLazyItemsTillLeafWithHead)(b,void 0,c,s,h);let R={buildId:n,tree:c,cache:b,prefetchCache:m,pushRef:{pendingPush:!1,mpaNavigation:!1,preserveCustomHistoryState:!0},focusAndScrollRef:{apply:!1,onlyHashChange:!1,hashFragment:null,segmentPaths:[]},canonicalUrl:g,nextUrl:null!=(t=(0,u.extractPathFromFlightRouterState)(c)||(null==p?void 0:p.pathname))?t:null};if(p){let e=new URL(""+p.pathname+p.search,p.origin),t=[["",c,null,null]];(0,l.createPrefetchCacheEntryForInitialLoad)({url:e,kind:a.PrefetchKind.AUTO,data:[t,void 0,!1,y],tree:R.tree,prefetchCache:R.prefetchCache,nextUrl:R.nextUrl})}return R}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},78505:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createRouterCacheKey",{enumerable:!0,get:function(){return o}});let r=n(84541);function o(e,t){return(void 0===t&&(t=!1),Array.isArray(e))?e[0]+"|"+e[1]+"|"+e[2]:t&&e.startsWith(r.PAGE_SEGMENT_KEY)?r.PAGE_SEGMENT_KEY:e}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},44848:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"fetchServerResponse",{enumerable:!0,get:function(){return s}});let r=n(6866),o=n(12846),u=n(83079),l=n(24673),a=n(37207),{createFromFetch:i}=n(6671);function c(e){return[(0,o.urlToUrlWithoutFlightMarker)(e).toString(),void 0,!1,!1]}async function s(e,t,n,s,f){let d={[r.RSC_HEADER]:"1",[r.NEXT_ROUTER_STATE_TREE]:encodeURIComponent(JSON.stringify(t))};f===l.PrefetchKind.AUTO&&(d[r.NEXT_ROUTER_PREFETCH_HEADER]="1"),n&&(d[r.NEXT_URL]=n);let p=(0,a.hexHash)([d[r.NEXT_ROUTER_PREFETCH_HEADER]||"0",d[r.NEXT_ROUTER_STATE_TREE],d[r.NEXT_URL]].join(","));try{var h;let t=new URL(e);t.pathname.endsWith("/")?t.pathname+="index.txt":t.pathname+=".txt",t.searchParams.set(r.NEXT_RSC_UNION_QUERY,p);let n=await fetch(t,{credentials:"same-origin",headers:d}),l=(0,o.urlToUrlWithoutFlightMarker)(n.url),a=n.redirected?l:void 0,f=n.headers.get("content-type")||"",y=!!n.headers.get(r.NEXT_DID_POSTPONE_HEADER),_=!!(null==(h=n.headers.get("vary"))?void 0:h.includes(r.NEXT_URL)),v=f===r.RSC_CONTENT_TYPE_HEADER;if(v||(v=f.startsWith("text/plain")),!v||!n.ok)return e.hash&&(l.hash=e.hash),c(l.toString());let[b,g]=await i(Promise.resolve(n),{callServer:u.callServer});if(s!==b)return c(n.url);return[g,a,y,_]}catch(t){return console.error("Failed to fetch RSC payload for "+e+". Falling back to browser navigation.",t),[e.toString(),void 0,!1,!1]}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},92576:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"fillCacheWithNewSubTreeData",{enumerable:!0,get:function(){return function e(t,n,l,a){let i=l.length<=5,[c,s]=l,f=(0,u.createRouterCacheKey)(s),d=n.parallelRoutes.get(c);if(!d)return;let p=t.parallelRoutes.get(c);p&&p!==d||(p=new Map(d),t.parallelRoutes.set(c,p));let h=d.get(f),y=p.get(f);if(i){if(!y||!y.lazyData||y===h){let e=l[3];y={lazyData:null,rsc:e[2],prefetchRsc:null,head:null,prefetchHead:null,loading:e[3],parallelRoutes:h?new Map(h.parallelRoutes):new Map,lazyDataResolved:!1},h&&(0,r.invalidateCacheByRouterState)(y,h,l[2]),(0,o.fillLazyItemsTillLeafWithHead)(y,h,l[2],e,l[4],a),p.set(f,y)}return}y&&h&&(y===h&&(y={lazyData:y.lazyData,rsc:y.rsc,prefetchRsc:y.prefetchRsc,head:y.head,prefetchHead:y.prefetchHead,parallelRoutes:new Map(y.parallelRoutes),lazyDataResolved:!1,loading:y.loading},p.set(f,y)),e(y,h,l.slice(2),a))}}});let r=n(94377),o=n(27420),u=n(78505);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},27420:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"fillLazyItemsTillLeafWithHead",{enumerable:!0,get:function(){return function e(t,n,u,l,a,i){if(0===Object.keys(u[1]).length){t.head=a;return}for(let c in u[1]){let s;let f=u[1][c],d=f[0],p=(0,r.createRouterCacheKey)(d),h=null!==l&&void 0!==l[1][c]?l[1][c]:null;if(n){let r=n.parallelRoutes.get(c);if(r){let n;let u=(null==i?void 0:i.kind)==="auto"&&i.status===o.PrefetchCacheEntryStatus.reusable,l=new Map(r),s=l.get(p);n=null!==h?{lazyData:null,rsc:h[2],prefetchRsc:null,head:null,prefetchHead:null,loading:h[3],parallelRoutes:new Map(null==s?void 0:s.parallelRoutes),lazyDataResolved:!1}:u&&s?{lazyData:s.lazyData,rsc:s.rsc,prefetchRsc:s.prefetchRsc,head:s.head,prefetchHead:s.prefetchHead,parallelRoutes:new Map(s.parallelRoutes),lazyDataResolved:s.lazyDataResolved,loading:s.loading}:{lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map(null==s?void 0:s.parallelRoutes),lazyDataResolved:!1,loading:null},l.set(p,n),e(n,s,f,h||null,a,i),t.parallelRoutes.set(c,l);continue}}if(null!==h){let e=h[2],t=h[3];s={lazyData:null,rsc:e,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:t}}else s={lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null};let y=t.parallelRoutes.get(c);y?y.set(p,s):t.parallelRoutes.set(c,new Map([[p,s]])),e(s,void 0,f,h,a,i)}}}});let r=n(78505),o=n(24673);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},44510:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"handleMutable",{enumerable:!0,get:function(){return u}});let r=n(5410);function o(e){return void 0!==e}function u(e,t){var n,u,l;let a=null==(u=t.shouldScroll)||u,i=e.nextUrl;if(o(t.patchedTree)){let n=(0,r.computeChangedPath)(e.tree,t.patchedTree);n?i=n:i||(i=e.canonicalUrl)}return{buildId:e.buildId,canonicalUrl:o(t.canonicalUrl)?t.canonicalUrl===e.canonicalUrl?e.canonicalUrl:t.canonicalUrl:e.canonicalUrl,pushRef:{pendingPush:o(t.pendingPush)?t.pendingPush:e.pushRef.pendingPush,mpaNavigation:o(t.mpaNavigation)?t.mpaNavigation:e.pushRef.mpaNavigation,preserveCustomHistoryState:o(t.preserveCustomHistoryState)?t.preserveCustomHistoryState:e.pushRef.preserveCustomHistoryState},focusAndScrollRef:{apply:!!a&&(!!o(null==t?void 0:t.scrollableSegments)||e.focusAndScrollRef.apply),onlyHashChange:!!t.hashFragment&&e.canonicalUrl.split("#",1)[0]===(null==(n=t.canonicalUrl)?void 0:n.split("#",1)[0]),hashFragment:a?t.hashFragment&&""!==t.hashFragment?decodeURIComponent(t.hashFragment.slice(1)):e.focusAndScrollRef.hashFragment:null,segmentPaths:a?null!=(l=null==t?void 0:t.scrollableSegments)?l:e.focusAndScrollRef.segmentPaths:[]},cache:t.cache?t.cache:e.cache,prefetchCache:t.prefetchCache?t.prefetchCache:e.prefetchCache,tree:o(t.patchedTree)?t.patchedTree:e.tree,nextUrl:i}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},77831:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"handleSegmentMismatch",{enumerable:!0,get:function(){return o}});let r=n(95967);function o(e,t,n){return(0,r.handleExternalUrl)(e,{},e.canonicalUrl,!0)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},77058:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"invalidateCacheBelowFlightSegmentPath",{enumerable:!0,get:function(){return function e(t,n,o){let u=o.length<=2,[l,a]=o,i=(0,r.createRouterCacheKey)(a),c=n.parallelRoutes.get(l);if(!c)return;let s=t.parallelRoutes.get(l);if(s&&s!==c||(s=new Map(c),t.parallelRoutes.set(l,s)),u){s.delete(i);return}let f=c.get(i),d=s.get(i);d&&f&&(d===f&&(d={lazyData:d.lazyData,rsc:d.rsc,prefetchRsc:d.prefetchRsc,head:d.head,prefetchHead:d.prefetchHead,parallelRoutes:new Map(d.parallelRoutes),lazyDataResolved:d.lazyDataResolved},s.set(i,d)),e(d,f,o.slice(2)))}}});let r=n(78505);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},94377:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"invalidateCacheByRouterState",{enumerable:!0,get:function(){return o}});let r=n(78505);function o(e,t,n){for(let o in n[1]){let u=n[1][o][0],l=(0,r.createRouterCacheKey)(u),a=t.parallelRoutes.get(o);if(a){let t=new Map(a);t.delete(l),e.parallelRoutes.set(o,t)}}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},63237:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"isNavigatingToNewRootLayout",{enumerable:!0,get:function(){return function e(t,n){let r=t[0],o=n[0];if(Array.isArray(r)&&Array.isArray(o)){if(r[0]!==o[0]||r[2]!==o[2])return!0}else if(r!==o)return!0;if(t[4])return!n[4];if(n[4])return!0;let u=Object.values(t[1])[0],l=Object.values(n[1])[0];return!u||!l||e(u,l)}}}),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},56118:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{abortTask:function(){return c},listenForDynamicRequest:function(){return a},updateCacheNodeOnNavigation:function(){return function e(t,n,a,c,s){let f=n[1],d=a[1],p=c[1],h=t.parallelRoutes,y=new Map(h),_={},v=null;for(let t in d){let n;let a=d[t],c=f[t],b=h.get(t),g=p[t],m=a[0],R=(0,u.createRouterCacheKey)(m),P=void 0!==c?c[0]:void 0,j=void 0!==b?b.get(R):void 0;if(null!==(n=m===r.PAGE_SEGMENT_KEY?l(a,void 0!==g?g:null,s):m===r.DEFAULT_SEGMENT_KEY?void 0!==c?{route:c,node:null,children:null}:l(a,void 0!==g?g:null,s):void 0!==P&&(0,o.matchSegment)(m,P)&&void 0!==j&&void 0!==c?null!=g?e(j,c,a,g,s):function(e){let t=i(e,null,null);return{route:e,node:t,children:null}}(a):l(a,void 0!==g?g:null,s))){null===v&&(v=new Map),v.set(t,n);let e=n.node;if(null!==e){let n=new Map(b);n.set(R,e),y.set(t,n)}_[t]=n.route}else _[t]=a}if(null===v)return null;let b={lazyData:null,rsc:t.rsc,prefetchRsc:t.prefetchRsc,head:t.head,prefetchHead:t.prefetchHead,loading:t.loading,parallelRoutes:y,lazyDataResolved:!1};return{route:function(e,t){let n=[e[0],t];return 2 in e&&(n[2]=e[2]),3 in e&&(n[3]=e[3]),4 in e&&(n[4]=e[4]),n}(a,_),node:b,children:v}}},updateCacheNodeOnPopstateRestoration:function(){return function e(t,n){let r=n[1],o=t.parallelRoutes,l=new Map(o);for(let t in r){let n=r[t],a=n[0],i=(0,u.createRouterCacheKey)(a),c=o.get(t);if(void 0!==c){let r=c.get(i);if(void 0!==r){let o=e(r,n),u=new Map(c);u.set(i,o),l.set(t,u)}}}let a=t.rsc,i=d(a)&&"pending"===a.status;return{lazyData:null,rsc:a,head:t.head,prefetchHead:i?t.prefetchHead:null,prefetchRsc:i?t.prefetchRsc:null,loading:i?t.loading:null,parallelRoutes:l,lazyDataResolved:!1}}}});let r=n(84541),o=n(76015),u=n(78505);function l(e,t,n){let r=i(e,t,n);return{route:e,node:r,children:null}}function a(e,t){t.then(t=>{for(let n of t[0]){let t=n.slice(0,-3),r=n[n.length-3],l=n[n.length-2],a=n[n.length-1];"string"!=typeof t&&function(e,t,n,r,l){let a=e;for(let e=0;e{c(e,t)})}function i(e,t,n){let r=e[1],o=null!==t?t[1]:null,l=new Map;for(let e in r){let t=r[e],a=null!==o?o[e]:null,c=t[0],s=(0,u.createRouterCacheKey)(c),f=i(t,void 0===a?null:a,n),d=new Map;d.set(s,f),l.set(e,d)}let a=0===l.size,c=null!==t?t[2]:null,s=null!==t?t[3]:null;return{lazyData:null,parallelRoutes:l,prefetchRsc:void 0!==c?c:null,prefetchHead:a?n:null,loading:void 0!==s?s:null,rsc:p(),head:a?p():null,lazyDataResolved:!1}}function c(e,t){let n=e.node;if(null===n)return;let r=e.children;if(null===r)s(e.route,n,t);else for(let e of r.values())c(e,t);e.node=null}function s(e,t,n){let r=e[1],o=t.parallelRoutes;for(let e in r){let t=r[e],l=o.get(e);if(void 0===l)continue;let a=t[0],i=(0,u.createRouterCacheKey)(a),c=l.get(i);void 0!==c&&s(t,c,n)}let l=t.rsc;d(l)&&(null===n?l.resolve(null):l.reject(n));let a=t.head;d(a)&&a.resolve(null)}let f=Symbol();function d(e){return e&&e.tag===f}function p(){let e,t;let n=new Promise((n,r)=>{e=n,t=r});return n.status="pending",n.resolve=t=>{"pending"===n.status&&(n.status="fulfilled",n.value=t,e(t))},n.reject=e=>{"pending"===n.status&&(n.status="rejected",n.reason=e,t(e))},n.tag=f,n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},60305:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{createPrefetchCacheEntryForInitialLoad:function(){return c},getOrCreatePrefetchCacheEntry:function(){return i},prunePrefetchCache:function(){return f}});let r=n(33456),o=n(44848),u=n(24673),l=n(24819);function a(e,t){let n=(0,r.createHrefFromUrl)(e,!1);return t?t+"%"+n:n}function i(e){let t,{url:n,nextUrl:r,tree:o,buildId:l,prefetchCache:i,kind:c}=e,f=a(n,r),d=i.get(f);if(d)t=d;else{let e=a(n),r=i.get(e);r&&(t=r)}return t?(t.status=h(t),t.kind!==u.PrefetchKind.FULL&&c===u.PrefetchKind.FULL)?s({tree:o,url:n,buildId:l,nextUrl:r,prefetchCache:i,kind:null!=c?c:u.PrefetchKind.TEMPORARY}):(c&&t.kind===u.PrefetchKind.TEMPORARY&&(t.kind=c),t):s({tree:o,url:n,buildId:l,nextUrl:r,prefetchCache:i,kind:c||u.PrefetchKind.TEMPORARY})}function c(e){let{nextUrl:t,tree:n,prefetchCache:r,url:o,kind:l,data:i}=e,[,,,c]=i,s=c?a(o,t):a(o),f={treeAtTimeOfPrefetch:n,data:Promise.resolve(i),kind:l,prefetchTime:Date.now(),lastUsedTime:Date.now(),key:s,status:u.PrefetchCacheEntryStatus.fresh};return r.set(s,f),f}function s(e){let{url:t,kind:n,tree:r,nextUrl:i,buildId:c,prefetchCache:s}=e,f=a(t),d=l.prefetchQueue.enqueue(()=>(0,o.fetchServerResponse)(t,r,i,c,n).then(e=>{let[,,,n]=e;return n&&function(e){let{url:t,nextUrl:n,prefetchCache:r}=e,o=a(t),u=r.get(o);if(!u)return;let l=a(t,n);r.set(l,u),r.delete(o)}({url:t,nextUrl:i,prefetchCache:s}),e})),p={treeAtTimeOfPrefetch:r,data:d,kind:n,prefetchTime:Date.now(),lastUsedTime:null,key:f,status:u.PrefetchCacheEntryStatus.fresh};return s.set(f,p),p}function f(e){for(let[t,n]of e)h(n)===u.PrefetchCacheEntryStatus.expired&&e.delete(t)}let d=1e3*Number("30"),p=1e3*Number("300");function h(e){let{kind:t,prefetchTime:n,lastUsedTime:r}=e;return Date.now()<(null!=r?r:n)+d?r?u.PrefetchCacheEntryStatus.reusable:u.PrefetchCacheEntryStatus.fresh:"auto"===t&&Date.now(){let[n,f]=t,h=!1;if(S.lastUsedTime||(S.lastUsedTime=Date.now(),h=!0),"string"==typeof n)return _(e,R,n,O);if(document.getElementById("__next-page-redirect"))return _(e,R,j,O);let b=e.tree,g=e.cache,w=[];for(let t of n){let n=t.slice(0,-4),r=t.slice(-3)[0],c=["",...n],f=(0,u.applyRouterStatePatchToTree)(c,b,r,j);if(null===f&&(f=(0,u.applyRouterStatePatchToTree)(c,E,r,j)),null!==f){if((0,a.isNavigatingToNewRootLayout)(b,f))return _(e,R,j,O);let u=(0,d.createEmptyCacheNode)(),m=!1;for(let e of(S.status!==i.PrefetchCacheEntryStatus.stale||h?m=(0,s.applyFlightData)(g,u,t,S):(m=function(e,t,n,r){let o=!1;for(let u of(e.rsc=t.rsc,e.prefetchRsc=t.prefetchRsc,e.loading=t.loading,e.parallelRoutes=new Map(t.parallelRoutes),v(r).map(e=>[...n,...e])))(0,y.clearCacheNodeDataForSegmentPath)(e,t,u),o=!0;return o}(u,g,n,r),S.lastUsedTime=Date.now()),(0,l.shouldHardNavigate)(c,b)?(u.rsc=g.rsc,u.prefetchRsc=g.prefetchRsc,(0,o.invalidateCacheBelowFlightSegmentPath)(u,g,n),R.cache=u):m&&(R.cache=u,g=u),b=f,v(r))){let t=[...n,...e];t[t.length-1]!==p.DEFAULT_SEGMENT_KEY&&w.push(t)}}}return R.patchedTree=b,R.canonicalUrl=f?(0,r.createHrefFromUrl)(f):j,R.pendingPush=O,R.scrollableSegments=w,R.hashFragment=P,R.shouldScroll=m,(0,c.handleMutable)(e,R)},()=>e)};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},24819:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{prefetchQueue:function(){return l},prefetchReducer:function(){return a}});let r=n(6866),o=n(29744),u=n(60305),l=new o.PromiseQueue(5);function a(e,t){(0,u.prunePrefetchCache)(e.prefetchCache);let{url:n}=t;return n.searchParams.delete(r.NEXT_RSC_UNION_QUERY),(0,u.getOrCreatePrefetchCacheEntry)({url:n,nextUrl:e.nextUrl,prefetchCache:e.prefetchCache,kind:t.kind,tree:e.tree,buildId:e.buildId}),e}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},99601:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"refreshReducer",{enumerable:!0,get:function(){return h}});let r=n(44848),o=n(33456),u=n(81935),l=n(63237),a=n(95967),i=n(44510),c=n(27420),s=n(12846),f=n(77831),d=n(28077),p=n(50232);function h(e,t){let{origin:n}=t,h={},y=e.canonicalUrl,_=e.tree;h.preserveCustomHistoryState=!1;let v=(0,s.createEmptyCacheNode)(),b=(0,d.hasInterceptionRouteInCurrentTree)(e.tree);return v.lazyData=(0,r.fetchServerResponse)(new URL(y,n),[_[0],_[1],_[2],"refetch"],b?e.nextUrl:null,e.buildId),v.lazyData.then(async n=>{let[r,s]=n;if("string"==typeof r)return(0,a.handleExternalUrl)(e,h,r,e.pushRef.pendingPush);for(let n of(v.lazyData=null,r)){if(3!==n.length)return console.log("REFRESH FAILED"),e;let[r]=n,i=(0,u.applyRouterStatePatchToTree)([""],_,r,e.canonicalUrl);if(null===i)return(0,f.handleSegmentMismatch)(e,t,r);if((0,l.isNavigatingToNewRootLayout)(_,i))return(0,a.handleExternalUrl)(e,h,y,e.pushRef.pendingPush);let d=s?(0,o.createHrefFromUrl)(s):void 0;s&&(h.canonicalUrl=d);let[g,m]=n.slice(-2);if(null!==g){let e=g[2];v.rsc=e,v.prefetchRsc=null,(0,c.fillLazyItemsTillLeafWithHead)(v,void 0,r,g,m),h.prefetchCache=new Map}await (0,p.refreshInactiveParallelSegments)({state:e,updatedTree:i,updatedCache:v,includeNextUrl:b,canonicalUrl:h.canonicalUrl||e.canonicalUrl}),h.cache=v,h.patchedTree=i,h.canonicalUrl=y,_=i}return(0,i.handleMutable)(e,h)},()=>e)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},77784:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"restoreReducer",{enumerable:!0,get:function(){return u}});let r=n(33456),o=n(5410);function u(e,t){var n;let{url:u,tree:l}=t,a=(0,r.createHrefFromUrl)(u),i=l||e.tree,c=e.cache;return{buildId:e.buildId,canonicalUrl:a,pushRef:{pendingPush:!1,mpaNavigation:!1,preserveCustomHistoryState:!0},focusAndScrollRef:e.focusAndScrollRef,cache:c,prefetchCache:e.prefetchCache,tree:i,nextUrl:null!=(n=(0,o.extractPathFromFlightRouterState)(i))?n:u.pathname}}n(56118),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},13722:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"serverActionReducer",{enumerable:!0,get:function(){return g}});let r=n(83079),o=n(6866),u=n(1634),l=n(33456),a=n(95967),i=n(81935),c=n(63237),s=n(44510),f=n(27420),d=n(12846),p=n(28077),h=n(77831),y=n(50232),{createFromFetch:_,encodeReply:v}=n(6671);async function b(e,t,n){let l,{actionId:a,actionArgs:i}=n,c=await v(i),s=await fetch("",{method:"POST",headers:{Accept:o.RSC_CONTENT_TYPE_HEADER,[o.ACTION]:a,[o.NEXT_ROUTER_STATE_TREE]:encodeURIComponent(JSON.stringify(e.tree)),...t?{[o.NEXT_URL]:t}:{}},body:c}),f=s.headers.get("x-action-redirect");try{let e=JSON.parse(s.headers.get("x-action-revalidated")||"[[],0,0]");l={paths:e[0]||[],tag:!!e[1],cookie:e[2]}}catch(e){l={paths:[],tag:!1,cookie:!1}}let d=f?new URL((0,u.addBasePath)(f),new URL(e.canonicalUrl,window.location.href)):void 0;if(s.headers.get("content-type")===o.RSC_CONTENT_TYPE_HEADER){let e=await _(Promise.resolve(s),{callServer:r.callServer});if(f){let[,t]=null!=e?e:[];return{actionFlightData:t,redirectLocation:d,revalidatedParts:l}}let[t,[,n]]=null!=e?e:[];return{actionResult:t,actionFlightData:n,redirectLocation:d,revalidatedParts:l}}return{redirectLocation:d,revalidatedParts:l}}function g(e,t){let{resolve:n,reject:r}=t,o={},u=e.canonicalUrl,_=e.tree;o.preserveCustomHistoryState=!1;let v=e.nextUrl&&(0,p.hasInterceptionRouteInCurrentTree)(e.tree)?e.nextUrl:null;return o.inFlightServerAction=b(e,v,t),o.inFlightServerAction.then(async r=>{let{actionResult:p,actionFlightData:b,redirectLocation:g}=r;if(g&&(e.pushRef.pendingPush=!0,o.pendingPush=!0),!b)return(n(p),g)?(0,a.handleExternalUrl)(e,o,g.href,e.pushRef.pendingPush):e;if("string"==typeof b)return(0,a.handleExternalUrl)(e,o,b,e.pushRef.pendingPush);if(o.inFlightServerAction=null,g){let e=(0,l.createHrefFromUrl)(g,!1);o.canonicalUrl=e}for(let n of b){if(3!==n.length)return console.log("SERVER ACTION APPLY FAILED"),e;let[r]=n,s=(0,i.applyRouterStatePatchToTree)([""],_,r,g?(0,l.createHrefFromUrl)(g):e.canonicalUrl);if(null===s)return(0,h.handleSegmentMismatch)(e,t,r);if((0,c.isNavigatingToNewRootLayout)(_,s))return(0,a.handleExternalUrl)(e,o,u,e.pushRef.pendingPush);let[p,b]=n.slice(-2),m=null!==p?p[2]:null;if(null!==m){let t=(0,d.createEmptyCacheNode)();t.rsc=m,t.prefetchRsc=null,(0,f.fillLazyItemsTillLeafWithHead)(t,void 0,r,p,b),await (0,y.refreshInactiveParallelSegments)({state:e,updatedTree:s,updatedCache:t,includeNextUrl:!!v,canonicalUrl:o.canonicalUrl||e.canonicalUrl}),o.cache=t,o.prefetchCache=new Map}o.patchedTree=s,_=s}return n(p),(0,s.handleMutable)(e,o)},t=>(r(t),e))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},68448:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"serverPatchReducer",{enumerable:!0,get:function(){return f}});let r=n(33456),o=n(81935),u=n(63237),l=n(95967),a=n(22356),i=n(44510),c=n(12846),s=n(77831);function f(e,t){let{serverResponse:n}=t,[f,d]=n,p={};if(p.preserveCustomHistoryState=!1,"string"==typeof f)return(0,l.handleExternalUrl)(e,p,f,e.pushRef.pendingPush);let h=e.tree,y=e.cache;for(let n of f){let i=n.slice(0,-4),[f]=n.slice(-3,-2),_=(0,o.applyRouterStatePatchToTree)(["",...i],h,f,e.canonicalUrl);if(null===_)return(0,s.handleSegmentMismatch)(e,t,f);if((0,u.isNavigatingToNewRootLayout)(h,_))return(0,l.handleExternalUrl)(e,p,e.canonicalUrl,e.pushRef.pendingPush);let v=d?(0,r.createHrefFromUrl)(d):void 0;v&&(p.canonicalUrl=v);let b=(0,c.createEmptyCacheNode)();(0,a.applyFlightData)(y,b,n),p.patchedTree=_,p.cache=b,y=b,h=_}return(0,i.handleMutable)(e,p)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},50232:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{addRefreshMarkerToActiveParallelSegments:function(){return function e(t,n){let[r,o,,l]=t;for(let a in r.includes(u.PAGE_SEGMENT_KEY)&&"refresh"!==l&&(t[2]=n,t[3]="refresh"),o)e(o[a],n)}},refreshInactiveParallelSegments:function(){return l}});let r=n(22356),o=n(44848),u=n(84541);async function l(e){let t=new Set;await a({...e,rootTree:e.updatedTree,fetchedSegments:t})}async function a(e){let{state:t,updatedTree:n,updatedCache:u,includeNextUrl:l,fetchedSegments:i,rootTree:c=n,canonicalUrl:s}=e,[,f,d,p]=n,h=[];if(d&&d!==s&&"refresh"===p&&!i.has(d)){i.add(d);let e=(0,o.fetchServerResponse)(new URL(d,location.origin),[c[0],c[1],c[2],"refetch"],l?t.nextUrl:null,t.buildId).then(e=>{let t=e[0];if("string"!=typeof t)for(let e of t)(0,r.applyFlightData)(u,u,e)});h.push(e)}for(let e in f){let n=a({state:t,updatedTree:f[e],updatedCache:u,includeNextUrl:l,fetchedSegments:i,rootTree:c,canonicalUrl:s});h.push(n)}await Promise.all(h)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},24673:function(e,t){"use strict";var n,r,o,u;Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ACTION_FAST_REFRESH:function(){return f},ACTION_NAVIGATE:function(){return a},ACTION_PREFETCH:function(){return s},ACTION_REFRESH:function(){return l},ACTION_RESTORE:function(){return i},ACTION_SERVER_ACTION:function(){return d},ACTION_SERVER_PATCH:function(){return c},PrefetchCacheEntryStatus:function(){return r},PrefetchKind:function(){return n},isThenable:function(){return p}});let l="refresh",a="navigate",i="restore",c="server-patch",s="prefetch",f="fast-refresh",d="server-action";function p(e){return e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}(o=n||(n={})).AUTO="auto",o.FULL="full",o.TEMPORARY="temporary",(u=r||(r={})).fresh="fresh",u.reusable="reusable",u.expired="expired",u.stale="stale",("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},91450:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"reducer",{enumerable:!0,get:function(){return f}});let r=n(24673),o=n(95967),u=n(68448),l=n(77784),a=n(99601),i=n(24819),c=n(44529),s=n(13722),f="undefined"==typeof window?function(e,t){return e}:function(e,t){switch(t.type){case r.ACTION_NAVIGATE:return(0,o.navigateReducer)(e,t);case r.ACTION_SERVER_PATCH:return(0,u.serverPatchReducer)(e,t);case r.ACTION_RESTORE:return(0,l.restoreReducer)(e,t);case r.ACTION_REFRESH:return(0,a.refreshReducer)(e,t);case r.ACTION_FAST_REFRESH:return(0,c.fastRefreshReducer)(e,t);case r.ACTION_PREFETCH:return(0,i.prefetchReducer)(e,t);case r.ACTION_SERVER_ACTION:return(0,s.serverActionReducer)(e,t);default:throw Error("Unknown action")}};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},53728:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"shouldHardNavigate",{enumerable:!0,get:function(){return function e(t,n){let[o,u]=n,[l,a]=t;return(0,r.matchSegment)(l,o)?!(t.length<=2)&&e(t.slice(2),u[a]):!!Array.isArray(l)}}});let r=n(76015);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},54535:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{createDynamicallyTrackedSearchParams:function(){return a},createUntrackedSearchParams:function(){return l}});let r=n(51845),o=n(86999),u=n(30650);function l(e){let t=r.staticGenerationAsyncStorage.getStore();return t&&t.forceStatic?{}:e}function a(e){let t=r.staticGenerationAsyncStorage.getStore();return t?t.forceStatic?{}:t.isStaticGeneration||t.dynamicShouldError?new Proxy({},{get:(e,n,r)=>("string"==typeof n&&(0,o.trackDynamicDataAccessed)(t,"searchParams."+n),u.ReflectAdapter.get(e,n,r)),has:(e,n)=>("string"==typeof n&&(0,o.trackDynamicDataAccessed)(t,"searchParams."+n),Reflect.has(e,n)),ownKeys:e=>((0,o.trackDynamicDataAccessed)(t,"searchParams"),Reflect.ownKeys(e))}):e:e}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},51845:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"staticGenerationAsyncStorage",{enumerable:!0,get:function(){return r.staticGenerationAsyncStorage}});let r=n(20030);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},36864:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{StaticGenBailoutError:function(){return r},isStaticGenBailoutError:function(){return o}});let n="NEXT_STATIC_GEN_BAILOUT";class r extends Error{constructor(...e){super(...e),this.code=n}}function o(e){return"object"==typeof e&&null!==e&&"code"in e&&e.code===n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},38137:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"unresolvedThenable",{enumerable:!0,get:function(){return n}});let n={then:()=>{}};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},47744:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{useReducerWithReduxDevtools:function(){return i},useUnwrapState:function(){return a}});let r=n(53099)._(n(2265)),o=n(24673),u=n(2103);function l(e){if(e instanceof Map){let t={};for(let[n,r]of e.entries()){if("function"==typeof r){t[n]="fn()";continue}if("object"==typeof r&&null!==r){if(r.$$typeof){t[n]=r.$$typeof.toString();continue}if(r._bundlerConfig){t[n]="FlightData";continue}}t[n]=l(r)}return t}if("object"==typeof e&&null!==e){let t={};for(let n in e){let r=e[n];if("function"==typeof r){t[n]="fn()";continue}if("object"==typeof r&&null!==r){if(r.$$typeof){t[n]=r.$$typeof.toString();continue}if(r.hasOwnProperty("_bundlerConfig")){t[n]="FlightData";continue}}t[n]=l(r)}return t}return Array.isArray(e)?e.map(l):e}function a(e){return(0,o.isThenable)(e)?(0,r.use)(e):e}let i="undefined"!=typeof window?function(e){let[t,n]=r.default.useState(e),o=(0,r.useContext)(u.ActionQueueContext);if(!o)throw Error("Invariant: Missing ActionQueueContext");let a=(0,r.useRef)(),i=(0,r.useRef)();return(0,r.useEffect)(()=>{if(!a.current&&!1!==i.current){if(void 0===i.current&&void 0===window.__REDUX_DEVTOOLS_EXTENSION__){i.current=!1;return}return a.current=window.__REDUX_DEVTOOLS_EXTENSION__.connect({instanceId:8e3,name:"next-router"}),a.current&&(a.current.init(l(e)),o&&(o.devToolsInstance=a.current)),()=>{a.current=void 0}}},[e,o]),[t,(0,r.useCallback)(t=>{o.state||(o.state=e),o.dispatch(t,n)},[o,e]),(0,r.useCallback)(e=>{a.current&&a.current.send({type:"RENDER_SYNC"},l(e))},[])]}:function(e){return[e,()=>{},()=>{}]};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},11283:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"hasBasePath",{enumerable:!0,get:function(){return o}});let r=n(10580);function o(e){return(0,r.pathHasPrefix)(e,"")}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},33068:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"normalizePathTrailingSlash",{enumerable:!0,get:function(){return u}});let r=n(26674),o=n(63381),u=e=>{if(!e.startsWith("/"))return e;let{pathname:t,query:n,hash:u}=(0,o.parsePath)(e);return""+(0,r.removeTrailingSlash)(t)+n+u};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},61404:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return o}});let r=n(18993);function o(e){let t="function"==typeof reportError?reportError:e=>{window.console.error(e)};(0,r.isBailoutToCSRError)(e)||t(e)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},35076:function(e,t,n){"use strict";function r(e){return e}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"removeBasePath",{enumerable:!0,get:function(){return r}}),n(11283),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},12010:function(e,t){"use strict";function n(e,t){var n=e.length;for(e.push(t);0>>1,o=e[r];if(0>>1;ru(i,n))cu(s,i)?(e[r]=s,e[c]=n,r=c):(e[r]=i,e[a]=n,r=a);else if(cu(s,n))e[r]=s,e[c]=n,r=c;else break}}return t}function u(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}if(t.unstable_now=void 0,"object"==typeof performance&&"function"==typeof performance.now){var l,a=performance;t.unstable_now=function(){return a.now()}}else{var i=Date,c=i.now();t.unstable_now=function(){return i.now()-c}}var s=[],f=[],d=1,p=null,h=3,y=!1,_=!1,v=!1,b="function"==typeof setTimeout?setTimeout:null,g="function"==typeof clearTimeout?clearTimeout:null,m="undefined"!=typeof setImmediate?setImmediate:null;function R(e){for(var t=r(f);null!==t;){if(null===t.callback)o(f);else if(t.startTime<=e)o(f),t.sortIndex=t.expirationTime,n(s,t);else break;t=r(f)}}function P(e){if(v=!1,R(e),!_){if(null!==r(s))_=!0,C();else{var t=r(f);null!==t&&A(P,t.startTime-e)}}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var j=!1,O=-1,S=5,E=-1;function w(){return!(t.unstable_now()-Ee&&w());){var a=p.callback;if("function"==typeof a){p.callback=null,h=p.priorityLevel;var i=a(p.expirationTime<=e);if(e=t.unstable_now(),"function"==typeof i){p.callback=i,R(e),n=!0;break t}p===r(s)&&o(s),R(e)}else o(s);p=r(s)}if(null!==p)n=!0;else{var c=r(f);null!==c&&A(P,c.startTime-e),n=!1}}break e}finally{p=null,h=u,y=!1}n=void 0}}finally{n?l():j=!1}}}if("function"==typeof m)l=function(){m(T)};else if("undefined"!=typeof MessageChannel){var M=new MessageChannel,x=M.port2;M.port1.onmessage=T,l=function(){x.postMessage(null)}}else l=function(){b(T,0)};function C(){j||(j=!0,l())}function A(e,n){O=b(function(){e(t.unstable_now())},n)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){_||y||(_=!0,C())},t.unstable_forceFrameRate=function(e){0>e||125l?(e.sortIndex=u,n(f,e),null===r(s)&&e===r(f)&&(v?(g(O),O=-1):v=!0,A(P,u-l))):(e.sortIndex=a,n(s,e),_||y||(_=!0,C())),e},t.unstable_shouldYield=w,t.unstable_wrapCallback=function(e){var t=h;return function(){var n=h;h=t;try{return e.apply(this,arguments)}finally{h=n}}}},71767:function(e,t,n){"use strict";e.exports=n(12010)},60934:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{getPathname:function(){return r},isFullStringUrl:function(){return o},parseUrl:function(){return u}});let n="http://n";function r(e){return new URL(e,n).pathname}function o(e){return/https?:\/\//.test(e)}function u(e){let t;try{t=new URL(e,n)}catch{}return t}},86999:function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{Postpone:function(){return d},createPostponedAbortSignal:function(){return b},createPrerenderState:function(){return c},formatDynamicAPIAccesses:function(){return _},markCurrentScopeAsDynamic:function(){return s},trackDynamicDataAccessed:function(){return f},trackDynamicFetch:function(){return p},usedDynamicAPIs:function(){return y}});let o=(r=n(2265))&&r.__esModule?r:{default:r},u=n(46177),l=n(36864),a=n(60934),i="function"==typeof o.default.unstable_postpone;function c(e){return{isDebugSkeleton:e,dynamicAccesses:[]}}function s(e,t){let n=(0,a.getPathname)(e.urlPathname);if(!e.isUnstableCacheCallback){if(e.dynamicShouldError)throw new l.StaticGenBailoutError(`Route ${n} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${t}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`);if(e.prerenderState)h(e.prerenderState,t,n);else if(e.revalidate=0,e.isStaticGeneration){let r=new u.DynamicServerError(`Route ${n} couldn't be rendered statically because it used ${t}. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`);throw e.dynamicUsageDescription=t,e.dynamicUsageStack=r.stack,r}}}function f(e,t){let n=(0,a.getPathname)(e.urlPathname);if(e.isUnstableCacheCallback)throw Error(`Route ${n} used "${t}" inside a function cached with "unstable_cache(...)". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use "${t}" outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`);if(e.dynamicShouldError)throw new l.StaticGenBailoutError(`Route ${n} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${t}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`);if(e.prerenderState)h(e.prerenderState,t,n);else if(e.revalidate=0,e.isStaticGeneration){let r=new u.DynamicServerError(`Route ${n} couldn't be rendered statically because it used \`${t}\`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`);throw e.dynamicUsageDescription=t,e.dynamicUsageStack=r.stack,r}}function d({reason:e,prerenderState:t,pathname:n}){h(t,e,n)}function p(e,t){e.prerenderState&&h(e.prerenderState,t,e.urlPathname)}function h(e,t,n){v();let r=`Route ${n} needs to bail out of prerendering at this point because it used ${t}. React throws this special object to indicate where. It should not be caught by your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error`;e.dynamicAccesses.push({stack:e.isDebugSkeleton?Error().stack:void 0,expression:t}),o.default.unstable_postpone(r)}function y(e){return e.dynamicAccesses.length>0}function _(e){return e.dynamicAccesses.filter(e=>"string"==typeof e.stack&&e.stack.length>0).map(({expression:e,stack:t})=>(t=t.split("\n").slice(4).filter(e=>!(e.includes("node_modules/next/")||e.includes(" ()")||e.includes(" (node:"))).join("\n"),`Dynamic API Usage Debug - ${e}: +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[117],{65157:function(e,t){"use strict";function n(){return""}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"getDeploymentIdQueryOrEmptyString",{enumerable:!0,get:function(){return n}})},91572:function(){"trimStart"in String.prototype||(String.prototype.trimStart=String.prototype.trimLeft),"trimEnd"in String.prototype||(String.prototype.trimEnd=String.prototype.trimRight),"description"in Symbol.prototype||Object.defineProperty(Symbol.prototype,"description",{configurable:!0,get:function(){var e=/\((.*)\)/.exec(this.toString());return e?e[1]:void 0}}),Array.prototype.flat||(Array.prototype.flat=function(e,t){return t=this.concat.apply([],this),e>1&&t.some(Array.isArray)?t.flat(e-1):t},Array.prototype.flatMap=function(e,t){return this.map(e,t).flat()}),Promise.prototype.finally||(Promise.prototype.finally=function(e){if("function"!=typeof e)return this.then(e,e);var t=this.constructor||Promise;return this.then(function(n){return t.resolve(e()).then(function(){return n})},function(n){return t.resolve(e()).then(function(){throw n})})}),Object.fromEntries||(Object.fromEntries=function(e){return Array.from(e).reduce(function(e,t){return e[t[0]]=t[1],e},{})}),Array.prototype.at||(Array.prototype.at=function(e){var t=Math.trunc(e)||0;if(t<0&&(t+=this.length),!(t<0||t>=this.length))return this[t]}),Object.hasOwn||(Object.hasOwn=function(e,t){if(null==e)throw TypeError("Cannot convert undefined or null to object");return Object.prototype.hasOwnProperty.call(Object(e),t)}),"canParse"in URL||(URL.canParse=function(e,t){try{return new URL(e,t),!0}catch(e){return!1}})},1634:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"addBasePath",{enumerable:!0,get:function(){return u}});let r=n(68498),o=n(33068);function u(e,t){return(0,o.normalizePathTrailingSlash)((0,r.addPathPrefix)(e,""))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},75266:function(e,t){"use strict";function n(e){var t,n;t=self.__next_s,n=()=>{e()},t&&t.length?t.reduce((e,t)=>{let[n,r]=t;return e.then(()=>new Promise((e,t)=>{let o=document.createElement("script");if(r)for(let e in r)"children"!==e&&o.setAttribute(e,r[e]);n?(o.src=n,o.onload=()=>e(),o.onerror=t):r&&(o.innerHTML=r.children,setTimeout(e)),document.head.appendChild(o)}))},Promise.resolve()).catch(e=>{console.error(e)}).then(()=>{n()}):n()}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"appBootstrap",{enumerable:!0,get:function(){return n}}),window.next={version:"14.2.32",appDir:!0},("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},83079:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"callServer",{enumerable:!0,get:function(){return o}});let r=n(12846);async function o(e,t){let n=(0,r.getServerActionDispatcher)();if(!n)throw Error("Invariant: missing action dispatcher.");return new Promise((r,o)=>{n({actionId:e,actionArgs:t,resolve:r,reject:o})})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},92304:function(e,t,n){"use strict";let r,o;Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"hydrate",{enumerable:!0,get:function(){return x}});let u=n(47043),l=n(53099),a=n(57437);n(91572);let i=u._(n(34040)),c=l._(n(2265)),s=n(6671),f=n(48701),d=u._(n(61404)),p=n(83079),h=n(89721),y=n(2103);n(70647);let _=window.console.error;window.console.error=function(){for(var e=arguments.length,t=Array(e),n=0;n{if((0,h.isNextRouterError)(e.error)){e.preventDefault();return}});let v=document,b=new TextEncoder,g=!1,m=!1,R=null;function P(e){if(0===e[0])r=[];else if(1===e[0]){if(!r)throw Error("Unexpected server data: missing bootstrap script.");o?o.enqueue(b.encode(e[1])):r.push(e[1])}else 2===e[0]&&(R=e[1])}let j=function(){o&&!m&&(o.close(),m=!0,r=void 0),g=!0};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",j,!1):j();let O=self.__next_f=self.__next_f||[];O.forEach(P),O.push=P;let S=new ReadableStream({start(e){r&&(r.forEach(t=>{e.enqueue(b.encode(t))}),g&&!m&&(e.close(),m=!0,r=void 0)),o=e}}),E=(0,s.createFromReadableStream)(S,{callServer:p.callServer});function w(){return(0,c.use)(E)}let T=c.default.StrictMode;function M(e){let{children:t}=e;return t}function x(){let e=(0,y.createMutableActionQueue)(),t=(0,a.jsx)(T,{children:(0,a.jsx)(f.HeadManagerContext.Provider,{value:{appDir:!0},children:(0,a.jsx)(y.ActionQueueContext.Provider,{value:e,children:(0,a.jsx)(M,{children:(0,a.jsx)(w,{})})})})}),n=window.__next_root_layout_missing_tags,r=!!(null==n?void 0:n.length),o={onRecoverableError:d.default};"__next_error__"===document.documentElement.id||r?i.default.createRoot(v,o).render(t):c.default.startTransition(()=>i.default.hydrateRoot(v,t,{...o,formState:R}))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},54278:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(19506),(0,n(75266).appBootstrap)(()=>{let{hydrate:e}=n(92304);n(12846),n(4707),e()}),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},19506:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(65157);{let e=n.u;n.u=function(){for(var t=arguments.length,n=Array(t),r=0;r(l(function(){var e;let t=document.getElementsByName(u)[0];if(null==t?void 0:null==(e=t.shadowRoot)?void 0:e.childNodes[0])return t.shadowRoot.childNodes[0];{let e=document.createElement(u);e.style.cssText="position:absolute";let t=document.createElement("div");return t.ariaLive="assertive",t.id="__next-route-announcer__",t.role="alert",t.style.cssText="position:absolute;border:0;height:1px;margin:-1px;padding:0;width:1px;clip:rect(0 0 0 0);overflow:hidden;white-space:nowrap;word-wrap:normal",e.attachShadow({mode:"open"}).appendChild(t),document.body.appendChild(e),t}}()),()=>{let e=document.getElementsByTagName(u)[0];(null==e?void 0:e.isConnected)&&document.body.removeChild(e)}),[]);let[a,i]=(0,r.useState)(""),c=(0,r.useRef)();return(0,r.useEffect)(()=>{let e="";if(document.title)e=document.title;else{let t=document.querySelector("h1");t&&(e=t.innerText||t.textContent||"")}void 0!==c.current&&c.current!==e&&i(e),c.current=e},[t]),n?(0,o.createPortal)(a,n):null}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},6866:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ACTION:function(){return r},FLIGHT_PARAMETERS:function(){return i},NEXT_DID_POSTPONE_HEADER:function(){return s},NEXT_ROUTER_PREFETCH_HEADER:function(){return u},NEXT_ROUTER_STATE_TREE:function(){return o},NEXT_RSC_UNION_QUERY:function(){return c},NEXT_URL:function(){return l},RSC_CONTENT_TYPE_HEADER:function(){return a},RSC_HEADER:function(){return n}});let n="RSC",r="Next-Action",o="Next-Router-State-Tree",u="Next-Router-Prefetch",l="Next-Url",a="text/x-component",i=[[n],[o],[u]],c="_rsc",s="x-nextjs-postponed";("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},12846:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{createEmptyCacheNode:function(){return C},default:function(){return I},getServerActionDispatcher:function(){return E},urlToUrlWithoutFlightMarker:function(){return T}});let r=n(53099),o=n(57437),u=r._(n(2265)),l=n(61956),a=n(24673),i=n(33456),c=n(79060),s=n(47744),f=n(61060),d=n(82952),p=n(86146),h=n(1634),y=n(6495),_=n(4123),v=n(39320),b=n(38137),g=n(6866),m=n(35076),R=n(11283),P=n(84541),j="undefined"==typeof window,O=j?null:new Map,S=null;function E(){return S}let w={};function T(e){let t=new URL(e,location.origin);if(t.searchParams.delete(g.NEXT_RSC_UNION_QUERY),t.pathname.endsWith(".txt")){let{pathname:e}=t,n=e.endsWith("/index.txt")?10:4;t.pathname=e.slice(0,-n)}return t}function M(e){return e.origin!==window.location.origin}function x(e){let{appRouterState:t,sync:n}=e;return(0,u.useInsertionEffect)(()=>{let{tree:e,pushRef:r,canonicalUrl:o}=t,u={...r.preserveCustomHistoryState?window.history.state:{},__NA:!0,__PRIVATE_NEXTJS_INTERNALS_TREE:e};r.pendingPush&&(0,i.createHrefFromUrl)(new URL(window.location.href))!==o?(r.pendingPush=!1,window.history.pushState(u,"",o)):window.history.replaceState(u,"",o),n(t)},[t,n]),null}function C(){return{lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null}}function A(e){null==e&&(e={});let t=window.history.state,n=null==t?void 0:t.__NA;n&&(e.__NA=n);let r=null==t?void 0:t.__PRIVATE_NEXTJS_INTERNALS_TREE;return r&&(e.__PRIVATE_NEXTJS_INTERNALS_TREE=r),e}function N(e){let{headCacheNode:t}=e,n=null!==t?t.head:null,r=null!==t?t.prefetchHead:null,o=null!==r?r:n;return(0,u.useDeferredValue)(n,o)}function D(e){let t,{buildId:n,initialHead:r,initialTree:i,urlParts:f,initialSeedData:g,couldBeIntercepted:E,assetPrefix:T,missingSlots:C}=e,D=(0,u.useMemo)(()=>(0,d.createInitialRouterState)({buildId:n,initialSeedData:g,urlParts:f,initialTree:i,initialParallelRoutes:O,location:j?null:window.location,initialHead:r,couldBeIntercepted:E}),[n,g,f,i,r,E]),[I,U,k]=(0,s.useReducerWithReduxDevtools)(D);(0,u.useEffect)(()=>{O=null},[]);let{canonicalUrl:F}=(0,s.useUnwrapState)(I),{searchParams:L,pathname:H}=(0,u.useMemo)(()=>{let e=new URL(F,"undefined"==typeof window?"http://n":window.location.href);return{searchParams:e.searchParams,pathname:(0,R.hasBasePath)(e.pathname)?(0,m.removeBasePath)(e.pathname):e.pathname}},[F]),$=(0,u.useCallback)(e=>{let{previousTree:t,serverResponse:n}=e;(0,u.startTransition)(()=>{U({type:a.ACTION_SERVER_PATCH,previousTree:t,serverResponse:n})})},[U]),G=(0,u.useCallback)((e,t,n)=>{let r=new URL((0,h.addBasePath)(e),location.href);return U({type:a.ACTION_NAVIGATE,url:r,isExternalUrl:M(r),locationSearch:location.search,shouldScroll:null==n||n,navigateType:t})},[U]);S=(0,u.useCallback)(e=>{(0,u.startTransition)(()=>{U({...e,type:a.ACTION_SERVER_ACTION})})},[U]);let z=(0,u.useMemo)(()=>({back:()=>window.history.back(),forward:()=>window.history.forward(),prefetch:(e,t)=>{let n;if(!(0,p.isBot)(window.navigator.userAgent)){try{n=new URL((0,h.addBasePath)(e),window.location.href)}catch(t){throw Error("Cannot prefetch '"+e+"' because it cannot be converted to a URL.")}M(n)||(0,u.startTransition)(()=>{var e;U({type:a.ACTION_PREFETCH,url:n,kind:null!=(e=null==t?void 0:t.kind)?e:a.PrefetchKind.FULL})})}},replace:(e,t)=>{void 0===t&&(t={}),(0,u.startTransition)(()=>{var n;G(e,"replace",null==(n=t.scroll)||n)})},push:(e,t)=>{void 0===t&&(t={}),(0,u.startTransition)(()=>{var n;G(e,"push",null==(n=t.scroll)||n)})},refresh:()=>{(0,u.startTransition)(()=>{U({type:a.ACTION_REFRESH,origin:window.location.origin})})},fastRefresh:()=>{throw Error("fastRefresh can only be used in development mode. Please use refresh instead.")}}),[U,G]);(0,u.useEffect)(()=>{window.next&&(window.next.router=z)},[z]),(0,u.useEffect)(()=>{function e(e){var t;e.persisted&&(null==(t=window.history.state)?void 0:t.__PRIVATE_NEXTJS_INTERNALS_TREE)&&(w.pendingMpaPath=void 0,U({type:a.ACTION_RESTORE,url:new URL(window.location.href),tree:window.history.state.__PRIVATE_NEXTJS_INTERNALS_TREE}))}return window.addEventListener("pageshow",e),()=>{window.removeEventListener("pageshow",e)}},[U]);let{pushRef:B}=(0,s.useUnwrapState)(I);if(B.mpaNavigation){if(w.pendingMpaPath!==F){let e=window.location;B.pendingPush?e.assign(F):e.replace(F),w.pendingMpaPath=F}(0,u.use)(b.unresolvedThenable)}(0,u.useEffect)(()=>{let e=window.history.pushState.bind(window.history),t=window.history.replaceState.bind(window.history),n=e=>{var t;let n=window.location.href,r=null==(t=window.history.state)?void 0:t.__PRIVATE_NEXTJS_INTERNALS_TREE;(0,u.startTransition)(()=>{U({type:a.ACTION_RESTORE,url:new URL(null!=e?e:n,n),tree:r})})};window.history.pushState=function(t,r,o){return(null==t?void 0:t.__NA)||(null==t?void 0:t._N)||(t=A(t),o&&n(o)),e(t,r,o)},window.history.replaceState=function(e,r,o){return(null==e?void 0:e.__NA)||(null==e?void 0:e._N)||(e=A(e),o&&n(o)),t(e,r,o)};let r=e=>{let{state:t}=e;if(t){if(!t.__NA){window.location.reload();return}(0,u.startTransition)(()=>{U({type:a.ACTION_RESTORE,url:new URL(window.location.href),tree:t.__PRIVATE_NEXTJS_INTERNALS_TREE})})}};return window.addEventListener("popstate",r),()=>{window.history.pushState=e,window.history.replaceState=t,window.removeEventListener("popstate",r)}},[U]);let{cache:W,tree:K,nextUrl:V,focusAndScrollRef:Y}=(0,s.useUnwrapState)(I),X=(0,u.useMemo)(()=>(0,v.findHeadInCache)(W,K[1]),[W,K]),q=(0,u.useMemo)(()=>(function e(t,n){for(let r of(void 0===n&&(n={}),Object.values(t[1]))){let t=r[0],o=Array.isArray(t),u=o?t[1]:t;!u||u.startsWith(P.PAGE_SEGMENT_KEY)||(o&&("c"===t[2]||"oc"===t[2])?n[t[0]]=t[1].split("/"):o&&(n[t[0]]=t[1]),n=e(r,n))}return n})(K),[K]);if(null!==X){let[e,n]=X;t=(0,o.jsx)(N,{headCacheNode:e},n)}else t=null;let J=(0,o.jsxs)(_.RedirectBoundary,{children:[t,W.rsc,(0,o.jsx)(y.AppRouterAnnouncer,{tree:K})]});return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(x,{appRouterState:(0,s.useUnwrapState)(I),sync:k}),(0,o.jsx)(c.PathParamsContext.Provider,{value:q,children:(0,o.jsx)(c.PathnameContext.Provider,{value:H,children:(0,o.jsx)(c.SearchParamsContext.Provider,{value:L,children:(0,o.jsx)(l.GlobalLayoutRouterContext.Provider,{value:{buildId:n,changeByServerResponse:$,tree:K,focusAndScrollRef:Y,nextUrl:V},children:(0,o.jsx)(l.AppRouterContext.Provider,{value:z,children:(0,o.jsx)(l.LayoutRouterContext.Provider,{value:{childNodes:W.parallelRoutes,tree:K,url:F,loading:W.loading},children:J})})})})})})]})}function I(e){let{globalErrorComponent:t,...n}=e;return(0,o.jsx)(f.ErrorBoundary,{errorComponent:t,children:(0,o.jsx)(D,{...n})})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},96149:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"bailoutToClientRendering",{enumerable:!0,get:function(){return u}});let r=n(18993),o=n(51845);function u(e){let t=o.staticGenerationAsyncStorage.getStore();if((null==t||!t.forceStatic)&&(null==t?void 0:t.isStaticGeneration))throw new r.BailoutToCSRError(e)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},19107:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"ClientPageRoot",{enumerable:!0,get:function(){return u}});let r=n(57437),o=n(54535);function u(e){let{Component:t,props:n}=e;return n.searchParams=(0,o.createDynamicallyTrackedSearchParams)(n.searchParams||{}),(0,r.jsx)(t,{...n})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},61060:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ErrorBoundary:function(){return h},ErrorBoundaryHandler:function(){return f},GlobalError:function(){return d},default:function(){return p}});let r=n(47043),o=n(57437),u=r._(n(2265)),l=n(35475),a=n(89721),i=n(51845),c={error:{fontFamily:'system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"',height:"100vh",textAlign:"center",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},text:{fontSize:"14px",fontWeight:400,lineHeight:"28px",margin:"0 8px"}};function s(e){let{error:t}=e,n=i.staticGenerationAsyncStorage.getStore();if((null==n?void 0:n.isRevalidate)||(null==n?void 0:n.isStaticGeneration))throw console.error(t),t;return null}class f extends u.default.Component{static getDerivedStateFromError(e){if((0,a.isNextRouterError)(e))throw e;return{error:e}}static getDerivedStateFromProps(e,t){return e.pathname!==t.previousPathname&&t.error?{error:null,previousPathname:e.pathname}:{error:t.error,previousPathname:e.pathname}}render(){return this.state.error?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(s,{error:this.state.error}),this.props.errorStyles,this.props.errorScripts,(0,o.jsx)(this.props.errorComponent,{error:this.state.error,reset:this.reset})]}):this.props.children}constructor(e){super(e),this.reset=()=>{this.setState({error:null})},this.state={error:null,previousPathname:this.props.pathname}}}function d(e){let{error:t}=e,n=null==t?void 0:t.digest;return(0,o.jsxs)("html",{id:"__next_error__",children:[(0,o.jsx)("head",{}),(0,o.jsxs)("body",{children:[(0,o.jsx)(s,{error:t}),(0,o.jsx)("div",{style:c.error,children:(0,o.jsxs)("div",{children:[(0,o.jsx)("h2",{style:c.text,children:"Application error: a "+(n?"server":"client")+"-side exception has occurred (see the "+(n?"server logs":"browser console")+" for more information)."}),n?(0,o.jsx)("p",{style:c.text,children:"Digest: "+n}):null]})})]})]})}let p=d;function h(e){let{errorComponent:t,errorStyles:n,errorScripts:r,children:u}=e,a=(0,l.usePathname)();return t?(0,o.jsx)(f,{pathname:a,errorComponent:t,errorStyles:n,errorScripts:r,children:u}):(0,o.jsx)(o.Fragment,{children:u})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},46177:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{DynamicServerError:function(){return r},isDynamicServerError:function(){return o}});let n="DYNAMIC_SERVER_USAGE";class r extends Error{constructor(e){super("Dynamic server usage: "+e),this.description=e,this.digest=n}}function o(e){return"object"==typeof e&&null!==e&&"digest"in e&&"string"==typeof e.digest&&e.digest===n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},89721:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"isNextRouterError",{enumerable:!0,get:function(){return u}});let r=n(98200),o=n(88968);function u(e){return e&&e.digest&&((0,o.isRedirectError)(e)||(0,r.isNotFoundError)(e))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},4707:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return S}});let r=n(47043),o=n(53099),u=n(57437),l=o._(n(2265)),a=r._(n(54887)),i=n(61956),c=n(44848),s=n(38137),f=n(61060),d=n(76015),p=n(7092),h=n(4123),y=n(80),_=n(73171),v=n(78505),b=n(28077),g=["bottom","height","left","right","top","width","x","y"];function m(e,t){let n=e.getBoundingClientRect();return n.top>=0&&n.top<=t}class R extends l.default.Component{componentDidMount(){this.handlePotentialScroll()}componentDidUpdate(){this.props.focusAndScrollRef.apply&&this.handlePotentialScroll()}render(){return this.props.children}constructor(...e){super(...e),this.handlePotentialScroll=()=>{let{focusAndScrollRef:e,segmentPath:t}=this.props;if(e.apply){var n;if(0!==e.segmentPaths.length&&!e.segmentPaths.some(e=>t.every((t,n)=>(0,d.matchSegment)(t,e[n]))))return;let r=null,o=e.hashFragment;if(o&&(r="top"===o?document.body:null!=(n=document.getElementById(o))?n:document.getElementsByName(o)[0]),r||(r="undefined"==typeof window?null:a.default.findDOMNode(this)),!(r instanceof Element))return;for(;!(r instanceof HTMLElement)||function(e){if(["sticky","fixed"].includes(getComputedStyle(e).position))return!0;let t=e.getBoundingClientRect();return g.every(e=>0===t[e])}(r);){if(null===r.nextElementSibling)return;r=r.nextElementSibling}e.apply=!1,e.hashFragment=null,e.segmentPaths=[],(0,p.handleSmoothScroll)(()=>{if(o){r.scrollIntoView();return}let e=document.documentElement,t=e.clientHeight;!m(r,t)&&(e.scrollTop=0,m(r,t)||r.scrollIntoView())},{dontForceLayout:!0,onlyHashChange:e.onlyHashChange}),e.onlyHashChange=!1,r.focus()}}}}function P(e){let{segmentPath:t,children:n}=e,r=(0,l.useContext)(i.GlobalLayoutRouterContext);if(!r)throw Error("invariant global layout router not mounted");return(0,u.jsx)(R,{segmentPath:t,focusAndScrollRef:r.focusAndScrollRef,children:n})}function j(e){let{parallelRouterKey:t,url:n,childNodes:r,segmentPath:o,tree:a,cacheKey:f}=e,p=(0,l.useContext)(i.GlobalLayoutRouterContext);if(!p)throw Error("invariant global layout router not mounted");let{buildId:h,changeByServerResponse:y,tree:_}=p,v=r.get(f);if(void 0===v){let e={lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null};v=e,r.set(f,e)}let g=null!==v.prefetchRsc?v.prefetchRsc:v.rsc,m=(0,l.useDeferredValue)(v.rsc,g),R="object"==typeof m&&null!==m&&"function"==typeof m.then?(0,l.use)(m):m;if(!R){let e=v.lazyData;if(null===e){let t=function e(t,n){if(t){let[r,o]=t,u=2===t.length;if((0,d.matchSegment)(n[0],r)&&n[1].hasOwnProperty(o)){if(u){let t=e(void 0,n[1][o]);return[n[0],{...n[1],[o]:[t[0],t[1],t[2],"refetch"]}]}return[n[0],{...n[1],[o]:e(t.slice(2),n[1][o])}]}}return n}(["",...o],_),r=(0,b.hasInterceptionRouteInCurrentTree)(_);v.lazyData=e=(0,c.fetchServerResponse)(new URL(n,location.origin),t,r?p.nextUrl:null,h),v.lazyDataResolved=!1}let t=(0,l.use)(e);v.lazyDataResolved||(setTimeout(()=>{(0,l.startTransition)(()=>{y({previousTree:_,serverResponse:t})})}),v.lazyDataResolved=!0),(0,l.use)(s.unresolvedThenable)}return(0,u.jsx)(i.LayoutRouterContext.Provider,{value:{tree:a[1][t],childNodes:v.parallelRoutes,url:n,loading:v.loading},children:R})}function O(e){let{children:t,hasLoading:n,loading:r,loadingStyles:o,loadingScripts:a}=e;return n?(0,u.jsx)(l.Suspense,{fallback:(0,u.jsxs)(u.Fragment,{children:[o,a,r]}),children:t}):(0,u.jsx)(u.Fragment,{children:t})}function S(e){let{parallelRouterKey:t,segmentPath:n,error:r,errorStyles:o,errorScripts:a,templateStyles:c,templateScripts:s,template:d,notFound:p,notFoundStyles:b}=e,g=(0,l.useContext)(i.LayoutRouterContext);if(!g)throw Error("invariant expected layout router to be mounted");let{childNodes:m,tree:R,url:S,loading:E}=g,w=m.get(t);w||(w=new Map,m.set(t,w));let T=R[1][t][0],M=(0,_.getSegmentValue)(T),x=[T];return(0,u.jsx)(u.Fragment,{children:x.map(e=>{let l=(0,_.getSegmentValue)(e),g=(0,v.createRouterCacheKey)(e);return(0,u.jsxs)(i.TemplateContext.Provider,{value:(0,u.jsx)(P,{segmentPath:n,children:(0,u.jsx)(f.ErrorBoundary,{errorComponent:r,errorStyles:o,errorScripts:a,children:(0,u.jsx)(O,{hasLoading:!!E,loading:null==E?void 0:E[0],loadingStyles:null==E?void 0:E[1],loadingScripts:null==E?void 0:E[2],children:(0,u.jsx)(y.NotFoundBoundary,{notFound:p,notFoundStyles:b,children:(0,u.jsx)(h.RedirectBoundary,{children:(0,u.jsx)(j,{parallelRouterKey:t,url:S,tree:R,childNodes:w,segmentPath:n,cacheKey:g,isActive:M===l})})})})})}),children:[c,s,d]},(0,v.createRouterCacheKey)(e,!0))})})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},76015:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{canSegmentBeOverridden:function(){return u},matchSegment:function(){return o}});let r=n(87417),o=(e,t)=>"string"==typeof e?"string"==typeof t&&e===t:"string"!=typeof t&&e[0]===t[0]&&e[1]===t[1],u=(e,t)=>{var n;return!Array.isArray(e)&&!!Array.isArray(t)&&(null==(n=(0,r.getSegmentParam)(e))?void 0:n.param)===t[0]};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},35475:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ReadonlyURLSearchParams:function(){return i.ReadonlyURLSearchParams},RedirectType:function(){return i.RedirectType},ServerInsertedHTMLContext:function(){return c.ServerInsertedHTMLContext},notFound:function(){return i.notFound},permanentRedirect:function(){return i.permanentRedirect},redirect:function(){return i.redirect},useParams:function(){return p},usePathname:function(){return f},useRouter:function(){return d},useSearchParams:function(){return s},useSelectedLayoutSegment:function(){return y},useSelectedLayoutSegments:function(){return h},useServerInsertedHTML:function(){return c.useServerInsertedHTML}});let r=n(2265),o=n(61956),u=n(79060),l=n(73171),a=n(84541),i=n(52646),c=n(55501);function s(){let e=(0,r.useContext)(u.SearchParamsContext),t=(0,r.useMemo)(()=>e?new i.ReadonlyURLSearchParams(e):null,[e]);if("undefined"==typeof window){let{bailoutToClientRendering:e}=n(96149);e("useSearchParams()")}return t}function f(){return(0,r.useContext)(u.PathnameContext)}function d(){let e=(0,r.useContext)(o.AppRouterContext);if(null===e)throw Error("invariant expected app router to be mounted");return e}function p(){return(0,r.useContext)(u.PathParamsContext)}function h(e){void 0===e&&(e="children");let t=(0,r.useContext)(o.LayoutRouterContext);return t?function e(t,n,r,o){let u;if(void 0===r&&(r=!0),void 0===o&&(o=[]),r)u=t[1][n];else{var i;let e=t[1];u=null!=(i=e.children)?i:Object.values(e)[0]}if(!u)return o;let c=u[0],s=(0,l.getSegmentValue)(c);return!s||s.startsWith(a.PAGE_SEGMENT_KEY)?o:(o.push(s),e(u,n,!1,o))}(t.tree,e):null}function y(e){void 0===e&&(e="children");let t=h(e);if(!t||0===t.length)return null;let n="children"===e?t[0]:t[t.length-1];return n===a.DEFAULT_SEGMENT_KEY?null:n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},52646:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ReadonlyURLSearchParams:function(){return l},RedirectType:function(){return r.RedirectType},notFound:function(){return o.notFound},permanentRedirect:function(){return r.permanentRedirect},redirect:function(){return r.redirect}});let r=n(88968),o=n(98200);class u extends Error{constructor(){super("Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams")}}class l extends URLSearchParams{append(){throw new u}delete(){throw new u}set(){throw new u}sort(){throw new u}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},80:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"NotFoundBoundary",{enumerable:!0,get:function(){return s}});let r=n(53099),o=n(57437),u=r._(n(2265)),l=n(35475),a=n(98200);n(31765);let i=n(61956);class c extends u.default.Component{componentDidCatch(){}static getDerivedStateFromError(e){if((0,a.isNotFoundError)(e))return{notFoundTriggered:!0};throw e}static getDerivedStateFromProps(e,t){return e.pathname!==t.previousPathname&&t.notFoundTriggered?{notFoundTriggered:!1,previousPathname:e.pathname}:{notFoundTriggered:t.notFoundTriggered,previousPathname:e.pathname}}render(){return this.state.notFoundTriggered?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)("meta",{name:"robots",content:"noindex"}),!1,this.props.notFoundStyles,this.props.notFound]}):this.props.children}constructor(e){super(e),this.state={notFoundTriggered:!!e.asNotFound,previousPathname:e.pathname}}}function s(e){let{notFound:t,notFoundStyles:n,asNotFound:r,children:a}=e,s=(0,l.usePathname)(),f=(0,u.useContext)(i.MissingSlotContext);return t?(0,o.jsx)(c,{pathname:s,notFound:t,notFoundStyles:n,asNotFound:r,missingSlots:f,children:a}):(0,o.jsx)(o.Fragment,{children:a})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},98200:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{isNotFoundError:function(){return o},notFound:function(){return r}});let n="NEXT_NOT_FOUND";function r(){let e=Error(n);throw e.digest=n,e}function o(e){return"object"==typeof e&&null!==e&&"digest"in e&&e.digest===n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},29744:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"PromiseQueue",{enumerable:!0,get:function(){return c}});let r=n(2522),o=n(90675);var u=o._("_maxConcurrency"),l=o._("_runningCount"),a=o._("_queue"),i=o._("_processNext");class c{enqueue(e){let t,n;let o=new Promise((e,r)=>{t=e,n=r}),u=async()=>{try{r._(this,l)[l]++;let n=await e();t(n)}catch(e){n(e)}finally{r._(this,l)[l]--,r._(this,i)[i]()}};return r._(this,a)[a].push({promiseFn:o,task:u}),r._(this,i)[i](),o}bump(e){let t=r._(this,a)[a].findIndex(t=>t.promiseFn===e);if(t>-1){let e=r._(this,a)[a].splice(t,1)[0];r._(this,a)[a].unshift(e),r._(this,i)[i](!0)}}constructor(e=5){Object.defineProperty(this,i,{value:s}),Object.defineProperty(this,u,{writable:!0,value:void 0}),Object.defineProperty(this,l,{writable:!0,value:void 0}),Object.defineProperty(this,a,{writable:!0,value:void 0}),r._(this,u)[u]=e,r._(this,l)[l]=0,r._(this,a)[a]=[]}}function s(e){if(void 0===e&&(e=!1),(r._(this,l)[l]0){var t;null==(t=r._(this,a)[a].shift())||t.task()}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},4123:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{RedirectBoundary:function(){return s},RedirectErrorBoundary:function(){return c}});let r=n(53099),o=n(57437),u=r._(n(2265)),l=n(35475),a=n(88968);function i(e){let{redirect:t,reset:n,redirectType:r}=e,o=(0,l.useRouter)();return(0,u.useEffect)(()=>{u.default.startTransition(()=>{r===a.RedirectType.push?o.push(t,{}):o.replace(t,{}),n()})},[t,r,n,o]),null}class c extends u.default.Component{static getDerivedStateFromError(e){if((0,a.isRedirectError)(e))return{redirect:(0,a.getURLFromRedirectError)(e),redirectType:(0,a.getRedirectTypeFromError)(e)};throw e}render(){let{redirect:e,redirectType:t}=this.state;return null!==e&&null!==t?(0,o.jsx)(i,{redirect:e,redirectType:t,reset:()=>this.setState({redirect:null})}):this.props.children}constructor(e){super(e),this.state={redirect:null,redirectType:null}}}function s(e){let{children:t}=e,n=(0,l.useRouter)();return(0,o.jsx)(c,{router:n,children:t})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},5001:function(e,t){"use strict";var n,r;Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"RedirectStatusCode",{enumerable:!0,get:function(){return n}}),(r=n||(n={}))[r.SeeOther=303]="SeeOther",r[r.TemporaryRedirect=307]="TemporaryRedirect",r[r.PermanentRedirect=308]="PermanentRedirect",("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},88968:function(e,t,n){"use strict";var r,o;Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{RedirectType:function(){return r},getRedirectError:function(){return c},getRedirectStatusCodeFromError:function(){return y},getRedirectTypeFromError:function(){return h},getURLFromRedirectError:function(){return p},isRedirectError:function(){return d},permanentRedirect:function(){return f},redirect:function(){return s}});let u=n(20544),l=n(90295),a=n(5001),i="NEXT_REDIRECT";function c(e,t,n){void 0===n&&(n=a.RedirectStatusCode.TemporaryRedirect);let r=Error(i);r.digest=i+";"+t+";"+e+";"+n+";";let o=u.requestAsyncStorage.getStore();return o&&(r.mutableCookies=o.mutableCookies),r}function s(e,t){void 0===t&&(t="replace");let n=l.actionAsyncStorage.getStore();throw c(e,t,(null==n?void 0:n.isAction)?a.RedirectStatusCode.SeeOther:a.RedirectStatusCode.TemporaryRedirect)}function f(e,t){void 0===t&&(t="replace");let n=l.actionAsyncStorage.getStore();throw c(e,t,(null==n?void 0:n.isAction)?a.RedirectStatusCode.SeeOther:a.RedirectStatusCode.PermanentRedirect)}function d(e){if("object"!=typeof e||null===e||!("digest"in e)||"string"!=typeof e.digest)return!1;let[t,n,r,o]=e.digest.split(";",4),u=Number(o);return t===i&&("replace"===n||"push"===n)&&"string"==typeof r&&!isNaN(u)&&u in a.RedirectStatusCode}function p(e){return d(e)?e.digest.split(";",3)[2]:null}function h(e){if(!d(e))throw Error("Not a redirect error");return e.digest.split(";",2)[1]}function y(e){if(!d(e))throw Error("Not a redirect error");return Number(e.digest.split(";",4)[3])}(o=r||(r={})).push="push",o.replace="replace",("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},36423:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return a}});let r=n(53099),o=n(57437),u=r._(n(2265)),l=n(61956);function a(){let e=(0,u.useContext)(l.TemplateContext);return(0,o.jsx)(o.Fragment,{children:e})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},20544:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{getExpectedRequestStore:function(){return o},requestAsyncStorage:function(){return r.requestAsyncStorage}});let r=n(25575);function o(e){let t=r.requestAsyncStorage.getStore();if(t)return t;throw Error("`"+e+"` was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context")}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},22356:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"applyFlightData",{enumerable:!0,get:function(){return u}});let r=n(27420),o=n(92576);function u(e,t,n,u){let[l,a,i]=n.slice(-3);if(null===a)return!1;if(3===n.length){let n=a[2],o=a[3];t.loading=o,t.rsc=n,t.prefetchRsc=null,(0,r.fillLazyItemsTillLeafWithHead)(t,e,l,a,i,u)}else t.rsc=e.rsc,t.prefetchRsc=e.prefetchRsc,t.parallelRoutes=new Map(e.parallelRoutes),t.loading=e.loading,(0,o.fillCacheWithNewSubTreeData)(t,e,n,u);return!0}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},81935:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"applyRouterStatePatchToTree",{enumerable:!0,get:function(){return function e(t,n,r,a){let i;let[c,s,f,d,p]=n;if(1===t.length){let e=l(n,r,t);return(0,u.addRefreshMarkerToActiveParallelSegments)(e,a),e}let[h,y]=t;if(!(0,o.matchSegment)(h,c))return null;if(2===t.length)i=l(s[y],r,t);else if(null===(i=e(t.slice(2),s[y],r,a)))return null;let _=[t[0],{...s,[y]:i},f,d];return p&&(_[4]=!0),(0,u.addRefreshMarkerToActiveParallelSegments)(_,a),_}}});let r=n(84541),o=n(76015),u=n(50232);function l(e,t,n){let[u,a]=e,[i,c]=t;if(i===r.DEFAULT_SEGMENT_KEY&&u!==r.DEFAULT_SEGMENT_KEY)return e;if((0,o.matchSegment)(u,i)){let t={};for(let e in a)void 0!==c[e]?t[e]=l(a[e],c[e],n):t[e]=a[e];for(let e in c)t[e]||(t[e]=c[e]);let r=[u,t];return e[2]&&(r[2]=e[2]),e[3]&&(r[3]=e[3]),e[4]&&(r[4]=e[4]),r}return t}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},65556:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"clearCacheNodeDataForSegmentPath",{enumerable:!0,get:function(){return function e(t,n,o){let u=o.length<=2,[l,a]=o,i=(0,r.createRouterCacheKey)(a),c=n.parallelRoutes.get(l),s=t.parallelRoutes.get(l);s&&s!==c||(s=new Map(c),t.parallelRoutes.set(l,s));let f=null==c?void 0:c.get(i),d=s.get(i);if(u){d&&d.lazyData&&d!==f||s.set(i,{lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null});return}if(!d||!f){d||s.set(i,{lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null});return}return d===f&&(d={lazyData:d.lazyData,rsc:d.rsc,prefetchRsc:d.prefetchRsc,head:d.head,prefetchHead:d.prefetchHead,parallelRoutes:new Map(d.parallelRoutes),lazyDataResolved:d.lazyDataResolved,loading:d.loading},s.set(i,d)),e(d,f,o.slice(2))}}});let r=n(78505);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},5410:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{computeChangedPath:function(){return s},extractPathFromFlightRouterState:function(){return c}});let r=n(91182),o=n(84541),u=n(76015),l=e=>"/"===e[0]?e.slice(1):e,a=e=>"string"==typeof e?"children"===e?"":e:e[1];function i(e){return e.reduce((e,t)=>""===(t=l(t))||(0,o.isGroupSegment)(t)?e:e+"/"+t,"")||"/"}function c(e){var t;let n=Array.isArray(e[0])?e[0][1]:e[0];if(n===o.DEFAULT_SEGMENT_KEY||r.INTERCEPTION_ROUTE_MARKERS.some(e=>n.startsWith(e)))return;if(n.startsWith(o.PAGE_SEGMENT_KEY))return"";let u=[a(n)],l=null!=(t=e[1])?t:{},s=l.children?c(l.children):void 0;if(void 0!==s)u.push(s);else for(let[e,t]of Object.entries(l)){if("children"===e)continue;let n=c(t);void 0!==n&&u.push(n)}return i(u)}function s(e,t){let n=function e(t,n){let[o,l]=t,[i,s]=n,f=a(o),d=a(i);if(r.INTERCEPTION_ROUTE_MARKERS.some(e=>f.startsWith(e)||d.startsWith(e)))return"";if(!(0,u.matchSegment)(o,i)){var p;return null!=(p=c(n))?p:""}for(let t in l)if(s[t]){let n=e(l[t],s[t]);if(null!==n)return a(i)+"/"+n}return null}(e,t);return null==n||"/"===n?n:i(n.split("/"))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},33456:function(e,t){"use strict";function n(e,t){return void 0===t&&(t=!0),e.pathname+e.search+(t?e.hash:"")}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createHrefFromUrl",{enumerable:!0,get:function(){return n}}),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},82952:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createInitialRouterState",{enumerable:!0,get:function(){return c}});let r=n(33456),o=n(27420),u=n(5410),l=n(60305),a=n(24673),i=n(50232);function c(e){var t;let{buildId:n,initialTree:c,initialSeedData:s,urlParts:f,initialParallelRoutes:d,location:p,initialHead:h,couldBeIntercepted:y}=e,_=f.join("/"),v=!p,b={lazyData:null,rsc:s[2],prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:v?new Map:d,lazyDataResolved:!1,loading:s[3]},g=p?(0,r.createHrefFromUrl)(p):_;(0,i.addRefreshMarkerToActiveParallelSegments)(c,g);let m=new Map;(null===d||0===d.size)&&(0,o.fillLazyItemsTillLeafWithHead)(b,void 0,c,s,h);let R={buildId:n,tree:c,cache:b,prefetchCache:m,pushRef:{pendingPush:!1,mpaNavigation:!1,preserveCustomHistoryState:!0},focusAndScrollRef:{apply:!1,onlyHashChange:!1,hashFragment:null,segmentPaths:[]},canonicalUrl:g,nextUrl:null!=(t=(0,u.extractPathFromFlightRouterState)(c)||(null==p?void 0:p.pathname))?t:null};if(p){let e=new URL(""+p.pathname+p.search,p.origin),t=[["",c,null,null]];(0,l.createPrefetchCacheEntryForInitialLoad)({url:e,kind:a.PrefetchKind.AUTO,data:[t,void 0,!1,y],tree:R.tree,prefetchCache:R.prefetchCache,nextUrl:R.nextUrl})}return R}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},78505:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createRouterCacheKey",{enumerable:!0,get:function(){return o}});let r=n(84541);function o(e,t){return(void 0===t&&(t=!1),Array.isArray(e))?e[0]+"|"+e[1]+"|"+e[2]:t&&e.startsWith(r.PAGE_SEGMENT_KEY)?r.PAGE_SEGMENT_KEY:e}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},44848:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"fetchServerResponse",{enumerable:!0,get:function(){return s}});let r=n(6866),o=n(12846),u=n(83079),l=n(24673),a=n(37207),{createFromFetch:i}=n(6671);function c(e){return[(0,o.urlToUrlWithoutFlightMarker)(e).toString(),void 0,!1,!1]}async function s(e,t,n,s,f){let d={[r.RSC_HEADER]:"1",[r.NEXT_ROUTER_STATE_TREE]:encodeURIComponent(JSON.stringify(t))};f===l.PrefetchKind.AUTO&&(d[r.NEXT_ROUTER_PREFETCH_HEADER]="1"),n&&(d[r.NEXT_URL]=n);let p=(0,a.hexHash)([d[r.NEXT_ROUTER_PREFETCH_HEADER]||"0",d[r.NEXT_ROUTER_STATE_TREE],d[r.NEXT_URL]].join(","));try{var h;let t=new URL(e);t.pathname.endsWith("/")?t.pathname+="index.txt":t.pathname+=".txt",t.searchParams.set(r.NEXT_RSC_UNION_QUERY,p);let n=await fetch(t,{credentials:"same-origin",headers:d}),l=(0,o.urlToUrlWithoutFlightMarker)(n.url),a=n.redirected?l:void 0,f=n.headers.get("content-type")||"",y=!!n.headers.get(r.NEXT_DID_POSTPONE_HEADER),_=!!(null==(h=n.headers.get("vary"))?void 0:h.includes(r.NEXT_URL)),v=f===r.RSC_CONTENT_TYPE_HEADER;if(v||(v=f.startsWith("text/plain")),!v||!n.ok)return e.hash&&(l.hash=e.hash),c(l.toString());let[b,g]=await i(Promise.resolve(n),{callServer:u.callServer});if(s!==b)return c(n.url);return[g,a,y,_]}catch(t){return console.error("Failed to fetch RSC payload for "+e+". Falling back to browser navigation.",t),[e.toString(),void 0,!1,!1]}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},92576:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"fillCacheWithNewSubTreeData",{enumerable:!0,get:function(){return function e(t,n,l,a){let i=l.length<=5,[c,s]=l,f=(0,u.createRouterCacheKey)(s),d=n.parallelRoutes.get(c);if(!d)return;let p=t.parallelRoutes.get(c);p&&p!==d||(p=new Map(d),t.parallelRoutes.set(c,p));let h=d.get(f),y=p.get(f);if(i){if(!y||!y.lazyData||y===h){let e=l[3];y={lazyData:null,rsc:e[2],prefetchRsc:null,head:null,prefetchHead:null,loading:e[3],parallelRoutes:h?new Map(h.parallelRoutes):new Map,lazyDataResolved:!1},h&&(0,r.invalidateCacheByRouterState)(y,h,l[2]),(0,o.fillLazyItemsTillLeafWithHead)(y,h,l[2],e,l[4],a),p.set(f,y)}return}y&&h&&(y===h&&(y={lazyData:y.lazyData,rsc:y.rsc,prefetchRsc:y.prefetchRsc,head:y.head,prefetchHead:y.prefetchHead,parallelRoutes:new Map(y.parallelRoutes),lazyDataResolved:!1,loading:y.loading},p.set(f,y)),e(y,h,l.slice(2),a))}}});let r=n(94377),o=n(27420),u=n(78505);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},27420:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"fillLazyItemsTillLeafWithHead",{enumerable:!0,get:function(){return function e(t,n,u,l,a,i){if(0===Object.keys(u[1]).length){t.head=a;return}for(let c in u[1]){let s;let f=u[1][c],d=f[0],p=(0,r.createRouterCacheKey)(d),h=null!==l&&void 0!==l[1][c]?l[1][c]:null;if(n){let r=n.parallelRoutes.get(c);if(r){let n;let u=(null==i?void 0:i.kind)==="auto"&&i.status===o.PrefetchCacheEntryStatus.reusable,l=new Map(r),s=l.get(p);n=null!==h?{lazyData:null,rsc:h[2],prefetchRsc:null,head:null,prefetchHead:null,loading:h[3],parallelRoutes:new Map(null==s?void 0:s.parallelRoutes),lazyDataResolved:!1}:u&&s?{lazyData:s.lazyData,rsc:s.rsc,prefetchRsc:s.prefetchRsc,head:s.head,prefetchHead:s.prefetchHead,parallelRoutes:new Map(s.parallelRoutes),lazyDataResolved:s.lazyDataResolved,loading:s.loading}:{lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map(null==s?void 0:s.parallelRoutes),lazyDataResolved:!1,loading:null},l.set(p,n),e(n,s,f,h||null,a,i),t.parallelRoutes.set(c,l);continue}}if(null!==h){let e=h[2],t=h[3];s={lazyData:null,rsc:e,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:t}}else s={lazyData:null,rsc:null,prefetchRsc:null,head:null,prefetchHead:null,parallelRoutes:new Map,lazyDataResolved:!1,loading:null};let y=t.parallelRoutes.get(c);y?y.set(p,s):t.parallelRoutes.set(c,new Map([[p,s]])),e(s,void 0,f,h,a,i)}}}});let r=n(78505),o=n(24673);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},44510:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"handleMutable",{enumerable:!0,get:function(){return u}});let r=n(5410);function o(e){return void 0!==e}function u(e,t){var n,u,l;let a=null==(u=t.shouldScroll)||u,i=e.nextUrl;if(o(t.patchedTree)){let n=(0,r.computeChangedPath)(e.tree,t.patchedTree);n?i=n:i||(i=e.canonicalUrl)}return{buildId:e.buildId,canonicalUrl:o(t.canonicalUrl)?t.canonicalUrl===e.canonicalUrl?e.canonicalUrl:t.canonicalUrl:e.canonicalUrl,pushRef:{pendingPush:o(t.pendingPush)?t.pendingPush:e.pushRef.pendingPush,mpaNavigation:o(t.mpaNavigation)?t.mpaNavigation:e.pushRef.mpaNavigation,preserveCustomHistoryState:o(t.preserveCustomHistoryState)?t.preserveCustomHistoryState:e.pushRef.preserveCustomHistoryState},focusAndScrollRef:{apply:!!a&&(!!o(null==t?void 0:t.scrollableSegments)||e.focusAndScrollRef.apply),onlyHashChange:!!t.hashFragment&&e.canonicalUrl.split("#",1)[0]===(null==(n=t.canonicalUrl)?void 0:n.split("#",1)[0]),hashFragment:a?t.hashFragment&&""!==t.hashFragment?decodeURIComponent(t.hashFragment.slice(1)):e.focusAndScrollRef.hashFragment:null,segmentPaths:a?null!=(l=null==t?void 0:t.scrollableSegments)?l:e.focusAndScrollRef.segmentPaths:[]},cache:t.cache?t.cache:e.cache,prefetchCache:t.prefetchCache?t.prefetchCache:e.prefetchCache,tree:o(t.patchedTree)?t.patchedTree:e.tree,nextUrl:i}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},77831:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"handleSegmentMismatch",{enumerable:!0,get:function(){return o}});let r=n(95967);function o(e,t,n){return(0,r.handleExternalUrl)(e,{},e.canonicalUrl,!0)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},77058:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"invalidateCacheBelowFlightSegmentPath",{enumerable:!0,get:function(){return function e(t,n,o){let u=o.length<=2,[l,a]=o,i=(0,r.createRouterCacheKey)(a),c=n.parallelRoutes.get(l);if(!c)return;let s=t.parallelRoutes.get(l);if(s&&s!==c||(s=new Map(c),t.parallelRoutes.set(l,s)),u){s.delete(i);return}let f=c.get(i),d=s.get(i);d&&f&&(d===f&&(d={lazyData:d.lazyData,rsc:d.rsc,prefetchRsc:d.prefetchRsc,head:d.head,prefetchHead:d.prefetchHead,parallelRoutes:new Map(d.parallelRoutes),lazyDataResolved:d.lazyDataResolved},s.set(i,d)),e(d,f,o.slice(2)))}}});let r=n(78505);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},94377:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"invalidateCacheByRouterState",{enumerable:!0,get:function(){return o}});let r=n(78505);function o(e,t,n){for(let o in n[1]){let u=n[1][o][0],l=(0,r.createRouterCacheKey)(u),a=t.parallelRoutes.get(o);if(a){let t=new Map(a);t.delete(l),e.parallelRoutes.set(o,t)}}}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},63237:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"isNavigatingToNewRootLayout",{enumerable:!0,get:function(){return function e(t,n){let r=t[0],o=n[0];if(Array.isArray(r)&&Array.isArray(o)){if(r[0]!==o[0]||r[2]!==o[2])return!0}else if(r!==o)return!0;if(t[4])return!n[4];if(n[4])return!0;let u=Object.values(t[1])[0],l=Object.values(n[1])[0];return!u||!l||e(u,l)}}}),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},56118:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{abortTask:function(){return c},listenForDynamicRequest:function(){return a},updateCacheNodeOnNavigation:function(){return function e(t,n,a,c,s){let f=n[1],d=a[1],p=c[1],h=t.parallelRoutes,y=new Map(h),_={},v=null;for(let t in d){let n;let a=d[t],c=f[t],b=h.get(t),g=p[t],m=a[0],R=(0,u.createRouterCacheKey)(m),P=void 0!==c?c[0]:void 0,j=void 0!==b?b.get(R):void 0;if(null!==(n=m===r.PAGE_SEGMENT_KEY?l(a,void 0!==g?g:null,s):m===r.DEFAULT_SEGMENT_KEY?void 0!==c?{route:c,node:null,children:null}:l(a,void 0!==g?g:null,s):void 0!==P&&(0,o.matchSegment)(m,P)&&void 0!==j&&void 0!==c?null!=g?e(j,c,a,g,s):function(e){let t=i(e,null,null);return{route:e,node:t,children:null}}(a):l(a,void 0!==g?g:null,s))){null===v&&(v=new Map),v.set(t,n);let e=n.node;if(null!==e){let n=new Map(b);n.set(R,e),y.set(t,n)}_[t]=n.route}else _[t]=a}if(null===v)return null;let b={lazyData:null,rsc:t.rsc,prefetchRsc:t.prefetchRsc,head:t.head,prefetchHead:t.prefetchHead,loading:t.loading,parallelRoutes:y,lazyDataResolved:!1};return{route:function(e,t){let n=[e[0],t];return 2 in e&&(n[2]=e[2]),3 in e&&(n[3]=e[3]),4 in e&&(n[4]=e[4]),n}(a,_),node:b,children:v}}},updateCacheNodeOnPopstateRestoration:function(){return function e(t,n){let r=n[1],o=t.parallelRoutes,l=new Map(o);for(let t in r){let n=r[t],a=n[0],i=(0,u.createRouterCacheKey)(a),c=o.get(t);if(void 0!==c){let r=c.get(i);if(void 0!==r){let o=e(r,n),u=new Map(c);u.set(i,o),l.set(t,u)}}}let a=t.rsc,i=d(a)&&"pending"===a.status;return{lazyData:null,rsc:a,head:t.head,prefetchHead:i?t.prefetchHead:null,prefetchRsc:i?t.prefetchRsc:null,loading:i?t.loading:null,parallelRoutes:l,lazyDataResolved:!1}}}});let r=n(84541),o=n(76015),u=n(78505);function l(e,t,n){let r=i(e,t,n);return{route:e,node:r,children:null}}function a(e,t){t.then(t=>{for(let n of t[0]){let t=n.slice(0,-3),r=n[n.length-3],l=n[n.length-2],a=n[n.length-1];"string"!=typeof t&&function(e,t,n,r,l){let a=e;for(let e=0;e{c(e,t)})}function i(e,t,n){let r=e[1],o=null!==t?t[1]:null,l=new Map;for(let e in r){let t=r[e],a=null!==o?o[e]:null,c=t[0],s=(0,u.createRouterCacheKey)(c),f=i(t,void 0===a?null:a,n),d=new Map;d.set(s,f),l.set(e,d)}let a=0===l.size,c=null!==t?t[2]:null,s=null!==t?t[3]:null;return{lazyData:null,parallelRoutes:l,prefetchRsc:void 0!==c?c:null,prefetchHead:a?n:null,loading:void 0!==s?s:null,rsc:p(),head:a?p():null,lazyDataResolved:!1}}function c(e,t){let n=e.node;if(null===n)return;let r=e.children;if(null===r)s(e.route,n,t);else for(let e of r.values())c(e,t);e.node=null}function s(e,t,n){let r=e[1],o=t.parallelRoutes;for(let e in r){let t=r[e],l=o.get(e);if(void 0===l)continue;let a=t[0],i=(0,u.createRouterCacheKey)(a),c=l.get(i);void 0!==c&&s(t,c,n)}let l=t.rsc;d(l)&&(null===n?l.resolve(null):l.reject(n));let a=t.head;d(a)&&a.resolve(null)}let f=Symbol();function d(e){return e&&e.tag===f}function p(){let e,t;let n=new Promise((n,r)=>{e=n,t=r});return n.status="pending",n.resolve=t=>{"pending"===n.status&&(n.status="fulfilled",n.value=t,e(t))},n.reject=e=>{"pending"===n.status&&(n.status="rejected",n.reason=e,t(e))},n.tag=f,n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},60305:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{createPrefetchCacheEntryForInitialLoad:function(){return c},getOrCreatePrefetchCacheEntry:function(){return i},prunePrefetchCache:function(){return f}});let r=n(33456),o=n(44848),u=n(24673),l=n(24819);function a(e,t){let n=(0,r.createHrefFromUrl)(e,!1);return t?t+"%"+n:n}function i(e){let t,{url:n,nextUrl:r,tree:o,buildId:l,prefetchCache:i,kind:c}=e,f=a(n,r),d=i.get(f);if(d)t=d;else{let e=a(n),r=i.get(e);r&&(t=r)}return t?(t.status=h(t),t.kind!==u.PrefetchKind.FULL&&c===u.PrefetchKind.FULL)?s({tree:o,url:n,buildId:l,nextUrl:r,prefetchCache:i,kind:null!=c?c:u.PrefetchKind.TEMPORARY}):(c&&t.kind===u.PrefetchKind.TEMPORARY&&(t.kind=c),t):s({tree:o,url:n,buildId:l,nextUrl:r,prefetchCache:i,kind:c||u.PrefetchKind.TEMPORARY})}function c(e){let{nextUrl:t,tree:n,prefetchCache:r,url:o,kind:l,data:i}=e,[,,,c]=i,s=c?a(o,t):a(o),f={treeAtTimeOfPrefetch:n,data:Promise.resolve(i),kind:l,prefetchTime:Date.now(),lastUsedTime:Date.now(),key:s,status:u.PrefetchCacheEntryStatus.fresh};return r.set(s,f),f}function s(e){let{url:t,kind:n,tree:r,nextUrl:i,buildId:c,prefetchCache:s}=e,f=a(t),d=l.prefetchQueue.enqueue(()=>(0,o.fetchServerResponse)(t,r,i,c,n).then(e=>{let[,,,n]=e;return n&&function(e){let{url:t,nextUrl:n,prefetchCache:r}=e,o=a(t),u=r.get(o);if(!u)return;let l=a(t,n);r.set(l,u),r.delete(o)}({url:t,nextUrl:i,prefetchCache:s}),e})),p={treeAtTimeOfPrefetch:r,data:d,kind:n,prefetchTime:Date.now(),lastUsedTime:null,key:f,status:u.PrefetchCacheEntryStatus.fresh};return s.set(f,p),p}function f(e){for(let[t,n]of e)h(n)===u.PrefetchCacheEntryStatus.expired&&e.delete(t)}let d=1e3*Number("30"),p=1e3*Number("300");function h(e){let{kind:t,prefetchTime:n,lastUsedTime:r}=e;return Date.now()<(null!=r?r:n)+d?r?u.PrefetchCacheEntryStatus.reusable:u.PrefetchCacheEntryStatus.fresh:"auto"===t&&Date.now(){let[n,f]=t,h=!1;if(S.lastUsedTime||(S.lastUsedTime=Date.now(),h=!0),"string"==typeof n)return _(e,R,n,O);if(document.getElementById("__next-page-redirect"))return _(e,R,j,O);let b=e.tree,g=e.cache,w=[];for(let t of n){let n=t.slice(0,-4),r=t.slice(-3)[0],c=["",...n],f=(0,u.applyRouterStatePatchToTree)(c,b,r,j);if(null===f&&(f=(0,u.applyRouterStatePatchToTree)(c,E,r,j)),null!==f){if((0,a.isNavigatingToNewRootLayout)(b,f))return _(e,R,j,O);let u=(0,d.createEmptyCacheNode)(),m=!1;for(let e of(S.status!==i.PrefetchCacheEntryStatus.stale||h?m=(0,s.applyFlightData)(g,u,t,S):(m=function(e,t,n,r){let o=!1;for(let u of(e.rsc=t.rsc,e.prefetchRsc=t.prefetchRsc,e.loading=t.loading,e.parallelRoutes=new Map(t.parallelRoutes),v(r).map(e=>[...n,...e])))(0,y.clearCacheNodeDataForSegmentPath)(e,t,u),o=!0;return o}(u,g,n,r),S.lastUsedTime=Date.now()),(0,l.shouldHardNavigate)(c,b)?(u.rsc=g.rsc,u.prefetchRsc=g.prefetchRsc,(0,o.invalidateCacheBelowFlightSegmentPath)(u,g,n),R.cache=u):m&&(R.cache=u,g=u),b=f,v(r))){let t=[...n,...e];t[t.length-1]!==p.DEFAULT_SEGMENT_KEY&&w.push(t)}}}return R.patchedTree=b,R.canonicalUrl=f?(0,r.createHrefFromUrl)(f):j,R.pendingPush=O,R.scrollableSegments=w,R.hashFragment=P,R.shouldScroll=m,(0,c.handleMutable)(e,R)},()=>e)};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},24819:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{prefetchQueue:function(){return l},prefetchReducer:function(){return a}});let r=n(6866),o=n(29744),u=n(60305),l=new o.PromiseQueue(5);function a(e,t){(0,u.prunePrefetchCache)(e.prefetchCache);let{url:n}=t;return n.searchParams.delete(r.NEXT_RSC_UNION_QUERY),(0,u.getOrCreatePrefetchCacheEntry)({url:n,nextUrl:e.nextUrl,prefetchCache:e.prefetchCache,kind:t.kind,tree:e.tree,buildId:e.buildId}),e}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},99601:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"refreshReducer",{enumerable:!0,get:function(){return h}});let r=n(44848),o=n(33456),u=n(81935),l=n(63237),a=n(95967),i=n(44510),c=n(27420),s=n(12846),f=n(77831),d=n(28077),p=n(50232);function h(e,t){let{origin:n}=t,h={},y=e.canonicalUrl,_=e.tree;h.preserveCustomHistoryState=!1;let v=(0,s.createEmptyCacheNode)(),b=(0,d.hasInterceptionRouteInCurrentTree)(e.tree);return v.lazyData=(0,r.fetchServerResponse)(new URL(y,n),[_[0],_[1],_[2],"refetch"],b?e.nextUrl:null,e.buildId),v.lazyData.then(async n=>{let[r,s]=n;if("string"==typeof r)return(0,a.handleExternalUrl)(e,h,r,e.pushRef.pendingPush);for(let n of(v.lazyData=null,r)){if(3!==n.length)return console.log("REFRESH FAILED"),e;let[r]=n,i=(0,u.applyRouterStatePatchToTree)([""],_,r,e.canonicalUrl);if(null===i)return(0,f.handleSegmentMismatch)(e,t,r);if((0,l.isNavigatingToNewRootLayout)(_,i))return(0,a.handleExternalUrl)(e,h,y,e.pushRef.pendingPush);let d=s?(0,o.createHrefFromUrl)(s):void 0;s&&(h.canonicalUrl=d);let[g,m]=n.slice(-2);if(null!==g){let e=g[2];v.rsc=e,v.prefetchRsc=null,(0,c.fillLazyItemsTillLeafWithHead)(v,void 0,r,g,m),h.prefetchCache=new Map}await (0,p.refreshInactiveParallelSegments)({state:e,updatedTree:i,updatedCache:v,includeNextUrl:b,canonicalUrl:h.canonicalUrl||e.canonicalUrl}),h.cache=v,h.patchedTree=i,h.canonicalUrl=y,_=i}return(0,i.handleMutable)(e,h)},()=>e)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},77784:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"restoreReducer",{enumerable:!0,get:function(){return u}});let r=n(33456),o=n(5410);function u(e,t){var n;let{url:u,tree:l}=t,a=(0,r.createHrefFromUrl)(u),i=l||e.tree,c=e.cache;return{buildId:e.buildId,canonicalUrl:a,pushRef:{pendingPush:!1,mpaNavigation:!1,preserveCustomHistoryState:!0},focusAndScrollRef:e.focusAndScrollRef,cache:c,prefetchCache:e.prefetchCache,tree:i,nextUrl:null!=(n=(0,o.extractPathFromFlightRouterState)(i))?n:u.pathname}}n(56118),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},13722:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"serverActionReducer",{enumerable:!0,get:function(){return g}});let r=n(83079),o=n(6866),u=n(1634),l=n(33456),a=n(95967),i=n(81935),c=n(63237),s=n(44510),f=n(27420),d=n(12846),p=n(28077),h=n(77831),y=n(50232),{createFromFetch:_,encodeReply:v}=n(6671);async function b(e,t,n){let l,{actionId:a,actionArgs:i}=n,c=await v(i),s=await fetch("",{method:"POST",headers:{Accept:o.RSC_CONTENT_TYPE_HEADER,[o.ACTION]:a,[o.NEXT_ROUTER_STATE_TREE]:encodeURIComponent(JSON.stringify(e.tree)),...t?{[o.NEXT_URL]:t}:{}},body:c}),f=s.headers.get("x-action-redirect");try{let e=JSON.parse(s.headers.get("x-action-revalidated")||"[[],0,0]");l={paths:e[0]||[],tag:!!e[1],cookie:e[2]}}catch(e){l={paths:[],tag:!1,cookie:!1}}let d=f?new URL((0,u.addBasePath)(f),new URL(e.canonicalUrl,window.location.href)):void 0;if(s.headers.get("content-type")===o.RSC_CONTENT_TYPE_HEADER){let e=await _(Promise.resolve(s),{callServer:r.callServer});if(f){let[,t]=null!=e?e:[];return{actionFlightData:t,redirectLocation:d,revalidatedParts:l}}let[t,[,n]]=null!=e?e:[];return{actionResult:t,actionFlightData:n,redirectLocation:d,revalidatedParts:l}}return{redirectLocation:d,revalidatedParts:l}}function g(e,t){let{resolve:n,reject:r}=t,o={},u=e.canonicalUrl,_=e.tree;o.preserveCustomHistoryState=!1;let v=e.nextUrl&&(0,p.hasInterceptionRouteInCurrentTree)(e.tree)?e.nextUrl:null;return o.inFlightServerAction=b(e,v,t),o.inFlightServerAction.then(async r=>{let{actionResult:p,actionFlightData:b,redirectLocation:g}=r;if(g&&(e.pushRef.pendingPush=!0,o.pendingPush=!0),!b)return(n(p),g)?(0,a.handleExternalUrl)(e,o,g.href,e.pushRef.pendingPush):e;if("string"==typeof b)return(0,a.handleExternalUrl)(e,o,b,e.pushRef.pendingPush);if(o.inFlightServerAction=null,g){let e=(0,l.createHrefFromUrl)(g,!1);o.canonicalUrl=e}for(let n of b){if(3!==n.length)return console.log("SERVER ACTION APPLY FAILED"),e;let[r]=n,s=(0,i.applyRouterStatePatchToTree)([""],_,r,g?(0,l.createHrefFromUrl)(g):e.canonicalUrl);if(null===s)return(0,h.handleSegmentMismatch)(e,t,r);if((0,c.isNavigatingToNewRootLayout)(_,s))return(0,a.handleExternalUrl)(e,o,u,e.pushRef.pendingPush);let[p,b]=n.slice(-2),m=null!==p?p[2]:null;if(null!==m){let t=(0,d.createEmptyCacheNode)();t.rsc=m,t.prefetchRsc=null,(0,f.fillLazyItemsTillLeafWithHead)(t,void 0,r,p,b),await (0,y.refreshInactiveParallelSegments)({state:e,updatedTree:s,updatedCache:t,includeNextUrl:!!v,canonicalUrl:o.canonicalUrl||e.canonicalUrl}),o.cache=t,o.prefetchCache=new Map}o.patchedTree=s,_=s}return n(p),(0,s.handleMutable)(e,o)},t=>(r(t),e))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},68448:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"serverPatchReducer",{enumerable:!0,get:function(){return f}});let r=n(33456),o=n(81935),u=n(63237),l=n(95967),a=n(22356),i=n(44510),c=n(12846),s=n(77831);function f(e,t){let{serverResponse:n}=t,[f,d]=n,p={};if(p.preserveCustomHistoryState=!1,"string"==typeof f)return(0,l.handleExternalUrl)(e,p,f,e.pushRef.pendingPush);let h=e.tree,y=e.cache;for(let n of f){let i=n.slice(0,-4),[f]=n.slice(-3,-2),_=(0,o.applyRouterStatePatchToTree)(["",...i],h,f,e.canonicalUrl);if(null===_)return(0,s.handleSegmentMismatch)(e,t,f);if((0,u.isNavigatingToNewRootLayout)(h,_))return(0,l.handleExternalUrl)(e,p,e.canonicalUrl,e.pushRef.pendingPush);let v=d?(0,r.createHrefFromUrl)(d):void 0;v&&(p.canonicalUrl=v);let b=(0,c.createEmptyCacheNode)();(0,a.applyFlightData)(y,b,n),p.patchedTree=_,p.cache=b,y=b,h=_}return(0,i.handleMutable)(e,p)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},50232:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{addRefreshMarkerToActiveParallelSegments:function(){return function e(t,n){let[r,o,,l]=t;for(let a in r.includes(u.PAGE_SEGMENT_KEY)&&"refresh"!==l&&(t[2]=n,t[3]="refresh"),o)e(o[a],n)}},refreshInactiveParallelSegments:function(){return l}});let r=n(22356),o=n(44848),u=n(84541);async function l(e){let t=new Set;await a({...e,rootTree:e.updatedTree,fetchedSegments:t})}async function a(e){let{state:t,updatedTree:n,updatedCache:u,includeNextUrl:l,fetchedSegments:i,rootTree:c=n,canonicalUrl:s}=e,[,f,d,p]=n,h=[];if(d&&d!==s&&"refresh"===p&&!i.has(d)){i.add(d);let e=(0,o.fetchServerResponse)(new URL(d,location.origin),[c[0],c[1],c[2],"refetch"],l?t.nextUrl:null,t.buildId).then(e=>{let t=e[0];if("string"!=typeof t)for(let e of t)(0,r.applyFlightData)(u,u,e)});h.push(e)}for(let e in f){let n=a({state:t,updatedTree:f[e],updatedCache:u,includeNextUrl:l,fetchedSegments:i,rootTree:c,canonicalUrl:s});h.push(n)}await Promise.all(h)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},24673:function(e,t){"use strict";var n,r,o,u;Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ACTION_FAST_REFRESH:function(){return f},ACTION_NAVIGATE:function(){return a},ACTION_PREFETCH:function(){return s},ACTION_REFRESH:function(){return l},ACTION_RESTORE:function(){return i},ACTION_SERVER_ACTION:function(){return d},ACTION_SERVER_PATCH:function(){return c},PrefetchCacheEntryStatus:function(){return r},PrefetchKind:function(){return n},isThenable:function(){return p}});let l="refresh",a="navigate",i="restore",c="server-patch",s="prefetch",f="fast-refresh",d="server-action";function p(e){return e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}(o=n||(n={})).AUTO="auto",o.FULL="full",o.TEMPORARY="temporary",(u=r||(r={})).fresh="fresh",u.reusable="reusable",u.expired="expired",u.stale="stale",("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},91450:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"reducer",{enumerable:!0,get:function(){return f}});let r=n(24673),o=n(95967),u=n(68448),l=n(77784),a=n(99601),i=n(24819),c=n(44529),s=n(13722),f="undefined"==typeof window?function(e,t){return e}:function(e,t){switch(t.type){case r.ACTION_NAVIGATE:return(0,o.navigateReducer)(e,t);case r.ACTION_SERVER_PATCH:return(0,u.serverPatchReducer)(e,t);case r.ACTION_RESTORE:return(0,l.restoreReducer)(e,t);case r.ACTION_REFRESH:return(0,a.refreshReducer)(e,t);case r.ACTION_FAST_REFRESH:return(0,c.fastRefreshReducer)(e,t);case r.ACTION_PREFETCH:return(0,i.prefetchReducer)(e,t);case r.ACTION_SERVER_ACTION:return(0,s.serverActionReducer)(e,t);default:throw Error("Unknown action")}};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},53728:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"shouldHardNavigate",{enumerable:!0,get:function(){return function e(t,n){let[o,u]=n,[l,a]=t;return(0,r.matchSegment)(l,o)?!(t.length<=2)&&e(t.slice(2),u[a]):!!Array.isArray(l)}}});let r=n(76015);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},54535:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{createDynamicallyTrackedSearchParams:function(){return a},createUntrackedSearchParams:function(){return l}});let r=n(51845),o=n(86999),u=n(30650);function l(e){let t=r.staticGenerationAsyncStorage.getStore();return t&&t.forceStatic?{}:e}function a(e){let t=r.staticGenerationAsyncStorage.getStore();return t?t.forceStatic?{}:t.isStaticGeneration||t.dynamicShouldError?new Proxy({},{get:(e,n,r)=>("string"==typeof n&&(0,o.trackDynamicDataAccessed)(t,"searchParams."+n),u.ReflectAdapter.get(e,n,r)),has:(e,n)=>("string"==typeof n&&(0,o.trackDynamicDataAccessed)(t,"searchParams."+n),Reflect.has(e,n)),ownKeys:e=>((0,o.trackDynamicDataAccessed)(t,"searchParams"),Reflect.ownKeys(e))}):e:e}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},51845:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"staticGenerationAsyncStorage",{enumerable:!0,get:function(){return r.staticGenerationAsyncStorage}});let r=n(20030);("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},36864:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{StaticGenBailoutError:function(){return r},isStaticGenBailoutError:function(){return o}});let n="NEXT_STATIC_GEN_BAILOUT";class r extends Error{constructor(...e){super(...e),this.code=n}}function o(e){return"object"==typeof e&&null!==e&&"code"in e&&e.code===n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},38137:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"unresolvedThenable",{enumerable:!0,get:function(){return n}});let n={then:()=>{}};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},47744:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{useReducerWithReduxDevtools:function(){return i},useUnwrapState:function(){return a}});let r=n(53099)._(n(2265)),o=n(24673),u=n(2103);function l(e){if(e instanceof Map){let t={};for(let[n,r]of e.entries()){if("function"==typeof r){t[n]="fn()";continue}if("object"==typeof r&&null!==r){if(r.$$typeof){t[n]=r.$$typeof.toString();continue}if(r._bundlerConfig){t[n]="FlightData";continue}}t[n]=l(r)}return t}if("object"==typeof e&&null!==e){let t={};for(let n in e){let r=e[n];if("function"==typeof r){t[n]="fn()";continue}if("object"==typeof r&&null!==r){if(r.$$typeof){t[n]=r.$$typeof.toString();continue}if(r.hasOwnProperty("_bundlerConfig")){t[n]="FlightData";continue}}t[n]=l(r)}return t}return Array.isArray(e)?e.map(l):e}function a(e){return(0,o.isThenable)(e)?(0,r.use)(e):e}let i="undefined"!=typeof window?function(e){let[t,n]=r.default.useState(e),o=(0,r.useContext)(u.ActionQueueContext);if(!o)throw Error("Invariant: Missing ActionQueueContext");let a=(0,r.useRef)(),i=(0,r.useRef)();return(0,r.useEffect)(()=>{if(!a.current&&!1!==i.current){if(void 0===i.current&&void 0===window.__REDUX_DEVTOOLS_EXTENSION__){i.current=!1;return}return a.current=window.__REDUX_DEVTOOLS_EXTENSION__.connect({instanceId:8e3,name:"next-router"}),a.current&&(a.current.init(l(e)),o&&(o.devToolsInstance=a.current)),()=>{a.current=void 0}}},[e,o]),[t,(0,r.useCallback)(t=>{o.state||(o.state=e),o.dispatch(t,n)},[o,e]),(0,r.useCallback)(e=>{a.current&&a.current.send({type:"RENDER_SYNC"},l(e))},[])]}:function(e){return[e,()=>{},()=>{}]};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},11283:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"hasBasePath",{enumerable:!0,get:function(){return o}});let r=n(10580);function o(e){return(0,r.pathHasPrefix)(e,"")}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},33068:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"normalizePathTrailingSlash",{enumerable:!0,get:function(){return u}});let r=n(26674),o=n(63381),u=e=>{if(!e.startsWith("/"))return e;let{pathname:t,query:n,hash:u}=(0,o.parsePath)(e);return""+(0,r.removeTrailingSlash)(t)+n+u};("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},61404:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return o}});let r=n(18993);function o(e){let t="function"==typeof reportError?reportError:e=>{window.console.error(e)};(0,r.isBailoutToCSRError)(e)||t(e)}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},35076:function(e,t,n){"use strict";function r(e){return e}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"removeBasePath",{enumerable:!0,get:function(){return r}}),n(11283),("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},12010:function(e,t){"use strict";function n(e,t){var n=e.length;for(e.push(t);0>>1,o=e[r];if(0>>1;ru(i,n))cu(s,i)?(e[r]=s,e[c]=n,r=c):(e[r]=i,e[a]=n,r=a);else if(cu(s,n))e[r]=s,e[c]=n,r=c;else break}}return t}function u(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}if(t.unstable_now=void 0,"object"==typeof performance&&"function"==typeof performance.now){var l,a=performance;t.unstable_now=function(){return a.now()}}else{var i=Date,c=i.now();t.unstable_now=function(){return i.now()-c}}var s=[],f=[],d=1,p=null,h=3,y=!1,_=!1,v=!1,b="function"==typeof setTimeout?setTimeout:null,g="function"==typeof clearTimeout?clearTimeout:null,m="undefined"!=typeof setImmediate?setImmediate:null;function R(e){for(var t=r(f);null!==t;){if(null===t.callback)o(f);else if(t.startTime<=e)o(f),t.sortIndex=t.expirationTime,n(s,t);else break;t=r(f)}}function P(e){if(v=!1,R(e),!_){if(null!==r(s))_=!0,C();else{var t=r(f);null!==t&&A(P,t.startTime-e)}}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var j=!1,O=-1,S=5,E=-1;function w(){return!(t.unstable_now()-Ee&&w());){var a=p.callback;if("function"==typeof a){p.callback=null,h=p.priorityLevel;var i=a(p.expirationTime<=e);if(e=t.unstable_now(),"function"==typeof i){p.callback=i,R(e),n=!0;break t}p===r(s)&&o(s),R(e)}else o(s);p=r(s)}if(null!==p)n=!0;else{var c=r(f);null!==c&&A(P,c.startTime-e),n=!1}}break e}finally{p=null,h=u,y=!1}n=void 0}}finally{n?l():j=!1}}}if("function"==typeof m)l=function(){m(T)};else if("undefined"!=typeof MessageChannel){var M=new MessageChannel,x=M.port2;M.port1.onmessage=T,l=function(){x.postMessage(null)}}else l=function(){b(T,0)};function C(){j||(j=!0,l())}function A(e,n){O=b(function(){e(t.unstable_now())},n)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){_||y||(_=!0,C())},t.unstable_forceFrameRate=function(e){0>e||125l?(e.sortIndex=u,n(f,e),null===r(s)&&e===r(f)&&(v?(g(O),O=-1):v=!0,A(P,u-l))):(e.sortIndex=a,n(s,e),_||y||(_=!0,C())),e},t.unstable_shouldYield=w,t.unstable_wrapCallback=function(e){var t=h;return function(){var n=h;h=t;try{return e.apply(this,arguments)}finally{h=n}}}},71767:function(e,t,n){"use strict";e.exports=n(12010)},60934:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{getPathname:function(){return r},isFullStringUrl:function(){return o},parseUrl:function(){return u}});let n="http://n";function r(e){return new URL(e,n).pathname}function o(e){return/https?:\/\//.test(e)}function u(e){let t;try{t=new URL(e,n)}catch{}return t}},86999:function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{Postpone:function(){return d},createPostponedAbortSignal:function(){return b},createPrerenderState:function(){return c},formatDynamicAPIAccesses:function(){return _},markCurrentScopeAsDynamic:function(){return s},trackDynamicDataAccessed:function(){return f},trackDynamicFetch:function(){return p},usedDynamicAPIs:function(){return y}});let o=(r=n(2265))&&r.__esModule?r:{default:r},u=n(46177),l=n(36864),a=n(60934),i="function"==typeof o.default.unstable_postpone;function c(e){return{isDebugSkeleton:e,dynamicAccesses:[]}}function s(e,t){let n=(0,a.getPathname)(e.urlPathname);if(!e.isUnstableCacheCallback){if(e.dynamicShouldError)throw new l.StaticGenBailoutError(`Route ${n} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${t}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`);if(e.prerenderState)h(e.prerenderState,t,n);else if(e.revalidate=0,e.isStaticGeneration){let r=new u.DynamicServerError(`Route ${n} couldn't be rendered statically because it used ${t}. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`);throw e.dynamicUsageDescription=t,e.dynamicUsageStack=r.stack,r}}}function f(e,t){let n=(0,a.getPathname)(e.urlPathname);if(e.isUnstableCacheCallback)throw Error(`Route ${n} used "${t}" inside a function cached with "unstable_cache(...)". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use "${t}" outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`);if(e.dynamicShouldError)throw new l.StaticGenBailoutError(`Route ${n} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${t}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`);if(e.prerenderState)h(e.prerenderState,t,n);else if(e.revalidate=0,e.isStaticGeneration){let r=new u.DynamicServerError(`Route ${n} couldn't be rendered statically because it used \`${t}\`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`);throw e.dynamicUsageDescription=t,e.dynamicUsageStack=r.stack,r}}function d({reason:e,prerenderState:t,pathname:n}){h(t,e,n)}function p(e,t){e.prerenderState&&h(e.prerenderState,t,e.urlPathname)}function h(e,t,n){v();let r=`Route ${n} needs to bail out of prerendering at this point because it used ${t}. React throws this special object to indicate where. It should not be caught by your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error`;e.dynamicAccesses.push({stack:e.isDebugSkeleton?Error().stack:void 0,expression:t}),o.default.unstable_postpone(r)}function y(e){return e.dynamicAccesses.length>0}function _(e){return e.dynamicAccesses.filter(e=>"string"==typeof e.stack&&e.stack.length>0).map(({expression:e,stack:t})=>(t=t.split("\n").slice(4).filter(e=>!(e.includes("node_modules/next/")||e.includes(" ()")||e.includes(" (node:"))).join("\n"),`Dynamic API Usage Debug - ${e}: ${t}`))}function v(){if(!i)throw Error("Invariant: React.unstable_postpone is not defined. This suggests the wrong version of React was loaded. This is a bug in Next.js")}function b(e){v();let t=new AbortController;try{o.default.unstable_postpone(e)}catch(e){t.abort(e)}return t.signal}},87417:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"getSegmentParam",{enumerable:!0,get:function(){return o}});let r=n(91182);function o(e){let t=r.INTERCEPTION_ROUTE_MARKERS.find(t=>e.startsWith(t));return(t&&(e=e.slice(t.length)),e.startsWith("[[...")&&e.endsWith("]]"))?{type:"optional-catchall",param:e.slice(5,-2)}:e.startsWith("[...")&&e.endsWith("]")?{type:t?"catchall-intercepted":"catchall",param:e.slice(4,-1)}:e.startsWith("[")&&e.endsWith("]")?{type:t?"dynamic-intercepted":"dynamic",param:e.slice(1,-1)}:null}},70647:function(e,t){"use strict";var n,r;Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"HMR_ACTIONS_SENT_TO_BROWSER",{enumerable:!0,get:function(){return n}}),(r=n||(n={})).ADDED_PAGE="addedPage",r.REMOVED_PAGE="removedPage",r.RELOAD_PAGE="reloadPage",r.SERVER_COMPONENT_CHANGES="serverComponentChanges",r.MIDDLEWARE_CHANGES="middlewareChanges",r.CLIENT_CHANGES="clientChanges",r.SERVER_ONLY_CHANGES="serverOnlyChanges",r.SYNC="sync",r.BUILT="built",r.BUILDING="building",r.DEV_PAGES_MANIFEST_UPDATE="devPagesManifestUpdate",r.TURBOPACK_MESSAGE="turbopack-message",r.SERVER_ERROR="serverError",r.TURBOPACK_CONNECTED="turbopack-connected"},91182:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{INTERCEPTION_ROUTE_MARKERS:function(){return o},extractInterceptionRouteInformation:function(){return l},isInterceptionRouteAppPath:function(){return u}});let r=n(20926),o=["(..)(..)","(.)","(..)","(...)"];function u(e){return void 0!==e.split("/").find(e=>o.find(t=>e.startsWith(t)))}function l(e){let t,n,u;for(let r of e.split("/"))if(n=o.find(e=>r.startsWith(e))){[t,u]=e.split(n,2);break}if(!t||!n||!u)throw Error(`Invalid interception route: ${e}. Must be in the format //(..|...|..)(..)/`);switch(t=(0,r.normalizeAppPath)(t),n){case"(.)":u="/"===t?`/${u}`:t+"/"+u;break;case"(..)":if("/"===t)throw Error(`Invalid interception route: ${e}. Cannot use (..) marker at the root level, use (.) instead.`);u=t.split("/").slice(0,-1).concat(u).join("/");break;case"(...)":u="/"+u;break;case"(..)(..)":let l=t.split("/");if(l.length<=2)throw Error(`Invalid interception route: ${e}. Cannot use (..)(..) marker at the root level or one level up.`);u=l.slice(0,-2).concat(u).join("/");break;default:throw Error("Invariant: unexpected marker")}return{interceptingRoute:t,interceptedRoute:u}}},30650:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"ReflectAdapter",{enumerable:!0,get:function(){return n}});class n{static get(e,t,n){let r=Reflect.get(e,t,n);return"function"==typeof r?r.bind(e):r}static set(e,t,n,r){return Reflect.set(e,t,n,r)}static has(e,t){return Reflect.has(e,t)}static deleteProperty(e,t){return Reflect.deleteProperty(e,t)}}},61956:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{AppRouterContext:function(){return o},GlobalLayoutRouterContext:function(){return l},LayoutRouterContext:function(){return u},MissingSlotContext:function(){return i},TemplateContext:function(){return a}});let r=n(47043)._(n(2265)),o=r.default.createContext(null),u=r.default.createContext(null),l=r.default.createContext(null),a=r.default.createContext(null),i=r.default.createContext(new Set)},37207:function(e,t){"use strict";function n(e){let t=5381;for(let n=0;n>>0}function r(e){return n(e).toString(36).slice(0,5)}Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{djb2Hash:function(){return n},hexHash:function(){return r}})},48701:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"HeadManagerContext",{enumerable:!0,get:function(){return r}});let r=n(47043)._(n(2265)).default.createContext({})},79060:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{PathParamsContext:function(){return l},PathnameContext:function(){return u},SearchParamsContext:function(){return o}});let r=n(2265),o=(0,r.createContext)(null),u=(0,r.createContext)(null),l=(0,r.createContext)(null)},18993:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{BailoutToCSRError:function(){return r},isBailoutToCSRError:function(){return o}});let n="BAILOUT_TO_CLIENT_SIDE_RENDERING";class r extends Error{constructor(e){super("Bail out to client-side rendering: "+e),this.reason=e,this.digest=n}}function o(e){return"object"==typeof e&&null!==e&&"digest"in e&&e.digest===n}},78162:function(e,t){"use strict";function n(e){return e.startsWith("/")?e:"/"+e}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"ensureLeadingSlash",{enumerable:!0,get:function(){return n}})},2103:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ActionQueueContext:function(){return a},createMutableActionQueue:function(){return s}});let r=n(53099),o=n(24673),u=n(91450),l=r._(n(2265)),a=l.default.createContext(null);function i(e,t){null!==e.pending&&(e.pending=e.pending.next,null!==e.pending?c({actionQueue:e,action:e.pending,setState:t}):e.needsRefresh&&(e.needsRefresh=!1,e.dispatch({type:o.ACTION_REFRESH,origin:window.location.origin},t)))}async function c(e){let{actionQueue:t,action:n,setState:r}=e,u=t.state;if(!u)throw Error("Invariant: Router state not initialized");t.pending=n;let l=n.payload,a=t.action(u,l);function c(e){n.discarded||(t.state=e,t.devToolsInstance&&t.devToolsInstance.send(l,e),i(t,r),n.resolve(e))}(0,o.isThenable)(a)?a.then(c,e=>{i(t,r),n.reject(e)}):c(a)}function s(){let e={state:null,dispatch:(t,n)=>(function(e,t,n){let r={resolve:n,reject:()=>{}};if(t.type!==o.ACTION_RESTORE){let e=new Promise((e,t)=>{r={resolve:e,reject:t}});(0,l.startTransition)(()=>{n(e)})}let u={payload:t,next:null,resolve:r.resolve,reject:r.reject};null===e.pending?(e.last=u,c({actionQueue:e,action:u,setState:n})):t.type===o.ACTION_NAVIGATE||t.type===o.ACTION_RESTORE?(e.pending.discarded=!0,e.last=u,e.pending.payload.type===o.ACTION_SERVER_ACTION&&(e.needsRefresh=!0),c({actionQueue:e,action:u,setState:n})):(null!==e.last&&(e.last.next=u),e.last=u)})(e,t,n),action:async(e,t)=>{if(null===e)throw Error("Invariant: Router state not initialized");return(0,u.reducer)(e,t)},pending:null,last:null};return e}},68498:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"addPathPrefix",{enumerable:!0,get:function(){return o}});let r=n(63381);function o(e,t){if(!e.startsWith("/")||!t)return e;let{pathname:n,query:o,hash:u}=(0,r.parsePath)(e);return""+t+n+o+u}},20926:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{normalizeAppPath:function(){return u},normalizeRscURL:function(){return l}});let r=n(78162),o=n(84541);function u(e){return(0,r.ensureLeadingSlash)(e.split("/").reduce((e,t,n,r)=>!t||(0,o.isGroupSegment)(t)||"@"===t[0]||("page"===t||"route"===t)&&n===r.length-1?e:e+"/"+t,""))}function l(e){return e.replace(/\.rsc($|\?)/,"$1")}},7092:function(e,t){"use strict";function n(e,t){if(void 0===t&&(t={}),t.onlyHashChange){e();return}let n=document.documentElement,r=n.style.scrollBehavior;n.style.scrollBehavior="auto",t.dontForceLayout||n.getClientRects(),e(),n.style.scrollBehavior=r}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"handleSmoothScroll",{enumerable:!0,get:function(){return n}})},86146:function(e,t){"use strict";function n(e){return/Googlebot|Mediapartners-Google|AdsBot-Google|googleweblight|Storebot-Google|Google-PageRenderer|Bingbot|BingPreview|Slurp|DuckDuckBot|baiduspider|yandex|sogou|LinkedInBot|bitlybot|tumblr|vkShare|quora link preview|facebookexternalhit|facebookcatalog|Twitterbot|applebot|redditbot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|ia_archiver/i.test(e)}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"isBot",{enumerable:!0,get:function(){return n}})},63381:function(e,t){"use strict";function n(e){let t=e.indexOf("#"),n=e.indexOf("?"),r=n>-1&&(t<0||n-1?{pathname:e.substring(0,r?n:t),query:r?e.substring(n,t>-1?t:void 0):"",hash:t>-1?e.slice(t):""}:{pathname:e,query:"",hash:""}}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"parsePath",{enumerable:!0,get:function(){return n}})},10580:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"pathHasPrefix",{enumerable:!0,get:function(){return o}});let r=n(63381);function o(e,t){if("string"!=typeof e)return!1;let{pathname:n}=(0,r.parsePath)(e);return n===t||n.startsWith(t+"/")}},26674:function(e,t){"use strict";function n(e){return e.replace(/\/$/,"")||"/"}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"removeTrailingSlash",{enumerable:!0,get:function(){return n}})},84541:function(e,t){"use strict";function n(e){return"("===e[0]&&e.endsWith(")")}Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{DEFAULT_SEGMENT_KEY:function(){return o},PAGE_SEGMENT_KEY:function(){return r},isGroupSegment:function(){return n}});let r="__PAGE__",o="__DEFAULT__"},55501:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{ServerInsertedHTMLContext:function(){return o},useServerInsertedHTML:function(){return u}});let r=n(53099)._(n(2265)),o=r.default.createContext(null);function u(e){let t=(0,r.useContext)(o);t&&t(e)}},31765:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"warnOnce",{enumerable:!0,get:function(){return n}});let n=e=>{}},47149:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"actionAsyncStorage",{enumerable:!0,get:function(){return r}});let r=(0,n(54832).createAsyncLocalStorage)();("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},54832:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createAsyncLocalStorage",{enumerable:!0,get:function(){return u}});let n=Error("Invariant: AsyncLocalStorage accessed in runtime where it is not available");class r{disable(){throw n}getStore(){}run(){throw n}exit(){throw n}enterWith(){throw n}}let o=globalThis.AsyncLocalStorage;function u(){return o?new o:new r}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},25575:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"requestAsyncStorage",{enumerable:!0,get:function(){return r}});let r=(0,n(54832).createAsyncLocalStorage)();("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},20030:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"staticGenerationAsyncStorage",{enumerable:!0,get:function(){return r}});let r=(0,n(54832).createAsyncLocalStorage)();("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},34040:function(e,t,n){"use strict";var r=n(54887);t.createRoot=r.createRoot,t.hydrateRoot=r.hydrateRoot},54887:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(84417)},97950:function(e,t,n){"use strict";var r=n(54887),o={stream:!0},u=new Map;function l(e){var t=n(e);return"function"!=typeof t.then||"fulfilled"===t.status?null:(t.then(function(e){t.status="fulfilled",t.value=e},function(e){t.status="rejected",t.reason=e}),t)}function a(){}var i=new Map,c=n.u;n.u=function(e){var t=i.get(e);return void 0!==t?t:c(e)};var s=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Dispatcher,f=Symbol.for("react.element"),d=Symbol.for("react.lazy"),p=Symbol.iterator,h=Array.isArray,y=Object.getPrototypeOf,_=Object.prototype,v=new WeakMap;function b(e,t,n,r){this.status=e,this.value=t,this.reason=n,this._response=r}function g(e){switch(e.status){case"resolved_model":E(e);break;case"resolved_module":w(e)}switch(e.status){case"fulfilled":return e.value;case"pending":case"blocked":case"cyclic":throw e;default:throw e.reason}}function m(e,t){for(var n=0;nh?(_=h,h=3,p++):(_=0,h=3);continue;case 2:44===(m=d[p++])?h=4:v=v<<4|(96d.length&&(m=-1)}var O=d.byteOffset+p;if(-1{let t;let{apiKeySource:n,accessToken:s,apiKey:r,inputMessage:i,chatHistory:o,selectedTags:l,selectedVectorStores:c,selectedGuardrails:d,endpointType:m,selectedModel:p,selectedSdk:u}=e,g="session"===n?s:r,x=window.location.origin,h=i||"Your prompt here",f=h.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n"),_=o.filter(e=>!e.isImage).map(e=>{let{role:t,content:n}=e;return{role:t,content:n}}),b={};l.length>0&&(b.tags=l),c.length>0&&(b.vector_stores=c),d.length>0&&(b.guardrails=d);let v=p||"your-model-name",j="azure"===u?'import openai\n\nclient = openai.AzureOpenAI(\n api_key="'.concat(g||"YOUR_LITELLM_API_KEY",'",\n azure_endpoint="').concat(x,'",\n api_version="2024-02-01"\n)'):'import openai\n\nclient = openai.OpenAI(\n api_key="'.concat(g||"YOUR_LITELLM_API_KEY",'",\n base_url="').concat(x,'"\n)');switch(m){case a.KP.CHAT:{let e=Object.keys(b).length>0,n="";if(e){let e=JSON.stringify({metadata:b},null,2).split("\n").map(e=>" ".repeat(4)+e).join("\n").trim();n=",\n extra_body=".concat(e)}let a=_.length>0?_:[{role:"user",content:h}];t='\nimport base64\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, "rb") as image_file:\n return base64.b64encode(image_file.read()).decode(\'utf-8\')\n\n# Example with text only\nresponse = client.chat.completions.create(\n model="'.concat(v,'",\n messages=').concat(JSON.stringify(a,null,4)).concat(n,'\n)\n\nprint(response)\n\n# Example with image or PDF (uncomment and provide file path to use)\n# base64_file = encode_image("path/to/your/file.jpg") # or .pdf\n# response_with_file = client.chat.completions.create(\n# model="').concat(v,'",\n# messages=[\n# {\n# "role": "user",\n# "content": [\n# {\n# "type": "text",\n# "text": "').concat(f,'"\n# },\n# {\n# "type": "image_url",\n# "image_url": {\n# "url": f"data:image/jpeg;base64,{base64_file}" # or data:application/pdf;base64,{base64_file}\n# }\n# }\n# ]\n# }\n# ]').concat(n,"\n# )\n# print(response_with_file)\n");break}case a.KP.RESPONSES:{let e=Object.keys(b).length>0,n="";if(e){let e=JSON.stringify({metadata:b},null,2).split("\n").map(e=>" ".repeat(4)+e).join("\n").trim();n=",\n extra_body=".concat(e)}let a=_.length>0?_:[{role:"user",content:h}];t='\nimport base64\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, "rb") as image_file:\n return base64.b64encode(image_file.read()).decode(\'utf-8\')\n\n# Example with text only\nresponse = client.responses.create(\n model="'.concat(v,'",\n input=').concat(JSON.stringify(a,null,4)).concat(n,'\n)\n\nprint(response.output_text)\n\n# Example with image or PDF (uncomment and provide file path to use)\n# base64_file = encode_image("path/to/your/file.jpg") # or .pdf\n# response_with_file = client.responses.create(\n# model="').concat(v,'",\n# input=[\n# {\n# "role": "user",\n# "content": [\n# {"type": "input_text", "text": "').concat(f,'"},\n# {\n# "type": "input_image",\n# "image_url": f"data:image/jpeg;base64,{base64_file}", # or data:application/pdf;base64,{base64_file}\n# },\n# ],\n# }\n# ]').concat(n,"\n# )\n# print(response_with_file.output_text)\n");break}case a.KP.IMAGE:t="azure"===u?"\n# NOTE: The Azure SDK does not have a direct equivalent to the multi-modal 'responses.create' method shown for OpenAI.\n# This snippet uses 'client.images.generate' and will create a new image based on your prompt.\n# It does not use the uploaded image, as 'client.images.generate' does not support image inputs in this context.\nimport os\nimport requests\nimport json\nimport time\nfrom PIL import Image\n\nresult = client.images.generate(\n model=\"".concat(v,'",\n prompt="').concat(i,'",\n n=1\n)\n\njson_response = json.loads(result.model_dump_json())\n\n# Set the directory for the stored image\nimage_dir = os.path.join(os.curdir, \'images\')\n\n# If the directory doesn\'t exist, create it\nif not os.path.isdir(image_dir):\n os.mkdir(image_dir)\n\n# Initialize the image path\nimage_filename = f"generated_image_{int(time.time())}.png"\nimage_path = os.path.join(image_dir, image_filename)\n\ntry:\n # Retrieve the generated image\n if json_response.get("data") && len(json_response["data"]) > 0 && json_response["data"][0].get("url"):\n image_url = json_response["data"][0]["url"]\n generated_image = requests.get(image_url).content\n with open(image_path, "wb") as image_file:\n image_file.write(generated_image)\n\n print(f"Image saved to {image_path}")\n # Display the image\n image = Image.open(image_path)\n image.show()\n else:\n print("Could not find image URL in response.")\n print("Full response:", json_response)\nexcept Exception as e:\n print(f"An error occurred: {e}")\n print("Full response:", json_response)\n'):"\nimport base64\nimport os\nimport time\nimport json\nfrom PIL import Image\nimport requests\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, \"rb\") as image_file:\n return base64.b64encode(image_file.read()).decode('utf-8')\n\n# Helper function to create a file (simplified for this example)\ndef create_file(image_path):\n # In a real implementation, this would upload the file to OpenAI\n # For this example, we'll just return a placeholder ID\n return f\"file_{os.path.basename(image_path).replace('.', '_')}\"\n\n# The prompt entered by the user\nprompt = \"".concat(f,'"\n\n# Encode images to base64\nbase64_image1 = encode_image("body-lotion.png")\nbase64_image2 = encode_image("soap.png")\n\n# Create file IDs\nfile_id1 = create_file("body-lotion.png")\nfile_id2 = create_file("incense-kit.png")\n\nresponse = client.responses.create(\n model="').concat(v,'",\n input=[\n {\n "role": "user",\n "content": [\n {"type": "input_text", "text": prompt},\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image1}",\n },\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image2}",\n },\n {\n "type": "input_image",\n "file_id": file_id1,\n },\n {\n "type": "input_image",\n "file_id": file_id2,\n }\n ],\n }\n ],\n tools=[{"type": "image_generation"}],\n)\n\n# Process the response\nimage_generation_calls = [\n output\n for output in response.output\n if output.type == "image_generation_call"\n]\n\nimage_data = [output.result for output in image_generation_calls]\n\nif image_data:\n image_base64 = image_data[0]\n image_filename = f"edited_image_{int(time.time())}.png"\n with open(image_filename, "wb") as f:\n f.write(base64.b64decode(image_base64))\n print(f"Image saved to {image_filename}")\nelse:\n # If no image is generated, there might be a text response with an explanation\n text_response = [output.text for output in response.output if hasattr(output, \'text\')]\n if text_response:\n print("No image generated. Model response:")\n print("\\n".join(text_response))\n else:\n print("No image data found in response.")\n print("Full response for debugging:")\n print(response)\n');break;case a.KP.IMAGE_EDITS:t="azure"===u?'\nimport base64\nimport os\nimport time\nimport json\nfrom PIL import Image\nimport requests\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, "rb") as image_file:\n return base64.b64encode(image_file.read()).decode(\'utf-8\')\n\n# The prompt entered by the user\nprompt = "'.concat(f,'"\n\n# Encode images to base64\nbase64_image1 = encode_image("body-lotion.png")\nbase64_image2 = encode_image("soap.png")\n\n# Create file IDs\nfile_id1 = create_file("body-lotion.png")\nfile_id2 = create_file("incense-kit.png")\n\nresponse = client.responses.create(\n model="').concat(v,'",\n input=[\n {\n "role": "user",\n "content": [\n {"type": "input_text", "text": prompt},\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image1}",\n },\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image2}",\n },\n {\n "type": "input_image",\n "file_id": file_id1,\n },\n {\n "type": "input_image",\n "file_id": file_id2,\n }\n ],\n }\n ],\n tools=[{"type": "image_generation"}],\n)\n\n# Process the response\nimage_generation_calls = [\n output\n for output in response.output\n if output.type == "image_generation_call"\n]\n\nimage_data = [output.result for output in image_generation_calls]\n\nif image_data:\n image_base64 = image_data[0]\n image_filename = f"edited_image_{int(time.time())}.png"\n with open(image_filename, "wb") as f:\n f.write(base64.b64decode(image_base64))\n print(f"Image saved to {image_filename}")\nelse:\n # If no image is generated, there might be a text response with an explanation\n text_response = [output.text for output in response.output if hasattr(output, \'text\')]\n if text_response:\n print("No image generated. Model response:")\n print("\\n".join(text_response))\n else:\n print("No image data found in response.")\n print("Full response for debugging:")\n print(response)\n'):"\nimport base64\nimport os\nimport time\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, \"rb\") as image_file:\n return base64.b64encode(image_file.read()).decode('utf-8')\n\n# Helper function to create a file (simplified for this example)\ndef create_file(image_path):\n # In a real implementation, this would upload the file to OpenAI\n # For this example, we'll just return a placeholder ID\n return f\"file_{os.path.basename(image_path).replace('.', '_')}\"\n\n# The prompt entered by the user\nprompt = \"".concat(f,'"\n\n# Encode images to base64\nbase64_image1 = encode_image("body-lotion.png")\nbase64_image2 = encode_image("soap.png")\n\n# Create file IDs\nfile_id1 = create_file("body-lotion.png")\nfile_id2 = create_file("incense-kit.png")\n\nresponse = client.responses.create(\n model="').concat(v,'",\n input=[\n {\n "role": "user",\n "content": [\n {"type": "input_text", "text": prompt},\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image1}",\n },\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image2}",\n },\n {\n "type": "input_image",\n "file_id": file_id1,\n },\n {\n "type": "input_image",\n "file_id": file_id2,\n }\n ],\n }\n ],\n tools=[{"type": "image_generation"}],\n)\n\n# Process the response\nimage_generation_calls = [\n output\n for output in response.output\n if output.type == "image_generation_call"\n]\n\nimage_data = [output.result for output in image_generation_calls]\n\nif image_data:\n image_base64 = image_data[0]\n image_filename = f"edited_image_{int(time.time())}.png"\n with open(image_filename, "wb") as f:\n f.write(base64.b64decode(image_base64))\n print(f"Image saved to {image_filename}")\nelse:\n # If no image is generated, there might be a text response with an explanation\n text_response = [output.text for output in response.output if hasattr(output, \'text\')]\n if text_response:\n print("No image generated. Model response:")\n print("\\n".join(text_response))\n else:\n print("No image data found in response.")\n print("Full response for debugging:")\n print(response)\n');break;default:t="\n# Code generation for this endpoint is not implemented yet."}return"".concat(j,"\n").concat(t)}},49817:function(e,t,n){var a,s,r,i;n.d(t,{KP:function(){return s},vf:function(){return l}}),(r=a||(a={})).IMAGE_GENERATION="image_generation",r.CHAT="chat",r.RESPONSES="responses",r.IMAGE_EDITS="image_edits",r.ANTHROPIC_MESSAGES="anthropic_messages",(i=s||(s={})).IMAGE="image",i.CHAT="chat",i.RESPONSES="responses",i.IMAGE_EDITS="image_edits",i.ANTHROPIC_MESSAGES="anthropic_messages";let o={image_generation:"image",chat:"chat",responses:"responses",image_edits:"image_edits",anthropic_messages:"anthropic_messages"},l=e=>{if(console.log("getEndpointType:",e),Object.values(a).includes(e)){let t=o[e];return console.log("endpointType:",t),t}return"chat"}},29488:function(e,t,n){n.d(t,{Hc:function(){return i},Ui:function(){return r},e4:function(){return o},xd:function(){return l}});let a="litellm_mcp_auth_tokens",s=()=>{try{let e=localStorage.getItem(a);return e?JSON.parse(e):{}}catch(e){return console.error("Error reading MCP auth tokens from localStorage:",e),{}}},r=(e,t)=>{try{let n=s()[e];if(n&&n.serverAlias===t||n&&!t&&!n.serverAlias)return n.authValue;return null}catch(e){return console.error("Error getting MCP auth token:",e),null}},i=(e,t,n,r)=>{try{let i=s();i[e]={serverId:e,serverAlias:r,authValue:t,authType:n,timestamp:Date.now()},localStorage.setItem(a,JSON.stringify(i))}catch(e){console.error("Error storing MCP auth token:",e)}},o=e=>{try{let t=s();delete t[e],localStorage.setItem(a,JSON.stringify(t))}catch(e){console.error("Error removing MCP auth token:",e)}},l=()=>{try{localStorage.removeItem(a)}catch(e){console.error("Error clearing MCP auth tokens:",e)}}},8048:function(e,t,n){n.d(t,{C:function(){return m}});var a=n(57437),s=n(71594),r=n(24525),i=n(2265),o=n(19130),l=n(44633),c=n(86462),d=n(49084);function m(e){let{data:t=[],columns:n,isLoading:m=!1,table:p,defaultSorting:u=[]}=e,[g,x]=i.useState(u),[h]=i.useState("onChange"),[f,_]=i.useState({}),[b,v]=i.useState({}),j=(0,s.b7)({data:t,columns:n,state:{sorting:g,columnSizing:f,columnVisibility:b},columnResizeMode:h,onSortingChange:x,onColumnSizingChange:_,onColumnVisibilityChange:v,getCoreRowModel:(0,r.sC)(),getSortedRowModel:(0,r.tj)(),enableSorting:!0,enableColumnResizing:!0,defaultColumn:{minSize:40,maxSize:500}});return i.useEffect(()=>{p&&(p.current=j)},[j,p]),(0,a.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,a.jsx)("div",{className:"overflow-x-auto",children:(0,a.jsx)("div",{className:"relative min-w-full",children:(0,a.jsxs)(o.iA,{className:"[&_td]:py-2 [&_th]:py-2 w-full",children:[(0,a.jsx)(o.ss,{children:j.getHeaderGroups().map(e=>(0,a.jsx)(o.SC,{children:e.headers.map(e=>{var t;return(0,a.jsxs)(o.xs,{className:"py-1 h-8 relative ".concat("actions"===e.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)] z-20 w-[120px] ml-8":""," ").concat((null===(t=e.column.columnDef.meta)||void 0===t?void 0:t.className)||""),style:{width:"actions"===e.id?120:e.getSize(),position:"actions"===e.id?"sticky":"relative",right:"actions"===e.id?0:"auto"},onClick:e.column.getCanSort()?e.column.getToggleSortingHandler():void 0,children:[(0,a.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,a.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,s.ie)(e.column.columnDef.header,e.getContext())}),"actions"!==e.id&&e.column.getCanSort()&&(0,a.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,a.jsx)(l.Z,{className:"h-4 w-4 text-blue-500"}),desc:(0,a.jsx)(c.Z,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,a.jsx)(d.Z,{className:"h-4 w-4 text-gray-400"})})]}),e.column.getCanResize()&&(0,a.jsx)("div",{onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:"absolute right-0 top-0 h-full w-2 cursor-col-resize select-none touch-none ".concat(e.column.getIsResizing()?"bg-blue-500":"hover:bg-blue-200")})]},e.id)})},e.id))}),(0,a.jsx)(o.RM,{children:m?(0,a.jsx)(o.SC,{children:(0,a.jsx)(o.pj,{colSpan:n.length,className:"h-8 text-center",children:(0,a.jsx)("div",{className:"text-center text-gray-500",children:(0,a.jsx)("p",{children:"\uD83D\uDE85 Loading models..."})})})}):j.getRowModel().rows.length>0?j.getRowModel().rows.map(e=>(0,a.jsx)(o.SC,{children:e.getVisibleCells().map(e=>{var t;return(0,a.jsx)(o.pj,{className:"py-0.5 ".concat("actions"===e.column.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)] z-20 w-[120px] ml-8":""," ").concat((null===(t=e.column.columnDef.meta)||void 0===t?void 0:t.className)||""),style:{width:"actions"===e.column.id?120:e.column.getSize(),position:"actions"===e.column.id?"sticky":"relative",right:"actions"===e.column.id?0:"auto"},children:(0,s.ie)(e.column.columnDef.cell,e.getContext())},e.id)})},e.id)):(0,a.jsx)(o.SC,{children:(0,a.jsx)(o.pj,{colSpan:n.length,className:"h-8 text-center",children:(0,a.jsx)("div",{className:"text-center text-gray-500",children:(0,a.jsx)("p",{children:"No models found"})})})})})]})})})})}},65373:function(e,t,n){n.d(t,{Z:function(){return v}});var a=n(57437),s=n(27648),r=n(2265),i=n(89970),o=n(80795),l=n(19250),c=n(15883),d=n(46346),m=n(57400),p=n(91870),u=n(40428),g=n(83884),x=n(45524),h=n(3914);let f=async e=>{if(!e)return null;try{return await (0,l.getProxyUISettings)(e)}catch(e){return console.error("Error fetching proxy settings:",e),null}};var _=n(69734),b=n(29488),v=e=>{let{userID:t,userEmail:n,userRole:v,premiumUser:j,proxySettings:y,setProxySettings:N,accessToken:w,isPublicPage:A=!1,sidebarCollapsed:I=!1,onToggleSidebar:S}=e,k=(0,l.getProxyBaseUrl)(),[C,E]=(0,r.useState)(""),{logoUrl:M}=(0,_.F)();(0,r.useEffect)(()=>{(async()=>{if(w){let e=await f(w);console.log("response from fetchProxySettings",e),e&&N(e)}})()},[w]),(0,r.useEffect)(()=>{E((null==y?void 0:y.PROXY_LOGOUT_URL)||"")},[y]);let O=[{key:"user-info",label:(0,a.jsxs)("div",{className:"px-3 py-3 border-b border-gray-100",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between mb-3",children:[(0,a.jsxs)("div",{className:"flex items-center",children:[(0,a.jsx)(c.Z,{className:"mr-2 text-gray-700"}),(0,a.jsx)("span",{className:"text-sm font-semibold text-gray-900",children:t})]}),j?(0,a.jsx)(i.Z,{title:"Premium User",placement:"left",children:(0,a.jsxs)("div",{className:"flex items-center bg-gradient-to-r from-amber-500 to-yellow-500 text-white px-2 py-0.5 rounded-full cursor-help",children:[(0,a.jsx)(d.Z,{className:"mr-1 text-xs"}),(0,a.jsx)("span",{className:"text-xs font-medium",children:"Premium"})]})}):(0,a.jsx)(i.Z,{title:"Upgrade to Premium for advanced features",placement:"left",children:(0,a.jsxs)("div",{className:"flex items-center bg-gray-100 text-gray-500 px-2 py-0.5 rounded-full cursor-help",children:[(0,a.jsx)(d.Z,{className:"mr-1 text-xs"}),(0,a.jsx)("span",{className:"text-xs font-medium",children:"Standard"})]})})]}),(0,a.jsxs)("div",{className:"space-y-2",children:[(0,a.jsxs)("div",{className:"flex items-center text-sm",children:[(0,a.jsx)(m.Z,{className:"mr-2 text-gray-400 text-xs"}),(0,a.jsx)("span",{className:"text-gray-500 text-xs",children:"Role"}),(0,a.jsx)("span",{className:"ml-auto text-gray-700 font-medium",children:v})]}),(0,a.jsxs)("div",{className:"flex items-center text-sm",children:[(0,a.jsx)(p.Z,{className:"mr-2 text-gray-400 text-xs"}),(0,a.jsx)("span",{className:"text-gray-500 text-xs",children:"Email"}),(0,a.jsx)("span",{className:"ml-auto text-gray-700 font-medium truncate max-w-[150px]",title:n||"Unknown",children:n||"Unknown"})]})]})]})},{key:"logout",label:(0,a.jsxs)("div",{className:"flex items-center py-2 px-3 hover:bg-gray-50 rounded-md mx-1 my-1",onClick:()=>{(0,h.b)(),(0,b.xd)(),window.location.href=C},children:[(0,a.jsx)(u.Z,{className:"mr-3 text-gray-600"}),(0,a.jsx)("span",{className:"text-gray-800",children:"Logout"})]})}];return(0,a.jsx)("nav",{className:"bg-white border-b border-gray-200 sticky top-0 z-10",children:(0,a.jsx)("div",{className:"w-full",children:(0,a.jsxs)("div",{className:"flex items-center h-14 px-4",children:[" ",(0,a.jsxs)("div",{className:"flex items-center flex-shrink-0",children:[S&&(0,a.jsx)("button",{onClick:S,className:"flex items-center justify-center w-10 h-10 mr-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded transition-colors",title:I?"Expand sidebar":"Collapse sidebar",children:(0,a.jsx)("span",{className:"text-lg",children:I?(0,a.jsx)(g.Z,{}):(0,a.jsx)(x.Z,{})})}),(0,a.jsx)(s.default,{href:"/",className:"flex items-center",children:(0,a.jsx)("img",{src:M||"".concat(k,"/get_image"),alt:"LiteLLM Brand",className:"h-10 w-auto"})})]}),(0,a.jsxs)("div",{className:"flex items-center space-x-5 ml-auto",children:[(0,a.jsx)("a",{href:"https://docs.litellm.ai/docs/",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 hover:text-gray-900 transition-colors",children:"Docs"}),!A&&(0,a.jsx)(o.Z,{menu:{items:O,className:"min-w-[200px]",style:{padding:"8px",marginTop:"8px",borderRadius:"12px",boxShadow:"0 4px 24px rgba(0, 0, 0, 0.08)"}},overlayStyle:{minWidth:"200px"},children:(0,a.jsxs)("button",{className:"inline-flex items-center text-sm text-gray-600 hover:text-gray-900 transition-colors",children:["User",(0,a.jsx)("svg",{className:"ml-1 w-5 h-5 text-gray-500",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,a.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1.5,d:"M19 9l-7 7-7-7"})})]})})]})]})})})}},42673:function(e,t,n){var a,s;n.d(t,{Cl:function(){return a},bK:function(){return d},cd:function(){return o},dr:function(){return l},fK:function(){return r},ph:function(){return c}}),n(2265),(s=a||(a={})).AIML="AI/ML API",s.Bedrock="Amazon Bedrock",s.Anthropic="Anthropic",s.AssemblyAI="AssemblyAI",s.SageMaker="AWS SageMaker",s.Azure="Azure",s.Azure_AI_Studio="Azure AI Foundry (Studio)",s.Cerebras="Cerebras",s.Cohere="Cohere",s.Databricks="Databricks",s.DeepInfra="DeepInfra",s.Deepgram="Deepgram",s.Deepseek="Deepseek",s.ElevenLabs="ElevenLabs",s.FireworksAI="Fireworks AI",s.Google_AI_Studio="Google AI Studio",s.GradientAI="GradientAI",s.Groq="Groq",s.Hosted_Vllm="vllm",s.JinaAI="Jina AI",s.MistralAI="Mistral AI",s.Ollama="Ollama",s.OpenAI="OpenAI",s.OpenAI_Compatible="OpenAI-Compatible Endpoints (Together AI, etc.)",s.OpenAI_Text="OpenAI Text Completion",s.OpenAI_Text_Compatible="OpenAI-Compatible Text Completion Models (Together AI, etc.)",s.Openrouter="Openrouter",s.Perplexity="Perplexity",s.Sambanova="Sambanova",s.TogetherAI="TogetherAI",s.Triton="Triton",s.Vertex_AI="Vertex AI (Anthropic, Gemini, etc.)",s.VolcEngine="VolcEngine",s.Voyage="Voyage AI",s.xAI="xAI";let r={AIML:"aiml",OpenAI:"openai",OpenAI_Text:"text-completion-openai",Azure:"azure",Azure_AI_Studio:"azure_ai",Anthropic:"anthropic",Google_AI_Studio:"gemini",Bedrock:"bedrock",Groq:"groq",MistralAI:"mistral",Cohere:"cohere",OpenAI_Compatible:"openai",OpenAI_Text_Compatible:"text-completion-openai",Vertex_AI:"vertex_ai",Databricks:"databricks",xAI:"xai",Deepseek:"deepseek",Ollama:"ollama",AssemblyAI:"assemblyai",Cerebras:"cerebras",Sambanova:"sambanova",Perplexity:"perplexity",TogetherAI:"together_ai",Openrouter:"openrouter",FireworksAI:"fireworks_ai",GradientAI:"gradient_ai",Triton:"triton",Deepgram:"deepgram",ElevenLabs:"elevenlabs",SageMaker:"sagemaker_chat",Voyage:"voyage",JinaAI:"jina_ai",VolcEngine:"volcengine",DeepInfra:"deepinfra",Hosted_Vllm:"hosted_vllm"},i="/ui/assets/logos/",o={"AI/ML API":"".concat(i,"aiml_api.svg"),Anthropic:"".concat(i,"anthropic.svg"),AssemblyAI:"".concat(i,"assemblyai_small.png"),Azure:"".concat(i,"microsoft_azure.svg"),"Azure AI Foundry (Studio)":"".concat(i,"microsoft_azure.svg"),"Amazon Bedrock":"".concat(i,"bedrock.svg"),"AWS SageMaker":"".concat(i,"bedrock.svg"),Cerebras:"".concat(i,"cerebras.svg"),Cohere:"".concat(i,"cohere.svg"),Databricks:"".concat(i,"databricks.svg"),Deepseek:"".concat(i,"deepseek.svg"),"Fireworks AI":"".concat(i,"fireworks.svg"),Groq:"".concat(i,"groq.svg"),"Google AI Studio":"".concat(i,"google.svg"),vllm:"".concat(i,"vllm.png"),"Mistral AI":"".concat(i,"mistral.svg"),Ollama:"".concat(i,"ollama.svg"),OpenAI:"".concat(i,"openai_small.svg"),"OpenAI Text Completion":"".concat(i,"openai_small.svg"),"OpenAI-Compatible Text Completion Models (Together AI, etc.)":"".concat(i,"openai_small.svg"),"OpenAI-Compatible Endpoints (Together AI, etc.)":"".concat(i,"openai_small.svg"),Openrouter:"".concat(i,"openrouter.svg"),Perplexity:"".concat(i,"perplexity-ai.svg"),Sambanova:"".concat(i,"sambanova.svg"),TogetherAI:"".concat(i,"togetherai.svg"),"Vertex AI (Anthropic, Gemini, etc.)":"".concat(i,"google.svg"),xAI:"".concat(i,"xai.svg"),GradientAI:"".concat(i,"gradientai.svg"),Triton:"".concat(i,"nvidia_triton.png"),Deepgram:"".concat(i,"deepgram.png"),ElevenLabs:"".concat(i,"elevenlabs.png"),"Voyage AI":"".concat(i,"voyage.webp"),"Jina AI":"".concat(i,"jina.png"),VolcEngine:"".concat(i,"volcengine.png"),DeepInfra:"".concat(i,"deepinfra.png")},l=e=>{if(!e)return{logo:"",displayName:"-"};if("gemini"===e.toLowerCase()){let e="Google AI Studio";return{logo:o[e],displayName:e}}let t=Object.keys(r).find(t=>r[t].toLowerCase()===e.toLowerCase());if(!t)return{logo:"",displayName:e};let n=a[t];return{logo:o[n],displayName:n}},c=e=>{if("AI/ML API"===e)return"aiml/flux-pro/v1.1";if("Vertex AI (Anthropic, Gemini, etc.)"===e)return"gemini-pro";if("Anthropic"==e||"Amazon Bedrock"==e)return"claude-3-opus";if("AWS SageMaker"==e)return"sagemaker/jumpstart-dft-meta-textgeneration-llama-2-7b";if("Google AI Studio"==e)return"gemini-pro";if("Azure AI Foundry (Studio)"==e)return"azure_ai/command-r-plus";else if("Azure"==e)return"azure/my-deployment";else if("Voyage AI"==e)return"voyage/";else if("Jina AI"==e)return"jina_ai/";else if("VolcEngine"==e)return"volcengine/";else if("DeepInfra"==e)return"deepinfra/";else return"gpt-3.5-turbo"},d=(e,t)=>{console.log("Provider key: ".concat(e));let n=r[e];console.log("Provider mapped to: ".concat(n));let a=[];return e&&"object"==typeof t&&(Object.entries(t).forEach(e=>{let[t,s]=e;null!==s&&"object"==typeof s&&"litellm_provider"in s&&(s.litellm_provider===n||s.litellm_provider.includes(n))&&a.push(t)}),"Cohere"==e&&(console.log("Adding cohere chat models"),Object.entries(t).forEach(e=>{let[t,n]=e;null!==n&&"object"==typeof n&&"litellm_provider"in n&&"cohere_chat"===n.litellm_provider&&a.push(t)})),"AWS SageMaker"==e&&(console.log("Adding sagemaker chat models"),Object.entries(t).forEach(e=>{let[t,n]=e;null!==n&&"object"==typeof n&&"litellm_provider"in n&&"sagemaker_chat"===n.litellm_provider&&a.push(t)}))),a}},72162:function(e,t,n){var a=n(57437),s=n(2265),r=n(19250),i=n(8048),o=n(36724),l=n(89970),c=n(3810),d=n(52787),m=n(82680),p=n(3477),u=n(17732),g=n(33245),x=n(78867),h=n(88658),f=n(49817),_=n(42673),b=n(65373),v=n(69734),j=n(9114);t.Z=e=>{var t,n;let{accessToken:y}=e,[N,w]=(0,s.useState)(null),[A,I]=(0,s.useState)("LiteLLM Gateway"),[S,k]=(0,s.useState)(null),[C,E]=(0,s.useState)(""),[M,O]=(0,s.useState)({}),[T,D]=(0,s.useState)(!0),[z,P]=(0,s.useState)(""),[L,Z]=(0,s.useState)([]),[G,R]=(0,s.useState)([]),[H,F]=(0,s.useState)([]),[K,V]=(0,s.useState)("I'm alive! ✓"),[U,W]=(0,s.useState)(!1),[q,J]=(0,s.useState)(null),[B,Y]=(0,s.useState)({}),$=(0,s.useRef)(null);(0,s.useEffect)(()=>{let e=async()=>{try{D(!0);let e=await (0,r.modelHubPublicModelsCall)();console.log("ModelHubData:",e),w(e)}catch(e){console.error("There was an error fetching the public model data",e),V("Service unavailable")}finally{D(!1)}};(async()=>{let e=await (0,r.getPublicModelHubInfo)();console.log("Public Model Hub Info:",e),I(e.docs_title),k(e.custom_docs_description),E(e.litellm_version),O(e.useful_links||{})})(),e()},[]),(0,s.useEffect)(()=>{},[z,L,G,H]);let X=(0,s.useMemo)(()=>{if(!N)return[];let e=N;if(z.trim()){let t=z.toLowerCase(),n=t.split(/\s+/),a=N.filter(e=>{let a=e.model_group.toLowerCase();return!!a.includes(t)||n.every(e=>a.includes(e))});a.length>0&&(e=a.sort((e,n)=>{let a=e.model_group.toLowerCase(),s=n.model_group.toLowerCase(),r=a===t?1e3:0,i=s===t?1e3:0,o=a.startsWith(t)?100:0,l=s.startsWith(t)?100:0,c=t.split(/\s+/).every(e=>a.includes(e))?50:0,d=t.split(/\s+/).every(e=>s.includes(e))?50:0,m=a.length;return i+l+d+(1e3-s.length)-(r+o+c+(1e3-m))}))}return e.filter(e=>{let t=0===L.length||L.some(t=>e.providers.includes(t)),n=0===G.length||G.includes(e.mode||""),a=0===H.length||Object.entries(e).filter(e=>{let[t,n]=e;return t.startsWith("supports_")&&!0===n}).some(e=>{let[t]=e,n=t.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ");return H.includes(n)});return t&&n&&a})},[N,z,L,G,H]),Q=e=>{J(e),W(!0)},ee=e=>{navigator.clipboard.writeText(e),j.Z.success("Copied to clipboard!")},et=e=>e.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" "),en=e=>Object.entries(e).filter(e=>{let[t,n]=e;return t.startsWith("supports_")&&!0===n}).map(e=>{let[t]=e;return t}),ea=e=>"$".concat((1e6*e).toFixed(4)),es=e=>e?e>=1e3?"".concat((e/1e3).toFixed(0),"K"):e.toString():"N/A",er=(e,t)=>{let n=[];return e&&n.push("RPM: ".concat(e.toLocaleString())),t&&n.push("TPM: ".concat(t.toLocaleString())),n.length>0?n.join(", "):"N/A"};return(0,a.jsx)(v.f,{accessToken:y,children:(0,a.jsxs)("div",{className:"min-h-screen bg-white",children:[(0,a.jsx)(b.Z,{userID:null,userEmail:null,userRole:null,premiumUser:!1,setProxySettings:Y,proxySettings:B,accessToken:y||null,isPublicPage:!0}),(0,a.jsxs)("div",{className:"w-full px-8 py-12",children:[(0,a.jsxs)(o.Zb,{className:"mb-10 p-8 bg-white border border-gray-200 rounded-lg shadow-sm",children:[(0,a.jsx)(o.Dx,{className:"text-2xl font-semibold mb-6 text-gray-900",children:"About"}),(0,a.jsx)("p",{className:"text-gray-700 mb-6 text-base leading-relaxed",children:S||"Proxy Server to call 100+ LLMs in the OpenAI format."}),(0,a.jsx)("div",{className:"flex items-center space-x-3 text-sm text-gray-600",children:(0,a.jsxs)("span",{className:"flex items-center",children:[(0,a.jsx)("span",{className:"w-4 h-4 mr-2",children:"\uD83D\uDD27"}),"Built with litellm: v",C]})})]}),M&&Object.keys(M).length>0&&(0,a.jsxs)(o.Zb,{className:"mb-10 p-8 bg-white border border-gray-200 rounded-lg shadow-sm",children:[(0,a.jsx)(o.Dx,{className:"text-2xl font-semibold mb-6 text-gray-900",children:"Useful Links"}),(0,a.jsx)("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6",children:Object.entries(M||{}).map(e=>{let[t,n]=e;return(0,a.jsxs)("button",{onClick:()=>window.open(n,"_blank"),className:"flex items-center space-x-3 text-blue-600 hover:text-blue-800 transition-colors p-3 rounded-lg hover:bg-blue-50 border border-gray-200",children:[(0,a.jsx)(p.Z,{className:"w-4 h-4"}),(0,a.jsx)(o.xv,{className:"text-sm font-medium",children:t})]},t)})})]}),(0,a.jsxs)(o.Zb,{className:"mb-10 p-8 bg-white border border-gray-200 rounded-lg shadow-sm",children:[(0,a.jsx)(o.Dx,{className:"text-2xl font-semibold mb-6 text-gray-900",children:"Health and Endpoint Status"}),(0,a.jsx)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-6",children:(0,a.jsxs)(o.xv,{className:"text-green-600 font-medium text-sm",children:["Service status: ",K]})})]}),(0,a.jsxs)(o.Zb,{className:"p-8 bg-white border border-gray-200 rounded-lg shadow-sm",children:[(0,a.jsx)("div",{className:"flex justify-between items-center mb-8",children:(0,a.jsx)(o.Dx,{className:"text-2xl font-semibold text-gray-900",children:"Available Models"})}),(0,a.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200",children:[(0,a.jsxs)("div",{children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2 mb-3",children:[(0,a.jsx)(o.xv,{className:"text-sm font-medium text-gray-700",children:"Search Models:"}),(0,a.jsx)(l.Z,{title:"Smart search with relevance ranking - finds models containing your search terms, ranked by relevance. Try searching 'xai grok-4', 'claude-4', 'gpt-4', or 'sonnet'",placement:"top",children:(0,a.jsx)(g.Z,{className:"w-4 h-4 text-gray-400 cursor-help"})})]}),(0,a.jsxs)("div",{className:"relative",children:[(0,a.jsx)(u.Z,{className:"w-4 h-4 text-gray-400 absolute left-3 top-1/2 transform -translate-y-1/2"}),(0,a.jsx)("input",{type:"text",placeholder:"Search model names... (smart search enabled)",value:z,onChange:e=>P(e.target.value),className:"border border-gray-300 rounded-lg pl-10 pr-4 py-2 w-full text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white"})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-sm font-medium mb-3 text-gray-700",children:"Provider:"}),(0,a.jsx)(d.default,{mode:"multiple",value:L,onChange:e=>Z(e),placeholder:"Select providers",className:"w-full",size:"large",allowClear:!0,optionRender:e=>{let{logo:t}=(0,_.dr)(e.value);return(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[t&&(0,a.jsx)("img",{src:t,alt:e.label,className:"w-5 h-5 flex-shrink-0 object-contain",onError:e=>{e.target.style.display="none"}}),(0,a.jsx)("span",{className:"capitalize",children:e.label})]})},children:N&&(e=>{let t=new Set;return e.forEach(e=>{e.providers.forEach(e=>t.add(e))}),Array.from(t)})(N).map(e=>(0,a.jsx)(d.default.Option,{value:e,children:e},e))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-sm font-medium mb-3 text-gray-700",children:"Mode:"}),(0,a.jsx)(d.default,{mode:"multiple",value:G,onChange:e=>R(e),placeholder:"Select modes",className:"w-full",size:"large",allowClear:!0,children:N&&(e=>{let t=new Set;return e.forEach(e=>{e.mode&&t.add(e.mode)}),Array.from(t)})(N).map(e=>(0,a.jsx)(d.default.Option,{value:e,children:e},e))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-sm font-medium mb-3 text-gray-700",children:"Features:"}),(0,a.jsx)(d.default,{mode:"multiple",value:H,onChange:e=>F(e),placeholder:"Select features",className:"w-full",size:"large",allowClear:!0,children:N&&(e=>{let t=new Set;return e.forEach(e=>{Object.entries(e).filter(e=>{let[t,n]=e;return t.startsWith("supports_")&&!0===n}).forEach(e=>{let[n]=e,a=n.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ");t.add(a)})}),Array.from(t).sort()})(N).map(e=>(0,a.jsx)(d.default.Option,{value:e,children:e},e))})]})]}),(0,a.jsx)(i.C,{columns:[{header:"Model Name",accessorKey:"model_group",enableSorting:!0,cell:e=>{let{row:t}=e;return(0,a.jsx)("div",{className:"overflow-hidden",children:(0,a.jsx)(l.Z,{title:t.original.model_group,children:(0,a.jsx)(o.zx,{size:"xs",variant:"light",className:"font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left",onClick:()=>Q(t.original),children:t.original.model_group})})})},size:150},{header:"Providers",accessorKey:"providers",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original.providers;return(0,a.jsx)("div",{className:"flex flex-wrap gap-1",children:n.map(e=>{let{logo:t}=(0,_.dr)(e);return(0,a.jsxs)("div",{className:"flex items-center space-x-1 px-2 py-1 bg-gray-100 rounded text-xs",children:[t&&(0,a.jsx)("img",{src:t,alt:e,className:"w-3 h-3 flex-shrink-0 object-contain",onError:e=>{e.target.style.display="none"}}),(0,a.jsx)("span",{className:"capitalize",children:e})]},e)})})},size:120},{header:"Mode",accessorKey:"mode",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original.mode;return(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)("span",{children:(e=>{switch(null==e?void 0:e.toLowerCase()){case"chat":return"\uD83D\uDCAC";case"rerank":return"\uD83D\uDD04";case"embedding":return"\uD83D\uDCC4";default:return"\uD83E\uDD16"}})(n||"")}),(0,a.jsx)(o.xv,{children:n||"Chat"})]})},size:100},{header:"Max Input",accessorKey:"max_input_tokens",enableSorting:!0,cell:e=>{let{row:t}=e;return(0,a.jsx)(o.xv,{className:"text-center",children:es(t.original.max_input_tokens)})},size:100,meta:{className:"text-center"}},{header:"Max Output",accessorKey:"max_output_tokens",enableSorting:!0,cell:e=>{let{row:t}=e;return(0,a.jsx)(o.xv,{className:"text-center",children:es(t.original.max_output_tokens)})},size:100,meta:{className:"text-center"}},{header:"Input $/1M",accessorKey:"input_cost_per_token",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original.input_cost_per_token;return(0,a.jsx)(o.xv,{className:"text-center",children:n?ea(n):"Free"})},size:100,meta:{className:"text-center"}},{header:"Output $/1M",accessorKey:"output_cost_per_token",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original.output_cost_per_token;return(0,a.jsx)(o.xv,{className:"text-center",children:n?ea(n):"Free"})},size:100,meta:{className:"text-center"}},{header:"Features",accessorKey:"supports_vision",enableSorting:!1,cell:e=>{let{row:t}=e,n=Object.entries(t.original).filter(e=>{let[t,n]=e;return t.startsWith("supports_")&&!0===n}).map(e=>{let[t]=e;return et(t)});return 0===n.length?(0,a.jsx)(o.xv,{className:"text-gray-400",children:"-"}):1===n.length?(0,a.jsx)("div",{className:"h-6 flex items-center",children:(0,a.jsx)(c.Z,{color:"blue",className:"text-xs",children:n[0]})}):(0,a.jsxs)("div",{className:"h-6 flex items-center space-x-1",children:[(0,a.jsx)(c.Z,{color:"blue",className:"text-xs",children:n[0]}),(0,a.jsx)(l.Z,{title:(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsx)("div",{className:"font-medium",children:"All Features:"}),n.map((e,t)=>(0,a.jsxs)("div",{className:"text-xs",children:["• ",e]},t))]}),trigger:"click",placement:"topLeft",children:(0,a.jsxs)("span",{className:"text-xs text-blue-600 cursor-pointer hover:text-blue-800 hover:underline",onClick:e=>e.stopPropagation(),children:["+",n.length-1]})})]})},size:120},{header:"Limits",accessorKey:"rpm",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original;return(0,a.jsx)(o.xv,{className:"text-xs text-gray-600",children:er(n.rpm,n.tpm)})},size:150}],data:X,isLoading:T,table:$,defaultSorting:[{id:"model_group",desc:!1}]}),(0,a.jsx)("div",{className:"mt-8 text-center",children:(0,a.jsxs)(o.xv,{className:"text-sm text-gray-600",children:["Showing ",X.length," of ",(null==N?void 0:N.length)||0," models"]})})]})]}),(0,a.jsx)(m.Z,{title:(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)("span",{children:(null==q?void 0:q.model_group)||"Model Details"}),q&&(0,a.jsx)(l.Z,{title:"Copy model name",children:(0,a.jsx)(x.Z,{onClick:()=>ee(q.model_group),className:"cursor-pointer text-gray-500 hover:text-blue-500 w-4 h-4"})})]}),width:1e3,open:U,footer:null,onOk:()=>{W(!1),J(null)},onCancel:()=>{W(!1),J(null)},children:q&&(0,a.jsxs)("div",{className:"space-y-6",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Model Overview"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Model Name:"}),(0,a.jsx)(o.xv,{children:q.model_group})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Mode:"}),(0,a.jsx)(o.xv,{children:q.mode||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Providers:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:q.providers.map(e=>{let{logo:t}=(0,_.dr)(e);return(0,a.jsx)(c.Z,{color:"blue",children:(0,a.jsxs)("div",{className:"flex items-center space-x-1",children:[t&&(0,a.jsx)("img",{src:t,alt:e,className:"w-3 h-3 flex-shrink-0 object-contain",onError:e=>{e.target.style.display="none"}}),(0,a.jsx)("span",{className:"capitalize",children:e})]})},e)})})]})]}),q.model_group.includes("*")&&(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-4 mb-4",children:(0,a.jsxs)("div",{className:"flex items-start space-x-2",children:[(0,a.jsx)(g.Z,{className:"w-4 h-4 text-blue-600 mt-0.5 flex-shrink-0"}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium text-blue-900 mb-2",children:"Wildcard Routing"}),(0,a.jsxs)(o.xv,{className:"text-sm text-blue-800 mb-2",children:["This model uses wildcard routing. You can pass any value where you see the ",(0,a.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded text-xs",children:"*"})," symbol."]}),(0,a.jsxs)(o.xv,{className:"text-sm text-blue-800",children:["For example, with ",(0,a.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded text-xs",children:q.model_group}),", you can use any string (",(0,a.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded text-xs",children:q.model_group.replace("*","my-custom-value")}),") that matches this pattern."]})]})]})})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Token & Cost Information"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Max Input Tokens:"}),(0,a.jsx)(o.xv,{children:(null===(t=q.max_input_tokens)||void 0===t?void 0:t.toLocaleString())||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Max Output Tokens:"}),(0,a.jsx)(o.xv,{children:(null===(n=q.max_output_tokens)||void 0===n?void 0:n.toLocaleString())||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Input Cost per 1M Tokens:"}),(0,a.jsx)(o.xv,{children:q.input_cost_per_token?ea(q.input_cost_per_token):"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Output Cost per 1M Tokens:"}),(0,a.jsx)(o.xv,{children:q.output_cost_per_token?ea(q.output_cost_per_token):"Not specified"})]})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Capabilities"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:(()=>{let e=en(q),t=["green","blue","purple","orange","red","yellow"];return 0===e.length?(0,a.jsx)(o.xv,{className:"text-gray-500",children:"No special capabilities listed"}):e.map((e,n)=>(0,a.jsx)(c.Z,{color:t[n%t.length],children:et(e)},e))})()})]}),(q.tpm||q.rpm)&&(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Rate Limits"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[q.tpm&&(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Tokens per Minute:"}),(0,a.jsx)(o.xv,{children:q.tpm.toLocaleString()})]}),q.rpm&&(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Requests per Minute:"}),(0,a.jsx)(o.xv,{children:q.rpm.toLocaleString()})]})]})]}),q.supported_openai_params&&(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Supported OpenAI Parameters"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:q.supported_openai_params.map(e=>(0,a.jsx)(c.Z,{color:"green",children:e},e))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Usage Example"}),(0,a.jsx)("div",{className:"bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto",children:(0,a.jsx)("pre",{className:"text-sm",children:(0,h.L)({apiKeySource:"custom",accessToken:null,apiKey:"your_api_key",inputMessage:"Hello, how are you?",chatHistory:[{role:"user",content:"Hello, how are you?",isImage:!1}],selectedTags:[],selectedVectorStores:[],selectedGuardrails:[],endpointType:(0,f.vf)(q.mode||"chat"),selectedModel:q.model_group,selectedSdk:"openai"})})}),(0,a.jsx)("div",{className:"mt-2 text-right",children:(0,a.jsx)("button",{onClick:()=>{ee((0,h.L)({apiKeySource:"custom",accessToken:null,apiKey:"your_api_key",inputMessage:"Hello, how are you?",chatHistory:[{role:"user",content:"Hello, how are you?",isImage:!1}],selectedTags:[],selectedVectorStores:[],selectedGuardrails:[],endpointType:(0,f.vf)(q.mode||"chat"),selectedModel:q.model_group,selectedSdk:"openai"}))},className:"text-sm text-blue-600 hover:text-blue-800 cursor-pointer",children:"Copy to clipboard"})})]})]})})]})})}},69734:function(e,t,n){n.d(t,{F:function(){return o},f:function(){return l}});var a=n(57437),s=n(2265),r=n(19250);let i=(0,s.createContext)(void 0),o=()=>{let e=(0,s.useContext)(i);if(!e)throw Error("useTheme must be used within a ThemeProvider");return e},l=e=>{let{children:t,accessToken:n}=e,[o,l]=(0,s.useState)(null);return(0,s.useEffect)(()=>{(async()=>{if(n)try{let t=(0,r.getProxyBaseUrl)(),a=await fetch(t?"".concat(t,"/get/ui_theme_settings"):"/get/ui_theme_settings",{method:"GET",headers:{Authorization:"Bearer ".concat(n),"Content-Type":"application/json"}});if(a.ok){var e;let t=await a.json();(null===(e=t.values)||void 0===e?void 0:e.logo_url)&&l(t.values.logo_url)}}catch(e){console.warn("Failed to load logo settings from backend:",e)}})()},[n]),(0,a.jsx)(i.Provider,{value:{logoUrl:o,setLogoUrl:l},children:t})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/162-76acc071cdf524f9.js b/litellm/proxy/_experimental/out/_next/static/chunks/162-76acc071cdf524f9.js deleted file mode 100644 index dd149327dfa..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/162-76acc071cdf524f9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[162],{36724:function(e,t,n){n.d(t,{Dx:function(){return i.Z},Zb:function(){return s.Z},xv:function(){return r.Z},zx:function(){return a.Z}});var a=n(20831),s=n(12514),r=n(84264),i=n(96761)},19130:function(e,t,n){n.d(t,{RM:function(){return s.Z},SC:function(){return l.Z},iA:function(){return a.Z},pj:function(){return r.Z},ss:function(){return i.Z},xs:function(){return o.Z}});var a=n(21626),s=n(97214),r=n(28241),i=n(58834),o=n(69552),l=n(71876)},88658:function(e,t,n){n.d(t,{L:function(){return s}});var a=n(49817);let s=e=>{let t;let{apiKeySource:n,accessToken:s,apiKey:r,inputMessage:i,chatHistory:o,selectedTags:l,selectedVectorStores:c,selectedGuardrails:d,endpointType:m,selectedModel:p,selectedSdk:u}=e,g="session"===n?s:r,x=window.location.origin,h=i||"Your prompt here",f=h.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n"),_=o.filter(e=>!e.isImage).map(e=>{let{role:t,content:n}=e;return{role:t,content:n}}),b={};l.length>0&&(b.tags=l),c.length>0&&(b.vector_stores=c),d.length>0&&(b.guardrails=d);let v=p||"your-model-name",j="azure"===u?'import openai\n\nclient = openai.AzureOpenAI(\n api_key="'.concat(g||"YOUR_LITELLM_API_KEY",'",\n azure_endpoint="').concat(x,'",\n api_version="2024-02-01"\n)'):'import openai\n\nclient = openai.OpenAI(\n api_key="'.concat(g||"YOUR_LITELLM_API_KEY",'",\n base_url="').concat(x,'"\n)');switch(m){case a.KP.CHAT:{let e=Object.keys(b).length>0,n="";if(e){let e=JSON.stringify({metadata:b},null,2).split("\n").map(e=>" ".repeat(4)+e).join("\n").trim();n=",\n extra_body=".concat(e)}let a=_.length>0?_:[{role:"user",content:h}];t='\nimport base64\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, "rb") as image_file:\n return base64.b64encode(image_file.read()).decode(\'utf-8\')\n\n# Example with text only\nresponse = client.chat.completions.create(\n model="'.concat(v,'",\n messages=').concat(JSON.stringify(a,null,4)).concat(n,'\n)\n\nprint(response)\n\n# Example with image or PDF (uncomment and provide file path to use)\n# base64_file = encode_image("path/to/your/file.jpg") # or .pdf\n# response_with_file = client.chat.completions.create(\n# model="').concat(v,'",\n# messages=[\n# {\n# "role": "user",\n# "content": [\n# {\n# "type": "text",\n# "text": "').concat(f,'"\n# },\n# {\n# "type": "image_url",\n# "image_url": {\n# "url": f"data:image/jpeg;base64,{base64_file}" # or data:application/pdf;base64,{base64_file}\n# }\n# }\n# ]\n# }\n# ]').concat(n,"\n# )\n# print(response_with_file)\n");break}case a.KP.RESPONSES:{let e=Object.keys(b).length>0,n="";if(e){let e=JSON.stringify({metadata:b},null,2).split("\n").map(e=>" ".repeat(4)+e).join("\n").trim();n=",\n extra_body=".concat(e)}let a=_.length>0?_:[{role:"user",content:h}];t='\nimport base64\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, "rb") as image_file:\n return base64.b64encode(image_file.read()).decode(\'utf-8\')\n\n# Example with text only\nresponse = client.responses.create(\n model="'.concat(v,'",\n input=').concat(JSON.stringify(a,null,4)).concat(n,'\n)\n\nprint(response.output_text)\n\n# Example with image or PDF (uncomment and provide file path to use)\n# base64_file = encode_image("path/to/your/file.jpg") # or .pdf\n# response_with_file = client.responses.create(\n# model="').concat(v,'",\n# input=[\n# {\n# "role": "user",\n# "content": [\n# {"type": "input_text", "text": "').concat(f,'"},\n# {\n# "type": "input_image",\n# "image_url": f"data:image/jpeg;base64,{base64_file}", # or data:application/pdf;base64,{base64_file}\n# },\n# ],\n# }\n# ]').concat(n,"\n# )\n# print(response_with_file.output_text)\n");break}case a.KP.IMAGE:t="azure"===u?"\n# NOTE: The Azure SDK does not have a direct equivalent to the multi-modal 'responses.create' method shown for OpenAI.\n# This snippet uses 'client.images.generate' and will create a new image based on your prompt.\n# It does not use the uploaded image, as 'client.images.generate' does not support image inputs in this context.\nimport os\nimport requests\nimport json\nimport time\nfrom PIL import Image\n\nresult = client.images.generate(\n model=\"".concat(v,'",\n prompt="').concat(i,'",\n n=1\n)\n\njson_response = json.loads(result.model_dump_json())\n\n# Set the directory for the stored image\nimage_dir = os.path.join(os.curdir, \'images\')\n\n# If the directory doesn\'t exist, create it\nif not os.path.isdir(image_dir):\n os.mkdir(image_dir)\n\n# Initialize the image path\nimage_filename = f"generated_image_{int(time.time())}.png"\nimage_path = os.path.join(image_dir, image_filename)\n\ntry:\n # Retrieve the generated image\n if json_response.get("data") && len(json_response["data"]) > 0 && json_response["data"][0].get("url"):\n image_url = json_response["data"][0]["url"]\n generated_image = requests.get(image_url).content\n with open(image_path, "wb") as image_file:\n image_file.write(generated_image)\n\n print(f"Image saved to {image_path}")\n # Display the image\n image = Image.open(image_path)\n image.show()\n else:\n print("Could not find image URL in response.")\n print("Full response:", json_response)\nexcept Exception as e:\n print(f"An error occurred: {e}")\n print("Full response:", json_response)\n'):"\nimport base64\nimport os\nimport time\nimport json\nfrom PIL import Image\nimport requests\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, \"rb\") as image_file:\n return base64.b64encode(image_file.read()).decode('utf-8')\n\n# Helper function to create a file (simplified for this example)\ndef create_file(image_path):\n # In a real implementation, this would upload the file to OpenAI\n # For this example, we'll just return a placeholder ID\n return f\"file_{os.path.basename(image_path).replace('.', '_')}\"\n\n# The prompt entered by the user\nprompt = \"".concat(f,'"\n\n# Encode images to base64\nbase64_image1 = encode_image("body-lotion.png")\nbase64_image2 = encode_image("soap.png")\n\n# Create file IDs\nfile_id1 = create_file("body-lotion.png")\nfile_id2 = create_file("incense-kit.png")\n\nresponse = client.responses.create(\n model="').concat(v,'",\n input=[\n {\n "role": "user",\n "content": [\n {"type": "input_text", "text": prompt},\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image1}",\n },\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image2}",\n },\n {\n "type": "input_image",\n "file_id": file_id1,\n },\n {\n "type": "input_image",\n "file_id": file_id2,\n }\n ],\n }\n ],\n tools=[{"type": "image_generation"}],\n)\n\n# Process the response\nimage_generation_calls = [\n output\n for output in response.output\n if output.type == "image_generation_call"\n]\n\nimage_data = [output.result for output in image_generation_calls]\n\nif image_data:\n image_base64 = image_data[0]\n image_filename = f"edited_image_{int(time.time())}.png"\n with open(image_filename, "wb") as f:\n f.write(base64.b64decode(image_base64))\n print(f"Image saved to {image_filename}")\nelse:\n # If no image is generated, there might be a text response with an explanation\n text_response = [output.text for output in response.output if hasattr(output, \'text\')]\n if text_response:\n print("No image generated. Model response:")\n print("\\n".join(text_response))\n else:\n print("No image data found in response.")\n print("Full response for debugging:")\n print(response)\n');break;case a.KP.IMAGE_EDITS:t="azure"===u?'\nimport base64\nimport os\nimport time\nimport json\nfrom PIL import Image\nimport requests\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, "rb") as image_file:\n return base64.b64encode(image_file.read()).decode(\'utf-8\')\n\n# The prompt entered by the user\nprompt = "'.concat(f,'"\n\n# Encode images to base64\nbase64_image1 = encode_image("body-lotion.png")\nbase64_image2 = encode_image("soap.png")\n\n# Create file IDs\nfile_id1 = create_file("body-lotion.png")\nfile_id2 = create_file("incense-kit.png")\n\nresponse = client.responses.create(\n model="').concat(v,'",\n input=[\n {\n "role": "user",\n "content": [\n {"type": "input_text", "text": prompt},\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image1}",\n },\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image2}",\n },\n {\n "type": "input_image",\n "file_id": file_id1,\n },\n {\n "type": "input_image",\n "file_id": file_id2,\n }\n ],\n }\n ],\n tools=[{"type": "image_generation"}],\n)\n\n# Process the response\nimage_generation_calls = [\n output\n for output in response.output\n if output.type == "image_generation_call"\n]\n\nimage_data = [output.result for output in image_generation_calls]\n\nif image_data:\n image_base64 = image_data[0]\n image_filename = f"edited_image_{int(time.time())}.png"\n with open(image_filename, "wb") as f:\n f.write(base64.b64decode(image_base64))\n print(f"Image saved to {image_filename}")\nelse:\n # If no image is generated, there might be a text response with an explanation\n text_response = [output.text for output in response.output if hasattr(output, \'text\')]\n if text_response:\n print("No image generated. Model response:")\n print("\\n".join(text_response))\n else:\n print("No image data found in response.")\n print("Full response for debugging:")\n print(response)\n'):"\nimport base64\nimport os\nimport time\n\n# Helper function to encode images to base64\ndef encode_image(image_path):\n with open(image_path, \"rb\") as image_file:\n return base64.b64encode(image_file.read()).decode('utf-8')\n\n# Helper function to create a file (simplified for this example)\ndef create_file(image_path):\n # In a real implementation, this would upload the file to OpenAI\n # For this example, we'll just return a placeholder ID\n return f\"file_{os.path.basename(image_path).replace('.', '_')}\"\n\n# The prompt entered by the user\nprompt = \"".concat(f,'"\n\n# Encode images to base64\nbase64_image1 = encode_image("body-lotion.png")\nbase64_image2 = encode_image("soap.png")\n\n# Create file IDs\nfile_id1 = create_file("body-lotion.png")\nfile_id2 = create_file("incense-kit.png")\n\nresponse = client.responses.create(\n model="').concat(v,'",\n input=[\n {\n "role": "user",\n "content": [\n {"type": "input_text", "text": prompt},\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image1}",\n },\n {\n "type": "input_image",\n "image_url": f"data:image/jpeg;base64,{base64_image2}",\n },\n {\n "type": "input_image",\n "file_id": file_id1,\n },\n {\n "type": "input_image",\n "file_id": file_id2,\n }\n ],\n }\n ],\n tools=[{"type": "image_generation"}],\n)\n\n# Process the response\nimage_generation_calls = [\n output\n for output in response.output\n if output.type == "image_generation_call"\n]\n\nimage_data = [output.result for output in image_generation_calls]\n\nif image_data:\n image_base64 = image_data[0]\n image_filename = f"edited_image_{int(time.time())}.png"\n with open(image_filename, "wb") as f:\n f.write(base64.b64decode(image_base64))\n print(f"Image saved to {image_filename}")\nelse:\n # If no image is generated, there might be a text response with an explanation\n text_response = [output.text for output in response.output if hasattr(output, \'text\')]\n if text_response:\n print("No image generated. Model response:")\n print("\\n".join(text_response))\n else:\n print("No image data found in response.")\n print("Full response for debugging:")\n print(response)\n');break;default:t="\n# Code generation for this endpoint is not implemented yet."}return"".concat(j,"\n").concat(t)}},49817:function(e,t,n){var a,s,r,i;n.d(t,{KP:function(){return s},vf:function(){return l}}),(r=a||(a={})).IMAGE_GENERATION="image_generation",r.CHAT="chat",r.RESPONSES="responses",r.IMAGE_EDITS="image_edits",r.ANTHROPIC_MESSAGES="anthropic_messages",(i=s||(s={})).IMAGE="image",i.CHAT="chat",i.RESPONSES="responses",i.IMAGE_EDITS="image_edits",i.ANTHROPIC_MESSAGES="anthropic_messages";let o={image_generation:"image",chat:"chat",responses:"responses",image_edits:"image_edits",anthropic_messages:"anthropic_messages"},l=e=>{if(console.log("getEndpointType:",e),Object.values(a).includes(e)){let t=o[e];return console.log("endpointType:",t),t}return"chat"}},29488:function(e,t,n){n.d(t,{Hc:function(){return i},Ui:function(){return r},e4:function(){return o},xd:function(){return l}});let a="litellm_mcp_auth_tokens",s=()=>{try{let e=localStorage.getItem(a);return e?JSON.parse(e):{}}catch(e){return console.error("Error reading MCP auth tokens from localStorage:",e),{}}},r=(e,t)=>{try{let n=s()[e];if(n&&n.serverAlias===t||n&&!t&&!n.serverAlias)return n.authValue;return null}catch(e){return console.error("Error getting MCP auth token:",e),null}},i=(e,t,n,r)=>{try{let i=s();i[e]={serverId:e,serverAlias:r,authValue:t,authType:n,timestamp:Date.now()},localStorage.setItem(a,JSON.stringify(i))}catch(e){console.error("Error storing MCP auth token:",e)}},o=e=>{try{let t=s();delete t[e],localStorage.setItem(a,JSON.stringify(t))}catch(e){console.error("Error removing MCP auth token:",e)}},l=()=>{try{localStorage.removeItem(a)}catch(e){console.error("Error clearing MCP auth tokens:",e)}}},8048:function(e,t,n){n.d(t,{C:function(){return m}});var a=n(57437),s=n(71594),r=n(24525),i=n(2265),o=n(19130),l=n(44633),c=n(86462),d=n(49084);function m(e){let{data:t=[],columns:n,isLoading:m=!1,table:p,defaultSorting:u=[]}=e,[g,x]=i.useState(u),[h]=i.useState("onChange"),[f,_]=i.useState({}),[b,v]=i.useState({}),j=(0,s.b7)({data:t,columns:n,state:{sorting:g,columnSizing:f,columnVisibility:b},columnResizeMode:h,onSortingChange:x,onColumnSizingChange:_,onColumnVisibilityChange:v,getCoreRowModel:(0,r.sC)(),getSortedRowModel:(0,r.tj)(),enableSorting:!0,enableColumnResizing:!0,defaultColumn:{minSize:40,maxSize:500}});return i.useEffect(()=>{p&&(p.current=j)},[j,p]),(0,a.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,a.jsx)("div",{className:"overflow-x-auto",children:(0,a.jsx)("div",{className:"relative min-w-full",children:(0,a.jsxs)(o.iA,{className:"[&_td]:py-2 [&_th]:py-2 w-full",children:[(0,a.jsx)(o.ss,{children:j.getHeaderGroups().map(e=>(0,a.jsx)(o.SC,{children:e.headers.map(e=>{var t;return(0,a.jsxs)(o.xs,{className:"py-1 h-8 relative ".concat("actions"===e.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)] z-20 w-[120px] ml-8":""," ").concat((null===(t=e.column.columnDef.meta)||void 0===t?void 0:t.className)||""),style:{width:"actions"===e.id?120:e.getSize(),position:"actions"===e.id?"sticky":"relative",right:"actions"===e.id?0:"auto"},onClick:e.column.getCanSort()?e.column.getToggleSortingHandler():void 0,children:[(0,a.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,a.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,s.ie)(e.column.columnDef.header,e.getContext())}),"actions"!==e.id&&e.column.getCanSort()&&(0,a.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,a.jsx)(l.Z,{className:"h-4 w-4 text-blue-500"}),desc:(0,a.jsx)(c.Z,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,a.jsx)(d.Z,{className:"h-4 w-4 text-gray-400"})})]}),e.column.getCanResize()&&(0,a.jsx)("div",{onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:"absolute right-0 top-0 h-full w-2 cursor-col-resize select-none touch-none ".concat(e.column.getIsResizing()?"bg-blue-500":"hover:bg-blue-200")})]},e.id)})},e.id))}),(0,a.jsx)(o.RM,{children:m?(0,a.jsx)(o.SC,{children:(0,a.jsx)(o.pj,{colSpan:n.length,className:"h-8 text-center",children:(0,a.jsx)("div",{className:"text-center text-gray-500",children:(0,a.jsx)("p",{children:"\uD83D\uDE85 Loading models..."})})})}):j.getRowModel().rows.length>0?j.getRowModel().rows.map(e=>(0,a.jsx)(o.SC,{children:e.getVisibleCells().map(e=>{var t;return(0,a.jsx)(o.pj,{className:"py-0.5 ".concat("actions"===e.column.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)] z-20 w-[120px] ml-8":""," ").concat((null===(t=e.column.columnDef.meta)||void 0===t?void 0:t.className)||""),style:{width:"actions"===e.column.id?120:e.column.getSize(),position:"actions"===e.column.id?"sticky":"relative",right:"actions"===e.column.id?0:"auto"},children:(0,s.ie)(e.column.columnDef.cell,e.getContext())},e.id)})},e.id)):(0,a.jsx)(o.SC,{children:(0,a.jsx)(o.pj,{colSpan:n.length,className:"h-8 text-center",children:(0,a.jsx)("div",{className:"text-center text-gray-500",children:(0,a.jsx)("p",{children:"No models found"})})})})})]})})})})}},65373:function(e,t,n){n.d(t,{Z:function(){return _}});var a=n(57437),s=n(27648),r=n(2265),i=n(89970),o=n(80795),l=n(19250),c=n(15883),d=n(46346),m=n(57400),p=n(91870),u=n(40428),g=n(3914);let x=async e=>{if(!e)return null;try{return await (0,l.getProxyUISettings)(e)}catch(e){return console.error("Error fetching proxy settings:",e),null}};var h=n(69734),f=n(29488),_=e=>{let{userID:t,userEmail:n,userRole:_,premiumUser:b,proxySettings:v,setProxySettings:j,accessToken:y,isPublicPage:N=!1}=e,w=(0,l.getProxyBaseUrl)(),[A,I]=(0,r.useState)(""),{logoUrl:S}=(0,h.F)();(0,r.useEffect)(()=>{(async()=>{if(y){let e=await x(y);console.log("response from fetchProxySettings",e),e&&j(e)}})()},[y]),(0,r.useEffect)(()=>{I((null==v?void 0:v.PROXY_LOGOUT_URL)||"")},[v]);let k=[{key:"user-info",label:(0,a.jsxs)("div",{className:"px-3 py-3 border-b border-gray-100",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between mb-3",children:[(0,a.jsxs)("div",{className:"flex items-center",children:[(0,a.jsx)(c.Z,{className:"mr-2 text-gray-700"}),(0,a.jsx)("span",{className:"text-sm font-semibold text-gray-900",children:t})]}),b?(0,a.jsx)(i.Z,{title:"Premium User",placement:"left",children:(0,a.jsxs)("div",{className:"flex items-center bg-gradient-to-r from-amber-500 to-yellow-500 text-white px-2 py-0.5 rounded-full cursor-help",children:[(0,a.jsx)(d.Z,{className:"mr-1 text-xs"}),(0,a.jsx)("span",{className:"text-xs font-medium",children:"Premium"})]})}):(0,a.jsx)(i.Z,{title:"Upgrade to Premium for advanced features",placement:"left",children:(0,a.jsxs)("div",{className:"flex items-center bg-gray-100 text-gray-500 px-2 py-0.5 rounded-full cursor-help",children:[(0,a.jsx)(d.Z,{className:"mr-1 text-xs"}),(0,a.jsx)("span",{className:"text-xs font-medium",children:"Standard"})]})})]}),(0,a.jsxs)("div",{className:"space-y-2",children:[(0,a.jsxs)("div",{className:"flex items-center text-sm",children:[(0,a.jsx)(m.Z,{className:"mr-2 text-gray-400 text-xs"}),(0,a.jsx)("span",{className:"text-gray-500 text-xs",children:"Role"}),(0,a.jsx)("span",{className:"ml-auto text-gray-700 font-medium",children:_})]}),(0,a.jsxs)("div",{className:"flex items-center text-sm",children:[(0,a.jsx)(p.Z,{className:"mr-2 text-gray-400 text-xs"}),(0,a.jsx)("span",{className:"text-gray-500 text-xs",children:"Email"}),(0,a.jsx)("span",{className:"ml-auto text-gray-700 font-medium truncate max-w-[150px]",title:n||"Unknown",children:n||"Unknown"})]})]})]})},{key:"logout",label:(0,a.jsxs)("div",{className:"flex items-center py-2 px-3 hover:bg-gray-50 rounded-md mx-1 my-1",onClick:()=>{(0,g.b)(),(0,f.xd)(),window.location.href=A},children:[(0,a.jsx)(u.Z,{className:"mr-3 text-gray-600"}),(0,a.jsx)("span",{className:"text-gray-800",children:"Logout"})]})}];return(0,a.jsx)("nav",{className:"bg-white border-b border-gray-200 sticky top-0 z-10",children:(0,a.jsx)("div",{className:"w-full",children:(0,a.jsxs)("div",{className:"flex items-center h-12 px-4",children:[(0,a.jsx)("div",{className:"flex items-center flex-shrink-0",children:(0,a.jsx)(s.default,{href:"/",className:"flex items-center",children:(0,a.jsx)("img",{src:S||"".concat(w,"/get_image"),alt:"LiteLLM Brand",className:"h-8 w-auto"})})}),(0,a.jsxs)("div",{className:"flex items-center space-x-5 ml-auto",children:[(0,a.jsx)("a",{href:"https://docs.litellm.ai/docs/",target:"_blank",rel:"noopener noreferrer",className:"text-[13px] text-gray-600 hover:text-gray-900 transition-colors",children:"Docs"}),!N&&(0,a.jsx)(o.Z,{menu:{items:k,className:"min-w-[200px]",style:{padding:"8px",marginTop:"8px",borderRadius:"12px",boxShadow:"0 4px 24px rgba(0, 0, 0, 0.08)"}},overlayStyle:{minWidth:"200px"},children:(0,a.jsxs)("button",{className:"inline-flex items-center text-[13px] text-gray-600 hover:text-gray-900 transition-colors",children:["User",(0,a.jsx)("svg",{className:"ml-1 w-4 h-4 text-gray-500",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,a.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1.5,d:"M19 9l-7 7-7-7"})})]})})]})]})})})}},42673:function(e,t,n){var a,s;n.d(t,{Cl:function(){return a},bK:function(){return d},cd:function(){return o},dr:function(){return l},fK:function(){return r},ph:function(){return c}}),n(2265),(s=a||(a={})).AIML="AI/ML API",s.Bedrock="Amazon Bedrock",s.Anthropic="Anthropic",s.AssemblyAI="AssemblyAI",s.SageMaker="AWS SageMaker",s.Azure="Azure",s.Azure_AI_Studio="Azure AI Foundry (Studio)",s.Cerebras="Cerebras",s.Cohere="Cohere",s.Databricks="Databricks",s.DeepInfra="DeepInfra",s.Deepgram="Deepgram",s.Deepseek="Deepseek",s.ElevenLabs="ElevenLabs",s.FireworksAI="Fireworks AI",s.Google_AI_Studio="Google AI Studio",s.GradientAI="GradientAI",s.Groq="Groq",s.Hosted_Vllm="vllm",s.JinaAI="Jina AI",s.MistralAI="Mistral AI",s.Ollama="Ollama",s.OpenAI="OpenAI",s.OpenAI_Compatible="OpenAI-Compatible Endpoints (Together AI, etc.)",s.OpenAI_Text="OpenAI Text Completion",s.OpenAI_Text_Compatible="OpenAI-Compatible Text Completion Models (Together AI, etc.)",s.Openrouter="Openrouter",s.Perplexity="Perplexity",s.Sambanova="Sambanova",s.TogetherAI="TogetherAI",s.Triton="Triton",s.Vertex_AI="Vertex AI (Anthropic, Gemini, etc.)",s.VolcEngine="VolcEngine",s.Voyage="Voyage AI",s.xAI="xAI";let r={AIML:"aiml",OpenAI:"openai",OpenAI_Text:"text-completion-openai",Azure:"azure",Azure_AI_Studio:"azure_ai",Anthropic:"anthropic",Google_AI_Studio:"gemini",Bedrock:"bedrock",Groq:"groq",MistralAI:"mistral",Cohere:"cohere",OpenAI_Compatible:"openai",OpenAI_Text_Compatible:"text-completion-openai",Vertex_AI:"vertex_ai",Databricks:"databricks",xAI:"xai",Deepseek:"deepseek",Ollama:"ollama",AssemblyAI:"assemblyai",Cerebras:"cerebras",Sambanova:"sambanova",Perplexity:"perplexity",TogetherAI:"together_ai",Openrouter:"openrouter",FireworksAI:"fireworks_ai",GradientAI:"gradient_ai",Triton:"triton",Deepgram:"deepgram",ElevenLabs:"elevenlabs",SageMaker:"sagemaker_chat",Voyage:"voyage",JinaAI:"jina_ai",VolcEngine:"volcengine",DeepInfra:"deepinfra",Hosted_Vllm:"hosted_vllm"},i="/ui/assets/logos/",o={"AI/ML API":"".concat(i,"aiml_api.svg"),Anthropic:"".concat(i,"anthropic.svg"),AssemblyAI:"".concat(i,"assemblyai_small.png"),Azure:"".concat(i,"microsoft_azure.svg"),"Azure AI Foundry (Studio)":"".concat(i,"microsoft_azure.svg"),"Amazon Bedrock":"".concat(i,"bedrock.svg"),"AWS SageMaker":"".concat(i,"bedrock.svg"),Cerebras:"".concat(i,"cerebras.svg"),Cohere:"".concat(i,"cohere.svg"),Databricks:"".concat(i,"databricks.svg"),Deepseek:"".concat(i,"deepseek.svg"),"Fireworks AI":"".concat(i,"fireworks.svg"),Groq:"".concat(i,"groq.svg"),"Google AI Studio":"".concat(i,"google.svg"),vllm:"".concat(i,"vllm.png"),"Mistral AI":"".concat(i,"mistral.svg"),Ollama:"".concat(i,"ollama.svg"),OpenAI:"".concat(i,"openai_small.svg"),"OpenAI Text Completion":"".concat(i,"openai_small.svg"),"OpenAI-Compatible Text Completion Models (Together AI, etc.)":"".concat(i,"openai_small.svg"),"OpenAI-Compatible Endpoints (Together AI, etc.)":"".concat(i,"openai_small.svg"),Openrouter:"".concat(i,"openrouter.svg"),Perplexity:"".concat(i,"perplexity-ai.svg"),Sambanova:"".concat(i,"sambanova.svg"),TogetherAI:"".concat(i,"togetherai.svg"),"Vertex AI (Anthropic, Gemini, etc.)":"".concat(i,"google.svg"),xAI:"".concat(i,"xai.svg"),GradientAI:"".concat(i,"gradientai.svg"),Triton:"".concat(i,"nvidia_triton.png"),Deepgram:"".concat(i,"deepgram.png"),ElevenLabs:"".concat(i,"elevenlabs.png"),"Voyage AI":"".concat(i,"voyage.webp"),"Jina AI":"".concat(i,"jina.png"),VolcEngine:"".concat(i,"volcengine.png"),DeepInfra:"".concat(i,"deepinfra.png")},l=e=>{if(!e)return{logo:"",displayName:"-"};if("gemini"===e.toLowerCase()){let e="Google AI Studio";return{logo:o[e],displayName:e}}let t=Object.keys(r).find(t=>r[t].toLowerCase()===e.toLowerCase());if(!t)return{logo:"",displayName:e};let n=a[t];return{logo:o[n],displayName:n}},c=e=>{if("AI/ML API"===e)return"aiml/flux-pro/v1.1";if("Vertex AI (Anthropic, Gemini, etc.)"===e)return"gemini-pro";if("Anthropic"==e||"Amazon Bedrock"==e)return"claude-3-opus";if("AWS SageMaker"==e)return"sagemaker/jumpstart-dft-meta-textgeneration-llama-2-7b";if("Google AI Studio"==e)return"gemini-pro";if("Azure AI Foundry (Studio)"==e)return"azure_ai/command-r-plus";else if("Azure"==e)return"azure/my-deployment";else if("Voyage AI"==e)return"voyage/";else if("Jina AI"==e)return"jina_ai/";else if("VolcEngine"==e)return"volcengine/";else if("DeepInfra"==e)return"deepinfra/";else return"gpt-3.5-turbo"},d=(e,t)=>{console.log("Provider key: ".concat(e));let n=r[e];console.log("Provider mapped to: ".concat(n));let a=[];return e&&"object"==typeof t&&(Object.entries(t).forEach(e=>{let[t,s]=e;null!==s&&"object"==typeof s&&"litellm_provider"in s&&(s.litellm_provider===n||s.litellm_provider.includes(n))&&a.push(t)}),"Cohere"==e&&(console.log("Adding cohere chat models"),Object.entries(t).forEach(e=>{let[t,n]=e;null!==n&&"object"==typeof n&&"litellm_provider"in n&&"cohere_chat"===n.litellm_provider&&a.push(t)})),"AWS SageMaker"==e&&(console.log("Adding sagemaker chat models"),Object.entries(t).forEach(e=>{let[t,n]=e;null!==n&&"object"==typeof n&&"litellm_provider"in n&&"sagemaker_chat"===n.litellm_provider&&a.push(t)}))),a}},72162:function(e,t,n){var a=n(57437),s=n(2265),r=n(19250),i=n(8048),o=n(36724),l=n(89970),c=n(3810),d=n(52787),m=n(82680),p=n(3477),u=n(17732),g=n(33245),x=n(78867),h=n(88658),f=n(49817),_=n(42673),b=n(65373),v=n(69734),j=n(9114);t.Z=e=>{var t,n;let{accessToken:y}=e,[N,w]=(0,s.useState)(null),[A,I]=(0,s.useState)("LiteLLM Gateway"),[S,k]=(0,s.useState)(null),[C,E]=(0,s.useState)(""),[M,O]=(0,s.useState)({}),[T,D]=(0,s.useState)(!0),[z,P]=(0,s.useState)(""),[L,Z]=(0,s.useState)([]),[G,R]=(0,s.useState)([]),[H,F]=(0,s.useState)([]),[K,V]=(0,s.useState)("I'm alive! ✓"),[U,W]=(0,s.useState)(!1),[q,J]=(0,s.useState)(null),[B,Y]=(0,s.useState)({}),$=(0,s.useRef)(null);(0,s.useEffect)(()=>{let e=async()=>{try{D(!0);let e=await (0,r.modelHubPublicModelsCall)();console.log("ModelHubData:",e),w(e)}catch(e){console.error("There was an error fetching the public model data",e),V("Service unavailable")}finally{D(!1)}};(async()=>{let e=await (0,r.getPublicModelHubInfo)();console.log("Public Model Hub Info:",e),I(e.docs_title),k(e.custom_docs_description),E(e.litellm_version),O(e.useful_links||{})})(),e()},[]),(0,s.useEffect)(()=>{},[z,L,G,H]);let X=(0,s.useMemo)(()=>{if(!N)return[];let e=N;if(z.trim()){let t=z.toLowerCase(),n=t.split(/\s+/),a=N.filter(e=>{let a=e.model_group.toLowerCase();return!!a.includes(t)||n.every(e=>a.includes(e))});a.length>0&&(e=a.sort((e,n)=>{let a=e.model_group.toLowerCase(),s=n.model_group.toLowerCase(),r=a===t?1e3:0,i=s===t?1e3:0,o=a.startsWith(t)?100:0,l=s.startsWith(t)?100:0,c=t.split(/\s+/).every(e=>a.includes(e))?50:0,d=t.split(/\s+/).every(e=>s.includes(e))?50:0,m=a.length;return i+l+d+(1e3-s.length)-(r+o+c+(1e3-m))}))}return e.filter(e=>{let t=0===L.length||L.some(t=>e.providers.includes(t)),n=0===G.length||G.includes(e.mode||""),a=0===H.length||Object.entries(e).filter(e=>{let[t,n]=e;return t.startsWith("supports_")&&!0===n}).some(e=>{let[t]=e,n=t.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ");return H.includes(n)});return t&&n&&a})},[N,z,L,G,H]),Q=e=>{J(e),W(!0)},ee=e=>{navigator.clipboard.writeText(e),j.Z.success("Copied to clipboard!")},et=e=>e.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" "),en=e=>Object.entries(e).filter(e=>{let[t,n]=e;return t.startsWith("supports_")&&!0===n}).map(e=>{let[t]=e;return t}),ea=e=>"$".concat((1e6*e).toFixed(4)),es=e=>e?e>=1e3?"".concat((e/1e3).toFixed(0),"K"):e.toString():"N/A",er=(e,t)=>{let n=[];return e&&n.push("RPM: ".concat(e.toLocaleString())),t&&n.push("TPM: ".concat(t.toLocaleString())),n.length>0?n.join(", "):"N/A"};return(0,a.jsx)(v.f,{accessToken:y,children:(0,a.jsxs)("div",{className:"min-h-screen bg-white",children:[(0,a.jsx)(b.Z,{userID:null,userEmail:null,userRole:null,premiumUser:!1,setProxySettings:Y,proxySettings:B,accessToken:y||null,isPublicPage:!0}),(0,a.jsxs)("div",{className:"w-full px-8 py-12",children:[(0,a.jsxs)(o.Zb,{className:"mb-10 p-8 bg-white border border-gray-200 rounded-lg shadow-sm",children:[(0,a.jsx)(o.Dx,{className:"text-2xl font-semibold mb-6 text-gray-900",children:"About"}),(0,a.jsx)("p",{className:"text-gray-700 mb-6 text-base leading-relaxed",children:S||"Proxy Server to call 100+ LLMs in the OpenAI format."}),(0,a.jsx)("div",{className:"flex items-center space-x-3 text-sm text-gray-600",children:(0,a.jsxs)("span",{className:"flex items-center",children:[(0,a.jsx)("span",{className:"w-4 h-4 mr-2",children:"\uD83D\uDD27"}),"Built with litellm: v",C]})})]}),M&&Object.keys(M).length>0&&(0,a.jsxs)(o.Zb,{className:"mb-10 p-8 bg-white border border-gray-200 rounded-lg shadow-sm",children:[(0,a.jsx)(o.Dx,{className:"text-2xl font-semibold mb-6 text-gray-900",children:"Useful Links"}),(0,a.jsx)("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6",children:Object.entries(M||{}).map(e=>{let[t,n]=e;return(0,a.jsxs)("button",{onClick:()=>window.open(n,"_blank"),className:"flex items-center space-x-3 text-blue-600 hover:text-blue-800 transition-colors p-3 rounded-lg hover:bg-blue-50 border border-gray-200",children:[(0,a.jsx)(p.Z,{className:"w-4 h-4"}),(0,a.jsx)(o.xv,{className:"text-sm font-medium",children:t})]},t)})})]}),(0,a.jsxs)(o.Zb,{className:"mb-10 p-8 bg-white border border-gray-200 rounded-lg shadow-sm",children:[(0,a.jsx)(o.Dx,{className:"text-2xl font-semibold mb-6 text-gray-900",children:"Health and Endpoint Status"}),(0,a.jsx)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-6",children:(0,a.jsxs)(o.xv,{className:"text-green-600 font-medium text-sm",children:["Service status: ",K]})})]}),(0,a.jsxs)(o.Zb,{className:"p-8 bg-white border border-gray-200 rounded-lg shadow-sm",children:[(0,a.jsx)("div",{className:"flex justify-between items-center mb-8",children:(0,a.jsx)(o.Dx,{className:"text-2xl font-semibold text-gray-900",children:"Available Models"})}),(0,a.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200",children:[(0,a.jsxs)("div",{children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2 mb-3",children:[(0,a.jsx)(o.xv,{className:"text-sm font-medium text-gray-700",children:"Search Models:"}),(0,a.jsx)(l.Z,{title:"Smart search with relevance ranking - finds models containing your search terms, ranked by relevance. Try searching 'xai grok-4', 'claude-4', 'gpt-4', or 'sonnet'",placement:"top",children:(0,a.jsx)(g.Z,{className:"w-4 h-4 text-gray-400 cursor-help"})})]}),(0,a.jsxs)("div",{className:"relative",children:[(0,a.jsx)(u.Z,{className:"w-4 h-4 text-gray-400 absolute left-3 top-1/2 transform -translate-y-1/2"}),(0,a.jsx)("input",{type:"text",placeholder:"Search model names... (smart search enabled)",value:z,onChange:e=>P(e.target.value),className:"border border-gray-300 rounded-lg pl-10 pr-4 py-2 w-full text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white"})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-sm font-medium mb-3 text-gray-700",children:"Provider:"}),(0,a.jsx)(d.default,{mode:"multiple",value:L,onChange:e=>Z(e),placeholder:"Select providers",className:"w-full",size:"large",allowClear:!0,optionRender:e=>{let{logo:t}=(0,_.dr)(e.value);return(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[t&&(0,a.jsx)("img",{src:t,alt:e.label,className:"w-5 h-5 flex-shrink-0 object-contain",onError:e=>{e.target.style.display="none"}}),(0,a.jsx)("span",{className:"capitalize",children:e.label})]})},children:N&&(e=>{let t=new Set;return e.forEach(e=>{e.providers.forEach(e=>t.add(e))}),Array.from(t)})(N).map(e=>(0,a.jsx)(d.default.Option,{value:e,children:e},e))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-sm font-medium mb-3 text-gray-700",children:"Mode:"}),(0,a.jsx)(d.default,{mode:"multiple",value:G,onChange:e=>R(e),placeholder:"Select modes",className:"w-full",size:"large",allowClear:!0,children:N&&(e=>{let t=new Set;return e.forEach(e=>{e.mode&&t.add(e.mode)}),Array.from(t)})(N).map(e=>(0,a.jsx)(d.default.Option,{value:e,children:e},e))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-sm font-medium mb-3 text-gray-700",children:"Features:"}),(0,a.jsx)(d.default,{mode:"multiple",value:H,onChange:e=>F(e),placeholder:"Select features",className:"w-full",size:"large",allowClear:!0,children:N&&(e=>{let t=new Set;return e.forEach(e=>{Object.entries(e).filter(e=>{let[t,n]=e;return t.startsWith("supports_")&&!0===n}).forEach(e=>{let[n]=e,a=n.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ");t.add(a)})}),Array.from(t).sort()})(N).map(e=>(0,a.jsx)(d.default.Option,{value:e,children:e},e))})]})]}),(0,a.jsx)(i.C,{columns:[{header:"Model Name",accessorKey:"model_group",enableSorting:!0,cell:e=>{let{row:t}=e;return(0,a.jsx)("div",{className:"overflow-hidden",children:(0,a.jsx)(l.Z,{title:t.original.model_group,children:(0,a.jsx)(o.zx,{size:"xs",variant:"light",className:"font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left",onClick:()=>Q(t.original),children:t.original.model_group})})})},size:150},{header:"Providers",accessorKey:"providers",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original.providers;return(0,a.jsx)("div",{className:"flex flex-wrap gap-1",children:n.map(e=>{let{logo:t}=(0,_.dr)(e);return(0,a.jsxs)("div",{className:"flex items-center space-x-1 px-2 py-1 bg-gray-100 rounded text-xs",children:[t&&(0,a.jsx)("img",{src:t,alt:e,className:"w-3 h-3 flex-shrink-0 object-contain",onError:e=>{e.target.style.display="none"}}),(0,a.jsx)("span",{className:"capitalize",children:e})]},e)})})},size:120},{header:"Mode",accessorKey:"mode",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original.mode;return(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)("span",{children:(e=>{switch(null==e?void 0:e.toLowerCase()){case"chat":return"\uD83D\uDCAC";case"rerank":return"\uD83D\uDD04";case"embedding":return"\uD83D\uDCC4";default:return"\uD83E\uDD16"}})(n||"")}),(0,a.jsx)(o.xv,{children:n||"Chat"})]})},size:100},{header:"Max Input",accessorKey:"max_input_tokens",enableSorting:!0,cell:e=>{let{row:t}=e;return(0,a.jsx)(o.xv,{className:"text-center",children:es(t.original.max_input_tokens)})},size:100,meta:{className:"text-center"}},{header:"Max Output",accessorKey:"max_output_tokens",enableSorting:!0,cell:e=>{let{row:t}=e;return(0,a.jsx)(o.xv,{className:"text-center",children:es(t.original.max_output_tokens)})},size:100,meta:{className:"text-center"}},{header:"Input $/1M",accessorKey:"input_cost_per_token",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original.input_cost_per_token;return(0,a.jsx)(o.xv,{className:"text-center",children:n?ea(n):"Free"})},size:100,meta:{className:"text-center"}},{header:"Output $/1M",accessorKey:"output_cost_per_token",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original.output_cost_per_token;return(0,a.jsx)(o.xv,{className:"text-center",children:n?ea(n):"Free"})},size:100,meta:{className:"text-center"}},{header:"Features",accessorKey:"supports_vision",enableSorting:!1,cell:e=>{let{row:t}=e,n=Object.entries(t.original).filter(e=>{let[t,n]=e;return t.startsWith("supports_")&&!0===n}).map(e=>{let[t]=e;return et(t)});return 0===n.length?(0,a.jsx)(o.xv,{className:"text-gray-400",children:"-"}):1===n.length?(0,a.jsx)("div",{className:"h-6 flex items-center",children:(0,a.jsx)(c.Z,{color:"blue",className:"text-xs",children:n[0]})}):(0,a.jsxs)("div",{className:"h-6 flex items-center space-x-1",children:[(0,a.jsx)(c.Z,{color:"blue",className:"text-xs",children:n[0]}),(0,a.jsx)(l.Z,{title:(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsx)("div",{className:"font-medium",children:"All Features:"}),n.map((e,t)=>(0,a.jsxs)("div",{className:"text-xs",children:["• ",e]},t))]}),trigger:"click",placement:"topLeft",children:(0,a.jsxs)("span",{className:"text-xs text-blue-600 cursor-pointer hover:text-blue-800 hover:underline",onClick:e=>e.stopPropagation(),children:["+",n.length-1]})})]})},size:120},{header:"Limits",accessorKey:"rpm",enableSorting:!0,cell:e=>{let{row:t}=e,n=t.original;return(0,a.jsx)(o.xv,{className:"text-xs text-gray-600",children:er(n.rpm,n.tpm)})},size:150}],data:X,isLoading:T,table:$,defaultSorting:[{id:"model_group",desc:!1}]}),(0,a.jsx)("div",{className:"mt-8 text-center",children:(0,a.jsxs)(o.xv,{className:"text-sm text-gray-600",children:["Showing ",X.length," of ",(null==N?void 0:N.length)||0," models"]})})]})]}),(0,a.jsx)(m.Z,{title:(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)("span",{children:(null==q?void 0:q.model_group)||"Model Details"}),q&&(0,a.jsx)(l.Z,{title:"Copy model name",children:(0,a.jsx)(x.Z,{onClick:()=>ee(q.model_group),className:"cursor-pointer text-gray-500 hover:text-blue-500 w-4 h-4"})})]}),width:1e3,open:U,footer:null,onOk:()=>{W(!1),J(null)},onCancel:()=>{W(!1),J(null)},children:q&&(0,a.jsxs)("div",{className:"space-y-6",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Model Overview"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Model Name:"}),(0,a.jsx)(o.xv,{children:q.model_group})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Mode:"}),(0,a.jsx)(o.xv,{children:q.mode||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Providers:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:q.providers.map(e=>{let{logo:t}=(0,_.dr)(e);return(0,a.jsx)(c.Z,{color:"blue",children:(0,a.jsxs)("div",{className:"flex items-center space-x-1",children:[t&&(0,a.jsx)("img",{src:t,alt:e,className:"w-3 h-3 flex-shrink-0 object-contain",onError:e=>{e.target.style.display="none"}}),(0,a.jsx)("span",{className:"capitalize",children:e})]})},e)})})]})]}),q.model_group.includes("*")&&(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-4 mb-4",children:(0,a.jsxs)("div",{className:"flex items-start space-x-2",children:[(0,a.jsx)(g.Z,{className:"w-4 h-4 text-blue-600 mt-0.5 flex-shrink-0"}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium text-blue-900 mb-2",children:"Wildcard Routing"}),(0,a.jsxs)(o.xv,{className:"text-sm text-blue-800 mb-2",children:["This model uses wildcard routing. You can pass any value where you see the ",(0,a.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded text-xs",children:"*"})," symbol."]}),(0,a.jsxs)(o.xv,{className:"text-sm text-blue-800",children:["For example, with ",(0,a.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded text-xs",children:q.model_group}),", you can use any string (",(0,a.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded text-xs",children:q.model_group.replace("*","my-custom-value")}),") that matches this pattern."]})]})]})})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Token & Cost Information"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Max Input Tokens:"}),(0,a.jsx)(o.xv,{children:(null===(t=q.max_input_tokens)||void 0===t?void 0:t.toLocaleString())||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Max Output Tokens:"}),(0,a.jsx)(o.xv,{children:(null===(n=q.max_output_tokens)||void 0===n?void 0:n.toLocaleString())||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Input Cost per 1M Tokens:"}),(0,a.jsx)(o.xv,{children:q.input_cost_per_token?ea(q.input_cost_per_token):"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Output Cost per 1M Tokens:"}),(0,a.jsx)(o.xv,{children:q.output_cost_per_token?ea(q.output_cost_per_token):"Not specified"})]})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Capabilities"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:(()=>{let e=en(q),t=["green","blue","purple","orange","red","yellow"];return 0===e.length?(0,a.jsx)(o.xv,{className:"text-gray-500",children:"No special capabilities listed"}):e.map((e,n)=>(0,a.jsx)(c.Z,{color:t[n%t.length],children:et(e)},e))})()})]}),(q.tpm||q.rpm)&&(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Rate Limits"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[q.tpm&&(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Tokens per Minute:"}),(0,a.jsx)(o.xv,{children:q.tpm.toLocaleString()})]}),q.rpm&&(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"font-medium",children:"Requests per Minute:"}),(0,a.jsx)(o.xv,{children:q.rpm.toLocaleString()})]})]})]}),q.supported_openai_params&&(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Supported OpenAI Parameters"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:q.supported_openai_params.map(e=>(0,a.jsx)(c.Z,{color:"green",children:e},e))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(o.xv,{className:"text-lg font-semibold mb-4",children:"Usage Example"}),(0,a.jsx)("div",{className:"bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto",children:(0,a.jsx)("pre",{className:"text-sm",children:(0,h.L)({apiKeySource:"custom",accessToken:null,apiKey:"your_api_key",inputMessage:"Hello, how are you?",chatHistory:[{role:"user",content:"Hello, how are you?",isImage:!1}],selectedTags:[],selectedVectorStores:[],selectedGuardrails:[],endpointType:(0,f.vf)(q.mode||"chat"),selectedModel:q.model_group,selectedSdk:"openai"})})}),(0,a.jsx)("div",{className:"mt-2 text-right",children:(0,a.jsx)("button",{onClick:()=>{ee((0,h.L)({apiKeySource:"custom",accessToken:null,apiKey:"your_api_key",inputMessage:"Hello, how are you?",chatHistory:[{role:"user",content:"Hello, how are you?",isImage:!1}],selectedTags:[],selectedVectorStores:[],selectedGuardrails:[],endpointType:(0,f.vf)(q.mode||"chat"),selectedModel:q.model_group,selectedSdk:"openai"}))},className:"text-sm text-blue-600 hover:text-blue-800 cursor-pointer",children:"Copy to clipboard"})})]})]})})]})})}},69734:function(e,t,n){n.d(t,{F:function(){return o},f:function(){return l}});var a=n(57437),s=n(2265),r=n(19250);let i=(0,s.createContext)(void 0),o=()=>{let e=(0,s.useContext)(i);if(!e)throw Error("useTheme must be used within a ThemeProvider");return e},l=e=>{let{children:t,accessToken:n}=e,[o,l]=(0,s.useState)(null);return(0,s.useEffect)(()=>{(async()=>{if(n)try{let t=(0,r.getProxyBaseUrl)(),a=await fetch(t?"".concat(t,"/get/ui_theme_settings"):"/get/ui_theme_settings",{method:"GET",headers:{Authorization:"Bearer ".concat(n),"Content-Type":"application/json"}});if(a.ok){var e;let t=await a.json();(null===(e=t.values)||void 0===e?void 0:e.logo_url)&&l(t.values.logo_url)}}catch(e){console.warn("Failed to load logo settings from backend:",e)}})()},[n]),(0,a.jsx)(i.Provider,{value:{logoUrl:o,setLogoUrl:l},children:t})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/220-1c8d82f7ce7658c4.js b/litellm/proxy/_experimental/out/_next/static/chunks/220-1c8d82f7ce7658c4.js new file mode 100644 index 00000000000..206acc40d24 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/220-1c8d82f7ce7658c4.js @@ -0,0 +1,12 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[220],{12660:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M917.7 148.8l-42.4-42.4c-1.6-1.6-3.6-2.3-5.7-2.3s-4.1.8-5.7 2.3l-76.1 76.1a199.27 199.27 0 00-112.1-34.3c-51.2 0-102.4 19.5-141.5 58.6L432.3 308.7a8.03 8.03 0 000 11.3L704 591.7c1.6 1.6 3.6 2.3 5.7 2.3 2 0 4.1-.8 5.7-2.3l101.9-101.9c68.9-69 77-175.7 24.3-253.5l76.1-76.1c3.1-3.2 3.1-8.3 0-11.4zM769.1 441.7l-59.4 59.4-186.8-186.8 59.4-59.4c24.9-24.9 58.1-38.7 93.4-38.7 35.3 0 68.4 13.7 93.4 38.7 24.9 24.9 38.7 58.1 38.7 93.4 0 35.3-13.8 68.4-38.7 93.4zm-190.2 105a8.03 8.03 0 00-11.3 0L501 613.3 410.7 523l66.7-66.7c3.1-3.1 3.1-8.2 0-11.3L441 408.6a8.03 8.03 0 00-11.3 0L363 475.3l-43-43a7.85 7.85 0 00-5.7-2.3c-2 0-4.1.8-5.7 2.3L206.8 534.2c-68.9 69-77 175.7-24.3 253.5l-76.1 76.1a8.03 8.03 0 000 11.3l42.4 42.4c1.6 1.6 3.6 2.3 5.7 2.3s4.1-.8 5.7-2.3l76.1-76.1c33.7 22.9 72.9 34.3 112.1 34.3 51.2 0 102.4-19.5 141.5-58.6l101.9-101.9c3.1-3.1 3.1-8.2 0-11.3l-43-43 66.7-66.7c3.1-3.1 3.1-8.2 0-11.3l-36.6-36.2zM441.7 769.1a131.32 131.32 0 01-93.4 38.7c-35.3 0-68.4-13.7-93.4-38.7a131.32 131.32 0 01-38.7-93.4c0-35.3 13.7-68.4 38.7-93.4l59.4-59.4 186.8 186.8-59.4 59.4z"}}]},name:"api",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},88009:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"}}]},name:"appstore",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},79276:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"}}]},name:"arrow-up",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},37527:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M894 462c30.9 0 43.8-39.7 18.7-58L530.8 126.2a31.81 31.81 0 00-37.6 0L111.3 404c-25.1 18.2-12.2 58 18.8 58H192v374h-72c-4.4 0-8 3.6-8 8v52c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-52c0-4.4-3.6-8-8-8h-72V462h62zM512 196.7l271.1 197.2H240.9L512 196.7zM264 462h117v374H264V462zm189 0h117v374H453V462zm307 374H642V462h118v374z"}}]},name:"bank",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},9775:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm-600-80h56c4.4 0 8-3.6 8-8V560c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v144c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V384c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v320c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V462c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v242c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V304c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v400c0 4.4 3.6 8 8 8z"}}]},name:"bar-chart",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},11429:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M766.4 744.3c43.7 0 79.4-36.2 79.4-80.5 0-53.5-79.4-140.8-79.4-140.8S687 610.3 687 663.8c0 44.3 35.7 80.5 79.4 80.5zm-377.1-44.1c7.1 7.1 18.6 7.1 25.6 0l256.1-256c7.1-7.1 7.1-18.6 0-25.6l-256-256c-.6-.6-1.3-1.2-2-1.7l-78.2-78.2a9.11 9.11 0 00-12.8 0l-48 48a9.11 9.11 0 000 12.8l67.2 67.2-207.8 207.9c-7.1 7.1-7.1 18.6 0 25.6l255.9 256zm12.9-448.6l178.9 178.9H223.4l178.8-178.9zM904 816H120c-4.4 0-8 3.6-8 8v80c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-80c0-4.4-3.6-8-8-8z"}}]},name:"bg-colors",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},68208:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M856 376H648V168c0-8.8-7.2-16-16-16H168c-8.8 0-16 7.2-16 16v464c0 8.8 7.2 16 16 16h208v208c0 8.8 7.2 16 16 16h464c8.8 0 16-7.2 16-16V392c0-8.8-7.2-16-16-16zm-480 16v188H220V220h360v156H392c-8.8 0-16 7.2-16 16zm204 52v136H444V444h136zm224 360H444V648h188c8.8 0 16-7.2 16-16V444h156v360z"}}]},name:"block",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},83322:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M632 888H392c-4.4 0-8 3.6-8 8v32c0 17.7 14.3 32 32 32h192c17.7 0 32-14.3 32-32v-32c0-4.4-3.6-8-8-8zM512 64c-181.1 0-328 146.9-328 328 0 121.4 66 227.4 164 284.1V792c0 17.7 14.3 32 32 32h264c17.7 0 32-14.3 32-32V676.1c98-56.7 164-162.7 164-284.1 0-181.1-146.9-328-328-328zm127.9 549.8L604 634.6V752H420V634.6l-35.9-20.8C305.4 568.3 256 484.5 256 392c0-141.4 114.6-256 256-256s256 114.6 256 256c0 92.5-49.4 176.3-128.1 221.8z"}}]},name:"bulb",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},49634:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"}}]},name:"calendar",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},83669:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M699 353h-46.9c-10.2 0-19.9 4.9-25.9 13.3L469 584.3l-71.2-98.8c-6-8.3-15.6-13.3-25.9-13.3H325c-6.5 0-10.3 7.4-6.5 12.7l124.6 172.8a31.8 31.8 0 0051.7 0l210.6-292c3.9-5.3.1-12.7-6.4-12.7z"}},{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}}]},name:"check-circle",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},26430:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"defs",attrs:{},children:[{tag:"style",attrs:{}}]},{tag:"path",attrs:{d:"M899.1 869.6l-53-305.6H864c14.4 0 26-11.6 26-26V346c0-14.4-11.6-26-26-26H618V138c0-14.4-11.6-26-26-26H432c-14.4 0-26 11.6-26 26v182H160c-14.4 0-26 11.6-26 26v192c0 14.4 11.6 26 26 26h17.9l-53 305.6a25.95 25.95 0 0025.6 30.4h723c1.5 0 3-.1 4.4-.4a25.88 25.88 0 0021.2-30zM204 390h272V182h72v208h272v104H204V390zm468 440V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H416V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H202.8l45.1-260H776l45.1 260H672z"}}]},name:"clear",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},5540:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}},{tag:"path",attrs:{d:"M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"}}]},name:"clock-circle",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},11894:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M516 673c0 4.4 3.4 8 7.5 8h185c4.1 0 7.5-3.6 7.5-8v-48c0-4.4-3.4-8-7.5-8h-185c-4.1 0-7.5 3.6-7.5 8v48zm-194.9 6.1l192-161c3.8-3.2 3.8-9.1 0-12.3l-192-160.9A7.95 7.95 0 00308 351v62.7c0 2.4 1 4.6 2.9 6.1L420.7 512l-109.8 92.2a8.1 8.1 0 00-2.9 6.1V673c0 6.8 7.9 10.5 13.1 6.1zM880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-40 728H184V184h656v656z"}}]},name:"code",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},44625:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M832 64H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32zm-600 72h560v208H232V136zm560 480H232V408h560v208zm0 272H232V680h560v208zM304 240a40 40 0 1080 0 40 40 0 10-80 0zm0 272a40 40 0 1080 0 40 40 0 10-80 0zm0 272a40 40 0 1080 0 40 40 0 10-80 0z"}}]},name:"database",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},26349:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"}}]},name:"delete",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},62670:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372zm47.7-395.2l-25.4-5.9V348.6c38 5.2 61.5 29 65.5 58.2.5 4 3.9 6.9 7.9 6.9h44.9c4.7 0 8.4-4.1 8-8.8-6.1-62.3-57.4-102.3-125.9-109.2V263c0-4.4-3.6-8-8-8h-28.1c-4.4 0-8 3.6-8 8v33c-70.8 6.9-126.2 46-126.2 119 0 67.6 49.8 100.2 102.1 112.7l24.7 6.3v142.7c-44.2-5.9-69-29.5-74.1-61.3-.6-3.8-4-6.6-7.9-6.6H363c-4.7 0-8.4 4-8 8.7 4.5 55 46.2 105.6 135.2 112.1V761c0 4.4 3.6 8 8 8h28.4c4.4 0 8-3.6 8-8.1l-.2-31.7c78.3-6.9 134.3-48.8 134.3-124-.1-69.4-44.2-100.4-109-116.4zm-68.6-16.2c-5.6-1.6-10.3-3.1-15-5-33.8-12.2-49.5-31.9-49.5-57.3 0-36.3 27.5-57 64.5-61.7v124zM534.3 677V543.3c3.1.9 5.9 1.6 8.8 2.2 47.3 14.4 63.2 34.4 63.2 65.1 0 39.1-29.4 62.6-72 66.4z"}}]},name:"dollar",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},73879:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"}}]},name:"download",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},29271:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}},{tag:"path",attrs:{d:"M464 688a48 48 0 1096 0 48 48 0 10-96 0zm24-112h48c4.4 0 8-3.6 8-8V296c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8z"}}]},name:"exclamation-circle",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},41169:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 472a40 40 0 1080 0 40 40 0 10-80 0zm367 352.9L696.3 352V178H768v-68H256v68h71.7v174L145 824.9c-2.8 7.4-4.3 15.2-4.3 23.1 0 35.3 28.7 64 64 64h614.6c7.9 0 15.7-1.5 23.1-4.3 33-12.7 49.4-49.8 36.6-82.8zM395.7 364.7V180h232.6v184.7L719.2 600c-20.7-5.3-42.1-8-63.9-8-61.2 0-119.2 21.5-165.3 60a188.78 188.78 0 01-121.3 43.9c-32.7 0-64.1-8.3-91.8-23.7l118.8-307.5zM210.5 844l41.7-107.8c35.7 18.1 75.4 27.8 116.6 27.8 61.2 0 119.2-21.5 165.3-60 33.9-28.2 76.3-43.9 121.3-43.9 35 0 68.4 9.5 97.6 27.1L813.5 844h-603z"}}]},name:"experiment",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},11741:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{"fill-rule":"evenodd",viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M880 912H144c-17.7 0-32-14.3-32-32V144c0-17.7 14.3-32 32-32h360c4.4 0 8 3.6 8 8v56c0 4.4-3.6 8-8 8H184v656h656V520c0-4.4 3.6-8 8-8h56c4.4 0 8 3.6 8 8v360c0 17.7-14.3 32-32 32zM770.87 199.13l-52.2-52.2a8.01 8.01 0 014.7-13.6l179.4-21c5.1-.6 9.5 3.7 8.9 8.9l-21 179.4c-.8 6.6-8.9 9.4-13.6 4.7l-52.4-52.4-256.2 256.2a8.03 8.03 0 01-11.3 0l-42.4-42.4a8.03 8.03 0 010-11.3l256.1-256.3z"}}]},name:"export",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},34310:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM472 744a40 40 0 1080 0 40 40 0 10-80 0zm16-104h48c4.4 0 8-3.6 8-8V448c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v184c0 4.4 3.6 8 8 8z"}}]},name:"file-exclamation",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},50010:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M531.3 574.4l.3-1.4c5.8-23.9 13.1-53.7 7.4-80.7-3.8-21.3-19.5-29.6-32.9-30.2-15.8-.7-29.9 8.3-33.4 21.4-6.6 24-.7 56.8 10.1 98.6-13.6 32.4-35.3 79.5-51.2 107.5-29.6 15.3-69.3 38.9-75.2 68.7-1.2 5.5.2 12.5 3.5 18.8 3.7 7 9.6 12.4 16.5 15 3 1.1 6.6 2 10.8 2 17.6 0 46.1-14.2 84.1-79.4 5.8-1.9 11.8-3.9 17.6-5.9 27.2-9.2 55.4-18.8 80.9-23.1 28.2 15.1 60.3 24.8 82.1 24.8 21.6 0 30.1-12.8 33.3-20.5 5.6-13.5 2.9-30.5-6.2-39.6-13.2-13-45.3-16.4-95.3-10.2-24.6-15-40.7-35.4-52.4-65.8zM421.6 726.3c-13.9 20.2-24.4 30.3-30.1 34.7 6.7-12.3 19.8-25.3 30.1-34.7zm87.6-235.5c5.2 8.9 4.5 35.8.5 49.4-4.9-19.9-5.6-48.1-2.7-51.4.8.1 1.5.7 2.2 2zm-1.6 120.5c10.7 18.5 24.2 34.4 39.1 46.2-21.6 4.9-41.3 13-58.9 20.2-4.2 1.7-8.3 3.4-12.3 5 13.3-24.1 24.4-51.4 32.1-71.4zm155.6 65.5c.1.2.2.5-.4.9h-.2l-.2.3c-.8.5-9 5.3-44.3-8.6 40.6-1.9 45 7.3 45.1 7.4zm191.4-388.2L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"}}]},name:"file-pdf",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},38434:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"}}]},name:"file-text",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},10798:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M880.1 154H143.9c-24.5 0-39.8 26.7-27.5 48L349 597.4V838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V597.4L907.7 202c12.2-21.3-3.1-48-27.6-48zM603.4 798H420.6V642h182.9v156zm9.6-236.6l-9.5 16.6h-183l-9.5-16.6L212.7 226h598.6L613 561.4z"}}]},name:"filter",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},71282:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{"fill-rule":"evenodd",viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M880 912H144c-17.7 0-32-14.3-32-32V144c0-17.7 14.3-32 32-32h360c4.4 0 8 3.6 8 8v56c0 4.4-3.6 8-8 8H184v656h656V520c0-4.4 3.6-8 8-8h56c4.4 0 8 3.6 8 8v360c0 17.7-14.3 32-32 32zM653.3 424.6l52.2 52.2a8.01 8.01 0 01-4.7 13.6l-179.4 21c-5.1.6-9.5-3.7-8.9-8.9l21-179.4c.8-6.6 8.9-9.4 13.6-4.7l52.4 52.4 256.2-256.2c3.1-3.1 8.2-3.1 11.3 0l42.4 42.4c3.1 3.1 3.1 8.2 0 11.3L653.3 424.6z"}}]},name:"import",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},92403:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M608 112c-167.9 0-304 136.1-304 304 0 70.3 23.9 135 63.9 186.5l-41.1 41.1-62.3-62.3a8.15 8.15 0 00-11.4 0l-39.8 39.8a8.15 8.15 0 000 11.4l62.3 62.3-44.9 44.9-62.3-62.3a8.15 8.15 0 00-11.4 0l-39.8 39.8a8.15 8.15 0 000 11.4l62.3 62.3-65.3 65.3a8.03 8.03 0 000 11.3l42.3 42.3c3.1 3.1 8.2 3.1 11.3 0l253.6-253.6A304.06 304.06 0 00608 720c167.9 0 304-136.1 304-304S775.9 112 608 112zm161.2 465.2C726.2 620.3 668.9 644 608 644c-60.9 0-118.2-23.7-161.2-66.8-43.1-43-66.8-100.3-66.8-161.2 0-60.9 23.7-118.2 66.8-161.2 43-43.1 100.3-66.8 161.2-66.8 60.9 0 118.2 23.7 161.2 66.8 43.1 43 66.8 100.3 66.8 161.2 0 60.9-23.7 118.2-66.8 161.2z"}}]},name:"key",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},48231:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM305.8 637.7c3.1 3.1 8.1 3.1 11.3 0l138.3-137.6L583 628.5c3.1 3.1 8.2 3.1 11.3 0l275.4-275.3c3.1-3.1 3.1-8.2 0-11.3l-39.6-39.6a8.03 8.03 0 00-11.3 0l-230 229.9L461.4 404a8.03 8.03 0 00-11.3 0L266.3 586.7a8.03 8.03 0 000 11.3l39.5 39.7z"}}]},name:"line-chart",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},62272:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M574 665.4a8.03 8.03 0 00-11.3 0L446.5 781.6c-53.8 53.8-144.6 59.5-204 0-59.5-59.5-53.8-150.2 0-204l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3l-39.8-39.8a8.03 8.03 0 00-11.3 0L191.4 526.5c-84.6 84.6-84.6 221.5 0 306s221.5 84.6 306 0l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3L574 665.4zm258.6-474c-84.6-84.6-221.5-84.6-306 0L410.3 307.6a8.03 8.03 0 000 11.3l39.7 39.7c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c53.8-53.8 144.6-59.5 204 0 59.5 59.5 53.8 150.2 0 204L665.3 562.6a8.03 8.03 0 000 11.3l39.8 39.8c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c84.5-84.6 84.5-221.5 0-306.1zM610.1 372.3a8.03 8.03 0 00-11.3 0L372.3 598.7a8.03 8.03 0 000 11.3l39.6 39.6c3.1 3.1 8.2 3.1 11.3 0l226.4-226.4c3.1-3.1 3.1-8.2 0-11.3l-39.5-39.6z"}}]},name:"link",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},45246:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M696 480H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h368c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z"}},{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}}]},name:"minus-circle",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},16601:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M872 394c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8H708V152c0-4.4-3.6-8-8-8h-64c-4.4 0-8 3.6-8 8v166H400V152c0-4.4-3.6-8-8-8h-64c-4.4 0-8 3.6-8 8v166H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h168v236H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h168v166c0 4.4 3.6 8 8 8h64c4.4 0 8-3.6 8-8V706h228v166c0 4.4 3.6 8 8 8h64c4.4 0 8-3.6 8-8V706h164c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8H708V394h164zM628 630H400V394h228v236z"}}]},name:"number",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},53508:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"}}]},name:"paper-clip",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},99890:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 632H136v-39.9l138.5-164.3 150.1 178L658.1 489 888 761.6V792zm0-129.8L664.2 396.8c-3.2-3.8-9-3.8-12.2 0L424.6 666.4l-144-170.7c-3.2-3.8-9-3.8-12.2 0L136 652.7V232h752v430.2zM304 456a88 88 0 100-176 88 88 0 000 176zm0-116c15.5 0 28 12.5 28 28s-12.5 28-28 28-28-12.5-28-28 12.5-28 28-28z"}}]},name:"picture",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},28595:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}},{tag:"path",attrs:{d:"M719.4 499.1l-296.1-215A15.9 15.9 0 00398 297v430c0 13.1 14.8 20.5 25.3 12.9l296.1-215a15.9 15.9 0 000-25.8zm-257.6 134V390.9L628.5 512 461.8 633.1z"}}]},name:"play-circle",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},34419:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M696 480H544V328c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v152H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h152v152c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V544h152c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z"}},{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}}]},name:"plus-circle",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},96473:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},89245:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M909.1 209.3l-56.4 44.1C775.8 155.1 656.2 92 521.9 92 290 92 102.3 279.5 102 511.5 101.7 743.7 289.8 932 521.9 932c181.3 0 335.8-115 394.6-276.1 1.5-4.2-.7-8.9-4.9-10.3l-56.7-19.5a8 8 0 00-10.1 4.8c-1.8 5-3.8 10-5.9 14.9-17.3 41-42.1 77.8-73.7 109.4A344.77 344.77 0 01655.9 829c-42.3 17.9-87.4 27-133.8 27-46.5 0-91.5-9.1-133.8-27A341.5 341.5 0 01279 755.2a342.16 342.16 0 01-73.7-109.4c-17.9-42.4-27-87.4-27-133.9s9.1-91.5 27-133.9c17.3-41 42.1-77.8 73.7-109.4 31.6-31.6 68.4-56.4 109.3-73.8 42.3-17.9 87.4-27 133.8-27 46.5 0 91.5 9.1 133.8 27a341.5 341.5 0 01109.3 73.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.6 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c-.1-6.6-7.8-10.3-13-6.2z"}}]},name:"reload",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},69993:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M300 328a60 60 0 10120 0 60 60 0 10-120 0zM852 64H172c-17.7 0-32 14.3-32 32v660c0 17.7 14.3 32 32 32h680c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32zm-32 660H204V128h616v596zM604 328a60 60 0 10120 0 60 60 0 10-120 0zm250.2 556H169.8c-16.5 0-29.8 14.3-29.8 32v36c0 4.4 3.3 8 7.4 8h729.1c4.1 0 7.4-3.6 7.4-8v-36c.1-17.7-13.2-32-29.7-32zM664 508H360c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h304c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"robot",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},78355:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M893.3 293.3L730.7 130.7c-7.5-7.5-16.7-13-26.7-16V112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V338.5c0-17-6.7-33.2-18.7-45.2zM384 184h256v104H384V184zm456 656H184V184h136v136c0 17.7 14.3 32 32 32h320c17.7 0 32-14.3 32-32V205.8l136 136V840zM512 442c-79.5 0-144 64.5-144 144s64.5 144 144 144 144-64.5 144-144-64.5-144-144-144zm0 224c-44.2 0-80-35.8-80-80s35.8-80 80-80 80 35.8 80 80-35.8 80-80 80z"}}]},name:"save",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},23907:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"defs",attrs:{},children:[{tag:"style",attrs:{}}]},{tag:"path",attrs:{d:"M931.4 498.9L94.9 79.5c-3.4-1.7-7.3-2.1-11-1.2a15.99 15.99 0 00-11.7 19.3l86.2 352.2c1.3 5.3 5.2 9.6 10.4 11.3l147.7 50.7-147.6 50.7c-5.2 1.8-9.1 6-10.3 11.3L72.2 926.5c-.9 3.7-.5 7.6 1.2 10.9 3.9 7.9 13.5 11.1 21.5 7.2l836.5-417c3.1-1.5 5.6-4.1 7.2-7.1 3.9-8 .7-17.6-7.2-21.6zM170.8 826.3l50.3-205.6 295.2-101.3c2.3-.8 4.2-2.6 5-5 1.4-4.2-.8-8.7-5-10.2L221.1 403 171 198.2l628 314.9-628.2 313.2z"}}]},name:"send",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},55322:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"}}]},name:"setting",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},8881:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372 0-89 31.3-170.8 83.5-234.8l523.3 523.3C682.8 852.7 601 884 512 884zm288.5-137.2L277.2 223.5C341.2 171.3 423 140 512 140c205.4 0 372 166.6 372 372 0 89-31.3 170.8-83.5 234.8z"}}]},name:"stop",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},71891:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M483.2 790.3L861.4 412c1.7-1.7 2.5-4 2.3-6.3l-25.5-301.4c-.7-7.8-6.8-13.9-14.6-14.6L522.2 64.3c-2.3-.2-4.7.6-6.3 2.3L137.7 444.8a8.03 8.03 0 000 11.3l334.2 334.2c3.1 3.2 8.2 3.2 11.3 0zm62.6-651.7l224.6 19 19 224.6L477.5 694 233.9 450.5l311.9-311.9zm60.16 186.23a48 48 0 1067.88-67.89 48 48 0 10-67.88 67.89zM889.7 539.8l-39.6-39.5a8.03 8.03 0 00-11.3 0l-362 361.3-237.6-237a8.03 8.03 0 00-11.3 0l-39.6 39.5a8.03 8.03 0 000 11.3l243.2 242.8 39.6 39.5c3.1 3.1 8.2 3.1 11.3 0l407.3-406.6c3.1-3.1 3.1-8.2 0-11.3z"}}]},name:"tags",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},41361:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M824.2 699.9a301.55 301.55 0 00-86.4-60.4C783.1 602.8 812 546.8 812 484c0-110.8-92.4-201.7-203.2-200-109.1 1.7-197 90.6-197 200 0 62.8 29 118.8 74.2 155.5a300.95 300.95 0 00-86.4 60.4C345 754.6 314 826.8 312 903.8a8 8 0 008 8.2h56c4.3 0 7.9-3.4 8-7.7 1.9-58 25.4-112.3 66.7-153.5A226.62 226.62 0 01612 684c60.9 0 118.2 23.7 161.3 66.8C814.5 792 838 846.3 840 904.3c.1 4.3 3.7 7.7 8 7.7h56a8 8 0 008-8.2c-2-77-33-149.2-87.8-203.9zM612 612c-34.2 0-66.4-13.3-90.5-37.5a126.86 126.86 0 01-37.5-91.8c.3-32.8 13.4-64.5 36.3-88 24-24.6 56.1-38.3 90.4-38.7 33.9-.3 66.8 12.9 91 36.6 24.8 24.3 38.4 56.8 38.4 91.4 0 34.2-13.3 66.3-37.5 90.5A127.3 127.3 0 01612 612zM361.5 510.4c-.9-8.7-1.4-17.5-1.4-26.4 0-15.9 1.5-31.4 4.3-46.5.7-3.6-1.2-7.3-4.5-8.8-13.6-6.1-26.1-14.5-36.9-25.1a127.54 127.54 0 01-38.7-95.4c.9-32.1 13.8-62.6 36.3-85.6 24.7-25.3 57.9-39.1 93.2-38.7 31.9.3 62.7 12.6 86 34.4 7.9 7.4 14.7 15.6 20.4 24.4 2 3.1 5.9 4.4 9.3 3.2 17.6-6.1 36.2-10.4 55.3-12.4 5.6-.6 8.8-6.6 6.3-11.6-32.5-64.3-98.9-108.7-175.7-109.9-110.9-1.7-203.3 89.2-203.3 199.9 0 62.8 28.9 118.8 74.2 155.5-31.8 14.7-61.1 35-86.5 60.4-54.8 54.7-85.8 126.9-87.8 204a8 8 0 008 8.2h56.1c4.3 0 7.9-3.4 8-7.7 1.9-58 25.4-112.3 66.7-153.5 29.4-29.4 65.4-49.8 104.7-59.7 3.9-1 6.5-4.7 6-8.7z"}}]},name:"team",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},58630:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M876.6 239.5c-.5-.9-1.2-1.8-2-2.5-5-5-13.1-5-18.1 0L684.2 409.3l-67.9-67.9L788.7 169c.8-.8 1.4-1.6 2-2.5 3.6-6.1 1.6-13.9-4.5-17.5-98.2-58-226.8-44.7-311.3 39.7-67 67-89.2 162-66.5 247.4l-293 293c-3 3-2.8 7.9.3 11l169.7 169.7c3.1 3.1 8.1 3.3 11 .3l292.9-292.9c85.5 22.8 180.5.7 247.6-66.4 84.4-84.5 97.7-213.1 39.7-311.3zM786 499.8c-58.1 58.1-145.3 69.3-214.6 33.6l-8.8 8.8-.1-.1-274 274.1-79.2-79.2 230.1-230.1s0 .1.1.1l52.8-52.8c-35.7-69.3-24.5-156.5 33.6-214.6a184.2 184.2 0 01144-53.5L537 318.9a32.05 32.05 0 000 45.3l124.5 124.5a32.05 32.05 0 0045.3 0l132.8-132.8c3.7 51.8-14.4 104.8-53.6 143.9z"}}]},name:"tool",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},3632:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"}}]},name:"upload",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},35291:function(e,t,n){"use strict";n.d(t,{Z:function(){return l}});var r=n(1119),o=n(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 720a48 48 0 1096 0 48 48 0 10-96 0zm16-304v184c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V416c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8zm475.7 440l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48zm-783.5-27.9L512 239.9l339.8 588.2H172.2z"}}]},name:"warning",theme:"outlined"},a=n(55015),l=o.forwardRef(function(e,t){return o.createElement(a.Z,(0,r.Z)({},e,{ref:t,icon:i}))})},58747:function(e,t,n){"use strict";n.d(t,{Z:function(){return i}});var r=n(5853),o=n(2265);let i=e=>{var t=(0,r._T)(e,[]);return o.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),o.createElement("path",{d:"M11.9999 13.1714L16.9497 8.22168L18.3639 9.63589L11.9999 15.9999L5.63599 9.63589L7.0502 8.22168L11.9999 13.1714Z"}))}},4537:function(e,t,n){"use strict";n.d(t,{Z:function(){return i}});var r=n(5853),o=n(2265);let i=e=>{var t=(0,r._T)(e,[]);return o.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),o.createElement("path",{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 10.5858L9.17157 7.75736L7.75736 9.17157L10.5858 12L7.75736 14.8284L9.17157 16.2426L12 13.4142L14.8284 16.2426L16.2426 14.8284L13.4142 12L16.2426 9.17157L14.8284 7.75736L12 10.5858Z"}))}},75105:function(e,t,n){"use strict";n.d(t,{Z:function(){return et}});var r=n(5853),o=n(2265),i=n(47625),a=n(93765),l=n(87602),s=n(59221),c=n(86757),u=n.n(c),d=n(95645),f=n.n(d),p=n(77571),h=n.n(p),m=n(82559),g=n.n(m),v=n(21652),y=n.n(v),b=n(57165),x=n(81889),w=n(9841),k=n(58772),S=n(34067),E=n(16630),O=n(85355),C=n(82944),j=["layout","type","stroke","connectNulls","isRange","ref"];function _(e){return(_="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function P(){return(P=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}(i,j));return o.createElement(w.m,{clipPath:n?"url(#clipPath-".concat(r,")"):null},o.createElement(b.H,P({},(0,C.L6)(d,!0),{points:e,connectNulls:c,type:l,baseLine:t,layout:a,stroke:"none",className:"recharts-area-area"})),"none"!==s&&o.createElement(b.H,P({},(0,C.L6)(this.props,!1),{className:"recharts-area-curve",layout:a,type:l,connectNulls:c,fill:"none",points:e})),"none"!==s&&u&&o.createElement(b.H,P({},(0,C.L6)(this.props,!1),{className:"recharts-area-curve",layout:a,type:l,connectNulls:c,fill:"none",points:t})))}},{key:"renderAreaWithAnimation",value:function(e,t){var n=this,r=this.props,i=r.points,a=r.baseLine,l=r.isAnimationActive,c=r.animationBegin,u=r.animationDuration,d=r.animationEasing,f=r.animationId,p=this.state,m=p.prevPoints,v=p.prevBaseLine;return o.createElement(s.ZP,{begin:c,duration:u,isActive:l,easing:d,from:{t:0},to:{t:1},key:"area-".concat(f),onAnimationEnd:this.handleAnimationEnd,onAnimationStart:this.handleAnimationStart},function(r){var l=r.t;if(m){var s,c=m.length/i.length,u=i.map(function(e,t){var n=Math.floor(t*c);if(m[n]){var r=m[n],o=(0,E.k4)(r.x,e.x),i=(0,E.k4)(r.y,e.y);return M(M({},e),{},{x:o(l),y:i(l)})}return e});return s=(0,E.hj)(a)&&"number"==typeof a?(0,E.k4)(v,a)(l):h()(a)||g()(a)?(0,E.k4)(v,0)(l):a.map(function(e,t){var n=Math.floor(t*c);if(v[n]){var r=v[n],o=(0,E.k4)(r.x,e.x),i=(0,E.k4)(r.y,e.y);return M(M({},e),{},{x:o(l),y:i(l)})}return e}),n.renderAreaStatically(u,s,e,t)}return o.createElement(w.m,null,o.createElement("defs",null,o.createElement("clipPath",{id:"animationClipPath-".concat(t)},n.renderClipRect(l))),o.createElement(w.m,{clipPath:"url(#animationClipPath-".concat(t,")")},n.renderAreaStatically(i,a,e,t)))})}},{key:"renderArea",value:function(e,t){var n=this.props,r=n.points,o=n.baseLine,i=n.isAnimationActive,a=this.state,l=a.prevPoints,s=a.prevBaseLine,c=a.totalLength;return i&&r&&r.length&&(!l&&c>0||!y()(l,r)||!y()(s,o))?this.renderAreaWithAnimation(e,t):this.renderAreaStatically(r,o,e,t)}},{key:"render",value:function(){var e,t=this.props,n=t.hide,r=t.dot,i=t.points,a=t.className,s=t.top,c=t.left,u=t.xAxis,d=t.yAxis,f=t.width,p=t.height,m=t.isAnimationActive,g=t.id;if(n||!i||!i.length)return null;var v=this.state.isAnimationFinished,y=1===i.length,b=(0,l.Z)("recharts-area",a),x=u&&u.allowDataOverflow,S=d&&d.allowDataOverflow,E=x||S,O=h()(g)?this.id:g,j=null!==(e=(0,C.L6)(r,!1))&&void 0!==e?e:{r:3,strokeWidth:2},_=j.r,P=j.strokeWidth,T=((0,C.$k)(r)?r:{}).clipDot,M=void 0===T||T,N=2*(void 0===_?3:_)+(void 0===P?2:P);return o.createElement(w.m,{className:b},x||S?o.createElement("defs",null,o.createElement("clipPath",{id:"clipPath-".concat(O)},o.createElement("rect",{x:x?c:c-f/2,y:S?s:s-p/2,width:x?f:2*f,height:S?p:2*p})),!M&&o.createElement("clipPath",{id:"clipPath-dots-".concat(O)},o.createElement("rect",{x:c-N/2,y:s-N/2,width:f+N,height:p+N}))):null,y?null:this.renderArea(E,O),(r||y)&&this.renderDots(E,M,O),(!m||v)&&k.e.renderCallByParent(this.props,i))}}],r=[{key:"getDerivedStateFromProps",value:function(e,t){return e.animationId!==t.prevAnimationId?{prevAnimationId:e.animationId,curPoints:e.points,curBaseLine:e.baseLine,prevPoints:t.curPoints,prevBaseLine:t.curBaseLine}:e.points!==t.curPoints||e.baseLine!==t.curBaseLine?{curPoints:e.points,curBaseLine:e.baseLine}:null}}],n&&N(a.prototype,n),r&&N(a,r),Object.defineProperty(a,"prototype",{writable:!1}),a}(o.PureComponent);D(z,"displayName","Area"),D(z,"defaultProps",{stroke:"#3182bd",fill:"#3182bd",fillOpacity:.6,xAxisId:0,yAxisId:0,legendType:"line",connectNulls:!1,points:[],dot:!1,activeDot:!0,hide:!1,isAnimationActive:!S.x.isSsr,animationBegin:0,animationDuration:1500,animationEasing:"ease"}),D(z,"getBaseValue",function(e,t,n,r){var o=e.layout,i=e.baseValue,a=t.props.baseValue,l=null!=a?a:i;if((0,E.hj)(l)&&"number"==typeof l)return l;var s="horizontal"===o?r:n,c=s.scale.domain();if("number"===s.type){var u=Math.max(c[0],c[1]),d=Math.min(c[0],c[1]);return"dataMin"===l?d:"dataMax"===l?u:u<0?u:Math.max(Math.min(c[0],c[1]),0)}return"dataMin"===l?c[0]:"dataMax"===l?c[1]:c[0]}),D(z,"getComposedData",function(e){var t,n=e.props,r=e.item,o=e.xAxis,i=e.yAxis,a=e.xAxisTicks,l=e.yAxisTicks,s=e.bandSize,c=e.dataKey,u=e.stackedData,d=e.dataStartIndex,f=e.displayedData,p=e.offset,h=n.layout,m=u&&u.length,g=z.getBaseValue(n,r,o,i),v="horizontal"===h,y=!1,b=f.map(function(e,t){m?n=u[d+t]:Array.isArray(n=(0,O.F$)(e,c))?y=!0:n=[g,n];var n,r=null==n[1]||m&&null==(0,O.F$)(e,c);return v?{x:(0,O.Hv)({axis:o,ticks:a,bandSize:s,entry:e,index:t}),y:r?null:i.scale(n[1]),value:n,payload:e}:{x:r?null:o.scale(n[1]),y:(0,O.Hv)({axis:i,ticks:l,bandSize:s,entry:e,index:t}),value:n,payload:e}});return t=m||y?b.map(function(e){var t=Array.isArray(e.value)?e.value[0]:null;return v?{x:e.x,y:null!=t&&null!=e.y?i.scale(t):null}:{x:null!=t?o.scale(t):null,y:e.y}}):v?i.scale(g):o.scale(g),M({points:b,baseLine:t,layout:h,isRange:y},p)}),D(z,"renderDotItem",function(e,t){return o.isValidElement(e)?o.cloneElement(e,t):u()(e)?e(t):o.createElement(x.o,P({},t,{className:"recharts-area-dot"}))});var Z=n(97059),B=n(62994),F=n(25311),H=(0,a.z)({chartName:"AreaChart",GraphicalChild:z,axisComponents:[{axisType:"xAxis",AxisComp:Z.K},{axisType:"yAxis",AxisComp:B.B}],formatAxisMap:F.t9}),q=n(56940),U=n(8147),W=n(22190),K=n(54061),V=n(65278),$=n(98593),X=n(69448),G=n(32644),Y=n(7084),Q=n(26898),J=n(97324),ee=n(1153);let et=o.forwardRef((e,t)=>{let{data:n=[],categories:a=[],index:l,stack:s=!1,colors:c=Q.s,valueFormatter:u=ee.Cj,startEndOnly:d=!1,showXAxis:f=!0,showYAxis:p=!0,yAxisWidth:h=56,intervalType:m="equidistantPreserveStart",showAnimation:g=!1,animationDuration:v=900,showTooltip:y=!0,showLegend:b=!0,showGridLines:w=!0,showGradient:k=!0,autoMinValue:S=!1,curveType:E="linear",minValue:O,maxValue:C,connectNulls:j=!1,allowDecimals:_=!0,noDataText:P,className:T,onValueChange:M,enableLegendSlider:N=!1,customTooltip:A,rotateLabelX:I,tickGap:R=5}=e,D=(0,r._T)(e,["data","categories","index","stack","colors","valueFormatter","startEndOnly","showXAxis","showYAxis","yAxisWidth","intervalType","showAnimation","animationDuration","showTooltip","showLegend","showGridLines","showGradient","autoMinValue","curveType","minValue","maxValue","connectNulls","allowDecimals","noDataText","className","onValueChange","enableLegendSlider","customTooltip","rotateLabelX","tickGap"]),L=(f||p)&&(!d||p)?20:0,[F,et]=(0,o.useState)(60),[en,er]=(0,o.useState)(void 0),[eo,ei]=(0,o.useState)(void 0),ea=(0,G.me)(a,c),el=(0,G.i4)(S,O,C),es=!!M;function ec(e){es&&(e===eo&&!en||(0,G.FB)(n,e)&&en&&en.dataKey===e?(ei(void 0),null==M||M(null)):(ei(e),null==M||M({eventType:"category",categoryClicked:e})),er(void 0))}return o.createElement("div",Object.assign({ref:t,className:(0,J.q)("w-full h-80",T)},D),o.createElement(i.h,{className:"h-full w-full"},(null==n?void 0:n.length)?o.createElement(H,{data:n,onClick:es&&(eo||en)?()=>{er(void 0),ei(void 0),null==M||M(null)}:void 0},w?o.createElement(q.q,{className:(0,J.q)("stroke-1","stroke-tremor-border","dark:stroke-dark-tremor-border"),horizontal:!0,vertical:!1}):null,o.createElement(Z.K,{padding:{left:L,right:L},hide:!f,dataKey:l,tick:{transform:"translate(0, 6)"},ticks:d?[n[0][l],n[n.length-1][l]]:void 0,fill:"",stroke:"",className:(0,J.q)("text-tremor-label","fill-tremor-content","dark:fill-dark-tremor-content"),interval:d?"preserveStartEnd":m,tickLine:!1,axisLine:!1,minTickGap:R,angle:null==I?void 0:I.angle,dy:null==I?void 0:I.verticalShift,height:null==I?void 0:I.xAxisHeight}),o.createElement(B.B,{width:h,hide:!p,axisLine:!1,tickLine:!1,type:"number",domain:el,tick:{transform:"translate(-3, 0)"},fill:"",stroke:"",className:(0,J.q)("text-tremor-label","fill-tremor-content","dark:fill-dark-tremor-content"),tickFormatter:u,allowDecimals:_}),o.createElement(U.u,{wrapperStyle:{outline:"none"},isAnimationActive:!1,cursor:{stroke:"#d1d5db",strokeWidth:1},content:y?e=>{let{active:t,payload:n,label:r}=e;return A?o.createElement(A,{payload:null==n?void 0:n.map(e=>{var t;return Object.assign(Object.assign({},e),{color:null!==(t=ea.get(e.dataKey))&&void 0!==t?t:Y.fr.Gray})}),active:t,label:r}):o.createElement($.ZP,{active:t,payload:n,label:r,valueFormatter:u,categoryColors:ea})}:o.createElement(o.Fragment,null),position:{y:0}}),b?o.createElement(W.D,{verticalAlign:"top",height:F,content:e=>{let{payload:t}=e;return(0,V.Z)({payload:t},ea,et,eo,es?e=>ec(e):void 0,N)}}):null,a.map(e=>{var t,n;return o.createElement("defs",{key:e},k?o.createElement("linearGradient",{className:(0,ee.bM)(null!==(t=ea.get(e))&&void 0!==t?t:Y.fr.Gray,Q.K.text).textColor,id:ea.get(e),x1:"0",y1:"0",x2:"0",y2:"1"},o.createElement("stop",{offset:"5%",stopColor:"currentColor",stopOpacity:en||eo&&eo!==e?.15:.4}),o.createElement("stop",{offset:"95%",stopColor:"currentColor",stopOpacity:0})):o.createElement("linearGradient",{className:(0,ee.bM)(null!==(n=ea.get(e))&&void 0!==n?n:Y.fr.Gray,Q.K.text).textColor,id:ea.get(e),x1:"0",y1:"0",x2:"0",y2:"1"},o.createElement("stop",{stopColor:"currentColor",stopOpacity:en||eo&&eo!==e?.1:.3})))}),a.map(e=>{var t;return o.createElement(z,{className:(0,ee.bM)(null!==(t=ea.get(e))&&void 0!==t?t:Y.fr.Gray,Q.K.text).strokeColor,strokeOpacity:en||eo&&eo!==e?.3:1,activeDot:e=>{var t;let{cx:r,cy:i,stroke:a,strokeLinecap:l,strokeLinejoin:s,strokeWidth:c,dataKey:u}=e;return o.createElement(x.o,{className:(0,J.q)("stroke-tremor-background dark:stroke-dark-tremor-background",M?"cursor-pointer":"",(0,ee.bM)(null!==(t=ea.get(u))&&void 0!==t?t:Y.fr.Gray,Q.K.text).fillColor),cx:r,cy:i,r:5,fill:"",stroke:a,strokeLinecap:l,strokeLinejoin:s,strokeWidth:c,onClick:(t,r)=>{r.stopPropagation(),es&&(e.index===(null==en?void 0:en.index)&&e.dataKey===(null==en?void 0:en.dataKey)||(0,G.FB)(n,e.dataKey)&&eo&&eo===e.dataKey?(ei(void 0),er(void 0),null==M||M(null)):(ei(e.dataKey),er({index:e.index,dataKey:e.dataKey}),null==M||M(Object.assign({eventType:"dot",categoryClicked:e.dataKey},e.payload))))}})},dot:t=>{var r;let{stroke:i,strokeLinecap:a,strokeLinejoin:l,strokeWidth:s,cx:c,cy:u,dataKey:d,index:f}=t;return(0,G.FB)(n,e)&&!(en||eo&&eo!==e)||(null==en?void 0:en.index)===f&&(null==en?void 0:en.dataKey)===e?o.createElement(x.o,{key:f,cx:c,cy:u,r:5,stroke:i,fill:"",strokeLinecap:a,strokeLinejoin:l,strokeWidth:s,className:(0,J.q)("stroke-tremor-background dark:stroke-dark-tremor-background",M?"cursor-pointer":"",(0,ee.bM)(null!==(r=ea.get(d))&&void 0!==r?r:Y.fr.Gray,Q.K.text).fillColor)}):o.createElement(o.Fragment,{key:f})},key:e,name:e,type:E,dataKey:e,stroke:"",fill:"url(#".concat(ea.get(e),")"),strokeWidth:2,strokeLinejoin:"round",strokeLinecap:"round",isAnimationActive:g,animationDuration:v,stackId:s?"a":void 0,connectNulls:j})}),M?a.map(e=>o.createElement(K.x,{className:(0,J.q)("cursor-pointer"),strokeOpacity:0,key:e,name:e,type:E,dataKey:e,stroke:"transparent",fill:"transparent",legendType:"none",tooltipType:"none",strokeWidth:12,connectNulls:j,onClick:(e,t)=>{t.stopPropagation();let{name:n}=e;ec(n)}})):null):o.createElement(X.Z,{noDataText:P})))});et.displayName="AreaChart"},40278:function(e,t,n){"use strict";n.d(t,{Z:function(){return S}});var r=n(5853),o=n(7084),i=n(26898),a=n(97324),l=n(1153),s=n(2265),c=n(47625),u=n(93765),d=n(31699),f=n(97059),p=n(62994),h=n(25311),m=(0,u.z)({chartName:"BarChart",GraphicalChild:d.$,defaultTooltipEventType:"axis",validateTooltipEventTypes:["axis","item"],axisComponents:[{axisType:"xAxis",AxisComp:f.K},{axisType:"yAxis",AxisComp:p.B}],formatAxisMap:h.t9}),g=n(56940),v=n(8147),y=n(22190),b=n(65278),x=n(98593),w=n(69448),k=n(32644);let S=s.forwardRef((e,t)=>{let{data:n=[],categories:u=[],index:h,colors:S=i.s,valueFormatter:E=l.Cj,layout:O="horizontal",stack:C=!1,relative:j=!1,startEndOnly:_=!1,animationDuration:P=900,showAnimation:T=!1,showXAxis:M=!0,showYAxis:N=!0,yAxisWidth:A=56,intervalType:I="equidistantPreserveStart",showTooltip:R=!0,showLegend:D=!0,showGridLines:L=!0,autoMinValue:z=!1,minValue:Z,maxValue:B,allowDecimals:F=!0,noDataText:H,onValueChange:q,enableLegendSlider:U=!1,customTooltip:W,rotateLabelX:K,tickGap:V=5,className:$}=e,X=(0,r._T)(e,["data","categories","index","colors","valueFormatter","layout","stack","relative","startEndOnly","animationDuration","showAnimation","showXAxis","showYAxis","yAxisWidth","intervalType","showTooltip","showLegend","showGridLines","autoMinValue","minValue","maxValue","allowDecimals","noDataText","onValueChange","enableLegendSlider","customTooltip","rotateLabelX","tickGap","className"]),G=M||N?20:0,[Y,Q]=(0,s.useState)(60),J=(0,k.me)(u,S),[ee,et]=s.useState(void 0),[en,er]=(0,s.useState)(void 0),eo=!!q;function ei(e,t,n){var r,o,i,a;n.stopPropagation(),q&&((0,k.vZ)(ee,Object.assign(Object.assign({},e.payload),{value:e.value}))?(er(void 0),et(void 0),null==q||q(null)):(er(null===(o=null===(r=e.tooltipPayload)||void 0===r?void 0:r[0])||void 0===o?void 0:o.dataKey),et(Object.assign(Object.assign({},e.payload),{value:e.value})),null==q||q(Object.assign({eventType:"bar",categoryClicked:null===(a=null===(i=e.tooltipPayload)||void 0===i?void 0:i[0])||void 0===a?void 0:a.dataKey},e.payload))))}let ea=(0,k.i4)(z,Z,B);return s.createElement("div",Object.assign({ref:t,className:(0,a.q)("w-full h-80",$)},X),s.createElement(c.h,{className:"h-full w-full"},(null==n?void 0:n.length)?s.createElement(m,{data:n,stackOffset:C?"sign":j?"expand":"none",layout:"vertical"===O?"vertical":"horizontal",onClick:eo&&(en||ee)?()=>{et(void 0),er(void 0),null==q||q(null)}:void 0},L?s.createElement(g.q,{className:(0,a.q)("stroke-1","stroke-tremor-border","dark:stroke-dark-tremor-border"),horizontal:"vertical"!==O,vertical:"vertical"===O}):null,"vertical"!==O?s.createElement(f.K,{padding:{left:G,right:G},hide:!M,dataKey:h,interval:_?"preserveStartEnd":I,tick:{transform:"translate(0, 6)"},ticks:_?[n[0][h],n[n.length-1][h]]:void 0,fill:"",stroke:"",className:(0,a.q)("mt-4 text-tremor-label","fill-tremor-content","dark:fill-dark-tremor-content"),tickLine:!1,axisLine:!1,angle:null==K?void 0:K.angle,dy:null==K?void 0:K.verticalShift,height:null==K?void 0:K.xAxisHeight,minTickGap:V}):s.createElement(f.K,{hide:!M,type:"number",tick:{transform:"translate(-3, 0)"},domain:ea,fill:"",stroke:"",className:(0,a.q)("text-tremor-label","fill-tremor-content","dark:fill-dark-tremor-content"),tickLine:!1,axisLine:!1,tickFormatter:E,minTickGap:V,allowDecimals:F,angle:null==K?void 0:K.angle,dy:null==K?void 0:K.verticalShift,height:null==K?void 0:K.xAxisHeight}),"vertical"!==O?s.createElement(p.B,{width:A,hide:!N,axisLine:!1,tickLine:!1,type:"number",domain:ea,tick:{transform:"translate(-3, 0)"},fill:"",stroke:"",className:(0,a.q)("text-tremor-label","fill-tremor-content","dark:fill-dark-tremor-content"),tickFormatter:j?e=>"".concat((100*e).toString()," %"):E,allowDecimals:F}):s.createElement(p.B,{width:A,hide:!N,dataKey:h,axisLine:!1,tickLine:!1,ticks:_?[n[0][h],n[n.length-1][h]]:void 0,type:"category",interval:"preserveStartEnd",tick:{transform:"translate(0, 6)"},fill:"",stroke:"",className:(0,a.q)("text-tremor-label","fill-tremor-content","dark:fill-dark-tremor-content")}),s.createElement(v.u,{wrapperStyle:{outline:"none"},isAnimationActive:!1,cursor:{fill:"#d1d5db",opacity:"0.15"},content:R?e=>{let{active:t,payload:n,label:r}=e;return W?s.createElement(W,{payload:null==n?void 0:n.map(e=>{var t;return Object.assign(Object.assign({},e),{color:null!==(t=J.get(e.dataKey))&&void 0!==t?t:o.fr.Gray})}),active:t,label:r}):s.createElement(x.ZP,{active:t,payload:n,label:r,valueFormatter:E,categoryColors:J})}:s.createElement(s.Fragment,null),position:{y:0}}),D?s.createElement(y.D,{verticalAlign:"top",height:Y,content:e=>{let{payload:t}=e;return(0,b.Z)({payload:t},J,Q,en,eo?e=>{eo&&(e!==en||ee?(er(e),null==q||q({eventType:"category",categoryClicked:e})):(er(void 0),null==q||q(null)),et(void 0))}:void 0,U)}}):null,u.map(e=>{var t;return s.createElement(d.$,{className:(0,a.q)((0,l.bM)(null!==(t=J.get(e))&&void 0!==t?t:o.fr.Gray,i.K.background).fillColor,q?"cursor-pointer":""),key:e,name:e,type:"linear",stackId:C||j?"a":void 0,dataKey:e,fill:"",isAnimationActive:T,animationDuration:P,shape:e=>((e,t,n,r)=>{let{fillOpacity:o,name:i,payload:a,value:l}=e,{x:c,width:u,y:d,height:f}=e;return"horizontal"===r&&f<0?(d+=f,f=Math.abs(f)):"vertical"===r&&u<0&&(c+=u,u=Math.abs(u)),s.createElement("rect",{x:c,y:d,width:u,height:f,opacity:t||n&&n!==i?(0,k.vZ)(t,Object.assign(Object.assign({},a),{value:l}))?o:.3:o})})(e,ee,en,O),onClick:ei})})):s.createElement(w.Z,{noDataText:H})))});S.displayName="BarChart"},14042:function(e,t,n){"use strict";n.d(t,{Z:function(){return eZ}});var r=n(5853),o=n(7084),i=n(26898),a=n(97324),l=n(1153),s=n(2265),c=n(60474),u=n(47625),d=n(93765),f=n(86757),p=n.n(f),h=n(9841),m=n(81889),g=n(87602),v=n(82944),y=["points","className","baseLinePoints","connectNulls"];function b(){return(b=Object.assign?Object.assign.bind():function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:[],t=[[]];return e.forEach(function(e){k(e)?t[t.length-1].push(e):t[t.length-1].length>0&&t.push([])}),k(e[0])&&t[t.length-1].push(e[0]),t[t.length-1].length<=0&&(t=t.slice(0,-1)),t},E=function(e,t){var n=S(e);t&&(n=[n.reduce(function(e,t){return[].concat(x(e),x(t))},[])]);var r=n.map(function(e){return e.reduce(function(e,t,n){return"".concat(e).concat(0===n?"M":"L").concat(t.x,",").concat(t.y)},"")}).join("");return 1===n.length?"".concat(r,"Z"):r},O=function(e,t,n){var r=E(e,n);return"".concat("Z"===r.slice(-1)?r.slice(0,-1):r,"L").concat(E(t.reverse(),n).slice(1))},C=function(e){var t=e.points,n=e.className,r=e.baseLinePoints,o=e.connectNulls,i=function(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}(e,y);if(!t||!t.length)return null;var a=(0,g.Z)("recharts-polygon",n);if(r&&r.length){var l=i.stroke&&"none"!==i.stroke,c=O(t,r,o);return s.createElement("g",{className:a},s.createElement("path",b({},(0,v.L6)(i,!0),{fill:"Z"===c.slice(-1)?i.fill:"none",stroke:"none",d:c})),l?s.createElement("path",b({},(0,v.L6)(i,!0),{fill:"none",d:E(t,o)})):null,l?s.createElement("path",b({},(0,v.L6)(i,!0),{fill:"none",d:E(r,o)})):null)}var u=E(t,o);return s.createElement("path",b({},(0,v.L6)(i,!0),{fill:"Z"===u.slice(-1)?i.fill:"none",className:a,d:u}))},j=n(58811),_=n(41637),P=n(39206);function T(e){return(T="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function M(){return(M=Object.assign?Object.assign.bind():function(e){for(var t=1;t1e-5?"outer"===t?"start":"end":n<-.00001?"outer"===t?"end":"start":"middle"}},{key:"renderAxisLine",value:function(){var e=this.props,t=e.cx,n=e.cy,r=e.radius,o=e.axisLine,i=e.axisLineType,a=A(A({},(0,v.L6)(this.props,!1)),{},{fill:"none"},(0,v.L6)(o,!1));if("circle"===i)return s.createElement(m.o,M({className:"recharts-polar-angle-axis-line"},a,{cx:t,cy:n,r:r}));var l=this.props.ticks.map(function(e){return(0,P.op)(t,n,r,e.coordinate)});return s.createElement(C,M({className:"recharts-polar-angle-axis-line"},a,{points:l}))}},{key:"renderTicks",value:function(){var e=this,t=this.props,n=t.ticks,r=t.tick,o=t.tickLine,a=t.tickFormatter,l=t.stroke,c=(0,v.L6)(this.props,!1),u=(0,v.L6)(r,!1),d=A(A({},c),{},{fill:"none"},(0,v.L6)(o,!1)),f=n.map(function(t,n){var f=e.getTickLineCoord(t),p=A(A(A({textAnchor:e.getTickTextAnchor(t)},c),{},{stroke:"none",fill:l},u),{},{index:n,payload:t,x:f.x2,y:f.y2});return s.createElement(h.m,M({className:"recharts-polar-angle-axis-tick",key:"tick-".concat(t.coordinate)},(0,_.bw)(e.props,t,n)),o&&s.createElement("line",M({className:"recharts-polar-angle-axis-tick-line"},d,f)),r&&i.renderTickItem(r,p,a?a(t.value,n):t.value))});return s.createElement(h.m,{className:"recharts-polar-angle-axis-ticks"},f)}},{key:"render",value:function(){var e=this.props,t=e.ticks,n=e.radius,r=e.axisLine;return!(n<=0)&&t&&t.length?s.createElement(h.m,{className:"recharts-polar-angle-axis"},r&&this.renderAxisLine(),this.renderTicks()):null}}],r=[{key:"renderTickItem",value:function(e,t,n){return s.isValidElement(e)?s.cloneElement(e,t):p()(e)?e(t):s.createElement(j.x,M({},t,{className:"recharts-polar-angle-axis-tick-value"}),n)}}],n&&I(i.prototype,n),r&&I(i,r),Object.defineProperty(i,"prototype",{writable:!1}),i}(s.PureComponent);L(B,"displayName","PolarAngleAxis"),L(B,"axisType","angleAxis"),L(B,"defaultProps",{type:"category",angleAxisId:0,scale:"auto",cx:0,cy:0,orientation:"outer",axisLine:!0,tickLine:!0,tickSize:8,tick:!0,hide:!1,allowDuplicatedCategory:!0});var F=n(35802),H=n.n(F),q=n(37891),U=n.n(q),W=n(26680),K=["cx","cy","angle","ticks","axisLine"],V=["ticks","tick","angle","tickFormatter","stroke"];function $(e){return($="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function X(){return(X=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function J(e,t){for(var n=0;n0?el()(e,"paddingAngle",0):0;if(n){var l=(0,eg.k4)(n.endAngle-n.startAngle,e.endAngle-e.startAngle),s=eS(eS({},e),{},{startAngle:i+a,endAngle:i+l(r)+a});o.push(s),i=s.endAngle}else{var c=e.endAngle,d=e.startAngle,f=(0,eg.k4)(0,c-d)(r),p=eS(eS({},e),{},{startAngle:i+a,endAngle:i+f+a});o.push(p),i=p.endAngle}}),s.createElement(h.m,null,e.renderSectorsStatically(o))})}},{key:"attachKeyboardHandlers",value:function(e){var t=this;e.onkeydown=function(e){if(!e.altKey)switch(e.key){case"ArrowLeft":var n=++t.state.sectorToFocus%t.sectorRefs.length;t.sectorRefs[n].focus(),t.setState({sectorToFocus:n});break;case"ArrowRight":var r=--t.state.sectorToFocus<0?t.sectorRefs.length-1:t.state.sectorToFocus%t.sectorRefs.length;t.sectorRefs[r].focus(),t.setState({sectorToFocus:r});break;case"Escape":t.sectorRefs[t.state.sectorToFocus].blur(),t.setState({sectorToFocus:0})}}}},{key:"renderSectors",value:function(){var e=this.props,t=e.sectors,n=e.isAnimationActive,r=this.state.prevSectors;return n&&t&&t.length&&(!r||!ec()(r,t))?this.renderSectorsWithAnimation():this.renderSectorsStatically(t)}},{key:"componentDidMount",value:function(){this.pieRef&&this.attachKeyboardHandlers(this.pieRef)}},{key:"render",value:function(){var e=this,t=this.props,n=t.hide,r=t.sectors,o=t.className,i=t.label,a=t.cx,l=t.cy,c=t.innerRadius,u=t.outerRadius,d=t.isAnimationActive,f=this.state.isAnimationFinished;if(n||!r||!r.length||!(0,eg.hj)(a)||!(0,eg.hj)(l)||!(0,eg.hj)(c)||!(0,eg.hj)(u))return null;var p=(0,g.Z)("recharts-pie",o);return s.createElement(h.m,{tabIndex:this.props.rootTabIndex,className:p,ref:function(t){e.pieRef=t}},this.renderSectors(),i&&this.renderLabels(r),W._.renderCallByParent(this.props,null,!1),(!d||f)&&ep.e.renderCallByParent(this.props,r,!1))}}],r=[{key:"getDerivedStateFromProps",value:function(e,t){return t.prevIsAnimationActive!==e.isAnimationActive?{prevIsAnimationActive:e.isAnimationActive,prevAnimationId:e.animationId,curSectors:e.sectors,prevSectors:[],isAnimationFinished:!0}:e.isAnimationActive&&e.animationId!==t.prevAnimationId?{prevAnimationId:e.animationId,curSectors:e.sectors,prevSectors:t.curSectors,isAnimationFinished:!0}:e.sectors!==t.curSectors?{curSectors:e.sectors,isAnimationFinished:!0}:null}},{key:"getTextAnchor",value:function(e,t){return e>t?"start":e=360?x:x-1)*u,k=i.reduce(function(e,t){var n=(0,ev.F$)(t,b,0);return e+((0,eg.hj)(n)?n:0)},0);return k>0&&(t=i.map(function(e,t){var r,o=(0,ev.F$)(e,b,0),i=(0,ev.F$)(e,f,t),a=((0,eg.hj)(o)?o:0)/k,c=(r=t?n.endAngle+(0,eg.uY)(v)*u*(0!==o?1:0):s)+(0,eg.uY)(v)*((0!==o?m:0)+a*w),d=(r+c)/2,p=(g.innerRadius+g.outerRadius)/2,y=[{name:i,value:o,payload:e,dataKey:b,type:h}],x=(0,P.op)(g.cx,g.cy,p,d);return n=eS(eS(eS({percent:a,cornerRadius:l,name:i,tooltipPayload:y,midAngle:d,middleRadius:p,tooltipPosition:x},e),g),{},{value:(0,ev.F$)(e,b),startAngle:r,endAngle:c,payload:e,paddingAngle:(0,eg.uY)(v)*u})})),eS(eS({},g),{},{sectors:t,data:i})});var eM=(0,d.z)({chartName:"PieChart",GraphicalChild:eT,validateTooltipEventTypes:["item"],defaultTooltipEventType:"item",legendContent:"children",axisComponents:[{axisType:"angleAxis",AxisComp:B},{axisType:"radiusAxis",AxisComp:eo}],formatAxisMap:P.t9,defaultProps:{layout:"centric",startAngle:0,endAngle:360,cx:"50%",cy:"50%",innerRadius:0,outerRadius:"80%"}}),eN=n(8147),eA=n(69448),eI=n(98593);let eR=e=>{let{active:t,payload:n,valueFormatter:r}=e;if(t&&(null==n?void 0:n[0])){let e=null==n?void 0:n[0];return s.createElement(eI.$B,null,s.createElement("div",{className:(0,a.q)("px-4 py-2")},s.createElement(eI.zX,{value:r(e.value),name:e.name,color:e.payload.color})))}return null},eD=(e,t)=>e.map((e,n)=>{let r=ne||t((0,l.vP)(n.map(e=>e[r]))),ez=e=>{let{cx:t,cy:n,innerRadius:r,outerRadius:o,startAngle:i,endAngle:a,className:l}=e;return s.createElement("g",null,s.createElement(c.L,{cx:t,cy:n,innerRadius:r,outerRadius:o,startAngle:i,endAngle:a,className:l,fill:"",opacity:.3,style:{outline:"none"}}))},eZ=s.forwardRef((e,t)=>{let{data:n=[],category:c="value",index:d="name",colors:f=i.s,variant:p="donut",valueFormatter:h=l.Cj,label:m,showLabel:g=!0,animationDuration:v=900,showAnimation:y=!1,showTooltip:b=!0,noDataText:x,onValueChange:w,customTooltip:k,className:S}=e,E=(0,r._T)(e,["data","category","index","colors","variant","valueFormatter","label","showLabel","animationDuration","showAnimation","showTooltip","noDataText","onValueChange","customTooltip","className"]),O="donut"==p,C=eL(m,h,n,c),[j,_]=s.useState(void 0),P=!!w;return(0,s.useEffect)(()=>{let e=document.querySelectorAll(".recharts-pie-sector");e&&e.forEach(e=>{e.setAttribute("style","outline: none")})},[j]),s.createElement("div",Object.assign({ref:t,className:(0,a.q)("w-full h-40",S)},E),s.createElement(u.h,{className:"h-full w-full"},(null==n?void 0:n.length)?s.createElement(eM,{onClick:P&&j?()=>{_(void 0),null==w||w(null)}:void 0,margin:{top:0,left:0,right:0,bottom:0}},g&&O?s.createElement("text",{className:(0,a.q)("fill-tremor-content-emphasis","dark:fill-dark-tremor-content-emphasis"),x:"50%",y:"50%",textAnchor:"middle",dominantBaseline:"middle"},C):null,s.createElement(eT,{className:(0,a.q)("stroke-tremor-background dark:stroke-dark-tremor-background",w?"cursor-pointer":"cursor-default"),data:eD(n,f),cx:"50%",cy:"50%",startAngle:90,endAngle:-270,innerRadius:O?"75%":"0%",outerRadius:"100%",stroke:"",strokeLinejoin:"round",dataKey:c,nameKey:d,isAnimationActive:y,animationDuration:v,onClick:function(e,t,n){n.stopPropagation(),P&&(j===t?(_(void 0),null==w||w(null)):(_(t),null==w||w(Object.assign({eventType:"slice"},e.payload.payload))))},activeIndex:j,inactiveShape:ez,style:{outline:"none"}}),s.createElement(eN.u,{wrapperStyle:{outline:"none"},isAnimationActive:!1,content:b?e=>{var t;let{active:n,payload:r}=e;return k?s.createElement(k,{payload:null==r?void 0:r.map(e=>{var t,n,i;return Object.assign(Object.assign({},e),{color:null!==(i=null===(n=null===(t=null==r?void 0:r[0])||void 0===t?void 0:t.payload)||void 0===n?void 0:n.color)&&void 0!==i?i:o.fr.Gray})}),active:n,label:null===(t=null==r?void 0:r[0])||void 0===t?void 0:t.name}):s.createElement(eR,{active:n,payload:r,valueFormatter:h})}:s.createElement(s.Fragment,null)})):s.createElement(eA.Z,{noDataText:x})))});eZ.displayName="DonutChart"},59664:function(e,t,n){"use strict";n.d(t,{Z:function(){return E}});var r=n(5853),o=n(2265),i=n(47625),a=n(93765),l=n(54061),s=n(97059),c=n(62994),u=n(25311),d=(0,a.z)({chartName:"LineChart",GraphicalChild:l.x,axisComponents:[{axisType:"xAxis",AxisComp:s.K},{axisType:"yAxis",AxisComp:c.B}],formatAxisMap:u.t9}),f=n(56940),p=n(8147),h=n(22190),m=n(81889),g=n(65278),v=n(98593),y=n(69448),b=n(32644),x=n(7084),w=n(26898),k=n(97324),S=n(1153);let E=o.forwardRef((e,t)=>{let{data:n=[],categories:a=[],index:u,colors:E=w.s,valueFormatter:O=S.Cj,startEndOnly:C=!1,showXAxis:j=!0,showYAxis:_=!0,yAxisWidth:P=56,intervalType:T="equidistantPreserveStart",animationDuration:M=900,showAnimation:N=!1,showTooltip:A=!0,showLegend:I=!0,showGridLines:R=!0,autoMinValue:D=!1,curveType:L="linear",minValue:z,maxValue:Z,connectNulls:B=!1,allowDecimals:F=!0,noDataText:H,className:q,onValueChange:U,enableLegendSlider:W=!1,customTooltip:K,rotateLabelX:V,tickGap:$=5}=e,X=(0,r._T)(e,["data","categories","index","colors","valueFormatter","startEndOnly","showXAxis","showYAxis","yAxisWidth","intervalType","animationDuration","showAnimation","showTooltip","showLegend","showGridLines","autoMinValue","curveType","minValue","maxValue","connectNulls","allowDecimals","noDataText","className","onValueChange","enableLegendSlider","customTooltip","rotateLabelX","tickGap"]),G=j||_?20:0,[Y,Q]=(0,o.useState)(60),[J,ee]=(0,o.useState)(void 0),[et,en]=(0,o.useState)(void 0),er=(0,b.me)(a,E),eo=(0,b.i4)(D,z,Z),ei=!!U;function ea(e){ei&&(e===et&&!J||(0,b.FB)(n,e)&&J&&J.dataKey===e?(en(void 0),null==U||U(null)):(en(e),null==U||U({eventType:"category",categoryClicked:e})),ee(void 0))}return o.createElement("div",Object.assign({ref:t,className:(0,k.q)("w-full h-80",q)},X),o.createElement(i.h,{className:"h-full w-full"},(null==n?void 0:n.length)?o.createElement(d,{data:n,onClick:ei&&(et||J)?()=>{ee(void 0),en(void 0),null==U||U(null)}:void 0},R?o.createElement(f.q,{className:(0,k.q)("stroke-1","stroke-tremor-border","dark:stroke-dark-tremor-border"),horizontal:!0,vertical:!1}):null,o.createElement(s.K,{padding:{left:G,right:G},hide:!j,dataKey:u,interval:C?"preserveStartEnd":T,tick:{transform:"translate(0, 6)"},ticks:C?[n[0][u],n[n.length-1][u]]:void 0,fill:"",stroke:"",className:(0,k.q)("text-tremor-label","fill-tremor-content","dark:fill-dark-tremor-content"),tickLine:!1,axisLine:!1,minTickGap:$,angle:null==V?void 0:V.angle,dy:null==V?void 0:V.verticalShift,height:null==V?void 0:V.xAxisHeight}),o.createElement(c.B,{width:P,hide:!_,axisLine:!1,tickLine:!1,type:"number",domain:eo,tick:{transform:"translate(-3, 0)"},fill:"",stroke:"",className:(0,k.q)("text-tremor-label","fill-tremor-content","dark:fill-dark-tremor-content"),tickFormatter:O,allowDecimals:F}),o.createElement(p.u,{wrapperStyle:{outline:"none"},isAnimationActive:!1,cursor:{stroke:"#d1d5db",strokeWidth:1},content:A?e=>{let{active:t,payload:n,label:r}=e;return K?o.createElement(K,{payload:null==n?void 0:n.map(e=>{var t;return Object.assign(Object.assign({},e),{color:null!==(t=er.get(e.dataKey))&&void 0!==t?t:x.fr.Gray})}),active:t,label:r}):o.createElement(v.ZP,{active:t,payload:n,label:r,valueFormatter:O,categoryColors:er})}:o.createElement(o.Fragment,null),position:{y:0}}),I?o.createElement(h.D,{verticalAlign:"top",height:Y,content:e=>{let{payload:t}=e;return(0,g.Z)({payload:t},er,Q,et,ei?e=>ea(e):void 0,W)}}):null,a.map(e=>{var t;return o.createElement(l.x,{className:(0,k.q)((0,S.bM)(null!==(t=er.get(e))&&void 0!==t?t:x.fr.Gray,w.K.text).strokeColor),strokeOpacity:J||et&&et!==e?.3:1,activeDot:e=>{var t;let{cx:r,cy:i,stroke:a,strokeLinecap:l,strokeLinejoin:s,strokeWidth:c,dataKey:u}=e;return o.createElement(m.o,{className:(0,k.q)("stroke-tremor-background dark:stroke-dark-tremor-background",U?"cursor-pointer":"",(0,S.bM)(null!==(t=er.get(u))&&void 0!==t?t:x.fr.Gray,w.K.text).fillColor),cx:r,cy:i,r:5,fill:"",stroke:a,strokeLinecap:l,strokeLinejoin:s,strokeWidth:c,onClick:(t,r)=>{r.stopPropagation(),ei&&(e.index===(null==J?void 0:J.index)&&e.dataKey===(null==J?void 0:J.dataKey)||(0,b.FB)(n,e.dataKey)&&et&&et===e.dataKey?(en(void 0),ee(void 0),null==U||U(null)):(en(e.dataKey),ee({index:e.index,dataKey:e.dataKey}),null==U||U(Object.assign({eventType:"dot",categoryClicked:e.dataKey},e.payload))))}})},dot:t=>{var r;let{stroke:i,strokeLinecap:a,strokeLinejoin:l,strokeWidth:s,cx:c,cy:u,dataKey:d,index:f}=t;return(0,b.FB)(n,e)&&!(J||et&&et!==e)||(null==J?void 0:J.index)===f&&(null==J?void 0:J.dataKey)===e?o.createElement(m.o,{key:f,cx:c,cy:u,r:5,stroke:i,fill:"",strokeLinecap:a,strokeLinejoin:l,strokeWidth:s,className:(0,k.q)("stroke-tremor-background dark:stroke-dark-tremor-background",U?"cursor-pointer":"",(0,S.bM)(null!==(r=er.get(d))&&void 0!==r?r:x.fr.Gray,w.K.text).fillColor)}):o.createElement(o.Fragment,{key:f})},key:e,name:e,type:L,dataKey:e,stroke:"",strokeWidth:2,strokeLinejoin:"round",strokeLinecap:"round",isAnimationActive:N,animationDuration:M,connectNulls:B})}),U?a.map(e=>o.createElement(l.x,{className:(0,k.q)("cursor-pointer"),strokeOpacity:0,key:e,name:e,type:L,dataKey:e,stroke:"transparent",fill:"transparent",legendType:"none",tooltipType:"none",strokeWidth:12,connectNulls:B,onClick:(e,t)=>{t.stopPropagation();let{name:n}=e;ea(n)}})):null):o.createElement(y.Z,{noDataText:H})))});E.displayName="LineChart"},65278:function(e,t,n){"use strict";n.d(t,{Z:function(){return m}});var r=n(2265);let o=(e,t)=>{let[n,o]=(0,r.useState)(t);(0,r.useEffect)(()=>{let t=()=>{o(window.innerWidth),e()};return t(),window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[e,n])};var i=n(5853),a=n(26898),l=n(97324),s=n(1153);let c=e=>{var t=(0,i._T)(e,[]);return r.createElement("svg",Object.assign({},t,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"}),r.createElement("path",{d:"M8 12L14 6V18L8 12Z"}))},u=e=>{var t=(0,i._T)(e,[]);return r.createElement("svg",Object.assign({},t,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"}),r.createElement("path",{d:"M16 12L10 18V6L16 12Z"}))},d=(0,s.fn)("Legend"),f=e=>{let{name:t,color:n,onClick:o,activeLegend:i}=e,c=!!o;return r.createElement("li",{className:(0,l.q)(d("legendItem"),"group inline-flex items-center px-2 py-0.5 rounded-tremor-small transition whitespace-nowrap",c?"cursor-pointer":"cursor-default","text-tremor-content",c?"hover:bg-tremor-background-subtle":"","dark:text-dark-tremor-content",c?"dark:hover:bg-dark-tremor-background-subtle":""),onClick:e=>{e.stopPropagation(),null==o||o(t,n)}},r.createElement("svg",{className:(0,l.q)("flex-none h-2 w-2 mr-1.5",(0,s.bM)(n,a.K.text).textColor,i&&i!==t?"opacity-40":"opacity-100"),fill:"currentColor",viewBox:"0 0 8 8"},r.createElement("circle",{cx:4,cy:4,r:4})),r.createElement("p",{className:(0,l.q)("whitespace-nowrap truncate text-tremor-default","text-tremor-content",c?"group-hover:text-tremor-content-emphasis":"","dark:text-dark-tremor-content",i&&i!==t?"opacity-40":"opacity-100",c?"dark:group-hover:text-dark-tremor-content-emphasis":"")},t))},p=e=>{let{icon:t,onClick:n,disabled:o}=e,[i,a]=r.useState(!1),s=r.useRef(null);return r.useEffect(()=>(i?s.current=setInterval(()=>{null==n||n()},300):clearInterval(s.current),()=>clearInterval(s.current)),[i,n]),(0,r.useEffect)(()=>{o&&(clearInterval(s.current),a(!1))},[o]),r.createElement("button",{type:"button",className:(0,l.q)(d("legendSliderButton"),"w-5 group inline-flex items-center truncate rounded-tremor-small transition",o?"cursor-not-allowed":"cursor-pointer",o?"text-tremor-content-subtle":"text-tremor-content hover:text-tremor-content-emphasis hover:bg-tremor-background-subtle",o?"dark:text-dark-tremor-subtle":"dark:text-dark-tremor dark:hover:text-tremor-content-emphasis dark:hover:bg-dark-tremor-background-subtle"),disabled:o,onClick:e=>{e.stopPropagation(),null==n||n()},onMouseDown:e=>{e.stopPropagation(),a(!0)},onMouseUp:e=>{e.stopPropagation(),a(!1)}},r.createElement(t,{className:"w-full"}))},h=r.forwardRef((e,t)=>{var n,o;let{categories:s,colors:h=a.s,className:m,onClickLegendItem:g,activeLegend:v,enableLegendSlider:y=!1}=e,b=(0,i._T)(e,["categories","colors","className","onClickLegendItem","activeLegend","enableLegendSlider"]),x=r.useRef(null),[w,k]=r.useState(null),[S,E]=r.useState(null),O=r.useRef(null),C=(0,r.useCallback)(()=>{let e=null==x?void 0:x.current;e&&k({left:e.scrollLeft>0,right:e.scrollWidth-e.clientWidth>e.scrollLeft})},[k]),j=(0,r.useCallback)(e=>{var t;let n=null==x?void 0:x.current,r=null!==(t=null==n?void 0:n.clientWidth)&&void 0!==t?t:0;n&&y&&(n.scrollTo({left:"left"===e?n.scrollLeft-r:n.scrollLeft+r,behavior:"smooth"}),setTimeout(()=>{C()},400))},[y,C]);r.useEffect(()=>{let e=e=>{"ArrowLeft"===e?j("left"):"ArrowRight"===e&&j("right")};return S?(e(S),O.current=setInterval(()=>{e(S)},300)):clearInterval(O.current),()=>clearInterval(O.current)},[S,j]);let _=e=>{e.stopPropagation(),"ArrowLeft"!==e.key&&"ArrowRight"!==e.key||(e.preventDefault(),E(e.key))},P=e=>{e.stopPropagation(),E(null)};return r.useEffect(()=>{let e=null==x?void 0:x.current;return y&&(C(),null==e||e.addEventListener("keydown",_),null==e||e.addEventListener("keyup",P)),()=>{null==e||e.removeEventListener("keydown",_),null==e||e.removeEventListener("keyup",P)}},[C,y]),r.createElement("ol",Object.assign({ref:t,className:(0,l.q)(d("root"),"relative overflow-hidden",m)},b),r.createElement("div",{ref:x,tabIndex:0,className:(0,l.q)("h-full flex",y?(null==w?void 0:w.right)||(null==w?void 0:w.left)?"pl-4 pr-12 items-center overflow-auto snap-mandatory [&::-webkit-scrollbar]:hidden [scrollbar-width:none]":"":"flex-wrap")},s.map((e,t)=>r.createElement(f,{key:"item-".concat(t),name:e,color:h[t],onClick:g,activeLegend:v}))),y&&((null==w?void 0:w.right)||(null==w?void 0:w.left))?r.createElement(r.Fragment,null,r.createElement("div",{className:(0,l.q)("from-tremor-background","dark:from-dark-tremor-background","absolute top-0 bottom-0 left-0 w-4 bg-gradient-to-r to-transparent pointer-events-none")}),r.createElement("div",{className:(0,l.q)("to-tremor-background","dark:to-dark-tremor-background","absolute top-0 bottom-0 right-10 w-4 bg-gradient-to-r from-transparent pointer-events-none")}),r.createElement("div",{className:(0,l.q)("bg-tremor-background","dark:bg-dark-tremor-background","absolute flex top-0 pr-1 bottom-0 right-0 items-center justify-center h-full")},r.createElement(p,{icon:c,onClick:()=>{E(null),j("left")},disabled:!(null==w?void 0:w.left)}),r.createElement(p,{icon:u,onClick:()=>{E(null),j("right")},disabled:!(null==w?void 0:w.right)}))):null)});h.displayName="Legend";let m=(e,t,n,i,a,l)=>{let{payload:s}=e,c=(0,r.useRef)(null);o(()=>{var e,t;n((t=null===(e=c.current)||void 0===e?void 0:e.clientHeight)?Number(t)+20:60)});let u=s.filter(e=>"none"!==e.type);return r.createElement("div",{ref:c,className:"flex items-center justify-end"},r.createElement(h,{categories:u.map(e=>e.value),colors:u.map(e=>t.get(e.value)),onClickLegendItem:a,activeLegend:i,enableLegendSlider:l}))}},98593:function(e,t,n){"use strict";n.d(t,{$B:function(){return s},ZP:function(){return u},zX:function(){return c}});var r=n(2265),o=n(7084),i=n(26898),a=n(97324),l=n(1153);let s=e=>{let{children:t}=e;return r.createElement("div",{className:(0,a.q)("rounded-tremor-default text-tremor-default border","bg-tremor-background shadow-tremor-dropdown border-tremor-border","dark:bg-dark-tremor-background dark:shadow-dark-tremor-dropdown dark:border-dark-tremor-border")},t)},c=e=>{let{value:t,name:n,color:o}=e;return r.createElement("div",{className:"flex items-center justify-between space-x-8"},r.createElement("div",{className:"flex items-center space-x-2"},r.createElement("span",{className:(0,a.q)("shrink-0 rounded-tremor-full border-2 h-3 w-3","border-tremor-background shadow-tremor-card","dark:border-dark-tremor-background dark:shadow-dark-tremor-card",(0,l.bM)(o,i.K.background).bgColor)}),r.createElement("p",{className:(0,a.q)("text-right whitespace-nowrap","text-tremor-content","dark:text-dark-tremor-content")},n)),r.createElement("p",{className:(0,a.q)("font-medium tabular-nums text-right whitespace-nowrap","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis")},t))},u=e=>{let{active:t,payload:n,label:i,categoryColors:l,valueFormatter:u}=e;if(t&&n){let e=n.filter(e=>"none"!==e.type);return r.createElement(s,null,r.createElement("div",{className:(0,a.q)("border-tremor-border border-b px-4 py-2","dark:border-dark-tremor-border")},r.createElement("p",{className:(0,a.q)("font-medium","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis")},i)),r.createElement("div",{className:(0,a.q)("px-4 py-2 space-y-1")},e.map((e,t)=>{var n;let{value:i,name:a}=e;return r.createElement(c,{key:"id-".concat(t),value:u(i),name:a,color:null!==(n=l.get(a))&&void 0!==n?n:o.fr.Blue})})))}return null}},69448:function(e,t,n){"use strict";n.d(t,{Z:function(){return f}});var r=n(97324),o=n(2265),i=n(5853);let a=(0,n(1153).fn)("Flex"),l={start:"justify-start",end:"justify-end",center:"justify-center",between:"justify-between",around:"justify-around",evenly:"justify-evenly"},s={start:"items-start",end:"items-end",center:"items-center",baseline:"items-baseline",stretch:"items-stretch"},c={row:"flex-row",col:"flex-col","row-reverse":"flex-row-reverse","col-reverse":"flex-col-reverse"},u=o.forwardRef((e,t)=>{let{flexDirection:n="row",justifyContent:u="between",alignItems:d="center",children:f,className:p}=e,h=(0,i._T)(e,["flexDirection","justifyContent","alignItems","children","className"]);return o.createElement("div",Object.assign({ref:t,className:(0,r.q)(a("root"),"flex w-full",c[n],l[u],s[d],p)},h),f)});u.displayName="Flex";var d=n(84264);let f=e=>{let{noDataText:t="No data"}=e;return o.createElement(u,{alignItems:"center",justifyContent:"center",className:(0,r.q)("w-full h-full border border-dashed rounded-tremor-default","border-tremor-border","dark:border-dark-tremor-border")},o.createElement(d.Z,{className:(0,r.q)("text-tremor-content","dark:text-dark-tremor-content")},t))}},32644:function(e,t,n){"use strict";n.d(t,{FB:function(){return i},i4:function(){return o},me:function(){return r},vZ:function(){return function e(t,n){if(t===n)return!0;if("object"!=typeof t||"object"!=typeof n||null===t||null===n)return!1;let r=Object.keys(t),o=Object.keys(n);if(r.length!==o.length)return!1;for(let i of r)if(!o.includes(i)||!e(t[i],n[i]))return!1;return!0}}});let r=(e,t)=>{let n=new Map;return e.forEach((e,r)=>{n.set(e,t[r])}),n},o=(e,t,n)=>[e?"auto":null!=t?t:0,null!=n?n:"auto"];function i(e,t){let n=[];for(let r of e)if(Object.prototype.hasOwnProperty.call(r,t)&&(n.push(r[t]),n.length>1))return!1;return!0}},47323:function(e,t,n){"use strict";n.d(t,{Z:function(){return m}});var r=n(5853),o=n(2265),i=n(1526),a=n(7084),l=n(97324),s=n(1153),c=n(26898);let u={xs:{paddingX:"px-1.5",paddingY:"py-1.5"},sm:{paddingX:"px-1.5",paddingY:"py-1.5"},md:{paddingX:"px-2",paddingY:"py-2"},lg:{paddingX:"px-2",paddingY:"py-2"},xl:{paddingX:"px-2.5",paddingY:"py-2.5"}},d={xs:{height:"h-3",width:"w-3"},sm:{height:"h-5",width:"w-5"},md:{height:"h-5",width:"w-5"},lg:{height:"h-7",width:"w-7"},xl:{height:"h-9",width:"w-9"}},f={simple:{rounded:"",border:"",ring:"",shadow:""},light:{rounded:"rounded-tremor-default",border:"",ring:"",shadow:""},shadow:{rounded:"rounded-tremor-default",border:"border",ring:"",shadow:"shadow-tremor-card dark:shadow-dark-tremor-card"},solid:{rounded:"rounded-tremor-default",border:"border-2",ring:"ring-1",shadow:""},outlined:{rounded:"rounded-tremor-default",border:"border",ring:"ring-2",shadow:""}},p=(e,t)=>{switch(e){case"simple":return{textColor:t?(0,s.bM)(t,c.K.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:"",borderColor:"",ringColor:""};case"light":return{textColor:t?(0,s.bM)(t,c.K.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,l.q)((0,s.bM)(t,c.K.background).bgColor,"bg-opacity-20"):"bg-tremor-brand-muted dark:bg-dark-tremor-brand-muted",borderColor:"",ringColor:""};case"shadow":return{textColor:t?(0,s.bM)(t,c.K.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,l.q)((0,s.bM)(t,c.K.background).bgColor,"bg-opacity-20"):"bg-tremor-background dark:bg-dark-tremor-background",borderColor:"border-tremor-border dark:border-dark-tremor-border",ringColor:""};case"solid":return{textColor:t?(0,s.bM)(t,c.K.text).textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,l.q)((0,s.bM)(t,c.K.background).bgColor,"bg-opacity-20"):"bg-tremor-brand dark:bg-dark-tremor-brand",borderColor:"border-tremor-brand-inverted dark:border-dark-tremor-brand-inverted",ringColor:"ring-tremor-ring dark:ring-dark-tremor-ring"};case"outlined":return{textColor:t?(0,s.bM)(t,c.K.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,l.q)((0,s.bM)(t,c.K.background).bgColor,"bg-opacity-20"):"bg-tremor-background dark:bg-dark-tremor-background",borderColor:t?(0,s.bM)(t,c.K.ring).borderColor:"border-tremor-brand-subtle dark:border-dark-tremor-brand-subtle",ringColor:t?(0,l.q)((0,s.bM)(t,c.K.ring).ringColor,"ring-opacity-40"):"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"}}},h=(0,s.fn)("Icon"),m=o.forwardRef((e,t)=>{let{icon:n,variant:c="simple",tooltip:m,size:g=a.u8.SM,color:v,className:y}=e,b=(0,r._T)(e,["icon","variant","tooltip","size","color","className"]),x=p(c,v),{tooltipProps:w,getReferenceProps:k}=(0,i.l)();return o.createElement("span",Object.assign({ref:(0,s.lq)([t,w.refs.setReference]),className:(0,l.q)(h("root"),"inline-flex flex-shrink-0 items-center",x.bgColor,x.textColor,x.borderColor,x.ringColor,f[c].rounded,f[c].border,f[c].shadow,f[c].ring,u[g].paddingX,u[g].paddingY,y)},k,b),o.createElement(i.Z,Object.assign({text:m},w)),o.createElement(n,{className:(0,l.q)(h("icon"),"shrink-0",d[g].height,d[g].width)}))});m.displayName="Icon"},21487:function(e,t,n){"use strict";let r,o,i;n.d(t,{Z:function(){return nF}});var a,l,s,c,u=n(5853),d=n(2265),f=n(54887),p=n(13323),h=n(64518),m=n(96822),g=n(40048),v=n(72238),y=n(93689);let b=(0,d.createContext)(!1);var x=n(61424),w=n(27847);let k=d.Fragment,S=d.Fragment,E=(0,d.createContext)(null),O=(0,d.createContext)(null);Object.assign((0,w.yV)(function(e,t){var n;let r,o,i=(0,d.useRef)(null),a=(0,y.T)((0,y.h)(e=>{i.current=e}),t),l=(0,g.i)(i),s=function(e){let t=(0,d.useContext)(b),n=(0,d.useContext)(E),r=(0,g.i)(e),[o,i]=(0,d.useState)(()=>{if(!t&&null!==n||x.O.isServer)return null;let e=null==r?void 0:r.getElementById("headlessui-portal-root");if(e)return e;if(null===r)return null;let o=r.createElement("div");return o.setAttribute("id","headlessui-portal-root"),r.body.appendChild(o)});return(0,d.useEffect)(()=>{null!==o&&(null!=r&&r.body.contains(o)||null==r||r.body.appendChild(o))},[o,r]),(0,d.useEffect)(()=>{t||null!==n&&i(n.current)},[n,i,t]),o}(i),[c]=(0,d.useState)(()=>{var e;return x.O.isServer?null:null!=(e=null==l?void 0:l.createElement("div"))?e:null}),u=(0,d.useContext)(O),S=(0,v.H)();return(0,h.e)(()=>{!s||!c||s.contains(c)||(c.setAttribute("data-headlessui-portal",""),s.appendChild(c))},[s,c]),(0,h.e)(()=>{if(c&&u)return u.register(c)},[u,c]),n=()=>{var e;s&&c&&(c instanceof Node&&s.contains(c)&&s.removeChild(c),s.childNodes.length<=0&&(null==(e=s.parentElement)||e.removeChild(s)))},r=(0,p.z)(n),o=(0,d.useRef)(!1),(0,d.useEffect)(()=>(o.current=!1,()=>{o.current=!0,(0,m.Y)(()=>{o.current&&r()})}),[r]),S&&s&&c?(0,f.createPortal)((0,w.sY)({ourProps:{ref:a},theirProps:e,defaultTag:k,name:"Portal"}),c):null}),{Group:(0,w.yV)(function(e,t){let{target:n,...r}=e,o={ref:(0,y.T)(t)};return d.createElement(E.Provider,{value:n},(0,w.sY)({ourProps:o,theirProps:r,defaultTag:S,name:"Popover.Group"}))})});var C=n(31948),j=n(17684),_=n(32539),P=n(80004),T=n(38198),M=n(3141),N=((r=N||{})[r.Forwards=0]="Forwards",r[r.Backwards=1]="Backwards",r);function A(){let e=(0,d.useRef)(0);return(0,M.s)("keydown",t=>{"Tab"===t.key&&(e.current=t.shiftKey?1:0)},!0),e}var I=n(37863),R=n(47634),D=n(37105),L=n(24536),z=n(40293),Z=n(37388),B=((o=B||{})[o.Open=0]="Open",o[o.Closed=1]="Closed",o),F=((i=F||{})[i.TogglePopover=0]="TogglePopover",i[i.ClosePopover=1]="ClosePopover",i[i.SetButton=2]="SetButton",i[i.SetButtonId=3]="SetButtonId",i[i.SetPanel=4]="SetPanel",i[i.SetPanelId=5]="SetPanelId",i);let H={0:e=>{let t={...e,popoverState:(0,L.E)(e.popoverState,{0:1,1:0})};return 0===t.popoverState&&(t.__demoMode=!1),t},1:e=>1===e.popoverState?e:{...e,popoverState:1},2:(e,t)=>e.button===t.button?e:{...e,button:t.button},3:(e,t)=>e.buttonId===t.buttonId?e:{...e,buttonId:t.buttonId},4:(e,t)=>e.panel===t.panel?e:{...e,panel:t.panel},5:(e,t)=>e.panelId===t.panelId?e:{...e,panelId:t.panelId}},q=(0,d.createContext)(null);function U(e){let t=(0,d.useContext)(q);if(null===t){let t=Error("<".concat(e," /> is missing a parent component."));throw Error.captureStackTrace&&Error.captureStackTrace(t,U),t}return t}q.displayName="PopoverContext";let W=(0,d.createContext)(null);function K(e){let t=(0,d.useContext)(W);if(null===t){let t=Error("<".concat(e," /> is missing a parent component."));throw Error.captureStackTrace&&Error.captureStackTrace(t,K),t}return t}W.displayName="PopoverAPIContext";let V=(0,d.createContext)(null);function $(){return(0,d.useContext)(V)}V.displayName="PopoverGroupContext";let X=(0,d.createContext)(null);function G(e,t){return(0,L.E)(t.type,H,e,t)}X.displayName="PopoverPanelContext";let Y=w.AN.RenderStrategy|w.AN.Static,Q=w.AN.RenderStrategy|w.AN.Static,J=Object.assign((0,w.yV)(function(e,t){var n,r,o,i;let a,l,s,c,u,f;let{__demoMode:h=!1,...m}=e,v=(0,d.useRef)(null),b=(0,y.T)(t,(0,y.h)(e=>{v.current=e})),x=(0,d.useRef)([]),k=(0,d.useReducer)(G,{__demoMode:h,popoverState:h?0:1,buttons:x,button:null,buttonId:null,panel:null,panelId:null,beforePanelSentinel:(0,d.createRef)(),afterPanelSentinel:(0,d.createRef)()}),[{popoverState:S,button:E,buttonId:j,panel:P,panelId:M,beforePanelSentinel:N,afterPanelSentinel:A},R]=k,z=(0,g.i)(null!=(n=v.current)?n:E),Z=(0,d.useMemo)(()=>{if(!E||!P)return!1;for(let e of document.querySelectorAll("body > *"))if(Number(null==e?void 0:e.contains(E))^Number(null==e?void 0:e.contains(P)))return!0;let e=(0,D.GO)(),t=e.indexOf(E),n=(t+e.length-1)%e.length,r=(t+1)%e.length,o=e[n],i=e[r];return!P.contains(o)&&!P.contains(i)},[E,P]),B=(0,C.E)(j),F=(0,C.E)(M),H=(0,d.useMemo)(()=>({buttonId:B,panelId:F,close:()=>R({type:1})}),[B,F,R]),U=$(),K=null==U?void 0:U.registerPopover,V=(0,p.z)(()=>{var e;return null!=(e=null==U?void 0:U.isFocusWithinPopoverGroup())?e:(null==z?void 0:z.activeElement)&&((null==E?void 0:E.contains(z.activeElement))||(null==P?void 0:P.contains(z.activeElement)))});(0,d.useEffect)(()=>null==K?void 0:K(H),[K,H]);let[Y,Q]=(a=(0,d.useContext)(O),l=(0,d.useRef)([]),s=(0,p.z)(e=>(l.current.push(e),a&&a.register(e),()=>c(e))),c=(0,p.z)(e=>{let t=l.current.indexOf(e);-1!==t&&l.current.splice(t,1),a&&a.unregister(e)}),u=(0,d.useMemo)(()=>({register:s,unregister:c,portals:l}),[s,c,l]),[l,(0,d.useMemo)(()=>function(e){let{children:t}=e;return d.createElement(O.Provider,{value:u},t)},[u])]),J=function(){var e;let{defaultContainers:t=[],portals:n,mainTreeNodeRef:r}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},o=(0,d.useRef)(null!=(e=null==r?void 0:r.current)?e:null),i=(0,g.i)(o),a=(0,p.z)(()=>{var e,r,a;let l=[];for(let e of t)null!==e&&(e instanceof HTMLElement?l.push(e):"current"in e&&e.current instanceof HTMLElement&&l.push(e.current));if(null!=n&&n.current)for(let e of n.current)l.push(e);for(let t of null!=(e=null==i?void 0:i.querySelectorAll("html > *, body > *"))?e:[])t!==document.body&&t!==document.head&&t instanceof HTMLElement&&"headlessui-portal-root"!==t.id&&(t.contains(o.current)||t.contains(null==(a=null==(r=o.current)?void 0:r.getRootNode())?void 0:a.host)||l.some(e=>t.contains(e))||l.push(t));return l});return{resolveContainers:a,contains:(0,p.z)(e=>a().some(t=>t.contains(e))),mainTreeNodeRef:o,MainTreeNode:(0,d.useMemo)(()=>function(){return null!=r?null:d.createElement(T._,{features:T.A.Hidden,ref:o})},[o,r])}}({mainTreeNodeRef:null==U?void 0:U.mainTreeNodeRef,portals:Y,defaultContainers:[E,P]});r=null==z?void 0:z.defaultView,o="focus",i=e=>{var t,n,r,o;e.target!==window&&e.target instanceof HTMLElement&&0===S&&(V()||E&&P&&(J.contains(e.target)||null!=(n=null==(t=N.current)?void 0:t.contains)&&n.call(t,e.target)||null!=(o=null==(r=A.current)?void 0:r.contains)&&o.call(r,e.target)||R({type:1})))},f=(0,C.E)(i),(0,d.useEffect)(()=>{function e(e){f.current(e)}return(r=null!=r?r:window).addEventListener(o,e,!0),()=>r.removeEventListener(o,e,!0)},[r,o,!0]),(0,_.O)(J.resolveContainers,(e,t)=>{R({type:1}),(0,D.sP)(t,D.tJ.Loose)||(e.preventDefault(),null==E||E.focus())},0===S);let ee=(0,p.z)(e=>{R({type:1});let t=e?e instanceof HTMLElement?e:"current"in e&&e.current instanceof HTMLElement?e.current:E:E;null==t||t.focus()}),et=(0,d.useMemo)(()=>({close:ee,isPortalled:Z}),[ee,Z]),en=(0,d.useMemo)(()=>({open:0===S,close:ee}),[S,ee]);return d.createElement(X.Provider,{value:null},d.createElement(q.Provider,{value:k},d.createElement(W.Provider,{value:et},d.createElement(I.up,{value:(0,L.E)(S,{0:I.ZM.Open,1:I.ZM.Closed})},d.createElement(Q,null,(0,w.sY)({ourProps:{ref:b},theirProps:m,slot:en,defaultTag:"div",name:"Popover"}),d.createElement(J.MainTreeNode,null))))))}),{Button:(0,w.yV)(function(e,t){let n=(0,j.M)(),{id:r="headlessui-popover-button-".concat(n),...o}=e,[i,a]=U("Popover.Button"),{isPortalled:l}=K("Popover.Button"),s=(0,d.useRef)(null),c="headlessui-focus-sentinel-".concat((0,j.M)()),u=$(),f=null==u?void 0:u.closeOthers,h=null!==(0,d.useContext)(X);(0,d.useEffect)(()=>{if(!h)return a({type:3,buttonId:r}),()=>{a({type:3,buttonId:null})}},[h,r,a]);let[m]=(0,d.useState)(()=>Symbol()),v=(0,y.T)(s,t,h?null:e=>{if(e)i.buttons.current.push(m);else{let e=i.buttons.current.indexOf(m);-1!==e&&i.buttons.current.splice(e,1)}i.buttons.current.length>1&&console.warn("You are already using a but only 1 is supported."),e&&a({type:2,button:e})}),b=(0,y.T)(s,t),x=(0,g.i)(s),k=(0,p.z)(e=>{var t,n,r;if(h){if(1===i.popoverState)return;switch(e.key){case Z.R.Space:case Z.R.Enter:e.preventDefault(),null==(n=(t=e.target).click)||n.call(t),a({type:1}),null==(r=i.button)||r.focus()}}else switch(e.key){case Z.R.Space:case Z.R.Enter:e.preventDefault(),e.stopPropagation(),1===i.popoverState&&(null==f||f(i.buttonId)),a({type:0});break;case Z.R.Escape:if(0!==i.popoverState)return null==f?void 0:f(i.buttonId);if(!s.current||null!=x&&x.activeElement&&!s.current.contains(x.activeElement))return;e.preventDefault(),e.stopPropagation(),a({type:1})}}),S=(0,p.z)(e=>{h||e.key===Z.R.Space&&e.preventDefault()}),E=(0,p.z)(t=>{var n,r;(0,R.P)(t.currentTarget)||e.disabled||(h?(a({type:1}),null==(n=i.button)||n.focus()):(t.preventDefault(),t.stopPropagation(),1===i.popoverState&&(null==f||f(i.buttonId)),a({type:0}),null==(r=i.button)||r.focus()))}),O=(0,p.z)(e=>{e.preventDefault(),e.stopPropagation()}),C=0===i.popoverState,_=(0,d.useMemo)(()=>({open:C}),[C]),M=(0,P.f)(e,s),I=h?{ref:b,type:M,onKeyDown:k,onClick:E}:{ref:v,id:i.buttonId,type:M,"aria-expanded":0===i.popoverState,"aria-controls":i.panel?i.panelId:void 0,onKeyDown:k,onKeyUp:S,onClick:E,onMouseDown:O},z=A(),B=(0,p.z)(()=>{let e=i.panel;e&&(0,L.E)(z.current,{[N.Forwards]:()=>(0,D.jA)(e,D.TO.First),[N.Backwards]:()=>(0,D.jA)(e,D.TO.Last)})===D.fE.Error&&(0,D.jA)((0,D.GO)().filter(e=>"true"!==e.dataset.headlessuiFocusGuard),(0,L.E)(z.current,{[N.Forwards]:D.TO.Next,[N.Backwards]:D.TO.Previous}),{relativeTo:i.button})});return d.createElement(d.Fragment,null,(0,w.sY)({ourProps:I,theirProps:o,slot:_,defaultTag:"button",name:"Popover.Button"}),C&&!h&&l&&d.createElement(T._,{id:c,features:T.A.Focusable,"data-headlessui-focus-guard":!0,as:"button",type:"button",onFocus:B}))}),Overlay:(0,w.yV)(function(e,t){let n=(0,j.M)(),{id:r="headlessui-popover-overlay-".concat(n),...o}=e,[{popoverState:i},a]=U("Popover.Overlay"),l=(0,y.T)(t),s=(0,I.oJ)(),c=null!==s?(s&I.ZM.Open)===I.ZM.Open:0===i,u=(0,p.z)(e=>{if((0,R.P)(e.currentTarget))return e.preventDefault();a({type:1})}),f=(0,d.useMemo)(()=>({open:0===i}),[i]);return(0,w.sY)({ourProps:{ref:l,id:r,"aria-hidden":!0,onClick:u},theirProps:o,slot:f,defaultTag:"div",features:Y,visible:c,name:"Popover.Overlay"})}),Panel:(0,w.yV)(function(e,t){let n=(0,j.M)(),{id:r="headlessui-popover-panel-".concat(n),focus:o=!1,...i}=e,[a,l]=U("Popover.Panel"),{close:s,isPortalled:c}=K("Popover.Panel"),u="headlessui-focus-sentinel-before-".concat((0,j.M)()),f="headlessui-focus-sentinel-after-".concat((0,j.M)()),m=(0,d.useRef)(null),v=(0,y.T)(m,t,e=>{l({type:4,panel:e})}),b=(0,g.i)(m),x=(0,w.Y2)();(0,h.e)(()=>(l({type:5,panelId:r}),()=>{l({type:5,panelId:null})}),[r,l]);let k=(0,I.oJ)(),S=null!==k?(k&I.ZM.Open)===I.ZM.Open:0===a.popoverState,E=(0,p.z)(e=>{var t;if(e.key===Z.R.Escape){if(0!==a.popoverState||!m.current||null!=b&&b.activeElement&&!m.current.contains(b.activeElement))return;e.preventDefault(),e.stopPropagation(),l({type:1}),null==(t=a.button)||t.focus()}});(0,d.useEffect)(()=>{var t;e.static||1===a.popoverState&&(null==(t=e.unmount)||t)&&l({type:4,panel:null})},[a.popoverState,e.unmount,e.static,l]),(0,d.useEffect)(()=>{if(a.__demoMode||!o||0!==a.popoverState||!m.current)return;let e=null==b?void 0:b.activeElement;m.current.contains(e)||(0,D.jA)(m.current,D.TO.First)},[a.__demoMode,o,m,a.popoverState]);let O=(0,d.useMemo)(()=>({open:0===a.popoverState,close:s}),[a,s]),C={ref:v,id:r,onKeyDown:E,onBlur:o&&0===a.popoverState?e=>{var t,n,r,o,i;let s=e.relatedTarget;s&&m.current&&(null!=(t=m.current)&&t.contains(s)||(l({type:1}),(null!=(r=null==(n=a.beforePanelSentinel.current)?void 0:n.contains)&&r.call(n,s)||null!=(i=null==(o=a.afterPanelSentinel.current)?void 0:o.contains)&&i.call(o,s))&&s.focus({preventScroll:!0})))}:void 0,tabIndex:-1},_=A(),P=(0,p.z)(()=>{let e=m.current;e&&(0,L.E)(_.current,{[N.Forwards]:()=>{var t;(0,D.jA)(e,D.TO.First)===D.fE.Error&&(null==(t=a.afterPanelSentinel.current)||t.focus())},[N.Backwards]:()=>{var e;null==(e=a.button)||e.focus({preventScroll:!0})}})}),M=(0,p.z)(()=>{let e=m.current;e&&(0,L.E)(_.current,{[N.Forwards]:()=>{var e;if(!a.button)return;let t=(0,D.GO)(),n=t.indexOf(a.button),r=t.slice(0,n+1),o=[...t.slice(n+1),...r];for(let t of o.slice())if("true"===t.dataset.headlessuiFocusGuard||null!=(e=a.panel)&&e.contains(t)){let e=o.indexOf(t);-1!==e&&o.splice(e,1)}(0,D.jA)(o,D.TO.First,{sorted:!1})},[N.Backwards]:()=>{var t;(0,D.jA)(e,D.TO.Previous)===D.fE.Error&&(null==(t=a.button)||t.focus())}})});return d.createElement(X.Provider,{value:r},S&&c&&d.createElement(T._,{id:u,ref:a.beforePanelSentinel,features:T.A.Focusable,"data-headlessui-focus-guard":!0,as:"button",type:"button",onFocus:P}),(0,w.sY)({mergeRefs:x,ourProps:C,theirProps:i,slot:O,defaultTag:"div",features:Q,visible:S,name:"Popover.Panel"}),S&&c&&d.createElement(T._,{id:f,ref:a.afterPanelSentinel,features:T.A.Focusable,"data-headlessui-focus-guard":!0,as:"button",type:"button",onFocus:M}))}),Group:(0,w.yV)(function(e,t){let n;let r=(0,d.useRef)(null),o=(0,y.T)(r,t),[i,a]=(0,d.useState)([]),l={mainTreeNodeRef:n=(0,d.useRef)(null),MainTreeNode:(0,d.useMemo)(()=>function(){return d.createElement(T._,{features:T.A.Hidden,ref:n})},[n])},s=(0,p.z)(e=>{a(t=>{let n=t.indexOf(e);if(-1!==n){let e=t.slice();return e.splice(n,1),e}return t})}),c=(0,p.z)(e=>(a(t=>[...t,e]),()=>s(e))),u=(0,p.z)(()=>{var e;let t=(0,z.r)(r);if(!t)return!1;let n=t.activeElement;return!!(null!=(e=r.current)&&e.contains(n))||i.some(e=>{var r,o;return(null==(r=t.getElementById(e.buttonId.current))?void 0:r.contains(n))||(null==(o=t.getElementById(e.panelId.current))?void 0:o.contains(n))})}),f=(0,p.z)(e=>{for(let t of i)t.buttonId.current!==e&&t.close()}),h=(0,d.useMemo)(()=>({registerPopover:c,unregisterPopover:s,isFocusWithinPopoverGroup:u,closeOthers:f,mainTreeNodeRef:l.mainTreeNodeRef}),[c,s,u,f,l.mainTreeNodeRef]),m=(0,d.useMemo)(()=>({}),[]);return d.createElement(V.Provider,{value:h},(0,w.sY)({ourProps:{ref:o},theirProps:e,slot:m,defaultTag:"div",name:"Popover.Group"}),d.createElement(l.MainTreeNode,null))})});var ee=n(33044),et=n(9528);let en=e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({},t,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor"}),d.createElement("path",{fillRule:"evenodd",d:"M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z",clipRule:"evenodd"}))};var er=n(4537),eo=n(99735),ei=n(7656);function ea(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e);return t.setHours(0,0,0,0),t}function el(){return ea(Date.now())}function es(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e);return t.setDate(1),t.setHours(0,0,0,0),t}var ec=n(97324),eu=n(96398),ed=n(41154);function ef(e){var t,n;if((0,ei.Z)(1,arguments),e&&"function"==typeof e.forEach)t=e;else{if("object"!==(0,ed.Z)(e)||null===e)return new Date(NaN);t=Array.prototype.slice.call(e)}return t.forEach(function(e){var t=(0,eo.Z)(e);(void 0===n||nt||isNaN(t.getDate()))&&(n=t)}),n||new Date(NaN)}var eh=n(25721),em=n(47869);function eg(e,t){(0,ei.Z)(2,arguments);var n=(0,em.Z)(t);return(0,eh.Z)(e,-n)}var ev=n(55463);function ey(e,t){if((0,ei.Z)(2,arguments),!t||"object"!==(0,ed.Z)(t))return new Date(NaN);var n=t.years?(0,em.Z)(t.years):0,r=t.months?(0,em.Z)(t.months):0,o=t.weeks?(0,em.Z)(t.weeks):0,i=t.days?(0,em.Z)(t.days):0,a=t.hours?(0,em.Z)(t.hours):0,l=t.minutes?(0,em.Z)(t.minutes):0,s=t.seconds?(0,em.Z)(t.seconds):0;return new Date(eg(function(e,t){(0,ei.Z)(2,arguments);var n=(0,em.Z)(t);return(0,ev.Z)(e,-n)}(e,r+12*n),i+7*o).getTime()-1e3*(s+60*(l+60*a)))}function eb(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e),n=new Date(0);return n.setFullYear(t.getFullYear(),0,1),n.setHours(0,0,0,0),n}function ex(e){return(0,ei.Z)(1,arguments),e instanceof Date||"object"===(0,ed.Z)(e)&&"[object Date]"===Object.prototype.toString.call(e)}function ew(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e),n=t.getUTCDay();return t.setUTCDate(t.getUTCDate()-((n<1?7:0)+n-1)),t.setUTCHours(0,0,0,0),t}function ek(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e),n=t.getUTCFullYear(),r=new Date(0);r.setUTCFullYear(n+1,0,4),r.setUTCHours(0,0,0,0);var o=ew(r),i=new Date(0);i.setUTCFullYear(n,0,4),i.setUTCHours(0,0,0,0);var a=ew(i);return t.getTime()>=o.getTime()?n+1:t.getTime()>=a.getTime()?n:n-1}var eS={};function eE(e,t){(0,ei.Z)(1,arguments);var n,r,o,i,a,l,s,c,u=(0,em.Z)(null!==(n=null!==(r=null!==(o=null!==(i=null==t?void 0:t.weekStartsOn)&&void 0!==i?i:null==t?void 0:null===(a=t.locale)||void 0===a?void 0:null===(l=a.options)||void 0===l?void 0:l.weekStartsOn)&&void 0!==o?o:eS.weekStartsOn)&&void 0!==r?r:null===(s=eS.locale)||void 0===s?void 0:null===(c=s.options)||void 0===c?void 0:c.weekStartsOn)&&void 0!==n?n:0);if(!(u>=0&&u<=6))throw RangeError("weekStartsOn must be between 0 and 6 inclusively");var d=(0,eo.Z)(e),f=d.getUTCDay();return d.setUTCDate(d.getUTCDate()-((f=1&&f<=7))throw RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var p=new Date(0);p.setUTCFullYear(d+1,0,f),p.setUTCHours(0,0,0,0);var h=eE(p,t),m=new Date(0);m.setUTCFullYear(d,0,f),m.setUTCHours(0,0,0,0);var g=eE(m,t);return u.getTime()>=h.getTime()?d+1:u.getTime()>=g.getTime()?d:d-1}function eC(e,t){for(var n=Math.abs(e).toString();n.length0?n:1-n;return eC("yy"===t?r%100:r,t.length)},M:function(e,t){var n=e.getUTCMonth();return"M"===t?String(n+1):eC(n+1,2)},d:function(e,t){return eC(e.getUTCDate(),t.length)},h:function(e,t){return eC(e.getUTCHours()%12||12,t.length)},H:function(e,t){return eC(e.getUTCHours(),t.length)},m:function(e,t){return eC(e.getUTCMinutes(),t.length)},s:function(e,t){return eC(e.getUTCSeconds(),t.length)},S:function(e,t){var n=t.length;return eC(Math.floor(e.getUTCMilliseconds()*Math.pow(10,n-3)),t.length)}},e_={midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"};function eP(e,t){var n=e>0?"-":"+",r=Math.abs(e),o=Math.floor(r/60),i=r%60;return 0===i?n+String(o):n+String(o)+(t||"")+eC(i,2)}function eT(e,t){return e%60==0?(e>0?"-":"+")+eC(Math.abs(e)/60,2):eM(e,t)}function eM(e,t){var n=Math.abs(e);return(e>0?"-":"+")+eC(Math.floor(n/60),2)+(t||"")+eC(n%60,2)}var eN={G:function(e,t,n){var r=e.getUTCFullYear()>0?1:0;switch(t){case"G":case"GG":case"GGG":return n.era(r,{width:"abbreviated"});case"GGGGG":return n.era(r,{width:"narrow"});default:return n.era(r,{width:"wide"})}},y:function(e,t,n){if("yo"===t){var r=e.getUTCFullYear();return n.ordinalNumber(r>0?r:1-r,{unit:"year"})}return ej.y(e,t)},Y:function(e,t,n,r){var o=eO(e,r),i=o>0?o:1-o;return"YY"===t?eC(i%100,2):"Yo"===t?n.ordinalNumber(i,{unit:"year"}):eC(i,t.length)},R:function(e,t){return eC(ek(e),t.length)},u:function(e,t){return eC(e.getUTCFullYear(),t.length)},Q:function(e,t,n){var r=Math.ceil((e.getUTCMonth()+1)/3);switch(t){case"Q":return String(r);case"QQ":return eC(r,2);case"Qo":return n.ordinalNumber(r,{unit:"quarter"});case"QQQ":return n.quarter(r,{width:"abbreviated",context:"formatting"});case"QQQQQ":return n.quarter(r,{width:"narrow",context:"formatting"});default:return n.quarter(r,{width:"wide",context:"formatting"})}},q:function(e,t,n){var r=Math.ceil((e.getUTCMonth()+1)/3);switch(t){case"q":return String(r);case"qq":return eC(r,2);case"qo":return n.ordinalNumber(r,{unit:"quarter"});case"qqq":return n.quarter(r,{width:"abbreviated",context:"standalone"});case"qqqqq":return n.quarter(r,{width:"narrow",context:"standalone"});default:return n.quarter(r,{width:"wide",context:"standalone"})}},M:function(e,t,n){var r=e.getUTCMonth();switch(t){case"M":case"MM":return ej.M(e,t);case"Mo":return n.ordinalNumber(r+1,{unit:"month"});case"MMM":return n.month(r,{width:"abbreviated",context:"formatting"});case"MMMMM":return n.month(r,{width:"narrow",context:"formatting"});default:return n.month(r,{width:"wide",context:"formatting"})}},L:function(e,t,n){var r=e.getUTCMonth();switch(t){case"L":return String(r+1);case"LL":return eC(r+1,2);case"Lo":return n.ordinalNumber(r+1,{unit:"month"});case"LLL":return n.month(r,{width:"abbreviated",context:"standalone"});case"LLLLL":return n.month(r,{width:"narrow",context:"standalone"});default:return n.month(r,{width:"wide",context:"standalone"})}},w:function(e,t,n,r){var o=function(e,t){(0,ei.Z)(1,arguments);var n=(0,eo.Z)(e);return Math.round((eE(n,t).getTime()-(function(e,t){(0,ei.Z)(1,arguments);var n,r,o,i,a,l,s,c,u=(0,em.Z)(null!==(n=null!==(r=null!==(o=null!==(i=null==t?void 0:t.firstWeekContainsDate)&&void 0!==i?i:null==t?void 0:null===(a=t.locale)||void 0===a?void 0:null===(l=a.options)||void 0===l?void 0:l.firstWeekContainsDate)&&void 0!==o?o:eS.firstWeekContainsDate)&&void 0!==r?r:null===(s=eS.locale)||void 0===s?void 0:null===(c=s.options)||void 0===c?void 0:c.firstWeekContainsDate)&&void 0!==n?n:1),d=eO(e,t),f=new Date(0);return f.setUTCFullYear(d,0,u),f.setUTCHours(0,0,0,0),eE(f,t)})(n,t).getTime())/6048e5)+1}(e,r);return"wo"===t?n.ordinalNumber(o,{unit:"week"}):eC(o,t.length)},I:function(e,t,n){var r=function(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e);return Math.round((ew(t).getTime()-(function(e){(0,ei.Z)(1,arguments);var t=ek(e),n=new Date(0);return n.setUTCFullYear(t,0,4),n.setUTCHours(0,0,0,0),ew(n)})(t).getTime())/6048e5)+1}(e);return"Io"===t?n.ordinalNumber(r,{unit:"week"}):eC(r,t.length)},d:function(e,t,n){return"do"===t?n.ordinalNumber(e.getUTCDate(),{unit:"date"}):ej.d(e,t)},D:function(e,t,n){var r=function(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e),n=t.getTime();return t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0),Math.floor((n-t.getTime())/864e5)+1}(e);return"Do"===t?n.ordinalNumber(r,{unit:"dayOfYear"}):eC(r,t.length)},E:function(e,t,n){var r=e.getUTCDay();switch(t){case"E":case"EE":case"EEE":return n.day(r,{width:"abbreviated",context:"formatting"});case"EEEEE":return n.day(r,{width:"narrow",context:"formatting"});case"EEEEEE":return n.day(r,{width:"short",context:"formatting"});default:return n.day(r,{width:"wide",context:"formatting"})}},e:function(e,t,n,r){var o=e.getUTCDay(),i=(o-r.weekStartsOn+8)%7||7;switch(t){case"e":return String(i);case"ee":return eC(i,2);case"eo":return n.ordinalNumber(i,{unit:"day"});case"eee":return n.day(o,{width:"abbreviated",context:"formatting"});case"eeeee":return n.day(o,{width:"narrow",context:"formatting"});case"eeeeee":return n.day(o,{width:"short",context:"formatting"});default:return n.day(o,{width:"wide",context:"formatting"})}},c:function(e,t,n,r){var o=e.getUTCDay(),i=(o-r.weekStartsOn+8)%7||7;switch(t){case"c":return String(i);case"cc":return eC(i,t.length);case"co":return n.ordinalNumber(i,{unit:"day"});case"ccc":return n.day(o,{width:"abbreviated",context:"standalone"});case"ccccc":return n.day(o,{width:"narrow",context:"standalone"});case"cccccc":return n.day(o,{width:"short",context:"standalone"});default:return n.day(o,{width:"wide",context:"standalone"})}},i:function(e,t,n){var r=e.getUTCDay(),o=0===r?7:r;switch(t){case"i":return String(o);case"ii":return eC(o,t.length);case"io":return n.ordinalNumber(o,{unit:"day"});case"iii":return n.day(r,{width:"abbreviated",context:"formatting"});case"iiiii":return n.day(r,{width:"narrow",context:"formatting"});case"iiiiii":return n.day(r,{width:"short",context:"formatting"});default:return n.day(r,{width:"wide",context:"formatting"})}},a:function(e,t,n){var r=e.getUTCHours()/12>=1?"pm":"am";switch(t){case"a":case"aa":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"aaa":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"}).toLowerCase();case"aaaaa":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},b:function(e,t,n){var r,o=e.getUTCHours();switch(r=12===o?e_.noon:0===o?e_.midnight:o/12>=1?"pm":"am",t){case"b":case"bb":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"bbb":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"}).toLowerCase();case"bbbbb":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},B:function(e,t,n){var r,o=e.getUTCHours();switch(r=o>=17?e_.evening:o>=12?e_.afternoon:o>=4?e_.morning:e_.night,t){case"B":case"BB":case"BBB":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"BBBBB":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},h:function(e,t,n){if("ho"===t){var r=e.getUTCHours()%12;return 0===r&&(r=12),n.ordinalNumber(r,{unit:"hour"})}return ej.h(e,t)},H:function(e,t,n){return"Ho"===t?n.ordinalNumber(e.getUTCHours(),{unit:"hour"}):ej.H(e,t)},K:function(e,t,n){var r=e.getUTCHours()%12;return"Ko"===t?n.ordinalNumber(r,{unit:"hour"}):eC(r,t.length)},k:function(e,t,n){var r=e.getUTCHours();return(0===r&&(r=24),"ko"===t)?n.ordinalNumber(r,{unit:"hour"}):eC(r,t.length)},m:function(e,t,n){return"mo"===t?n.ordinalNumber(e.getUTCMinutes(),{unit:"minute"}):ej.m(e,t)},s:function(e,t,n){return"so"===t?n.ordinalNumber(e.getUTCSeconds(),{unit:"second"}):ej.s(e,t)},S:function(e,t){return ej.S(e,t)},X:function(e,t,n,r){var o=(r._originalDate||e).getTimezoneOffset();if(0===o)return"Z";switch(t){case"X":return eT(o);case"XXXX":case"XX":return eM(o);default:return eM(o,":")}},x:function(e,t,n,r){var o=(r._originalDate||e).getTimezoneOffset();switch(t){case"x":return eT(o);case"xxxx":case"xx":return eM(o);default:return eM(o,":")}},O:function(e,t,n,r){var o=(r._originalDate||e).getTimezoneOffset();switch(t){case"O":case"OO":case"OOO":return"GMT"+eP(o,":");default:return"GMT"+eM(o,":")}},z:function(e,t,n,r){var o=(r._originalDate||e).getTimezoneOffset();switch(t){case"z":case"zz":case"zzz":return"GMT"+eP(o,":");default:return"GMT"+eM(o,":")}},t:function(e,t,n,r){return eC(Math.floor((r._originalDate||e).getTime()/1e3),t.length)},T:function(e,t,n,r){return eC((r._originalDate||e).getTime(),t.length)}},eA=function(e,t){switch(e){case"P":return t.date({width:"short"});case"PP":return t.date({width:"medium"});case"PPP":return t.date({width:"long"});default:return t.date({width:"full"})}},eI=function(e,t){switch(e){case"p":return t.time({width:"short"});case"pp":return t.time({width:"medium"});case"ppp":return t.time({width:"long"});default:return t.time({width:"full"})}},eR={p:eI,P:function(e,t){var n,r=e.match(/(P+)(p+)?/)||[],o=r[1],i=r[2];if(!i)return eA(e,t);switch(o){case"P":n=t.dateTime({width:"short"});break;case"PP":n=t.dateTime({width:"medium"});break;case"PPP":n=t.dateTime({width:"long"});break;default:n=t.dateTime({width:"full"})}return n.replace("{{date}}",eA(o,t)).replace("{{time}}",eI(i,t))}};function eD(e){var t=new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds()));return t.setUTCFullYear(e.getFullYear()),e.getTime()-t.getTime()}var eL=["D","DD"],ez=["YY","YYYY"];function eZ(e,t,n){if("YYYY"===e)throw RangeError("Use `yyyy` instead of `YYYY` (in `".concat(t,"`) for formatting years to the input `").concat(n,"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md"));if("YY"===e)throw RangeError("Use `yy` instead of `YY` (in `".concat(t,"`) for formatting years to the input `").concat(n,"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md"));if("D"===e)throw RangeError("Use `d` instead of `D` (in `".concat(t,"`) for formatting days of the month to the input `").concat(n,"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md"));if("DD"===e)throw RangeError("Use `dd` instead of `DD` (in `".concat(t,"`) for formatting days of the month to the input `").concat(n,"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md"))}var eB={lessThanXSeconds:{one:"less than a second",other:"less than {{count}} seconds"},xSeconds:{one:"1 second",other:"{{count}} seconds"},halfAMinute:"half a minute",lessThanXMinutes:{one:"less than a minute",other:"less than {{count}} minutes"},xMinutes:{one:"1 minute",other:"{{count}} minutes"},aboutXHours:{one:"about 1 hour",other:"about {{count}} hours"},xHours:{one:"1 hour",other:"{{count}} hours"},xDays:{one:"1 day",other:"{{count}} days"},aboutXWeeks:{one:"about 1 week",other:"about {{count}} weeks"},xWeeks:{one:"1 week",other:"{{count}} weeks"},aboutXMonths:{one:"about 1 month",other:"about {{count}} months"},xMonths:{one:"1 month",other:"{{count}} months"},aboutXYears:{one:"about 1 year",other:"about {{count}} years"},xYears:{one:"1 year",other:"{{count}} years"},overXYears:{one:"over 1 year",other:"over {{count}} years"},almostXYears:{one:"almost 1 year",other:"almost {{count}} years"}};function eF(e){return function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.width?String(t.width):e.defaultWidth;return e.formats[n]||e.formats[e.defaultWidth]}}var eH={date:eF({formats:{full:"EEEE, MMMM do, y",long:"MMMM do, y",medium:"MMM d, y",short:"MM/dd/yyyy"},defaultWidth:"full"}),time:eF({formats:{full:"h:mm:ss a zzzz",long:"h:mm:ss a z",medium:"h:mm:ss a",short:"h:mm a"},defaultWidth:"full"}),dateTime:eF({formats:{full:"{{date}} 'at' {{time}}",long:"{{date}} 'at' {{time}}",medium:"{{date}}, {{time}}",short:"{{date}}, {{time}}"},defaultWidth:"full"})},eq={lastWeek:"'last' eeee 'at' p",yesterday:"'yesterday at' p",today:"'today at' p",tomorrow:"'tomorrow at' p",nextWeek:"eeee 'at' p",other:"P"};function eU(e){return function(t,n){var r;if("formatting"===(null!=n&&n.context?String(n.context):"standalone")&&e.formattingValues){var o=e.defaultFormattingWidth||e.defaultWidth,i=null!=n&&n.width?String(n.width):o;r=e.formattingValues[i]||e.formattingValues[o]}else{var a=e.defaultWidth,l=null!=n&&n.width?String(n.width):e.defaultWidth;r=e.values[l]||e.values[a]}return r[e.argumentCallback?e.argumentCallback(t):t]}}function eW(e){return function(t){var n,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=r.width,i=o&&e.matchPatterns[o]||e.matchPatterns[e.defaultMatchWidth],a=t.match(i);if(!a)return null;var l=a[0],s=o&&e.parsePatterns[o]||e.parsePatterns[e.defaultParseWidth],c=Array.isArray(s)?function(e,t){for(var n=0;n0?"in "+r:r+" ago":r},formatLong:eH,formatRelative:function(e,t,n,r){return eq[e]},localize:{ordinalNumber:function(e,t){var n=Number(e),r=n%100;if(r>20||r<10)switch(r%10){case 1:return n+"st";case 2:return n+"nd";case 3:return n+"rd"}return n+"th"},era:eU({values:{narrow:["B","A"],abbreviated:["BC","AD"],wide:["Before Christ","Anno Domini"]},defaultWidth:"wide"}),quarter:eU({values:{narrow:["1","2","3","4"],abbreviated:["Q1","Q2","Q3","Q4"],wide:["1st quarter","2nd quarter","3rd quarter","4th quarter"]},defaultWidth:"wide",argumentCallback:function(e){return e-1}}),month:eU({values:{narrow:["J","F","M","A","M","J","J","A","S","O","N","D"],abbreviated:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],wide:["January","February","March","April","May","June","July","August","September","October","November","December"]},defaultWidth:"wide"}),day:eU({values:{narrow:["S","M","T","W","T","F","S"],short:["Su","Mo","Tu","We","Th","Fr","Sa"],abbreviated:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],wide:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},defaultWidth:"wide"}),dayPeriod:eU({values:{narrow:{am:"a",pm:"p",midnight:"mi",noon:"n",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"},abbreviated:{am:"AM",pm:"PM",midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"},wide:{am:"a.m.",pm:"p.m.",midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"}},defaultWidth:"wide",formattingValues:{narrow:{am:"a",pm:"p",midnight:"mi",noon:"n",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"},abbreviated:{am:"AM",pm:"PM",midnight:"midnight",noon:"noon",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"},wide:{am:"a.m.",pm:"p.m.",midnight:"midnight",noon:"noon",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"}},defaultFormattingWidth:"wide"})},match:{ordinalNumber:(a={matchPattern:/^(\d+)(th|st|nd|rd)?/i,parsePattern:/\d+/i,valueCallback:function(e){return parseInt(e,10)}},function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=e.match(a.matchPattern);if(!n)return null;var r=n[0],o=e.match(a.parsePattern);if(!o)return null;var i=a.valueCallback?a.valueCallback(o[0]):o[0];return{value:i=t.valueCallback?t.valueCallback(i):i,rest:e.slice(r.length)}}),era:eW({matchPatterns:{narrow:/^(b|a)/i,abbreviated:/^(b\.?\s?c\.?|b\.?\s?c\.?\s?e\.?|a\.?\s?d\.?|c\.?\s?e\.?)/i,wide:/^(before christ|before common era|anno domini|common era)/i},defaultMatchWidth:"wide",parsePatterns:{any:[/^b/i,/^(a|c)/i]},defaultParseWidth:"any"}),quarter:eW({matchPatterns:{narrow:/^[1234]/i,abbreviated:/^q[1234]/i,wide:/^[1234](th|st|nd|rd)? quarter/i},defaultMatchWidth:"wide",parsePatterns:{any:[/1/i,/2/i,/3/i,/4/i]},defaultParseWidth:"any",valueCallback:function(e){return e+1}}),month:eW({matchPatterns:{narrow:/^[jfmasond]/i,abbreviated:/^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i,wide:/^(january|february|march|april|may|june|july|august|september|october|november|december)/i},defaultMatchWidth:"wide",parsePatterns:{narrow:[/^j/i,/^f/i,/^m/i,/^a/i,/^m/i,/^j/i,/^j/i,/^a/i,/^s/i,/^o/i,/^n/i,/^d/i],any:[/^ja/i,/^f/i,/^mar/i,/^ap/i,/^may/i,/^jun/i,/^jul/i,/^au/i,/^s/i,/^o/i,/^n/i,/^d/i]},defaultParseWidth:"any"}),day:eW({matchPatterns:{narrow:/^[smtwf]/i,short:/^(su|mo|tu|we|th|fr|sa)/i,abbreviated:/^(sun|mon|tue|wed|thu|fri|sat)/i,wide:/^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i},defaultMatchWidth:"wide",parsePatterns:{narrow:[/^s/i,/^m/i,/^t/i,/^w/i,/^t/i,/^f/i,/^s/i],any:[/^su/i,/^m/i,/^tu/i,/^w/i,/^th/i,/^f/i,/^sa/i]},defaultParseWidth:"any"}),dayPeriod:eW({matchPatterns:{narrow:/^(a|p|mi|n|(in the|at) (morning|afternoon|evening|night))/i,any:/^([ap]\.?\s?m\.?|midnight|noon|(in the|at) (morning|afternoon|evening|night))/i},defaultMatchWidth:"any",parsePatterns:{any:{am:/^a/i,pm:/^p/i,midnight:/^mi/i,noon:/^no/i,morning:/morning/i,afternoon:/afternoon/i,evening:/evening/i,night:/night/i}},defaultParseWidth:"any"})},options:{weekStartsOn:0,firstWeekContainsDate:1}},eV=/[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g,e$=/P+p+|P+|p+|''|'(''|[^'])+('|$)|./g,eX=/^'([^]*?)'?$/,eG=/''/g,eY=/[a-zA-Z]/;function eQ(e,t,n){(0,ei.Z)(2,arguments);var r,o,i,a,l,s,c,u,d,f,p,h,m,g,v,y,b,x,w=String(t),k=null!==(r=null!==(o=null==n?void 0:n.locale)&&void 0!==o?o:eS.locale)&&void 0!==r?r:eK,S=(0,em.Z)(null!==(i=null!==(a=null!==(l=null!==(s=null==n?void 0:n.firstWeekContainsDate)&&void 0!==s?s:null==n?void 0:null===(c=n.locale)||void 0===c?void 0:null===(u=c.options)||void 0===u?void 0:u.firstWeekContainsDate)&&void 0!==l?l:eS.firstWeekContainsDate)&&void 0!==a?a:null===(d=eS.locale)||void 0===d?void 0:null===(f=d.options)||void 0===f?void 0:f.firstWeekContainsDate)&&void 0!==i?i:1);if(!(S>=1&&S<=7))throw RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var E=(0,em.Z)(null!==(p=null!==(h=null!==(m=null!==(g=null==n?void 0:n.weekStartsOn)&&void 0!==g?g:null==n?void 0:null===(v=n.locale)||void 0===v?void 0:null===(y=v.options)||void 0===y?void 0:y.weekStartsOn)&&void 0!==m?m:eS.weekStartsOn)&&void 0!==h?h:null===(b=eS.locale)||void 0===b?void 0:null===(x=b.options)||void 0===x?void 0:x.weekStartsOn)&&void 0!==p?p:0);if(!(E>=0&&E<=6))throw RangeError("weekStartsOn must be between 0 and 6 inclusively");if(!k.localize)throw RangeError("locale must contain localize property");if(!k.formatLong)throw RangeError("locale must contain formatLong property");var O=(0,eo.Z)(e);if(!function(e){return(0,ei.Z)(1,arguments),(!!ex(e)||"number"==typeof e)&&!isNaN(Number((0,eo.Z)(e)))}(O))throw RangeError("Invalid time value");var C=eD(O),j=function(e,t){return(0,ei.Z)(2,arguments),function(e,t){return(0,ei.Z)(2,arguments),new Date((0,eo.Z)(e).getTime()+(0,em.Z)(t))}(e,-(0,em.Z)(t))}(O,C),_={firstWeekContainsDate:S,weekStartsOn:E,locale:k,_originalDate:O};return w.match(e$).map(function(e){var t=e[0];return"p"===t||"P"===t?(0,eR[t])(e,k.formatLong):e}).join("").match(eV).map(function(r){if("''"===r)return"'";var o,i=r[0];if("'"===i)return(o=r.match(eX))?o[1].replace(eG,"'"):r;var a=eN[i];if(a)return null!=n&&n.useAdditionalWeekYearTokens||-1===ez.indexOf(r)||eZ(r,t,String(e)),null!=n&&n.useAdditionalDayOfYearTokens||-1===eL.indexOf(r)||eZ(r,t,String(e)),a(j,r,k.localize,_);if(i.match(eY))throw RangeError("Format string contains an unescaped latin alphabet character `"+i+"`");return r}).join("")}var eJ=n(1153);let e0=(0,eJ.fn)("DateRangePicker"),e1=(e,t,n,r)=>{var o;if(n&&(e=null===(o=r.get(n))||void 0===o?void 0:o.from),e)return ea(e&&!t?e:ef([e,t]))},e2=(e,t,n,r)=>{var o,i;if(n&&(e=ea(null!==(i=null===(o=r.get(n))||void 0===o?void 0:o.to)&&void 0!==i?i:el())),e)return ea(e&&!t?e:ep([e,t]))},e4=[{value:"tdy",text:"Today",from:el()},{value:"w",text:"Last 7 days",from:ey(el(),{days:7})},{value:"t",text:"Last 30 days",from:ey(el(),{days:30})},{value:"m",text:"Month to Date",from:es(el())},{value:"y",text:"Year to Date",from:eb(el())}],e3=(e,t,n,r)=>{let o=(null==n?void 0:n.code)||"en-US";if(!e&&!t)return"";if(e&&!t)return r?eQ(e,r):e.toLocaleDateString(o,{year:"numeric",month:"short",day:"numeric"});if(e&&t){if(function(e,t){(0,ei.Z)(2,arguments);var n=(0,eo.Z)(e),r=(0,eo.Z)(t);return n.getTime()===r.getTime()}(e,t))return r?eQ(e,r):e.toLocaleDateString(o,{year:"numeric",month:"short",day:"numeric"});if(e.getMonth()===t.getMonth()&&e.getFullYear()===t.getFullYear())return r?"".concat(eQ(e,r)," - ").concat(eQ(t,r)):"".concat(e.toLocaleDateString(o,{month:"short",day:"numeric"})," - \n ").concat(t.getDate(),", ").concat(t.getFullYear());{if(r)return"".concat(eQ(e,r)," - ").concat(eQ(t,r));let n={year:"numeric",month:"short",day:"numeric"};return"".concat(e.toLocaleDateString(o,n)," - \n ").concat(t.toLocaleDateString(o,n))}}return""};function e6(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e),n=t.getMonth();return t.setFullYear(t.getFullYear(),n+1,0),t.setHours(23,59,59,999),t}function e8(e,t){(0,ei.Z)(2,arguments);var n=(0,eo.Z)(e),r=(0,em.Z)(t),o=n.getFullYear(),i=n.getDate(),a=new Date(0);a.setFullYear(o,r,15),a.setHours(0,0,0,0);var l=function(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e),n=t.getFullYear(),r=t.getMonth(),o=new Date(0);return o.setFullYear(n,r+1,0),o.setHours(0,0,0,0),o.getDate()}(a);return n.setMonth(r,Math.min(i,l)),n}function e5(e,t){(0,ei.Z)(2,arguments);var n=(0,eo.Z)(e),r=(0,em.Z)(t);return isNaN(n.getTime())?new Date(NaN):(n.setFullYear(r),n)}function e7(e,t){(0,ei.Z)(2,arguments);var n=(0,eo.Z)(e),r=(0,eo.Z)(t);return 12*(n.getFullYear()-r.getFullYear())+(n.getMonth()-r.getMonth())}function e9(e,t){(0,ei.Z)(2,arguments);var n=(0,eo.Z)(e),r=(0,eo.Z)(t);return n.getFullYear()===r.getFullYear()&&n.getMonth()===r.getMonth()}function te(e,t){(0,ei.Z)(2,arguments);var n=(0,eo.Z)(e),r=(0,eo.Z)(t);return n.getTime()=0&&u<=6))throw RangeError("weekStartsOn must be between 0 and 6 inclusively");var d=(0,eo.Z)(e),f=d.getDay();return d.setDate(d.getDate()-((fr.getTime()}function ti(e,t){(0,ei.Z)(2,arguments);var n=ea(e),r=ea(t);return Math.round((n.getTime()-eD(n)-(r.getTime()-eD(r)))/864e5)}function ta(e,t){(0,ei.Z)(2,arguments);var n=(0,em.Z)(t);return(0,eh.Z)(e,7*n)}function tl(e,t){(0,ei.Z)(2,arguments);var n=(0,em.Z)(t);return(0,ev.Z)(e,12*n)}function ts(e,t){(0,ei.Z)(1,arguments);var n,r,o,i,a,l,s,c,u=(0,em.Z)(null!==(n=null!==(r=null!==(o=null!==(i=null==t?void 0:t.weekStartsOn)&&void 0!==i?i:null==t?void 0:null===(a=t.locale)||void 0===a?void 0:null===(l=a.options)||void 0===l?void 0:l.weekStartsOn)&&void 0!==o?o:eS.weekStartsOn)&&void 0!==r?r:null===(s=eS.locale)||void 0===s?void 0:null===(c=s.options)||void 0===c?void 0:c.weekStartsOn)&&void 0!==n?n:0);if(!(u>=0&&u<=6))throw RangeError("weekStartsOn must be between 0 and 6 inclusively");var d=(0,eo.Z)(e),f=d.getDay();return d.setDate(d.getDate()+((fe7(l,a)&&(a=(0,ev.Z)(l,-1*((void 0===c?1:c)-1))),s&&0>e7(a,s)&&(a=s),u=es(a),f=t.month,h=(p=(0,d.useState)(u))[0],m=[void 0===f?h:f,p[1]])[0],v=m[1],[g,function(e){if(!t.disableNavigation){var n,r=es(e);v(r),null===(n=t.onMonthChange)||void 0===n||n.call(t,r)}}]),x=b[0],w=b[1],k=function(e,t){for(var n=t.reverseMonths,r=t.numberOfMonths,o=es(e),i=e7(es((0,ev.Z)(o,r)),o),a=[],l=0;l=e7(i,n)))return(0,ev.Z)(i,-(r?void 0===o?1:o:1))}}(x,y),O=function(e){return k.some(function(t){return e9(e,t)})};return th.jsx(tP.Provider,{value:{currentMonth:x,displayMonths:k,goToMonth:w,goToDate:function(e,t){O(e)||(t&&te(e,t)?w((0,ev.Z)(e,1+-1*y.numberOfMonths)):w(e))},previousMonth:E,nextMonth:S,isDateDisplayed:O},children:e.children})}function tM(){var e=(0,d.useContext)(tP);if(!e)throw Error("useNavigation must be used within a NavigationProvider");return e}function tN(e){var t,n=tS(),r=n.classNames,o=n.styles,i=n.components,a=tM().goToMonth,l=function(t){a((0,ev.Z)(t,e.displayIndex?-e.displayIndex:0))},s=null!==(t=null==i?void 0:i.CaptionLabel)&&void 0!==t?t:tE,c=th.jsx(s,{id:e.id,displayMonth:e.displayMonth});return th.jsxs("div",{className:r.caption_dropdowns,style:o.caption_dropdowns,children:[th.jsx("div",{className:r.vhidden,children:c}),th.jsx(tj,{onChange:l,displayMonth:e.displayMonth}),th.jsx(t_,{onChange:l,displayMonth:e.displayMonth})]})}function tA(e){return th.jsx("svg",tu({width:"16px",height:"16px",viewBox:"0 0 120 120"},e,{children:th.jsx("path",{d:"M69.490332,3.34314575 C72.6145263,0.218951416 77.6798462,0.218951416 80.8040405,3.34314575 C83.8617626,6.40086786 83.9268205,11.3179931 80.9992143,14.4548388 L80.8040405,14.6568542 L35.461,60 L80.8040405,105.343146 C83.8617626,108.400868 83.9268205,113.317993 80.9992143,116.454839 L80.8040405,116.656854 C77.7463184,119.714576 72.8291931,119.779634 69.6923475,116.852028 L69.490332,116.656854 L18.490332,65.6568542 C15.4326099,62.5991321 15.367552,57.6820069 18.2951583,54.5451612 L18.490332,54.3431458 L69.490332,3.34314575 Z",fill:"currentColor",fillRule:"nonzero"})}))}function tI(e){return th.jsx("svg",tu({width:"16px",height:"16px",viewBox:"0 0 120 120"},e,{children:th.jsx("path",{d:"M49.8040405,3.34314575 C46.6798462,0.218951416 41.6145263,0.218951416 38.490332,3.34314575 C35.4326099,6.40086786 35.367552,11.3179931 38.2951583,14.4548388 L38.490332,14.6568542 L83.8333725,60 L38.490332,105.343146 C35.4326099,108.400868 35.367552,113.317993 38.2951583,116.454839 L38.490332,116.656854 C41.5480541,119.714576 46.4651794,119.779634 49.602025,116.852028 L49.8040405,116.656854 L100.804041,65.6568542 C103.861763,62.5991321 103.926821,57.6820069 100.999214,54.5451612 L100.804041,54.3431458 L49.8040405,3.34314575 Z",fill:"currentColor"})}))}var tR=(0,d.forwardRef)(function(e,t){var n=tS(),r=n.classNames,o=n.styles,i=[r.button_reset,r.button];e.className&&i.push(e.className);var a=i.join(" "),l=tu(tu({},o.button_reset),o.button);return e.style&&Object.assign(l,e.style),th.jsx("button",tu({},e,{ref:t,type:"button",className:a,style:l}))});function tD(e){var t,n,r=tS(),o=r.dir,i=r.locale,a=r.classNames,l=r.styles,s=r.labels,c=s.labelPrevious,u=s.labelNext,d=r.components;if(!e.nextMonth&&!e.previousMonth)return th.jsx(th.Fragment,{});var f=c(e.previousMonth,{locale:i}),p=[a.nav_button,a.nav_button_previous].join(" "),h=u(e.nextMonth,{locale:i}),m=[a.nav_button,a.nav_button_next].join(" "),g=null!==(t=null==d?void 0:d.IconRight)&&void 0!==t?t:tI,v=null!==(n=null==d?void 0:d.IconLeft)&&void 0!==n?n:tA;return th.jsxs("div",{className:a.nav,style:l.nav,children:[!e.hidePrevious&&th.jsx(tR,{name:"previous-month","aria-label":f,className:p,style:l.nav_button_previous,disabled:!e.previousMonth,onClick:e.onPreviousClick,children:"rtl"===o?th.jsx(g,{className:a.nav_icon,style:l.nav_icon}):th.jsx(v,{className:a.nav_icon,style:l.nav_icon})}),!e.hideNext&&th.jsx(tR,{name:"next-month","aria-label":h,className:m,style:l.nav_button_next,disabled:!e.nextMonth,onClick:e.onNextClick,children:"rtl"===o?th.jsx(v,{className:a.nav_icon,style:l.nav_icon}):th.jsx(g,{className:a.nav_icon,style:l.nav_icon})})]})}function tL(e){var t=tS().numberOfMonths,n=tM(),r=n.previousMonth,o=n.nextMonth,i=n.goToMonth,a=n.displayMonths,l=a.findIndex(function(t){return e9(e.displayMonth,t)}),s=0===l,c=l===a.length-1;return th.jsx(tD,{displayMonth:e.displayMonth,hideNext:t>1&&(s||!c),hidePrevious:t>1&&(c||!s),nextMonth:o,previousMonth:r,onPreviousClick:function(){r&&i(r)},onNextClick:function(){o&&i(o)}})}function tz(e){var t,n,r=tS(),o=r.classNames,i=r.disableNavigation,a=r.styles,l=r.captionLayout,s=r.components,c=null!==(t=null==s?void 0:s.CaptionLabel)&&void 0!==t?t:tE;return n=i?th.jsx(c,{id:e.id,displayMonth:e.displayMonth}):"dropdown"===l?th.jsx(tN,{displayMonth:e.displayMonth,id:e.id}):"dropdown-buttons"===l?th.jsxs(th.Fragment,{children:[th.jsx(tN,{displayMonth:e.displayMonth,displayIndex:e.displayIndex,id:e.id}),th.jsx(tL,{displayMonth:e.displayMonth,displayIndex:e.displayIndex,id:e.id})]}):th.jsxs(th.Fragment,{children:[th.jsx(c,{id:e.id,displayMonth:e.displayMonth,displayIndex:e.displayIndex}),th.jsx(tL,{displayMonth:e.displayMonth,id:e.id})]}),th.jsx("div",{className:o.caption,style:a.caption,children:n})}function tZ(e){var t=tS(),n=t.footer,r=t.styles,o=t.classNames.tfoot;return n?th.jsx("tfoot",{className:o,style:r.tfoot,children:th.jsx("tr",{children:th.jsx("td",{colSpan:8,children:n})})}):th.jsx(th.Fragment,{})}function tB(){var e=tS(),t=e.classNames,n=e.styles,r=e.showWeekNumber,o=e.locale,i=e.weekStartsOn,a=e.ISOWeek,l=e.formatters.formatWeekdayName,s=e.labels.labelWeekday,c=function(e,t,n){for(var r=n?tn(new Date):tt(new Date,{locale:e,weekStartsOn:t}),o=[],i=0;i<7;i++){var a=(0,eh.Z)(r,i);o.push(a)}return o}(o,i,a);return th.jsxs("tr",{style:n.head_row,className:t.head_row,children:[r&&th.jsx("td",{style:n.head_cell,className:t.head_cell}),c.map(function(e,r){return th.jsx("th",{scope:"col",className:t.head_cell,style:n.head_cell,"aria-label":s(e,{locale:o}),children:l(e,{locale:o})},r)})]})}function tF(){var e,t=tS(),n=t.classNames,r=t.styles,o=t.components,i=null!==(e=null==o?void 0:o.HeadRow)&&void 0!==e?e:tB;return th.jsx("thead",{style:r.head,className:n.head,children:th.jsx(i,{})})}function tH(e){var t=tS(),n=t.locale,r=t.formatters.formatDay;return th.jsx(th.Fragment,{children:r(e.date,{locale:n})})}var tq=(0,d.createContext)(void 0);function tU(e){return tm(e.initialProps)?th.jsx(tW,{initialProps:e.initialProps,children:e.children}):th.jsx(tq.Provider,{value:{selected:void 0,modifiers:{disabled:[]}},children:e.children})}function tW(e){var t=e.initialProps,n=e.children,r=t.selected,o=t.min,i=t.max,a={disabled:[]};return r&&a.disabled.push(function(e){var t=i&&r.length>i-1,n=r.some(function(t){return tr(t,e)});return!!(t&&!n)}),th.jsx(tq.Provider,{value:{selected:r,onDayClick:function(e,n,a){if(null===(l=t.onDayClick)||void 0===l||l.call(t,e,n,a),(!n.selected||!o||(null==r?void 0:r.length)!==o)&&(n.selected||!i||(null==r?void 0:r.length)!==i)){var l,s,c=r?td([],r,!0):[];if(n.selected){var u=c.findIndex(function(t){return tr(e,t)});c.splice(u,1)}else c.push(e);null===(s=t.onSelect)||void 0===s||s.call(t,c,e,n,a)}},modifiers:a},children:n})}function tK(){var e=(0,d.useContext)(tq);if(!e)throw Error("useSelectMultiple must be used within a SelectMultipleProvider");return e}var tV=(0,d.createContext)(void 0);function t$(e){return tg(e.initialProps)?th.jsx(tX,{initialProps:e.initialProps,children:e.children}):th.jsx(tV.Provider,{value:{selected:void 0,modifiers:{range_start:[],range_end:[],range_middle:[],disabled:[]}},children:e.children})}function tX(e){var t=e.initialProps,n=e.children,r=t.selected,o=r||{},i=o.from,a=o.to,l=t.min,s=t.max,c={range_start:[],range_end:[],range_middle:[],disabled:[]};if(i?(c.range_start=[i],a?(c.range_end=[a],tr(i,a)||(c.range_middle=[{after:i,before:a}])):c.range_end=[i]):a&&(c.range_start=[a],c.range_end=[a]),l&&(i&&!a&&c.disabled.push({after:eg(i,l-1),before:(0,eh.Z)(i,l-1)}),i&&a&&c.disabled.push({after:i,before:(0,eh.Z)(i,l-1)}),!i&&a&&c.disabled.push({after:eg(a,l-1),before:(0,eh.Z)(a,l-1)})),s){if(i&&!a&&(c.disabled.push({before:(0,eh.Z)(i,-s+1)}),c.disabled.push({after:(0,eh.Z)(i,s-1)})),i&&a){var u=s-(ti(a,i)+1);c.disabled.push({before:eg(i,u)}),c.disabled.push({after:(0,eh.Z)(a,u)})}!i&&a&&(c.disabled.push({before:(0,eh.Z)(a,-s+1)}),c.disabled.push({after:(0,eh.Z)(a,s-1)}))}return th.jsx(tV.Provider,{value:{selected:r,onDayClick:function(e,n,o){null===(s=t.onDayClick)||void 0===s||s.call(t,e,n,o);var i,a,l,s,c,u=(a=(i=r||{}).from,l=i.to,a&&l?tr(l,e)&&tr(a,e)?void 0:tr(l,e)?{from:l,to:void 0}:tr(a,e)?void 0:to(a,e)?{from:e,to:l}:{from:a,to:e}:l?to(e,l)?{from:l,to:e}:{from:e,to:l}:a?te(e,a)?{from:e,to:a}:{from:a,to:e}:{from:e,to:void 0});null===(c=t.onSelect)||void 0===c||c.call(t,u,e,n,o)},modifiers:c},children:n})}function tG(){var e=(0,d.useContext)(tV);if(!e)throw Error("useSelectRange must be used within a SelectRangeProvider");return e}function tY(e){return Array.isArray(e)?td([],e,!0):void 0!==e?[e]:[]}(l=c||(c={})).Outside="outside",l.Disabled="disabled",l.Selected="selected",l.Hidden="hidden",l.Today="today",l.RangeStart="range_start",l.RangeEnd="range_end",l.RangeMiddle="range_middle";var tQ=c.Selected,tJ=c.Disabled,t0=c.Hidden,t1=c.Today,t2=c.RangeEnd,t4=c.RangeMiddle,t3=c.RangeStart,t6=c.Outside,t8=(0,d.createContext)(void 0);function t5(e){var t,n,r,o=tS(),i=tK(),a=tG(),l=((t={})[tQ]=tY(o.selected),t[tJ]=tY(o.disabled),t[t0]=tY(o.hidden),t[t1]=[o.today],t[t2]=[],t[t4]=[],t[t3]=[],t[t6]=[],o.fromDate&&t[tJ].push({before:o.fromDate}),o.toDate&&t[tJ].push({after:o.toDate}),tm(o)?t[tJ]=t[tJ].concat(i.modifiers[tJ]):tg(o)&&(t[tJ]=t[tJ].concat(a.modifiers[tJ]),t[t3]=a.modifiers[t3],t[t4]=a.modifiers[t4],t[t2]=a.modifiers[t2]),t),s=(n=o.modifiers,r={},Object.entries(n).forEach(function(e){var t=e[0],n=e[1];r[t]=tY(n)}),r),c=tu(tu({},l),s);return th.jsx(t8.Provider,{value:c,children:e.children})}function t7(){var e=(0,d.useContext)(t8);if(!e)throw Error("useModifiers must be used within a ModifiersProvider");return e}function t9(e,t,n){var r=Object.keys(t).reduce(function(n,r){return t[r].some(function(t){if("boolean"==typeof t)return t;if(ex(t))return tr(e,t);if(Array.isArray(t)&&t.every(ex))return t.includes(e);if(t&&"object"==typeof t&&"from"in t)return r=t.from,o=t.to,r&&o?(0>ti(o,r)&&(r=(n=[o,r])[0],o=n[1]),ti(e,r)>=0&&ti(o,e)>=0):o?tr(o,e):!!r&&tr(r,e);if(t&&"object"==typeof t&&"dayOfWeek"in t)return t.dayOfWeek.includes(e.getDay());if(t&&"object"==typeof t&&"before"in t&&"after"in t){var n,r,o,i=ti(t.before,e),a=ti(t.after,e),l=i>0,s=a<0;return to(t.before,t.after)?s&&l:l||s}return t&&"object"==typeof t&&"after"in t?ti(e,t.after)>0:t&&"object"==typeof t&&"before"in t?ti(t.before,e)>0:"function"==typeof t&&t(e)})&&n.push(r),n},[]),o={};return r.forEach(function(e){return o[e]=!0}),n&&!e9(e,n)&&(o.outside=!0),o}var ne=(0,d.createContext)(void 0);function nt(e){var t=tM(),n=t7(),r=(0,d.useState)(),o=r[0],i=r[1],a=(0,d.useState)(),l=a[0],s=a[1],c=function(e,t){for(var n,r,o=es(e[0]),i=e6(e[e.length-1]),a=o;a<=i;){var l=t9(a,t);if(!(!l.disabled&&!l.hidden)){a=(0,eh.Z)(a,1);continue}if(l.selected)return a;l.today&&!r&&(r=a),n||(n=a),a=(0,eh.Z)(a,1)}return r||n}(t.displayMonths,n),u=(null!=o?o:l&&t.isDateDisplayed(l))?l:c,f=function(e){i(e)},p=tS(),h=function(e,r){if(o){var i=function e(t,n){var r=n.moveBy,o=n.direction,i=n.context,a=n.modifiers,l=n.retry,s=void 0===l?{count:0,lastFocused:t}:l,c=i.weekStartsOn,u=i.fromDate,d=i.toDate,f=i.locale,p=({day:eh.Z,week:ta,month:ev.Z,year:tl,startOfWeek:function(e){return i.ISOWeek?tn(e):tt(e,{locale:f,weekStartsOn:c})},endOfWeek:function(e){return i.ISOWeek?tc(e):ts(e,{locale:f,weekStartsOn:c})}})[r](t,"after"===o?1:-1);"before"===o&&u?p=ef([u,p]):"after"===o&&d&&(p=ep([d,p]));var h=!0;if(a){var m=t9(p,a);h=!m.disabled&&!m.hidden}return h?p:s.count>365?s.lastFocused:e(p,{moveBy:r,direction:o,context:i,modifiers:a,retry:tu(tu({},s),{count:s.count+1})})}(o,{moveBy:e,direction:r,context:p,modifiers:n});tr(o,i)||(t.goToDate(i,o),f(i))}};return th.jsx(ne.Provider,{value:{focusedDay:o,focusTarget:u,blur:function(){s(o),i(void 0)},focus:f,focusDayAfter:function(){return h("day","after")},focusDayBefore:function(){return h("day","before")},focusWeekAfter:function(){return h("week","after")},focusWeekBefore:function(){return h("week","before")},focusMonthBefore:function(){return h("month","before")},focusMonthAfter:function(){return h("month","after")},focusYearBefore:function(){return h("year","before")},focusYearAfter:function(){return h("year","after")},focusStartOfWeek:function(){return h("startOfWeek","before")},focusEndOfWeek:function(){return h("endOfWeek","after")}},children:e.children})}function nn(){var e=(0,d.useContext)(ne);if(!e)throw Error("useFocusContext must be used within a FocusProvider");return e}var nr=(0,d.createContext)(void 0);function no(e){return tv(e.initialProps)?th.jsx(ni,{initialProps:e.initialProps,children:e.children}):th.jsx(nr.Provider,{value:{selected:void 0},children:e.children})}function ni(e){var t=e.initialProps,n=e.children,r={selected:t.selected,onDayClick:function(e,n,r){var o,i,a;if(null===(o=t.onDayClick)||void 0===o||o.call(t,e,n,r),n.selected&&!t.required){null===(i=t.onSelect)||void 0===i||i.call(t,void 0,e,n,r);return}null===(a=t.onSelect)||void 0===a||a.call(t,e,e,n,r)}};return th.jsx(nr.Provider,{value:r,children:n})}function na(){var e=(0,d.useContext)(nr);if(!e)throw Error("useSelectSingle must be used within a SelectSingleProvider");return e}function nl(e){var t,n,r,o,i,a,l,s,u,f,p,h,m,g,v,y,b,x,w,k,S,E,O,C,j,_,P,T,M,N,A,I,R,D,L,z,Z,B,F,H,q,U,W=(0,d.useRef)(null),K=(t=e.date,n=e.displayMonth,a=tS(),l=nn(),s=t9(t,t7(),n),u=tS(),f=na(),p=tK(),h=tG(),g=(m=nn()).focusDayAfter,v=m.focusDayBefore,y=m.focusWeekAfter,b=m.focusWeekBefore,x=m.blur,w=m.focus,k=m.focusMonthBefore,S=m.focusMonthAfter,E=m.focusYearBefore,O=m.focusYearAfter,C=m.focusStartOfWeek,j=m.focusEndOfWeek,_={onClick:function(e){var n,r,o,i;tv(u)?null===(n=f.onDayClick)||void 0===n||n.call(f,t,s,e):tm(u)?null===(r=p.onDayClick)||void 0===r||r.call(p,t,s,e):tg(u)?null===(o=h.onDayClick)||void 0===o||o.call(h,t,s,e):null===(i=u.onDayClick)||void 0===i||i.call(u,t,s,e)},onFocus:function(e){var n;w(t),null===(n=u.onDayFocus)||void 0===n||n.call(u,t,s,e)},onBlur:function(e){var n;x(),null===(n=u.onDayBlur)||void 0===n||n.call(u,t,s,e)},onKeyDown:function(e){var n;switch(e.key){case"ArrowLeft":e.preventDefault(),e.stopPropagation(),"rtl"===u.dir?g():v();break;case"ArrowRight":e.preventDefault(),e.stopPropagation(),"rtl"===u.dir?v():g();break;case"ArrowDown":e.preventDefault(),e.stopPropagation(),y();break;case"ArrowUp":e.preventDefault(),e.stopPropagation(),b();break;case"PageUp":e.preventDefault(),e.stopPropagation(),e.shiftKey?E():k();break;case"PageDown":e.preventDefault(),e.stopPropagation(),e.shiftKey?O():S();break;case"Home":e.preventDefault(),e.stopPropagation(),C();break;case"End":e.preventDefault(),e.stopPropagation(),j()}null===(n=u.onDayKeyDown)||void 0===n||n.call(u,t,s,e)},onKeyUp:function(e){var n;null===(n=u.onDayKeyUp)||void 0===n||n.call(u,t,s,e)},onMouseEnter:function(e){var n;null===(n=u.onDayMouseEnter)||void 0===n||n.call(u,t,s,e)},onMouseLeave:function(e){var n;null===(n=u.onDayMouseLeave)||void 0===n||n.call(u,t,s,e)},onPointerEnter:function(e){var n;null===(n=u.onDayPointerEnter)||void 0===n||n.call(u,t,s,e)},onPointerLeave:function(e){var n;null===(n=u.onDayPointerLeave)||void 0===n||n.call(u,t,s,e)},onTouchCancel:function(e){var n;null===(n=u.onDayTouchCancel)||void 0===n||n.call(u,t,s,e)},onTouchEnd:function(e){var n;null===(n=u.onDayTouchEnd)||void 0===n||n.call(u,t,s,e)},onTouchMove:function(e){var n;null===(n=u.onDayTouchMove)||void 0===n||n.call(u,t,s,e)},onTouchStart:function(e){var n;null===(n=u.onDayTouchStart)||void 0===n||n.call(u,t,s,e)}},P=tS(),T=na(),M=tK(),N=tG(),A=tv(P)?T.selected:tm(P)?M.selected:tg(P)?N.selected:void 0,I=!!(a.onDayClick||"default"!==a.mode),(0,d.useEffect)(function(){var e;!s.outside&&l.focusedDay&&I&&tr(l.focusedDay,t)&&(null===(e=W.current)||void 0===e||e.focus())},[l.focusedDay,t,W,I,s.outside]),D=(R=[a.classNames.day],Object.keys(s).forEach(function(e){var t=a.modifiersClassNames[e];if(t)R.push(t);else if(Object.values(c).includes(e)){var n=a.classNames["day_".concat(e)];n&&R.push(n)}}),R).join(" "),L=tu({},a.styles.day),Object.keys(s).forEach(function(e){var t;L=tu(tu({},L),null===(t=a.modifiersStyles)||void 0===t?void 0:t[e])}),z=L,Z=!!(s.outside&&!a.showOutsideDays||s.hidden),B=null!==(i=null===(o=a.components)||void 0===o?void 0:o.DayContent)&&void 0!==i?i:tH,F={style:z,className:D,children:th.jsx(B,{date:t,displayMonth:n,activeModifiers:s}),role:"gridcell"},H=l.focusTarget&&tr(l.focusTarget,t)&&!s.outside,q=l.focusedDay&&tr(l.focusedDay,t),U=tu(tu(tu({},F),((r={disabled:s.disabled,role:"gridcell"})["aria-selected"]=s.selected,r.tabIndex=q||H?0:-1,r)),_),{isButton:I,isHidden:Z,activeModifiers:s,selectedDays:A,buttonProps:U,divProps:F});return K.isHidden?th.jsx("div",{role:"gridcell"}):K.isButton?th.jsx(tR,tu({name:"day",ref:W},K.buttonProps)):th.jsx("div",tu({},K.divProps))}function ns(e){var t=e.number,n=e.dates,r=tS(),o=r.onWeekNumberClick,i=r.styles,a=r.classNames,l=r.locale,s=r.labels.labelWeekNumber,c=(0,r.formatters.formatWeekNumber)(Number(t),{locale:l});if(!o)return th.jsx("span",{className:a.weeknumber,style:i.weeknumber,children:c});var u=s(Number(t),{locale:l});return th.jsx(tR,{name:"week-number","aria-label":u,className:a.weeknumber,style:i.weeknumber,onClick:function(e){o(t,n,e)},children:c})}function nc(e){var t,n,r,o=tS(),i=o.styles,a=o.classNames,l=o.showWeekNumber,s=o.components,c=null!==(t=null==s?void 0:s.Day)&&void 0!==t?t:nl,u=null!==(n=null==s?void 0:s.WeekNumber)&&void 0!==n?n:ns;return l&&(r=th.jsx("td",{className:a.cell,style:i.cell,children:th.jsx(u,{number:e.weekNumber,dates:e.dates})})),th.jsxs("tr",{className:a.row,style:i.row,children:[r,e.dates.map(function(t){return th.jsx("td",{className:a.cell,style:i.cell,role:"presentation",children:th.jsx(c,{displayMonth:e.displayMonth,date:t})},function(e){return(0,ei.Z)(1,arguments),Math.floor(function(e){return(0,ei.Z)(1,arguments),(0,eo.Z)(e).getTime()}(e)/1e3)}(t))})]})}function nu(e,t,n){for(var r=(null==n?void 0:n.ISOWeek)?tc(t):ts(t,n),o=(null==n?void 0:n.ISOWeek)?tn(e):tt(e,n),i=ti(r,o),a=[],l=0;l<=i;l++)a.push((0,eh.Z)(o,l));return a.reduce(function(e,t){var r=(null==n?void 0:n.ISOWeek)?function(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e);return Math.round((tn(t).getTime()-(function(e){(0,ei.Z)(1,arguments);var t=function(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e),n=t.getFullYear(),r=new Date(0);r.setFullYear(n+1,0,4),r.setHours(0,0,0,0);var o=tn(r),i=new Date(0);i.setFullYear(n,0,4),i.setHours(0,0,0,0);var a=tn(i);return t.getTime()>=o.getTime()?n+1:t.getTime()>=a.getTime()?n:n-1}(e),n=new Date(0);return n.setFullYear(t,0,4),n.setHours(0,0,0,0),tn(n)})(t).getTime())/6048e5)+1}(t):function(e,t){(0,ei.Z)(1,arguments);var n=(0,eo.Z)(e);return Math.round((tt(n,t).getTime()-(function(e,t){(0,ei.Z)(1,arguments);var n,r,o,i,a,l,s,c,u=(0,em.Z)(null!==(n=null!==(r=null!==(o=null!==(i=null==t?void 0:t.firstWeekContainsDate)&&void 0!==i?i:null==t?void 0:null===(a=t.locale)||void 0===a?void 0:null===(l=a.options)||void 0===l?void 0:l.firstWeekContainsDate)&&void 0!==o?o:eS.firstWeekContainsDate)&&void 0!==r?r:null===(s=eS.locale)||void 0===s?void 0:null===(c=s.options)||void 0===c?void 0:c.firstWeekContainsDate)&&void 0!==n?n:1),d=function(e,t){(0,ei.Z)(1,arguments);var n,r,o,i,a,l,s,c,u=(0,eo.Z)(e),d=u.getFullYear(),f=(0,em.Z)(null!==(n=null!==(r=null!==(o=null!==(i=null==t?void 0:t.firstWeekContainsDate)&&void 0!==i?i:null==t?void 0:null===(a=t.locale)||void 0===a?void 0:null===(l=a.options)||void 0===l?void 0:l.firstWeekContainsDate)&&void 0!==o?o:eS.firstWeekContainsDate)&&void 0!==r?r:null===(s=eS.locale)||void 0===s?void 0:null===(c=s.options)||void 0===c?void 0:c.firstWeekContainsDate)&&void 0!==n?n:1);if(!(f>=1&&f<=7))throw RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var p=new Date(0);p.setFullYear(d+1,0,f),p.setHours(0,0,0,0);var h=tt(p,t),m=new Date(0);m.setFullYear(d,0,f),m.setHours(0,0,0,0);var g=tt(m,t);return u.getTime()>=h.getTime()?d+1:u.getTime()>=g.getTime()?d:d-1}(e,t),f=new Date(0);return f.setFullYear(d,0,u),f.setHours(0,0,0,0),tt(f,t)})(n,t).getTime())/6048e5)+1}(t,n),o=e.find(function(e){return e.weekNumber===r});return o?o.dates.push(t):e.push({weekNumber:r,dates:[t]}),e},[])}function nd(e){var t,n,r,o=tS(),i=o.locale,a=o.classNames,l=o.styles,s=o.hideHead,c=o.fixedWeeks,u=o.components,d=o.weekStartsOn,f=o.firstWeekContainsDate,p=o.ISOWeek,h=function(e,t){var n=nu(es(e),e6(e),t);if(null==t?void 0:t.useFixedWeeks){var r=function(e,t){return(0,ei.Z)(1,arguments),function(e,t,n){(0,ei.Z)(2,arguments);var r=tt(e,n),o=tt(t,n);return Math.round((r.getTime()-eD(r)-(o.getTime()-eD(o)))/6048e5)}(function(e){(0,ei.Z)(1,arguments);var t=(0,eo.Z)(e),n=t.getMonth();return t.setFullYear(t.getFullYear(),n+1,0),t.setHours(0,0,0,0),t}(e),es(e),t)+1}(e,t);if(r<6){var o=n[n.length-1],i=o.dates[o.dates.length-1],a=ta(i,6-r),l=nu(ta(i,1),a,t);n.push.apply(n,l)}}return n}(e.displayMonth,{useFixedWeeks:!!c,ISOWeek:p,locale:i,weekStartsOn:d,firstWeekContainsDate:f}),m=null!==(t=null==u?void 0:u.Head)&&void 0!==t?t:tF,g=null!==(n=null==u?void 0:u.Row)&&void 0!==n?n:nc,v=null!==(r=null==u?void 0:u.Footer)&&void 0!==r?r:tZ;return th.jsxs("table",{id:e.id,className:a.table,style:l.table,role:"grid","aria-labelledby":e["aria-labelledby"],children:[!s&&th.jsx(m,{}),th.jsx("tbody",{className:a.tbody,style:l.tbody,children:h.map(function(t){return th.jsx(g,{displayMonth:e.displayMonth,dates:t.dates,weekNumber:t.weekNumber},t.weekNumber)})}),th.jsx(v,{displayMonth:e.displayMonth})]})}var nf="undefined"!=typeof window&&window.document&&window.document.createElement?d.useLayoutEffect:d.useEffect,np=!1,nh=0;function nm(){return"react-day-picker-".concat(++nh)}function ng(e){var t,n,r,o,i,a,l,s,c=tS(),u=c.dir,f=c.classNames,p=c.styles,h=c.components,m=tM().displayMonths,g=(r=null!=(t=c.id?"".concat(c.id,"-").concat(e.displayIndex):void 0)?t:np?nm():null,i=(o=(0,d.useState)(r))[0],a=o[1],nf(function(){null===i&&a(nm())},[]),(0,d.useEffect)(function(){!1===np&&(np=!0)},[]),null!==(n=null!=t?t:i)&&void 0!==n?n:void 0),v=c.id?"".concat(c.id,"-grid-").concat(e.displayIndex):void 0,y=[f.month],b=p.month,x=0===e.displayIndex,w=e.displayIndex===m.length-1,k=!x&&!w;"rtl"===u&&(w=(l=[x,w])[0],x=l[1]),x&&(y.push(f.caption_start),b=tu(tu({},b),p.caption_start)),w&&(y.push(f.caption_end),b=tu(tu({},b),p.caption_end)),k&&(y.push(f.caption_between),b=tu(tu({},b),p.caption_between));var S=null!==(s=null==h?void 0:h.Caption)&&void 0!==s?s:tz;return th.jsxs("div",{className:y.join(" "),style:b,children:[th.jsx(S,{id:g,displayMonth:e.displayMonth,displayIndex:e.displayIndex}),th.jsx(nd,{id:v,"aria-labelledby":g,displayMonth:e.displayMonth})]},e.displayIndex)}function nv(e){var t=tS(),n=t.classNames,r=t.styles;return th.jsx("div",{className:n.months,style:r.months,children:e.children})}function ny(e){var t,n,r=e.initialProps,o=tS(),i=nn(),a=tM(),l=(0,d.useState)(!1),s=l[0],c=l[1];(0,d.useEffect)(function(){o.initialFocus&&i.focusTarget&&(s||(i.focus(i.focusTarget),c(!0)))},[o.initialFocus,s,i.focus,i.focusTarget,i]);var u=[o.classNames.root,o.className];o.numberOfMonths>1&&u.push(o.classNames.multiple_months),o.showWeekNumber&&u.push(o.classNames.with_weeknumber);var f=tu(tu({},o.styles.root),o.style),p=Object.keys(r).filter(function(e){return e.startsWith("data-")}).reduce(function(e,t){var n;return tu(tu({},e),((n={})[t]=r[t],n))},{}),h=null!==(n=null===(t=r.components)||void 0===t?void 0:t.Months)&&void 0!==n?n:nv;return th.jsx("div",tu({className:u.join(" "),style:f,dir:o.dir,id:o.id,nonce:r.nonce,title:r.title,lang:r.lang},p,{children:th.jsx(h,{children:a.displayMonths.map(function(e,t){return th.jsx(ng,{displayIndex:t,displayMonth:e},t)})})}))}function nb(e){var t=e.children,n=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,r=Object.getOwnPropertySymbols(e);ot.indexOf(r[o])&&Object.prototype.propertyIsEnumerable.call(e,r[o])&&(n[r[o]]=e[r[o]]);return n}(e,["children"]);return th.jsx(tk,{initialProps:n,children:th.jsx(tT,{children:th.jsx(no,{initialProps:n,children:th.jsx(tU,{initialProps:n,children:th.jsx(t$,{initialProps:n,children:th.jsx(t5,{children:th.jsx(nt,{children:t})})})})})})})}function nx(e){return th.jsx(nb,tu({},e,{children:th.jsx(ny,{initialProps:e})}))}let nw=e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M10.8284 12.0007L15.7782 16.9504L14.364 18.3646L8 12.0007L14.364 5.63672L15.7782 7.05093L10.8284 12.0007Z"}))},nk=e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M13.1717 12.0007L8.22192 7.05093L9.63614 5.63672L16.0001 12.0007L9.63614 18.3646L8.22192 16.9504L13.1717 12.0007Z"}))},nS=e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M4.83582 12L11.0429 18.2071L12.4571 16.7929L7.66424 12L12.4571 7.20712L11.0429 5.79291L4.83582 12ZM10.4857 12L16.6928 18.2071L18.107 16.7929L13.3141 12L18.107 7.20712L16.6928 5.79291L10.4857 12Z"}))},nE=e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M19.1642 12L12.9571 5.79291L11.5429 7.20712L16.3358 12L11.5429 16.7929L12.9571 18.2071L19.1642 12ZM13.5143 12L7.30722 5.79291L5.89301 7.20712L10.6859 12L5.89301 16.7929L7.30722 18.2071L13.5143 12Z"}))};var nO=n(84264);n(41649);var nC=n(1526),nj=n(7084),n_=n(26898);let nP={xs:{paddingX:"px-2",paddingY:"py-0.5",fontSize:"text-xs"},sm:{paddingX:"px-2.5",paddingY:"py-1",fontSize:"text-sm"},md:{paddingX:"px-3",paddingY:"py-1.5",fontSize:"text-md"},lg:{paddingX:"px-3.5",paddingY:"py-1.5",fontSize:"text-lg"},xl:{paddingX:"px-3.5",paddingY:"py-1.5",fontSize:"text-xl"}},nT={xs:{paddingX:"px-2",paddingY:"py-0.5",fontSize:"text-xs"},sm:{paddingX:"px-2.5",paddingY:"py-0.5",fontSize:"text-sm"},md:{paddingX:"px-3",paddingY:"py-0.5",fontSize:"text-md"},lg:{paddingX:"px-3.5",paddingY:"py-0.5",fontSize:"text-lg"},xl:{paddingX:"px-4",paddingY:"py-1",fontSize:"text-xl"}},nM={xs:{height:"h-4",width:"w-4"},sm:{height:"h-4",width:"w-4"},md:{height:"h-4",width:"w-4"},lg:{height:"h-5",width:"w-5"},xl:{height:"h-6",width:"w-6"}},nN={[nj.wu.Increase]:{bgColor:(0,eJ.bM)(nj.fr.Emerald,n_.K.background).bgColor,textColor:(0,eJ.bM)(nj.fr.Emerald,n_.K.text).textColor},[nj.wu.ModerateIncrease]:{bgColor:(0,eJ.bM)(nj.fr.Emerald,n_.K.background).bgColor,textColor:(0,eJ.bM)(nj.fr.Emerald,n_.K.text).textColor},[nj.wu.Decrease]:{bgColor:(0,eJ.bM)(nj.fr.Rose,n_.K.background).bgColor,textColor:(0,eJ.bM)(nj.fr.Rose,n_.K.text).textColor},[nj.wu.ModerateDecrease]:{bgColor:(0,eJ.bM)(nj.fr.Rose,n_.K.background).bgColor,textColor:(0,eJ.bM)(nj.fr.Rose,n_.K.text).textColor},[nj.wu.Unchanged]:{bgColor:(0,eJ.bM)(nj.fr.Orange,n_.K.background).bgColor,textColor:(0,eJ.bM)(nj.fr.Orange,n_.K.text).textColor}},nA={[nj.wu.Increase]:e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M13.0001 7.82843V20H11.0001V7.82843L5.63614 13.1924L4.22192 11.7782L12.0001 4L19.7783 11.7782L18.3641 13.1924L13.0001 7.82843Z"}))},[nj.wu.ModerateIncrease]:e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M16.0037 9.41421L7.39712 18.0208L5.98291 16.6066L14.5895 8H7.00373V6H18.0037V17H16.0037V9.41421Z"}))},[nj.wu.Decrease]:e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M13.0001 16.1716L18.3641 10.8076L19.7783 12.2218L12.0001 20L4.22192 12.2218L5.63614 10.8076L11.0001 16.1716V4H13.0001V16.1716Z"}))},[nj.wu.ModerateDecrease]:e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M14.5895 16.0032L5.98291 7.39664L7.39712 5.98242L16.0037 14.589V7.00324H18.0037V18.0032H7.00373V16.0032H14.5895Z"}))},[nj.wu.Unchanged]:e=>{var t=(0,u._T)(e,[]);return d.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),d.createElement("path",{d:"M16.1716 10.9999L10.8076 5.63589L12.2218 4.22168L20 11.9999L12.2218 19.778L10.8076 18.3638L16.1716 12.9999H4V10.9999H16.1716Z"}))}},nI=(0,eJ.fn)("BadgeDelta");d.forwardRef((e,t)=>{let{deltaType:n=nj.wu.Increase,isIncreasePositive:r=!0,size:o=nj.u8.SM,tooltip:i,children:a,className:l}=e,s=(0,u._T)(e,["deltaType","isIncreasePositive","size","tooltip","children","className"]),c=nA[n],f=(0,eJ.Fo)(n,r),p=a?nT:nP,{tooltipProps:h,getReferenceProps:m}=(0,nC.l)();return d.createElement("span",Object.assign({ref:(0,eJ.lq)([t,h.refs.setReference]),className:(0,ec.q)(nI("root"),"w-max flex-shrink-0 inline-flex justify-center items-center cursor-default rounded-tremor-full bg-opacity-20 dark:bg-opacity-25",nN[f].bgColor,nN[f].textColor,p[o].paddingX,p[o].paddingY,p[o].fontSize,l)},m,s),d.createElement(nC.Z,Object.assign({text:i},h)),d.createElement(c,{className:(0,ec.q)(nI("icon"),"shrink-0",a?(0,ec.q)("-ml-1 mr-1.5"):nM[o].height,nM[o].width)}),a?d.createElement("p",{className:(0,ec.q)(nI("text"),"text-sm whitespace-nowrap")},a):null)}).displayName="BadgeDelta";var nR=n(47323);let nD=e=>{var{onClick:t,icon:n}=e,r=(0,u._T)(e,["onClick","icon"]);return d.createElement("button",Object.assign({type:"button",className:(0,ec.q)("flex items-center justify-center p-1 h-7 w-7 outline-none focus:ring-2 transition duration-100 border border-tremor-border dark:border-dark-tremor-border hover:bg-tremor-background-muted dark:hover:bg-dark-tremor-background-muted rounded-tremor-small focus:border-tremor-brand-subtle select-none dark:focus:border-dark-tremor-brand-subtle focus:ring-tremor-brand-muted dark:focus:ring-dark-tremor-brand-muted text-tremor-content-subtle dark:text-dark-tremor-content-subtle hover:text-tremor-content dark:hover:text-dark-tremor-content")},r),d.createElement(nR.Z,{onClick:t,icon:n,variant:"simple",color:"slate",size:"sm"}))};function nL(e){var{mode:t,defaultMonth:n,selected:r,onSelect:o,locale:i,disabled:a,enableYearNavigation:l,classNames:s,weekStartsOn:c=0}=e,f=(0,u._T)(e,["mode","defaultMonth","selected","onSelect","locale","disabled","enableYearNavigation","classNames","weekStartsOn"]);return d.createElement(nx,Object.assign({showOutsideDays:!0,mode:t,defaultMonth:n,selected:r,onSelect:o,locale:i,disabled:a,weekStartsOn:c,classNames:Object.assign({months:"flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",month:"space-y-4",caption:"flex justify-center pt-2 relative items-center",caption_label:"text-tremor-default text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis font-medium",nav:"space-x-1 flex items-center",nav_button:"flex items-center justify-center p-1 h-7 w-7 outline-none focus:ring-2 transition duration-100 border border-tremor-border dark:border-dark-tremor-border hover:bg-tremor-background-muted dark:hover:bg-dark-tremor-background-muted rounded-tremor-small focus:border-tremor-brand-subtle dark:focus:border-dark-tremor-brand-subtle focus:ring-tremor-brand-muted dark:focus:ring-dark-tremor-brand-muted text-tremor-content-subtle dark:text-dark-tremor-content-subtle hover:text-tremor-content dark:hover:text-dark-tremor-content",nav_button_previous:"absolute left-1",nav_button_next:"absolute right-1",table:"w-full border-collapse space-y-1",head_row:"flex",head_cell:"w-9 font-normal text-center text-tremor-content-subtle dark:text-dark-tremor-content-subtle",row:"flex w-full mt-0.5",cell:"text-center p-0 relative focus-within:relative text-tremor-default text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis",day:"h-9 w-9 p-0 hover:bg-tremor-background-subtle dark:hover:bg-dark-tremor-background-subtle outline-tremor-brand dark:outline-dark-tremor-brand rounded-tremor-default",day_today:"font-bold",day_selected:"aria-selected:bg-tremor-background-emphasis aria-selected:text-tremor-content-inverted dark:aria-selected:bg-dark-tremor-background-emphasis dark:aria-selected:text-dark-tremor-content-inverted ",day_disabled:"text-tremor-content-subtle dark:text-dark-tremor-content-subtle disabled:hover:bg-transparent",day_outside:"text-tremor-content-subtle dark:text-dark-tremor-content-subtle"},s),components:{IconLeft:e=>{var t=(0,u._T)(e,[]);return d.createElement(nw,Object.assign({className:"h-4 w-4"},t))},IconRight:e=>{var t=(0,u._T)(e,[]);return d.createElement(nk,Object.assign({className:"h-4 w-4"},t))},Caption:e=>{var t=(0,u._T)(e,[]);let{goToMonth:n,nextMonth:r,previousMonth:o,currentMonth:a}=tM();return d.createElement("div",{className:"flex justify-between items-center"},d.createElement("div",{className:"flex items-center space-x-1"},l&&d.createElement(nD,{onClick:()=>a&&n(tl(a,-1)),icon:nS}),d.createElement(nD,{onClick:()=>o&&n(o),icon:nw})),d.createElement(nO.Z,{className:"text-tremor-default tabular-nums capitalize text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis font-medium"},eQ(t.displayMonth,"LLLL yyy",{locale:i})),d.createElement("div",{className:"flex items-center space-x-1"},d.createElement(nD,{onClick:()=>r&&n(r),icon:nk}),l&&d.createElement(nD,{onClick:()=>a&&n(tl(a,1)),icon:nE})))}}},f))}nL.displayName="DateRangePicker",n(27281);var nz=n(57365),nZ=n(44140);let nB=el(),nF=d.forwardRef((e,t)=>{var n,r;let{value:o,defaultValue:i,onValueChange:a,enableSelect:l=!0,minDate:s,maxDate:c,placeholder:f="Select range",selectPlaceholder:p="Select range",disabled:h=!1,locale:m=eK,enableClear:g=!0,displayFormat:v,children:y,className:b,enableYearNavigation:x=!1,weekStartsOn:w=0,disabledDates:k}=e,S=(0,u._T)(e,["value","defaultValue","onValueChange","enableSelect","minDate","maxDate","placeholder","selectPlaceholder","disabled","locale","enableClear","displayFormat","children","className","enableYearNavigation","weekStartsOn","disabledDates"]),[E,O]=(0,nZ.Z)(i,o),[C,j]=(0,d.useState)(!1),[_,P]=(0,d.useState)(!1),T=(0,d.useMemo)(()=>{let e=[];return s&&e.push({before:s}),c&&e.push({after:c}),[...e,...null!=k?k:[]]},[s,c,k]),M=(0,d.useMemo)(()=>{let e=new Map;return y?d.Children.forEach(y,t=>{var n;e.set(t.props.value,{text:null!==(n=(0,eu.qg)(t))&&void 0!==n?n:t.props.value,from:t.props.from,to:t.props.to})}):e4.forEach(t=>{e.set(t.value,{text:t.text,from:t.from,to:nB})}),e},[y]),N=(0,d.useMemo)(()=>{if(y)return(0,eu.sl)(y);let e=new Map;return e4.forEach(t=>e.set(t.value,t.text)),e},[y]),A=(null==E?void 0:E.selectValue)||"",I=e1(null==E?void 0:E.from,s,A,M),R=e2(null==E?void 0:E.to,c,A,M),D=I||R?e3(I,R,m,v):f,L=es(null!==(r=null!==(n=null!=R?R:I)&&void 0!==n?n:c)&&void 0!==r?r:nB),z=g&&!h;return d.createElement("div",Object.assign({ref:t,className:(0,ec.q)("w-full min-w-[10rem] relative flex justify-between text-tremor-default max-w-sm shadow-tremor-input dark:shadow-dark-tremor-input rounded-tremor-default",b)},S),d.createElement(J,{as:"div",className:(0,ec.q)("w-full",l?"rounded-l-tremor-default":"rounded-tremor-default",C&&"ring-2 ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted z-10")},d.createElement("div",{className:"relative w-full"},d.createElement(J.Button,{onFocus:()=>j(!0),onBlur:()=>j(!1),disabled:h,className:(0,ec.q)("w-full outline-none text-left whitespace-nowrap truncate focus:ring-2 transition duration-100 rounded-l-tremor-default flex flex-nowrap border pl-3 py-2","rounded-l-tremor-default border-tremor-border text-tremor-content-emphasis focus:border-tremor-brand-subtle focus:ring-tremor-brand-muted","dark:border-dark-tremor-border dark:text-dark-tremor-content-emphasis dark:focus:border-dark-tremor-brand-subtle dark:focus:ring-dark-tremor-brand-muted",l?"rounded-l-tremor-default":"rounded-tremor-default",z?"pr-8":"pr-4",(0,eu.um)((0,eu.Uh)(I||R),h))},d.createElement(en,{className:(0,ec.q)(e0("calendarIcon"),"flex-none shrink-0 h-5 w-5 -ml-0.5 mr-2","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle"),"aria-hidden":"true"}),d.createElement("p",{className:"truncate"},D)),z&&I?d.createElement("button",{type:"button",className:(0,ec.q)("absolute outline-none inset-y-0 right-0 flex items-center transition duration-100 mr-4"),onClick:e=>{e.preventDefault(),null==a||a({}),O({})}},d.createElement(er.Z,{className:(0,ec.q)(e0("clearIcon"),"flex-none h-4 w-4","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})):null),d.createElement(ee.u,{className:"absolute z-10 min-w-min left-0",enter:"transition ease duration-100 transform",enterFrom:"opacity-0 -translate-y-4",enterTo:"opacity-100 translate-y-0",leave:"transition ease duration-100 transform",leaveFrom:"opacity-100 translate-y-0",leaveTo:"opacity-0 -translate-y-4"},d.createElement(J.Panel,{focus:!0,className:(0,ec.q)("divide-y overflow-y-auto outline-none rounded-tremor-default p-3 border my-1","bg-tremor-background border-tremor-border divide-tremor-border shadow-tremor-dropdown","dark:bg-dark-tremor-background dark:border-dark-tremor-border dark:divide-dark-tremor-border dark:shadow-dark-tremor-dropdown")},d.createElement(nL,Object.assign({mode:"range",showOutsideDays:!0,defaultMonth:L,selected:{from:I,to:R},onSelect:e=>{null==a||a({from:null==e?void 0:e.from,to:null==e?void 0:e.to}),O({from:null==e?void 0:e.from,to:null==e?void 0:e.to})},locale:m,disabled:T,enableYearNavigation:x,classNames:{day_range_middle:(0,ec.q)("!rounded-none aria-selected:!bg-tremor-background-subtle aria-selected:dark:!bg-dark-tremor-background-subtle aria-selected:!text-tremor-content aria-selected:dark:!bg-dark-tremor-background-subtle"),day_range_start:"rounded-r-none rounded-l-tremor-small aria-selected:text-tremor-brand-inverted dark:aria-selected:text-dark-tremor-brand-inverted",day_range_end:"rounded-l-none rounded-r-tremor-small aria-selected:text-tremor-brand-inverted dark:aria-selected:text-dark-tremor-brand-inverted"},weekStartsOn:w},e))))),l&&d.createElement(et.R,{as:"div",className:(0,ec.q)("w-48 -ml-px rounded-r-tremor-default",_&&"ring-2 ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted z-10"),value:A,onChange:e=>{let{from:t,to:n}=M.get(e),r=null!=n?n:nB;null==a||a({from:t,to:r,selectValue:e}),O({from:t,to:r,selectValue:e})},disabled:h},e=>{var t;let{value:n}=e;return d.createElement(d.Fragment,null,d.createElement(et.R.Button,{onFocus:()=>P(!0),onBlur:()=>P(!1),className:(0,ec.q)("w-full outline-none text-left whitespace-nowrap truncate rounded-r-tremor-default transition duration-100 border px-4 py-2","border-tremor-border shadow-tremor-input text-tremor-content-emphasis focus:border-tremor-brand-subtle","dark:border-dark-tremor-border dark:shadow-dark-tremor-input dark:text-dark-tremor-content-emphasis dark:focus:border-dark-tremor-brand-subtle",(0,eu.um)((0,eu.Uh)(n),h))},n&&null!==(t=N.get(n))&&void 0!==t?t:p),d.createElement(ee.u,{className:"absolute z-10 w-full inset-x-0 right-0",enter:"transition ease duration-100 transform",enterFrom:"opacity-0 -translate-y-4",enterTo:"opacity-100 translate-y-0",leave:"transition ease duration-100 transform",leaveFrom:"opacity-100 translate-y-0",leaveTo:"opacity-0 -translate-y-4"},d.createElement(et.R.Options,{className:(0,ec.q)("divide-y overflow-y-auto outline-none border my-1","shadow-tremor-dropdown bg-tremor-background border-tremor-border divide-tremor-border rounded-tremor-default","dark:shadow-dark-tremor-dropdown dark:bg-dark-tremor-background dark:border-dark-tremor-border dark:divide-dark-tremor-border")},null!=y?y:e4.map(e=>d.createElement(nz.Z,{key:e.value,value:e.value},e.text)))))}))});nF.displayName="DateRangePicker"},92414:function(e,t,n){"use strict";n.d(t,{Z:function(){return v}});var r=n(5853),o=n(2265);n(42698),n(64016),n(8710);var i=n(33232),a=n(44140),l=n(58747);let s=e=>{var t=(0,r._T)(e,[]);return o.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),o.createElement("path",{d:"M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z"}))};var c=n(4537),u=n(9528),d=n(33044);let f=e=>{var t=(0,r._T)(e,[]);return o.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:"100%",height:"100%",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"},t),o.createElement("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),o.createElement("line",{x1:"6",y1:"6",x2:"18",y2:"18"}))};var p=n(97324),h=n(1153),m=n(96398);let g=(0,h.fn)("MultiSelect"),v=o.forwardRef((e,t)=>{let{defaultValue:n,value:h,onValueChange:v,placeholder:y="Select...",placeholderSearch:b="Search",disabled:x=!1,icon:w,children:k,className:S}=e,E=(0,r._T)(e,["defaultValue","value","onValueChange","placeholder","placeholderSearch","disabled","icon","children","className"]),[O,C]=(0,a.Z)(n,h),{reactElementChildren:j,optionsAvailable:_}=(0,o.useMemo)(()=>{let e=o.Children.toArray(k).filter(o.isValidElement);return{reactElementChildren:e,optionsAvailable:(0,m.n0)("",e)}},[k]),[P,T]=(0,o.useState)(""),M=(null!=O?O:[]).length>0,N=(0,o.useMemo)(()=>P?(0,m.n0)(P,j):_,[P,j,_]),A=()=>{T("")};return o.createElement(u.R,Object.assign({as:"div",ref:t,defaultValue:O,value:O,onChange:e=>{null==v||v(e),C(e)},disabled:x,className:(0,p.q)("w-full min-w-[10rem] relative text-tremor-default",S)},E,{multiple:!0}),e=>{let{value:t}=e;return o.createElement(o.Fragment,null,o.createElement(u.R.Button,{className:(0,p.q)("w-full outline-none text-left whitespace-nowrap truncate rounded-tremor-default focus:ring-2 transition duration-100 border pr-8 py-1.5","border-tremor-border shadow-tremor-input focus:border-tremor-brand-subtle focus:ring-tremor-brand-muted","dark:border-dark-tremor-border dark:shadow-dark-tremor-input dark:focus:border-dark-tremor-brand-subtle dark:focus:ring-dark-tremor-brand-muted",w?"pl-11 -ml-0.5":"pl-3",(0,m.um)(t.length>0,x))},w&&o.createElement("span",{className:(0,p.q)("absolute inset-y-0 left-0 flex items-center ml-px pl-2.5")},o.createElement(w,{className:(0,p.q)(g("Icon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})),o.createElement("div",{className:"h-6 flex items-center"},t.length>0?o.createElement("div",{className:"flex flex-nowrap overflow-x-scroll [&::-webkit-scrollbar]:hidden [scrollbar-width:none] gap-x-1 mr-5 -ml-1.5 relative"},_.filter(e=>t.includes(e.props.value)).map((e,n)=>{var r;return o.createElement("div",{key:n,className:(0,p.q)("max-w-[100px] lg:max-w-[200px] flex justify-center items-center pl-2 pr-1.5 py-1 font-medium","rounded-tremor-small","bg-tremor-background-muted dark:bg-dark-tremor-background-muted","bg-tremor-background-subtle dark:bg-dark-tremor-background-subtle","text-tremor-content-default dark:text-dark-tremor-content-default","text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis")},o.createElement("div",{className:"text-xs truncate "},null!==(r=e.props.children)&&void 0!==r?r:e.props.value),o.createElement("div",{onClick:n=>{n.preventDefault();let r=t.filter(t=>t!==e.props.value);null==v||v(r),C(r)}},o.createElement(f,{className:(0,p.q)(g("clearIconItem"),"cursor-pointer rounded-tremor-full w-3.5 h-3.5 ml-2","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle dark:hover:text-tremor-content")})))})):o.createElement("span",null,y)),o.createElement("span",{className:(0,p.q)("absolute inset-y-0 right-0 flex items-center mr-2.5")},o.createElement(l.Z,{className:(0,p.q)(g("arrowDownIcon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}))),M&&!x?o.createElement("button",{type:"button",className:(0,p.q)("absolute inset-y-0 right-0 flex items-center mr-8"),onClick:e=>{e.preventDefault(),C([]),null==v||v([])}},o.createElement(c.Z,{className:(0,p.q)(g("clearIconAllItems"),"flex-none h-4 w-4","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})):null,o.createElement(d.u,{className:"absolute z-10 w-full",enter:"transition ease duration-100 transform",enterFrom:"opacity-0 -translate-y-4",enterTo:"opacity-100 translate-y-0",leave:"transition ease duration-100 transform",leaveFrom:"opacity-100 translate-y-0",leaveTo:"opacity-0 -translate-y-4"},o.createElement(u.R.Options,{className:(0,p.q)("divide-y overflow-y-auto outline-none rounded-tremor-default max-h-[228px] left-0 border my-1","bg-tremor-background border-tremor-border divide-tremor-border shadow-tremor-dropdown","dark:bg-dark-tremor-background dark:border-dark-tremor-border dark:divide-dark-tremor-border dark:shadow-dark-tremor-dropdown")},o.createElement("div",{className:(0,p.q)("flex items-center w-full px-2.5","bg-tremor-background-muted","dark:bg-dark-tremor-background-muted")},o.createElement("span",null,o.createElement(s,{className:(0,p.q)("flex-none w-4 h-4 mr-2","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})),o.createElement("input",{name:"search",type:"input",autoComplete:"off",placeholder:b,className:(0,p.q)("w-full focus:outline-none focus:ring-none bg-transparent text-tremor-default py-2","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis"),onKeyDown:e=>{"Space"===e.code&&""!==e.target.value&&e.stopPropagation()},onChange:e=>T(e.target.value),value:P})),o.createElement(i.Z.Provider,Object.assign({},{onBlur:{handleResetSearch:A}},{value:{selectedValue:t}}),N))))})});v.displayName="MultiSelect"},46030:function(e,t,n){"use strict";n.d(t,{Z:function(){return u}});var r=n(5853);n(42698),n(64016),n(8710);var o=n(33232),i=n(2265),a=n(97324),l=n(1153),s=n(9528);let c=(0,l.fn)("MultiSelectItem"),u=i.forwardRef((e,t)=>{let{value:n,className:u,children:d}=e,f=(0,r._T)(e,["value","className","children"]),{selectedValue:p}=(0,i.useContext)(o.Z),h=(0,l.NZ)(n,p);return i.createElement(s.R.Option,Object.assign({className:(0,a.q)(c("root"),"flex justify-start items-center cursor-default text-tremor-default p-2.5","ui-active:bg-tremor-background-muted ui-active:text-tremor-content-strong ui-selected:text-tremor-content-strong text-tremor-content-emphasis","dark:ui-active:bg-dark-tremor-background-muted dark:ui-active:text-dark-tremor-content-strong dark:ui-selected:text-dark-tremor-content-strong dark:ui-selected:bg-dark-tremor-background-muted dark:text-dark-tremor-content-emphasis",u),ref:t,key:n,value:n},f),i.createElement("input",{type:"checkbox",className:(0,a.q)(c("checkbox"),"flex-none focus:ring-none focus:outline-none cursor-pointer mr-2.5","accent-tremor-brand","dark:accent-dark-tremor-brand"),checked:h,readOnly:!0}),i.createElement("span",{className:"whitespace-nowrap truncate"},null!=d?d:n))});u.displayName="MultiSelectItem"},30150:function(e,t,n){"use strict";n.d(t,{Z:function(){return f}});var r=n(5853),o=n(2265);let i=e=>{var t=(0,r._T)(e,[]);return o.createElement("svg",Object.assign({},t,{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:"2.5"}),o.createElement("path",{d:"M12 4v16m8-8H4"}))},a=e=>{var t=(0,r._T)(e,[]);return o.createElement("svg",Object.assign({},t,{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:"2.5"}),o.createElement("path",{d:"M20 12H4"}))};var l=n(97324),s=n(1153),c=n(69262);let u="flex mx-auto text-tremor-content-subtle dark:text-dark-tremor-content-subtle",d="cursor-pointer hover:text-tremor-content dark:hover:text-dark-tremor-content",f=o.forwardRef((e,t)=>{let{onSubmit:n,enableStepper:f=!0,disabled:p,onValueChange:h,onChange:m}=e,g=(0,r._T)(e,["onSubmit","enableStepper","disabled","onValueChange","onChange"]),v=(0,o.useRef)(null),[y,b]=o.useState(!1),x=o.useCallback(()=>{b(!0)},[]),w=o.useCallback(()=>{b(!1)},[]),[k,S]=o.useState(!1),E=o.useCallback(()=>{S(!0)},[]),O=o.useCallback(()=>{S(!1)},[]);return o.createElement(c.Z,Object.assign({type:"number",ref:(0,s.lq)([v,t]),disabled:p,makeInputClassName:(0,s.fn)("NumberInput"),onKeyDown:e=>{var t;if("Enter"===e.key&&!e.ctrlKey&&!e.altKey&&!e.shiftKey){let e=null===(t=v.current)||void 0===t?void 0:t.value;null==n||n(parseFloat(null!=e?e:""))}"ArrowDown"===e.key&&x(),"ArrowUp"===e.key&&E()},onKeyUp:e=>{"ArrowDown"===e.key&&w(),"ArrowUp"===e.key&&O()},onChange:e=>{p||(null==h||h(parseFloat(e.target.value)),null==m||m(e))},stepper:f?o.createElement("div",{className:(0,l.q)("flex justify-center align-middle")},o.createElement("div",{tabIndex:-1,onClick:e=>e.preventDefault(),onMouseDown:e=>e.preventDefault(),onTouchStart:e=>{e.cancelable&&e.preventDefault()},onMouseUp:()=>{var e,t;p||(null===(e=v.current)||void 0===e||e.stepDown(),null===(t=v.current)||void 0===t||t.dispatchEvent(new Event("input",{bubbles:!0})))},className:(0,l.q)(!p&&d,u,"group py-[10px] px-2.5 border-l border-tremor-border dark:border-dark-tremor-border")},o.createElement(a,{"data-testid":"step-down",className:(y?"scale-95":"")+" h-4 w-4 duration-75 transition group-active:scale-95"})),o.createElement("div",{tabIndex:-1,onClick:e=>e.preventDefault(),onMouseDown:e=>e.preventDefault(),onTouchStart:e=>{e.cancelable&&e.preventDefault()},onMouseUp:()=>{var e,t;p||(null===(e=v.current)||void 0===e||e.stepUp(),null===(t=v.current)||void 0===t||t.dispatchEvent(new Event("input",{bubbles:!0})))},className:(0,l.q)(!p&&d,u,"group py-[10px] px-2.5 border-l border-tremor-border dark:border-dark-tremor-border")},o.createElement(i,{"data-testid":"step-up",className:(k?"scale-95":"")+" h-4 w-4 duration-75 transition group-active:scale-95"}))):null},g))});f.displayName="NumberInput"},54250:function(e,t,n){"use strict";n.d(t,{Z:function(){return m}});var r=n(5853),o=n(2265),i=n(44140),a=n(34237),l=n(33044),s=n(58747),c=n(4537),u=n(97324),d=n(1153),f=n(96398);let p=(0,d.fn)("SearchSelect"),h=(0,d.fn)("SearchSelect"),m=o.forwardRef((e,t)=>{let{defaultValue:n,value:d,onValueChange:m,placeholder:g="Select...",disabled:v=!1,icon:y,enableClear:b=!0,children:x,className:w}=e,k=(0,r._T)(e,["defaultValue","value","onValueChange","placeholder","disabled","icon","enableClear","children","className"]),[S,E]=(0,o.useState)(""),[O,C]=(0,i.Z)(n,d),{reactElementChildren:j,valueToNameMapping:_}=(0,o.useMemo)(()=>{let e=o.Children.toArray(x).filter(o.isValidElement);return{reactElementChildren:e,valueToNameMapping:(0,f.sl)(e)}},[x]),P=(0,o.useMemo)(()=>(0,f.n0)(S,j),[S,j]);return o.createElement(a.h,Object.assign({as:"div",ref:t,defaultValue:O,value:O,onChange:e=>{null==m||m(e),C(e)},disabled:v,className:(0,u.q)("w-full min-w-[10rem] relative text-tremor-default",w)},k),e=>{let{value:t}=e;return o.createElement(o.Fragment,null,o.createElement(a.h.Button,{className:"w-full"},y&&o.createElement("span",{className:(0,u.q)("absolute inset-y-0 left-0 flex items-center ml-px pl-2.5")},o.createElement(y,{className:(0,u.q)(p("Icon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})),o.createElement(a.h.Input,{className:(0,u.q)("w-full outline-none text-left whitespace-nowrap truncate rounded-tremor-default focus:ring-2 transition duration-100 text-tremor-default pr-14 border py-2","border-tremor-border shadow-tremor-input focus:border-tremor-brand-subtle focus:ring-tremor-brand-muted","dark:border-dark-tremor-border dark:shadow-dark-tremor-input dark:focus:border-dark-tremor-brand-subtle dark:focus:ring-dark-tremor-brand-muted",y?"pl-10":"pl-3",v?"placeholder:text-tremor-content-subtle dark:placeholder:text-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-tremor-content",(0,f.um)((0,f.Uh)(t),v)),placeholder:g,onChange:e=>E(e.target.value),displayValue:e=>{var t;return null!==(t=_.get(e))&&void 0!==t?t:""}}),o.createElement("div",{className:(0,u.q)("absolute inset-y-0 right-0 flex items-center pr-2.5")},o.createElement(s.Z,{className:(0,u.q)(p("arrowDownIcon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}))),b&&O?o.createElement("button",{type:"button",className:(0,u.q)("absolute inset-y-0 right-0 flex items-center mr-8"),onClick:e=>{e.preventDefault(),C(""),E(""),null==m||m("")}},o.createElement(c.Z,{className:(0,u.q)(h("clearIcon"),"flex-none h-4 w-4","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})):null,P.length>0&&o.createElement(l.u,{className:"absolute z-10 w-full",enter:"transition ease duration-100 transform",enterFrom:"opacity-0 -translate-y-4",enterTo:"opacity-100 translate-y-0",leave:"transition ease duration-100 transform",leaveFrom:"opacity-100 translate-y-0",leaveTo:"opacity-0 -translate-y-4"},o.createElement(a.h.Options,{className:(0,u.q)("divide-y overflow-y-auto outline-none rounded-tremor-default text-tremor-default max-h-[228px] left-0 border my-1","bg-tremor-background border-tremor-border divide-tremor-border shadow-tremor-dropdown","dark:bg-dark-tremor-background dark:border-dark-tremor-border dark:divide-dark-tremor-border dark:shadow-dark-tremor-dropdown")},P)))})});m.displayName="SearchSelect"},70450:function(e,t,n){"use strict";n.d(t,{Z:function(){return c}});var r=n(5853),o=n(2265),i=n(97324),a=n(1153),l=n(34237);let s=(0,a.fn)("SearchSelectItem"),c=o.forwardRef((e,t)=>{let{value:n,icon:a,className:c,children:u}=e,d=(0,r._T)(e,["value","icon","className","children"]);return o.createElement(l.h.Option,Object.assign({className:(0,i.q)(s("root"),"flex justify-start items-center cursor-default text-tremor-default p-2.5","ui-active:bg-tremor-background-muted ui-active:text-tremor-content-strong ui-selected:text-tremor-content-strong ui-selected:bg-tremor-background-muted text-tremor-content-emphasis","dark:ui-active:bg-dark-tremor-background-muted dark:ui-active:text-dark-tremor-content-strong dark:ui-selected:text-dark-tremor-content-strong dark:ui-selected:bg-dark-tremor-background-muted dark:text-dark-tremor-content-emphasis",c),ref:t,key:n,value:n},d),a&&o.createElement(a,{className:(0,i.q)(s("icon"),"flex-none h-5 w-5 mr-3","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}),o.createElement("span",{className:"whitespace-nowrap truncate"},null!=u?u:n))});c.displayName="SearchSelectItem"},27281:function(e,t,n){"use strict";n.d(t,{Z:function(){return h}});var r=n(5853),o=n(2265),i=n(58747),a=n(4537),l=n(97324),s=n(1153),c=n(96398),u=n(9528),d=n(33044),f=n(44140);let p=(0,s.fn)("Select"),h=o.forwardRef((e,t)=>{let{defaultValue:n,value:s,onValueChange:h,placeholder:m="Select...",disabled:g=!1,icon:v,enableClear:y=!0,children:b,className:x}=e,w=(0,r._T)(e,["defaultValue","value","onValueChange","placeholder","disabled","icon","enableClear","children","className"]),[k,S]=(0,f.Z)(n,s),E=(0,o.useMemo)(()=>{let e=o.Children.toArray(b).filter(o.isValidElement);return(0,c.sl)(e)},[b]);return o.createElement(u.R,Object.assign({as:"div",ref:t,defaultValue:k,value:k,onChange:e=>{null==h||h(e),S(e)},disabled:g,className:(0,l.q)("w-full min-w-[10rem] relative text-tremor-default",x)},w),e=>{var t;let{value:n}=e;return o.createElement(o.Fragment,null,o.createElement(u.R.Button,{className:(0,l.q)("w-full outline-none text-left whitespace-nowrap truncate rounded-tremor-default focus:ring-2 transition duration-100 border pr-8 py-2","border-tremor-border shadow-tremor-input focus:border-tremor-brand-subtle focus:ring-tremor-brand-muted","dark:border-dark-tremor-border dark:shadow-dark-tremor-input dark:focus:border-dark-tremor-brand-subtle dark:focus:ring-dark-tremor-brand-muted",v?"pl-10":"pl-3",(0,c.um)((0,c.Uh)(n),g))},v&&o.createElement("span",{className:(0,l.q)("absolute inset-y-0 left-0 flex items-center ml-px pl-2.5")},o.createElement(v,{className:(0,l.q)(p("Icon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})),o.createElement("span",{className:"w-[90%] block truncate"},n&&null!==(t=E.get(n))&&void 0!==t?t:m),o.createElement("span",{className:(0,l.q)("absolute inset-y-0 right-0 flex items-center mr-3")},o.createElement(i.Z,{className:(0,l.q)(p("arrowDownIcon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}))),y&&k?o.createElement("button",{type:"button",className:(0,l.q)("absolute inset-y-0 right-0 flex items-center mr-8"),onClick:e=>{e.preventDefault(),S(""),null==h||h("")}},o.createElement(a.Z,{className:(0,l.q)(p("clearIcon"),"flex-none h-4 w-4","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})):null,o.createElement(d.u,{className:"absolute z-10 w-full",enter:"transition ease duration-100 transform",enterFrom:"opacity-0 -translate-y-4",enterTo:"opacity-100 translate-y-0",leave:"transition ease duration-100 transform",leaveFrom:"opacity-100 translate-y-0",leaveTo:"opacity-0 -translate-y-4"},o.createElement(u.R.Options,{className:(0,l.q)("divide-y overflow-y-auto outline-none rounded-tremor-default max-h-[228px] left-0 border my-1","bg-tremor-background border-tremor-border divide-tremor-border shadow-tremor-dropdown","dark:bg-dark-tremor-background dark:border-dark-tremor-border dark:divide-dark-tremor-border dark:shadow-dark-tremor-dropdown")},b)))})});h.displayName="Select"},57365:function(e,t,n){"use strict";n.d(t,{Z:function(){return s}});var r=n(5853),o=n(2265),i=n(9528),a=n(97324);let l=(0,n(1153).fn)("SelectItem"),s=o.forwardRef((e,t)=>{let{value:n,icon:s,className:c,children:u}=e,d=(0,r._T)(e,["value","icon","className","children"]);return o.createElement(i.R.Option,Object.assign({className:(0,a.q)(l("root"),"flex justify-start items-center cursor-default text-tremor-default px-2.5 py-2.5","ui-active:bg-tremor-background-muted ui-active:text-tremor-content-strong ui-selected:text-tremor-content-strong ui-selected:bg-tremor-background-muted text-tremor-content-emphasis","dark:ui-active:bg-dark-tremor-background-muted dark:ui-active:text-dark-tremor-content-strong dark:ui-selected:text-dark-tremor-content-strong dark:ui-selected:bg-dark-tremor-background-muted dark:text-dark-tremor-content-emphasis",c),ref:t,key:n,value:n},d),s&&o.createElement(s,{className:(0,a.q)(l("icon"),"flex-none w-5 h-5 mr-1.5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}),o.createElement("span",{className:"whitespace-nowrap truncate"},null!=u?u:n))});s.displayName="SelectItem"},92858:function(e,t,n){"use strict";n.d(t,{Z:function(){return T}});var r=n(5853),o=n(2265),i=n(62963),a=n(90945),l=n(13323),s=n(17684),c=n(80004),u=n(93689),d=n(38198),f=n(47634),p=n(56314),h=n(27847),m=n(64518);let g=(0,o.createContext)(null),v=Object.assign((0,h.yV)(function(e,t){let n=(0,s.M)(),{id:r="headlessui-description-".concat(n),...i}=e,a=function e(){let t=(0,o.useContext)(g);if(null===t){let t=Error("You used a component, but it is not inside a relevant parent.");throw Error.captureStackTrace&&Error.captureStackTrace(t,e),t}return t}(),l=(0,u.T)(t);(0,m.e)(()=>a.register(r),[r,a.register]);let c={ref:l,...a.props,id:r};return(0,h.sY)({ourProps:c,theirProps:i,slot:a.slot||{},defaultTag:"p",name:a.name||"Description"})}),{});var y=n(37388);let b=(0,o.createContext)(null),x=Object.assign((0,h.yV)(function(e,t){let n=(0,s.M)(),{id:r="headlessui-label-".concat(n),passive:i=!1,...a}=e,l=function e(){let t=(0,o.useContext)(b);if(null===t){let t=Error("You used a