Merge branch 'BerriAI:main' into LangfuseUsageDetails

This commit is contained in:
Fabrício Ceschin 2025-09-12 09:49:10 -04:00 • committed by GitHub
commit dae5b0f0f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 1842 additions and 128 deletions

View file

@ -1,4 +1,4 @@
# Dashscope
# Dashscope (Qwen API)
https://dashscope.console.aliyun.com/
**We support ALL Qwen models, just set `dashscope/` as a prefix when sending completion requests**

View file

@ -344,6 +344,11 @@ def cost_per_token( # noqa: PLR0915
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)
elif custom_llm_provider == "dashscope":
from litellm.llms.dashscope.cost_calculator import (
cost_per_token as dashscope_cost_per_token,
)
return dashscope_cost_per_token(model=model, usage=usage_block)
else:
model_info = _cached_get_model_info_helper(
model=model, custom_llm_provider=custom_llm_provider

View file

@ -1,10 +1,21 @@
import asyncio
import contextlib
from typing import Coroutine, Optional
import contextvars
from typing import Coroutine, Optional, TypedDict
from litellm._logging import verbose_logger
class LoggingTask(TypedDict):
"""
A logging task with its associated context to ensure logging is executed in
the original task's context.
"""
coroutine: Coroutine
context: contextvars.Context
class LoggingWorker:
"""
A simple, async logging worker that processes log coroutines in the background.
@ -13,77 +24,84 @@ class LoggingWorker:
This leads to a +200 RPS performance improvement when using LiteLLM Python SDK or Proxy Server.
- Use this to queue coroutine tasks that are not critical to the main flow of the application. e.g Success/Error callbacks, logging, etc.
"""
LOGGING_WORKER_MAX_QUEUE_SIZE = 50_000
LOGGING_WORKER_MAX_TIME_PER_COROUTINE = 20.0
MAX_ITERATIONS_TO_CLEAR_QUEUE = 200
MAX_TIME_TO_CLEAR_QUEUE = 5.0
def __init__(
self,
timeout: float = LOGGING_WORKER_MAX_TIME_PER_COROUTINE,
self,
timeout: float = LOGGING_WORKER_MAX_TIME_PER_COROUTINE,
max_queue_size: int = LOGGING_WORKER_MAX_QUEUE_SIZE,
):
self.timeout = timeout
self.max_queue_size = max_queue_size
self._queue: Optional[asyncio.Queue] = None
self._queue: Optional[asyncio.Queue[LoggingTask]] = None
self._worker_task: Optional[asyncio.Task] = None
def _ensure_queue(self) -> None:
"""Initialize the queue if it doesn't exist."""
if self._queue is None:
self._queue = asyncio.Queue(maxsize=self.max_queue_size)
def start(self) -> None:
"""Start the logging worker. Idempotent - safe to call multiple times."""
self._ensure_queue()
if self._worker_task is None or self._worker_task.done():
self._worker_task = asyncio.create_task(self._worker_loop())
async def _worker_loop(self) -> None:
"""Main worker loop that processes log coroutines sequentially."""
try:
if self._queue is None:
return
while True:
# Process one coroutine at a time to keep event loop load predictable
coroutine = await self._queue.get()
task = await self._queue.get()
try:
await asyncio.wait_for(coroutine, timeout=self.timeout)
# Run the coroutine in its original context
await asyncio.wait_for(
task["context"].run(asyncio.create_task, task["coroutine"]),
timeout=self.timeout,
)
except Exception as e:
verbose_logger.exception(f"LoggingWorker error: {e}")
pass
finally:
self._queue.task_done()
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:
"""
Add a coroutine to the logging queue.
Add a coroutine to the logging queue.
Hot path: never blocks, drops logs if queue is full.
"""
if self._queue is None:
return
try:
self._queue.put_nowait(coroutine)
# Capture the current context when enqueueing
task = LoggingTask(coroutine=coroutine, context=contextvars.copy_context())
self._queue.put_nowait(task)
except asyncio.QueueFull as e:
verbose_logger.exception(f"LoggingWorker queue is full: {e}")
# Drop logs on overload to protect request throughput
pass
def ensure_initialized_and_enqueue(self, async_coroutine: Coroutine):
"""
Ensure the logging worker is initialized and enqueue the coroutine.
"""
self.start()
self.enqueue(async_coroutine)
async def stop(self) -> None:
"""Stop the logging worker and clean up resources."""
if self._worker_task:
@ -91,34 +109,42 @@ class LoggingWorker:
with contextlib.suppress(Exception):
await self._worker_task
self._worker_task = None
async def flush(self) -> None:
"""Flush the logging queue."""
if self._queue is None:
return
while not self._queue.empty():
await self._queue.join()
async def clear_queue(self):
"""
Clear the queue with a maximum time limit.
"""
if self._queue is None:
return
start_time = asyncio.get_event_loop().time()
for _ in range(self.MAX_ITERATIONS_TO_CLEAR_QUEUE):
# Check if we've exceeded the maximum time
if asyncio.get_event_loop().time() - start_time >= self.MAX_TIME_TO_CLEAR_QUEUE:
verbose_logger.warning(f"clear_queue exceeded max_time of {self.MAX_TIME_TO_CLEAR_QUEUE}s, stopping early")
if (
asyncio.get_event_loop().time() - start_time
>= self.MAX_TIME_TO_CLEAR_QUEUE
):
verbose_logger.warning(
f"clear_queue exceeded max_time of {self.MAX_TIME_TO_CLEAR_QUEUE}s, stopping early"
)
break
try:
coroutine = self._queue.get_nowait()
task = self._queue.get_nowait()
# Await the coroutine to properly execute and avoid "never awaited" warnings
try:
await asyncio.wait_for(coroutine, timeout=self.timeout)
await asyncio.wait_for(
task["context"].run(asyncio.create_task, task["coroutine"]),
timeout=self.timeout,
)
except Exception:
# Suppress errors during cleanup
pass
@ -129,4 +155,3 @@ class LoggingWorker:
# Global instance for backward compatibility
GLOBAL_LOGGING_WORKER = LoggingWorker()

View file

@ -1,21 +1,155 @@
"""
Cost calculator for DeepSeek Chat models.
Cost calculator for Dashscope Chat models.
Handles prompt caching scenario.
Handles tiered pricing and prompt caching scenarios.
"""
from typing import Tuple
from dataclasses import dataclass
from typing import List, Optional, Tuple
from litellm.litellm_core_utils.llm_cost_calc.utils import generic_cost_per_token
from litellm.types.utils import Usage
from litellm.types.utils import ModelInfo, Usage
from litellm.utils import get_model_info
@dataclass
class TokenBreakdown:
"""Token breakdown for cost calculation."""
text_tokens: int
cached_tokens: int
completion_tokens: int
reasoning_tokens: int
def _extract_token_breakdown(usage: Usage) -> TokenBreakdown:
"""Extract token counts from usage, handling cached and reasoning tokens."""
cached_tokens = 0
if usage.prompt_tokens_details and hasattr(usage.prompt_tokens_details, "cached_tokens"):
cached_tokens = usage.prompt_tokens_details.cached_tokens or 0
text_tokens = usage.prompt_tokens - cached_tokens
reasoning_tokens = 0
if (hasattr(usage, "completion_tokens_details") and
usage.completion_tokens_details and
hasattr(usage.completion_tokens_details, "reasoning_tokens")):
reasoning_tokens = usage.completion_tokens_details.reasoning_tokens or 0
completion_tokens = (usage.completion_tokens or 0) - reasoning_tokens
return TokenBreakdown(text_tokens, cached_tokens, completion_tokens, reasoning_tokens)
def _calculate_tiered_cost(
tokens: int,
tiered_pricing: List[dict],
cost_key: str,
fallback_cost_key: Optional[str] = None
) -> float:
"""Calculate cost using tiered pricing structure.
Finds the appropriate tier based on token count and applies that tier's rate to all tokens.
"""
if not tiered_pricing or tokens <= 0:
return 0.0
# Find the appropriate tier for the token count
for tier in tiered_pricing:
tier_range = tier.get("range", [])
if len(tier_range) != 2:
continue
range_start, range_end = tier_range
# Check if tokens fall within this tier's range
if range_start <= tokens <= range_end:
cost_per_token = tier.get(cost_key) or tier.get(fallback_cost_key, 0)
return tokens * cost_per_token
# If no tier matches, use the last tier (highest tier)
if tiered_pricing:
last_tier = tiered_pricing[-1]
cost_per_token = last_tier.get(cost_key) or last_tier.get(fallback_cost_key, 0)
return tokens * cost_per_token
return 0.0
def _calculate_flat_cost(tokens: int, cost_per_token: float) -> float:
"""Calculate cost using flat pricing."""
return tokens * cost_per_token
def _calculate_prompt_cost(breakdown: TokenBreakdown, model_info: ModelInfo, tiered_pricing: Optional[List[dict]]) -> float:
"""Calculate total prompt cost including cached tokens."""
if tiered_pricing:
text_cost = _calculate_tiered_cost(
tokens=breakdown.text_tokens,
tiered_pricing=tiered_pricing,
cost_key="input_cost_per_token"
)
cache_cost = _calculate_tiered_cost(
tokens=breakdown.cached_tokens,
tiered_pricing=tiered_pricing,
cost_key="cache_read_input_token_cost"
)
return text_cost + cache_cost
input_cost = model_info.get("input_cost_per_token", 0.0)
cache_cost = model_info.get("cache_read_input_token_cost", input_cost) or input_cost
return (_calculate_flat_cost(tokens=breakdown.text_tokens, cost_per_token=input_cost) +
_calculate_flat_cost(tokens=breakdown.cached_tokens, cost_per_token=cache_cost))
def _calculate_completion_cost(breakdown: TokenBreakdown, model_info: ModelInfo, tiered_pricing: Optional[List[dict]]) -> float:
"""Calculate total completion cost including reasoning tokens."""
if tiered_pricing:
completion_cost = _calculate_tiered_cost(
tokens=breakdown.completion_tokens,
tiered_pricing=tiered_pricing,
cost_key="output_cost_per_token"
)
reasoning_cost = _calculate_tiered_cost(
tokens=breakdown.reasoning_tokens,
tiered_pricing=tiered_pricing,
cost_key="output_cost_per_reasoning_token",
fallback_cost_key="output_cost_per_token"
)
return completion_cost + reasoning_cost
output_cost = model_info.get("output_cost_per_token", 0.0)
reasoning_cost = model_info.get("output_cost_per_reasoning_token", output_cost) or output_cost
return (_calculate_flat_cost(tokens=breakdown.completion_tokens, cost_per_token=output_cost) +
_calculate_flat_cost(tokens=breakdown.reasoning_tokens, cost_per_token=reasoning_cost))
def cost_per_token(model: str, usage: Usage) -> Tuple[float, float]:
"""
Calculates the cost per token for a given model, prompt tokens, and completion tokens.
Follows the same logic as Anthropic's cost per token calculation.
Calculate cost per token for Dashscope models.
Supports both tiered and flat pricing with cached and reasoning tokens.
Args:
model: Model name without provider prefix
usage: LiteLLM Usage block
Returns:
Tuple[float, float] - (prompt_cost_in_usd, completion_cost_in_usd)
"""
return generic_cost_per_token(
model=model, usage=usage, custom_llm_provider="deepseek"
model_info = get_model_info(model=model, custom_llm_provider="dashscope")
breakdown = _extract_token_breakdown(usage)
tiered_pricing = model_info.get("tiered_pricing") if isinstance(model_info.get("tiered_pricing"), list) else None
prompt_cost = _calculate_prompt_cost(
breakdown=breakdown,
model_info=model_info,
tiered_pricing=tiered_pricing
)
completion_cost = _calculate_completion_cost(
breakdown=breakdown,
model_info=model_info,
tiered_pricing=tiered_pricing
)
return prompt_cost, completion_cost

View file

@ -169,18 +169,20 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig):
if tool is None:
return None
kwags: dict = {
# Build DatabricksFunction explicitly to avoid parameter conflicts
function_params: DatabricksFunction = {
"name": tool["name"],
"parameters": cast(dict, tool.get("input_schema") or {})
}
# Only add description if it exists
description = tool.get("description")
if description is not None:
kwags["description"] = cast(Union[dict, str], description)
function_params["description"] = cast(Union[dict, str], description)
return DatabricksTool(
type="function",
function=DatabricksFunction(name=tool["name"], **kwags),
function=function_params,
)
def _map_openai_to_dbrx_tool(self, model: str, tools: List) -> List[DatabricksTool]:

View file

@ -6,6 +6,7 @@
"input_cost_per_token": 0.0,
"output_cost_per_token": 0.0,
"output_cost_per_reasoning_token": 0.0,
"input_cost_per_audio_token": 0.0,
"litellm_provider": "one of https://docs.litellm.ai/docs/providers",
"mode": "one of: chat, embedding, completion, image_generation, audio_transcription, audio_speech, image_generation, moderation, rerank",
"supports_function_calling": true,
@ -19045,34 +19046,43 @@
"max_tokens": 32768,
"max_input_tokens": 30720,
"max_output_tokens": 8192,
"input_cost_per_token": 1.6e-06,
"output_cost_per_token": 6.4e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://bailian.console.alibabacloud.com/?spm=a2c63.p38356.0.0.4a615d7bjSUCb4&tab=doc#/doc/?type=model&url=https%3A%2F%2Fwww.alibabacloud.com%2Fhelp%2Fen%2Fdoc-detail%2F2840914.html"
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-latest": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://bailian.console.alibabacloud.com/?spm=a2c63.p38356.0.0.4a615d7bjSUCb4&tab=doc#/doc/?type=model&url=https%3A%2F%2Fwww.alibabacloud.com%2Fhelp%2Fen%2Fdoc-detail%2F2840914.html"
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 4e-07, "output_cost_per_token": 1.2e-06, "output_cost_per_reasoning_token": 4e-06},
{"range": [256e3, 1e6], "input_cost_per_token": 1.2e-06, "output_cost_per_token": 3.6e-06, "output_cost_per_reasoning_token": 1.2e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-turbo-latest": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_tokens": 1000000,
"max_input_tokens": 1000000,
"max_output_tokens": 16384,
"input_cost_per_token": 5e-08,
"output_cost_per_token": 2e-07,
"output_cost_per_reasoning_token": 5e-07,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://bailian.console.alibabacloud.com/?spm=a2c63.p38356.0.0.4a615d7bjSUCb4&tab=doc#/doc/?type=model&url=https%3A%2F%2Fwww.alibabacloud.com%2Fhelp%2Fen%2Fdoc-detail%2F2840914.html"
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-30b-a3b": {
"max_tokens": 131072,
@ -19083,7 +19093,272 @@
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://bailian.console.alibabacloud.com/?spm=a2c63.p38356.0.0.4a615d7bjSUCb4&tab=doc#/doc/?type=model&url=https%3A%2F%2Fwww.alibabacloud.com%2Fhelp%2Fen%2Fdoc-detail%2F2840914.html"
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-max-preview": {
"max_tokens": 262144,
"max_input_tokens": 258048,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 1.2e-06, "output_cost_per_token": 6e-06},
{"range": [32e3, 128e3], "input_cost_per_token": 2.4e-06, "output_cost_per_token": 1.2e-05},
{"range": [128e3, 252e3], "input_cost_per_token": 3.0e-06, "output_cost_per_token": 1.5e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"input_cost_per_token": 4e-07,
"output_cost_per_token": 1.2e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-flash": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 5e-08, "output_cost_per_token": 4e-07},
{"range": [256e3, 1e6], "input_cost_per_token": 2.5e-07, "output_cost_per_token": 2e-06}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-coder": {
"max_tokens": 1000000,
"max_input_tokens": 1000000,
"max_output_tokens": 16384,
"input_cost_per_token": 3e-07,
"output_cost_per_token": 1.5e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-coder-plus": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 1e-06, "output_cost_per_token": 5e-06, "cache_read_input_token_cost": 1e-07},
{"range": [32e3, 128e3], "input_cost_per_token": 1.8e-06, "output_cost_per_token": 9e-06, "cache_read_input_token_cost": 1.8e-07},
{"range": [128e3, 256e3], "input_cost_per_token": 3e-06, "output_cost_per_token": 1.5e-05, "cache_read_input_token_cost": 3e-07},
{"range": [256e3, 1e6], "input_cost_per_token": 6e-06, "output_cost_per_token": 6e-05, "cache_read_input_token_cost": 6e-07}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-coder-plus-2025-07-22": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 1e-06, "output_cost_per_token": 5e-06},
{"range": [32e3, 128e3], "input_cost_per_token": 1.8e-06, "output_cost_per_token": 9e-06},
{"range": [128e3, 256e3], "input_cost_per_token": 3e-06, "output_cost_per_token": 1.5e-05},
{"range": [256e3, 1e6], "input_cost_per_token": 6e-06, "output_cost_per_token": 6e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-coder-flash": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 3e-07, "output_cost_per_token": 1.5e-06, "cache_read_input_token_cost": 8e-08},
{"range": [32e3, 128e3], "input_cost_per_token": 5e-07, "output_cost_per_token": 2.5e-06, "cache_read_input_token_cost": 1.2e-07},
{"range": [128e3, 256e3], "input_cost_per_token": 8e-07, "output_cost_per_token": 4e-06, "cache_read_input_token_cost": 2e-07},
{"range": [256e3, 1e6], "input_cost_per_token": 1.6e-06, "output_cost_per_token": 9.6e-06, "cache_read_input_token_cost": 4e-07}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-coder-flash-2025-07-28": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 3e-07, "output_cost_per_token": 1.5e-06},
{"range": [32e3, 128e3], "input_cost_per_token": 5e-07, "output_cost_per_token": 2.5e-06},
{"range": [128e3, 256e3], "input_cost_per_token": 8e-07, "output_cost_per_token": 4e-06},
{"range": [256e3, 1e6], "input_cost_per_token": 1.6e-06, "output_cost_per_token": 9.6e-06}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-09-11": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 4e-07, "output_cost_per_token": 1.2e-06, "output_cost_per_reasoning_token": 4e-06},
{"range": [256e3, 1e6], "input_cost_per_token": 1.2e-06, "output_cost_per_token": 3.6e-06, "output_cost_per_reasoning_token": 1.2e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-07-28": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 4e-07, "output_cost_per_token": 1.2e-06, "output_cost_per_reasoning_token": 4e-06},
{"range": [256e3, 1e6], "input_cost_per_token": 1.2e-06, "output_cost_per_token": 3.6e-06, "output_cost_per_reasoning_token": 1.2e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-07-14": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"input_cost_per_token": 4e-07,
"output_cost_per_token": 1.2e-06,
"output_cost_per_reasoning_token": 4e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-04-28": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"input_cost_per_token": 4e-07,
"output_cost_per_token": 1.2e-06,
"output_cost_per_reasoning_token": 4e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-01-25": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 8192,
"input_cost_per_token": 4e-07,
"output_cost_per_token": 1.2e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-flash-2025-07-28": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 5e-08, "output_cost_per_token": 4e-07},
{"range": [256e3, 1e6], "input_cost_per_token": 2.5e-07, "output_cost_per_token": 2e-06}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-turbo": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"input_cost_per_token": 5e-08,
"output_cost_per_token": 2e-07,
"output_cost_per_reasoning_token": 5e-07,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-turbo-2025-04-28": {
"max_tokens": 1000000,
"max_input_tokens": 1000000,
"max_output_tokens": 16384,
"input_cost_per_token": 5e-08,
"output_cost_per_token": 2e-07,
"output_cost_per_reasoning_token": 5e-07,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-turbo-2024-11-01": {
"max_tokens": 1000000,
"max_input_tokens": 1000000,
"max_output_tokens": 8192,
"input_cost_per_token": 5e-08,
"output_cost_per_token": 2e-07,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwq-plus": {
"max_tokens": 131072,
"max_input_tokens": 98304,
"max_output_tokens": 8192,
"input_cost_per_token": 8e-07,
"output_cost_per_token": 2.4e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"moonshot/moonshot-v1-8k": {
"max_tokens": 8192,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
2:I[19107,[],"ClientPageRoot"]
3:I[75832,["665","static/chunks/3014691f-b7b79b78e27792f3.js","990","static/chunks/13b76428-ebdf3012af0e4489.js","50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","866","static/chunks/866-3523e0e07cf314f6.js","220","static/chunks/220-1c8d82f7ce7658c4.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-714ca0ed10a07f66.js","172","static/chunks/172-0f7049c565983c4d.js","931","static/chunks/app/page-8dc8d9524a1f3965.js"],"default",1]
3:I[30628,["665","static/chunks/3014691f-b7b79b78e27792f3.js","990","static/chunks/13b76428-ebdf3012af0e4489.js","50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","866","static/chunks/866-9e1803a09e9ae8da.js","220","static/chunks/220-5061c4cea850d728.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-4e7640b4d68e1ae4.js","172","static/chunks/172-0f7049c565983c4d.js","931","static/chunks/app/page-127adcf8da2b5294.js"],"default",1]
4:I[4707,[],""]
5:I[36423,[],""]
0:["0GF-OyXnYlAPMWfyPAZSs",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/060d5ddee53e45ce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
0:["FMlZjJYLUentCU02Wj6R_",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/c528590c6415a94c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"LiteLLM Dashboard"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","link","5",{"rel":"icon","href":"./favicon.ico"}],["$","meta","6",{"name":"next-size-adjust"}]]
1:null

View file

@ -1,7 +1,7 @@
2:I[19107,[],"ClientPageRoot"]
3:I[52829,["50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-714ca0ed10a07f66.js","418","static/chunks/app/model_hub/page-d6e5fb7de2cedde9.js"],"default",1]
3:I[52829,["50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-4e7640b4d68e1ae4.js","418","static/chunks/app/model_hub/page-d6e5fb7de2cedde9.js"],"default",1]
4:I[4707,[],""]
5:I[36423,[],""]
0:["0GF-OyXnYlAPMWfyPAZSs",[[["",{"children":["model_hub",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["model_hub",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","model_hub","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/060d5ddee53e45ce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
0:["FMlZjJYLUentCU02Wj6R_",[[["",{"children":["model_hub",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["model_hub",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","model_hub","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/c528590c6415a94c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"LiteLLM Dashboard"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","link","5",{"rel":"icon","href":"./favicon.ico"}],["$","meta","6",{"name":"next-size-adjust"}]]
1:null

View file

@ -1,7 +1,7 @@
2:I[19107,[],"ClientPageRoot"]
3:I[22775,["50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","866","static/chunks/866-3523e0e07cf314f6.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-714ca0ed10a07f66.js","172","static/chunks/172-0f7049c565983c4d.js","25","static/chunks/app/model_hub_table/page-e06e934de1021ee4.js"],"default",1]
3:I[22775,["50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","866","static/chunks/866-9e1803a09e9ae8da.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-4e7640b4d68e1ae4.js","172","static/chunks/172-0f7049c565983c4d.js","25","static/chunks/app/model_hub_table/page-e06e934de1021ee4.js"],"default",1]
4:I[4707,[],""]
5:I[36423,[],""]
0:["0GF-OyXnYlAPMWfyPAZSs",[[["",{"children":["model_hub_table",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["model_hub_table",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","model_hub_table","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/060d5ddee53e45ce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
0:["FMlZjJYLUentCU02Wj6R_",[[["",{"children":["model_hub_table",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["model_hub_table",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","model_hub_table","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/c528590c6415a94c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"LiteLLM Dashboard"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","link","5",{"rel":"icon","href":"./favicon.ico"}],["$","meta","6",{"name":"next-size-adjust"}]]
1:null

File diff suppressed because one or more lines are too long

View file

@ -2,6 +2,6 @@
3:I[12011,["665","static/chunks/3014691f-b7b79b78e27792f3.js","50","static/chunks/50-fe160ecfa8bc4059.js","154","static/chunks/154-fff436ed72b19a24.js","461","static/chunks/app/onboarding/page-3c5840c907b0a5c8.js"],"default",1]
4:I[4707,[],""]
5:I[36423,[],""]
0:["0GF-OyXnYlAPMWfyPAZSs",[[["",{"children":["onboarding",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["onboarding",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","onboarding","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/060d5ddee53e45ce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
0:["FMlZjJYLUentCU02Wj6R_",[[["",{"children":["onboarding",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["onboarding",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","onboarding","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/c528590c6415a94c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"LiteLLM Dashboard"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","link","5",{"rel":"icon","href":"./favicon.ico"}],["$","meta","6",{"name":"next-size-adjust"}]]
1:null

View file

@ -69,6 +69,29 @@ def get_files_provider_config(
):
global files_config
if custom_llm_provider == "vertex_ai":
# For Vertex AI, extract config from model_list instead of files_config
from litellm.proxy.proxy_server import proxy_config
if hasattr(proxy_config, "config") and "model_list" in proxy_config.config:
for model in proxy_config.config["model_list"]:
if isinstance(model, dict) and "litellm_params" in model:
litellm_params = model["litellm_params"]
if litellm_params.get("model", "").startswith("vertex_ai/"):
# Extract vertex_ai specific parameters
vertex_config = {}
if "vertex_project" in litellm_params:
vertex_config["vertex_project"] = litellm_params[
"vertex_project"
]
if "vertex_location" in litellm_params:
vertex_config["vertex_location"] = litellm_params[
"vertex_location"
]
if "vertex_credentials" in litellm_params:
vertex_config["vertex_credentials"] = litellm_params[
"vertex_credentials"
]
return vertex_config
return None
if files_config is None:
raise ValueError("files_settings is not set, set it on your config.yaml file.")

View file

@ -9,9 +9,9 @@ model_list:
- model_name: openai/*
litellm_params:
model: openai/*
- model_name: gemini/*
- model_name: dashscope/*
litellm_params:
model: gemini/*
model: dashscope/*
litellm_settings:

View file

@ -10,6 +10,7 @@ from fastapi import APIRouter, Depends, HTTPException, status
import litellm
from litellm._logging import verbose_proxy_logger
from litellm.router_strategy.budget_limiter import RouterBudgetLimiting
from litellm.proxy._types import *
from litellm.proxy._types import ProviderBudgetResponse, ProviderBudgetResponseObject
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
@ -2765,16 +2766,23 @@ async def provider_budgets() -> ProviderBudgetResponse:
provider_budget_response_dict: Dict[str, ProviderBudgetResponseObject] = {}
for _provider, _budget_info in provider_budget_config.items():
if llm_router.router_budget_logger is None:
router_budget_logger = next(
(
cb
for cb in (llm_router.optional_callbacks or [])
if isinstance(cb, RouterBudgetLimiting)
),
None,
)
if router_budget_logger is None:
raise ValueError("No router budget logger found")
_provider_spend = (
await llm_router.router_budget_logger._get_current_provider_spend(
await router_budget_logger._get_current_provider_spend(_provider) or 0.0
)
_provider_budget_ttl = (
await router_budget_logger._get_current_provider_budget_reset_at(
_provider
)
or 0.0
)
_provider_budget_ttl = await llm_router.router_budget_logger._get_current_provider_budget_reset_at(
_provider
)
provider_budget_response_object = ProviderBudgetResponseObject(
budget_limit=_budget_info.max_budget,

View file

@ -70,7 +70,8 @@ async def create_mcp_list_tools_events(
mcp_tools_dict = []
for tool in filtered_mcp_tools:
if hasattr(tool, 'model_dump') and callable(getattr(tool, 'model_dump')):
mcp_tools_dict.append(tool.model_dump())
# Type cast to help mypy understand this is safe after hasattr check
mcp_tools_dict.append(cast(Any, tool).model_dump())
elif hasattr(tool, '__dict__'):
mcp_tools_dict.append(tool.__dict__)
else:

View file

@ -113,7 +113,6 @@ class Schema(TypedDict, total=False):
pattern: str
example: Any
anyOf: List["Schema"]
additionalProperties: Any
class FunctionDeclaration(TypedDict, total=False):

View file

@ -162,6 +162,7 @@ class ModelInfoBase(ProviderSpecificModelInfo, total=False):
SearchContextCostPerQuery
] # Cost for using web search tool
citation_cost_per_token: Optional[float] # Cost per citation token for Perplexity
tiered_pricing: Optional[List[Dict[str, Any]]] # Tiered pricing structure for models like Dashscope
litellm_provider: Required[str]
mode: Required[
Literal[

View file

@ -2501,6 +2501,23 @@ def get_optional_params_transcription(
return optional_params
def _map_openai_size_to_vertex_ai_aspect_ratio(size: Optional[str]) -> str:
"""Map OpenAI size parameter to Vertex AI aspectRatio."""
if size is None:
return "1:1"
# Map OpenAI size strings to Vertex AI aspect ratio strings
# Vertex AI accepts: "1:1", "9:16", "16:9", "4:3", "3:4"
size_to_aspect_ratio = {
"256x256": "1:1", # Square
"512x512": "1:1", # Square
"1024x1024": "1:1", # Square (default)
"1792x1024": "16:9", # Landscape
"1024x1792": "9:16", # Portrait
}
return size_to_aspect_ratio.get(size, "1:1") # Default to square if size not recognized
def get_optional_params_image_gen(
model: Optional[str] = None,
n: Optional[int] = None,
@ -2614,19 +2631,7 @@ def get_optional_params_image_gen(
# Map OpenAI size parameter to Vertex AI aspectRatio
if size is not None:
# Map OpenAI size strings to Vertex AI aspect ratio strings
# Vertex AI accepts: "1:1", "9:16", "16:9", "4:3", "3:4"
size_to_aspect_ratio = {
"256x256": "1:1", # Square
"512x512": "1:1", # Square
"1024x1024": "1:1", # Square (default)
"1792x1024": "16:9", # Landscape
"1024x1792": "9:16", # Portrait
}
aspect_ratio = size_to_aspect_ratio.get(
size, "1:1"
) # Default to square if size not recognized
optional_params["aspectRatio"] = aspect_ratio
optional_params["aspectRatio"] = _map_openai_size_to_vertex_ai_aspect_ratio(size)
openai_params: list[str] = list(default_params.keys())
if provider_config is not None:
@ -2642,6 +2647,12 @@ def get_optional_params_image_gen(
openai_params=openai_params,
additional_drop_params=additional_drop_params,
)
# remove keys with None or empty dict/list values to avoid sending empty payloads
optional_params = {
k: v
for k, v in optional_params.items()
if v is not None and (not isinstance(v, (dict, list)) or len(v) > 0)
}
return optional_params
@ -4902,6 +4913,7 @@ def _get_model_info_helper( # noqa: PLR0915
citation_cost_per_token=_model_info.get(
"citation_cost_per_token", None
),
tiered_pricing=_model_info.get("tiered_pricing", None),
litellm_provider=_model_info.get(
"litellm_provider", custom_llm_provider
),

View file

@ -6,6 +6,7 @@
"input_cost_per_token": 0.0,
"output_cost_per_token": 0.0,
"output_cost_per_reasoning_token": 0.0,
"input_cost_per_audio_token": 0.0,
"litellm_provider": "one of https://docs.litellm.ai/docs/providers",
"mode": "one of: chat, embedding, completion, image_generation, audio_transcription, audio_speech, image_generation, moderation, rerank",
"supports_function_calling": true,
@ -19045,34 +19046,43 @@
"max_tokens": 32768,
"max_input_tokens": 30720,
"max_output_tokens": 8192,
"input_cost_per_token": 1.6e-06,
"output_cost_per_token": 6.4e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://bailian.console.alibabacloud.com/?spm=a2c63.p38356.0.0.4a615d7bjSUCb4&tab=doc#/doc/?type=model&url=https%3A%2F%2Fwww.alibabacloud.com%2Fhelp%2Fen%2Fdoc-detail%2F2840914.html"
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-latest": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://bailian.console.alibabacloud.com/?spm=a2c63.p38356.0.0.4a615d7bjSUCb4&tab=doc#/doc/?type=model&url=https%3A%2F%2Fwww.alibabacloud.com%2Fhelp%2Fen%2Fdoc-detail%2F2840914.html"
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 4e-07, "output_cost_per_token": 1.2e-06, "output_cost_per_reasoning_token": 4e-06},
{"range": [256e3, 1e6], "input_cost_per_token": 1.2e-06, "output_cost_per_token": 3.6e-06, "output_cost_per_reasoning_token": 1.2e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-turbo-latest": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_tokens": 1000000,
"max_input_tokens": 1000000,
"max_output_tokens": 16384,
"input_cost_per_token": 5e-08,
"output_cost_per_token": 2e-07,
"output_cost_per_reasoning_token": 5e-07,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://bailian.console.alibabacloud.com/?spm=a2c63.p38356.0.0.4a615d7bjSUCb4&tab=doc#/doc/?type=model&url=https%3A%2F%2Fwww.alibabacloud.com%2Fhelp%2Fen%2Fdoc-detail%2F2840914.html"
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-30b-a3b": {
"max_tokens": 131072,
@ -19083,7 +19093,272 @@
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://bailian.console.alibabacloud.com/?spm=a2c63.p38356.0.0.4a615d7bjSUCb4&tab=doc#/doc/?type=model&url=https%3A%2F%2Fwww.alibabacloud.com%2Fhelp%2Fen%2Fdoc-detail%2F2840914.html"
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-max-preview": {
"max_tokens": 262144,
"max_input_tokens": 258048,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 1.2e-06, "output_cost_per_token": 6e-06},
{"range": [32e3, 128e3], "input_cost_per_token": 2.4e-06, "output_cost_per_token": 1.2e-05},
{"range": [128e3, 252e3], "input_cost_per_token": 3.0e-06, "output_cost_per_token": 1.5e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"input_cost_per_token": 4e-07,
"output_cost_per_token": 1.2e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-flash": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 5e-08, "output_cost_per_token": 4e-07},
{"range": [256e3, 1e6], "input_cost_per_token": 2.5e-07, "output_cost_per_token": 2e-06}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-coder": {
"max_tokens": 1000000,
"max_input_tokens": 1000000,
"max_output_tokens": 16384,
"input_cost_per_token": 3e-07,
"output_cost_per_token": 1.5e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-coder-plus": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 1e-06, "output_cost_per_token": 5e-06, "cache_read_input_token_cost": 1e-07},
{"range": [32e3, 128e3], "input_cost_per_token": 1.8e-06, "output_cost_per_token": 9e-06, "cache_read_input_token_cost": 1.8e-07},
{"range": [128e3, 256e3], "input_cost_per_token": 3e-06, "output_cost_per_token": 1.5e-05, "cache_read_input_token_cost": 3e-07},
{"range": [256e3, 1e6], "input_cost_per_token": 6e-06, "output_cost_per_token": 6e-05, "cache_read_input_token_cost": 6e-07}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-coder-plus-2025-07-22": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 1e-06, "output_cost_per_token": 5e-06},
{"range": [32e3, 128e3], "input_cost_per_token": 1.8e-06, "output_cost_per_token": 9e-06},
{"range": [128e3, 256e3], "input_cost_per_token": 3e-06, "output_cost_per_token": 1.5e-05},
{"range": [256e3, 1e6], "input_cost_per_token": 6e-06, "output_cost_per_token": 6e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-coder-flash": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 3e-07, "output_cost_per_token": 1.5e-06, "cache_read_input_token_cost": 8e-08},
{"range": [32e3, 128e3], "input_cost_per_token": 5e-07, "output_cost_per_token": 2.5e-06, "cache_read_input_token_cost": 1.2e-07},
{"range": [128e3, 256e3], "input_cost_per_token": 8e-07, "output_cost_per_token": 4e-06, "cache_read_input_token_cost": 2e-07},
{"range": [256e3, 1e6], "input_cost_per_token": 1.6e-06, "output_cost_per_token": 9.6e-06, "cache_read_input_token_cost": 4e-07}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen3-coder-flash-2025-07-28": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 65536,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 32e3], "input_cost_per_token": 3e-07, "output_cost_per_token": 1.5e-06},
{"range": [32e3, 128e3], "input_cost_per_token": 5e-07, "output_cost_per_token": 2.5e-06},
{"range": [128e3, 256e3], "input_cost_per_token": 8e-07, "output_cost_per_token": 4e-06},
{"range": [256e3, 1e6], "input_cost_per_token": 1.6e-06, "output_cost_per_token": 9.6e-06}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-09-11": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 4e-07, "output_cost_per_token": 1.2e-06, "output_cost_per_reasoning_token": 4e-06},
{"range": [256e3, 1e6], "input_cost_per_token": 1.2e-06, "output_cost_per_token": 3.6e-06, "output_cost_per_reasoning_token": 1.2e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-07-28": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 4e-07, "output_cost_per_token": 1.2e-06, "output_cost_per_reasoning_token": 4e-06},
{"range": [256e3, 1e6], "input_cost_per_token": 1.2e-06, "output_cost_per_token": 3.6e-06, "output_cost_per_reasoning_token": 1.2e-05}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-07-14": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"input_cost_per_token": 4e-07,
"output_cost_per_token": 1.2e-06,
"output_cost_per_reasoning_token": 4e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-04-28": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"input_cost_per_token": 4e-07,
"output_cost_per_token": 1.2e-06,
"output_cost_per_reasoning_token": 4e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-plus-2025-01-25": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 8192,
"input_cost_per_token": 4e-07,
"output_cost_per_token": 1.2e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-flash-2025-07-28": {
"max_tokens": 1000000,
"max_input_tokens": 997952,
"max_output_tokens": 32768,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"tiered_pricing": [
{"range": [0, 256e3], "input_cost_per_token": 5e-08, "output_cost_per_token": 4e-07},
{"range": [256e3, 1e6], "input_cost_per_token": 2.5e-07, "output_cost_per_token": 2e-06}
],
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-turbo": {
"max_tokens": 131072,
"max_input_tokens": 129024,
"max_output_tokens": 16384,
"input_cost_per_token": 5e-08,
"output_cost_per_token": 2e-07,
"output_cost_per_reasoning_token": 5e-07,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-turbo-2025-04-28": {
"max_tokens": 1000000,
"max_input_tokens": 1000000,
"max_output_tokens": 16384,
"input_cost_per_token": 5e-08,
"output_cost_per_token": 2e-07,
"output_cost_per_reasoning_token": 5e-07,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwen-turbo-2024-11-01": {
"max_tokens": 1000000,
"max_input_tokens": 1000000,
"max_output_tokens": 8192,
"input_cost_per_token": 5e-08,
"output_cost_per_token": 2e-07,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"dashscope/qwq-plus": {
"max_tokens": 131072,
"max_input_tokens": 98304,
"max_output_tokens": 8192,
"input_cost_per_token": 8e-07,
"output_cost_per_token": 2.4e-06,
"litellm_provider": "dashscope",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_reasoning": true,
"mode": "chat",
"source": "https://www.alibabacloud.com/help/en/model-studio/models"
},
"moonshot/moonshot-v1-8k": {
"max_tokens": 8192,

View file

@ -0,0 +1,4 @@
{
"model": "gpt-image-1",
"prompt": "test prompt"
}

View file

@ -5,6 +5,7 @@ import logging
import os
import sys
import traceback
from unittest.mock import AsyncMock, patch
sys.path.insert(
@ -329,3 +330,33 @@ async def test_aiml_image_generation_with_dynamic_api_key():
assert captured_json_data is not None
assert captured_json_data["prompt"] == "A cute baby sea otter"
assert captured_json_data["model"] == "flux-pro/v1.1"
@pytest.mark.asyncio
async def test_azure_image_generation_request_body():
from litellm import aimage_generation
test_dir = os.path.dirname(__file__)
expected_path = os.path.join(
test_dir, "request_payloads", "azure_gpt_image_1.json"
)
with open(expected_path, "r") as f:
expected_body = json.load(f)
with patch(
"litellm.llms.custom_httpx.http_handler.AsyncHTTPHandler.post",
new_callable=AsyncMock,
) as mock_post:
mock_post.side_effect = Exception("test")
with pytest.raises(Exception):
await aimage_generation(
model="azure/gpt-image-1",
prompt="test prompt",
api_base="https://example.azure.com",
api_key="test-key",
api_version="2025-04-01-preview",
)
mock_post.assert_called_once()
call_args = mock_post.call_args
request_json = call_args.kwargs.get("json", {})
assert request_json == expected_body

View file

@ -467,3 +467,73 @@ async def test_e2e_generate_cold_storage_object_key_not_configured():
assert result is None
@pytest.mark.asyncio
async def test_logging_opentelemetry_context_propagation():
"""
Test that OpenTelemtry context propagation works with async completion.
"""
import asyncio
import litellm
from litellm.integrations.custom_logger import CustomLogger
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
provider = TracerProvider()
exporter = InMemorySpanExporter()
provider.add_span_processor(SimpleSpanProcessor(exporter))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
class MockOpenTelemetryLogger(CustomLogger):
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
span = tracer.start_span(start_time=start_time.timestamp() * 1e9, name="async_log_success_event")
span.end(end_time=end_time)
mock_logging_obj = MockOpenTelemetryLogger()
litellm.callbacks = [mock_logging_obj]
with tracer.start_as_current_span("span_1") as span:
span_1_id = span.get_span_context().span_id
await litellm.acompletion(
max_tokens=100,
messages=[{"role": "user", "content": "Hey"}],
model="openai/codex-mini-latest",
mock_response="Hello, world!",
)
with tracer.start_as_current_span("span_2") as span:
span_2_id = span.get_span_context().span_id
await litellm.acompletion(
max_tokens=100,
messages=[{"role": "user", "content": "Hey"}],
model="openai/codex-mini-latest",
mock_response="Hello, world!",
)
await asyncio.sleep(1)
spans = exporter.get_finished_spans()
assert len(spans) == 4
assert span_1_id != span_2_id
sorted_spans = sorted(list(spans), key=lambda x: x.start_time or 0)
assert sorted_spans[0].name == "span_1"
assert sorted_spans[1].name == "async_log_success_event"
assert sorted_spans[2].name == "span_2"
assert sorted_spans[3].name == "async_log_success_event"
first_span_context = sorted_spans[0].get_span_context()
assert first_span_context is not None and first_span_context.span_id == span_1_id
second_span_context = sorted_spans[2].get_span_context()
assert second_span_context is not None and second_span_context.span_id == span_2_id
first_completion_span_parent = sorted_spans[1].parent
assert first_completion_span_parent is not None and first_completion_span_parent.span_id == span_1_id
# This check would fail without the proper context propagation, and span[3] would end up with span_1_id as the parent
second_completion_span_parent = sorted_spans[3].parent
assert second_completion_span_parent is not None and second_completion_span_parent.span_id == span_2_id

View file

@ -2,6 +2,7 @@
Tests for the LoggingWorker class to ensure graceful shutdown handling.
"""
import asyncio
import contextvars
import pytest
from unittest.mock import AsyncMock, patch
@ -139,3 +140,81 @@ class TestLoggingWorker:
# Should have logged queue full exceptions
exception_calls = [call for call in mock_logger.exception.call_args_list if "queue is full" in str(call)]
assert len(exception_calls) > 0
@pytest.mark.asyncio
async def test_context_propagation(self, logging_worker):
"""Test that enqueued tasks execute in their original context."""
# Create a context variable for testing
test_context_var: contextvars.ContextVar[str] = contextvars.ContextVar('test_context_var')
# Track results from multiple tasks
task_results = []
async def test_task(task_id: str):
"""A test coroutine that checks if it can access the context variable."""
# Sleep a bit to simulate real work and ensure context persists
await asyncio.sleep(0.1)
try:
# Try to get the context variable value
value = test_context_var.get()
task_results.append({
'task_id': task_id,
'context_value': value,
'context_accessible': True
})
except LookupError:
# Context variable not found
task_results.append({
'task_id': task_id,
'context_accessible': False,
'context_value': None
})
# Start the logging worker
logging_worker.start()
# Create two separate contexts and enqueue tasks from each
# Context 1: Set context var to "context_1"
ctx1 = contextvars.copy_context()
ctx1.run(test_context_var.set, "context_1")
ctx1.run(logging_worker.enqueue, test_task("task_1"))
# Context 2: Set context var to "context_2"
ctx2 = contextvars.copy_context()
ctx2.run(test_context_var.set, "context_2")
ctx2.run(logging_worker.enqueue, test_task("task_2"))
# Context 3: No context variable set (should get LookupError)
ctx3 = contextvars.copy_context()
ctx3.run(logging_worker.enqueue, test_task("task_3"))
# Wait for all tasks to be processed
await asyncio.sleep(0.5)
# Stop the worker
await logging_worker.stop()
# Sort results by task_id for consistent testing
task_results.sort(key=lambda x: x['task_id'])
# Verify that each task saw its own context
assert len(task_results) == 3, f"Expected 3 results, got {len(task_results)}"
# Task 1 should see "context_1"
task1_result = next((r for r in task_results if r['task_id'] == 'task_1'), None)
assert task1_result is not None, "Task 1 result not found"
assert task1_result['context_accessible'] is True, "Task 1 should have access to context variable"
assert task1_result['context_value'] == "context_1", f"Task 1 should see 'context_1', got: {task1_result['context_value']}"
# Task 2 should see "context_2"
task2_result = next((r for r in task_results if r['task_id'] == 'task_2'), None)
assert task2_result is not None, "Task 2 result not found"
assert task2_result['context_accessible'] is True, "Task 2 should have access to context variable"
assert task2_result['context_value'] == "context_2", f"Task 2 should see 'context_2', got: {task2_result['context_value']}"
# Task 3 should not have access to the context variable
task3_result = next((r for r in task_results if r['task_id'] == 'task_3'), None)
assert task3_result is not None, "Task 3 result not found"
assert task3_result['context_accessible'] is False, "Task 3 should not have access to context variable"

View file

@ -0,0 +1,183 @@
"""
Test suite for Dashscope cost calculation functionality.
Tests the cost calculation for Dashscope models including:
- Tiered pricing based on input token ranges
- Caching discounts
- Reasoning tokens
- Standard flat pricing fallback
"""
import json
import math
import os
import sys
import pytest
# Add the project root to Python path
sys.path.insert(0, os.path.abspath("../../../.."))
import litellm
from litellm.llms.dashscope.cost_calculator import (
cost_per_token as dashscope_cost_per_token,
)
from litellm.types.utils import (
CompletionTokensDetailsWrapper,
PromptTokensDetailsWrapper,
Usage,
)
class TestDashscopeCostCalculator:
"""Test suite for Dashscope cost calculation functionality."""
@pytest.fixture(autouse=True)
def setup_model_cost_map(self):
"""Set up the model cost map for testing."""
# Ensure we use local model cost map for consistent testing
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
# Find the project root directory and load model cost map
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = current_dir
while not os.path.exists(os.path.join(project_root, "model_prices_and_context_window.json")):
parent = os.path.dirname(project_root)
if parent == project_root: # Reached filesystem root
break
project_root = parent
model_cost_path = os.path.join(project_root, "model_prices_and_context_window.json")
with open(model_cost_path, "r") as f:
model_cost_map = json.load(f)
litellm.model_cost = model_cost_map
def test_flat_pricing_basic_cost_calculation(self):
"""Test basic cost calculation for flat pricing models (qwen-max)."""
usage = Usage(
prompt_tokens=1000,
completion_tokens=500,
total_tokens=1500
)
prompt_cost, completion_cost = dashscope_cost_per_token(
model="qwen-max",
usage=usage
)
# Expected costs for qwen-max:
# Input: 1000 tokens * $1.6e-6 = $0.0016
# Output: 500 tokens * $6.4e-6 = $0.0032
expected_prompt_cost = 1000 * 1.6e-6
expected_completion_cost = 500 * 6.4e-6
assert math.isclose(prompt_cost, expected_prompt_cost, rel_tol=1e-10)
assert math.isclose(completion_cost, expected_completion_cost, rel_tol=1e-10)
def test_tiered_pricing_single_tier(self):
"""Test tiered pricing when all tokens fall within first tier."""
usage = Usage(
prompt_tokens=20000, # Within first tier (0-32K)
completion_tokens=1000,
total_tokens=21000
)
prompt_cost, completion_cost = dashscope_cost_per_token(
model="qwen3-coder-plus",
usage=usage
)
# Expected costs for qwen3-coder-plus (tier 1):
# Input: 20,000 tokens * $1e-6 = $0.02
# Output: 1,000 tokens * $5e-6 = $0.005
expected_prompt_cost = 20000 * 1e-6
expected_completion_cost = 1000 * 5e-6
assert math.isclose(prompt_cost, expected_prompt_cost, rel_tol=1e-10)
assert math.isclose(completion_cost, expected_completion_cost, rel_tol=1e-10)
def test_tiered_pricing_higher_tier(self):
"""Test tiered pricing when tokens fall in higher tier (tier 3)."""
usage = Usage(
prompt_tokens=150000, # Falls in tier 3 (128K-256K)
completion_tokens=2000,
total_tokens=152000
)
prompt_cost, completion_cost = dashscope_cost_per_token(
model="qwen3-coder-plus",
usage=usage
)
# Expected input cost calculation:
# 150,000 tokens falls in tier 3 (128K-256K), so all tokens are charged at tier 3 rate
# Input: 150,000 tokens * $3e-6 = $0.45
# Output: 2,000 tokens falls in tier 1 (0-32K), so charged at tier 1 rate
# Output: 2,000 tokens * $5e-6 = $0.01
expected_prompt_cost = 150000 * 3e-6 # All tokens at tier 3 rate
expected_completion_cost = 2000 * 5e-6 # All tokens at tier 1 rate
assert math.isclose(prompt_cost, expected_prompt_cost, rel_tol=1e-10)
assert math.isclose(completion_cost, expected_completion_cost, rel_tol=1e-10)
def test_tiered_pricing_with_caching(self):
"""Test tiered pricing with cached tokens."""
prompt_tokens_details = PromptTokensDetailsWrapper(
cached_tokens=10000 # 10K cached tokens
)
usage = Usage(
prompt_tokens=50000, # 40K regular + 10K cached = 50K total
completion_tokens=1000,
total_tokens=51000,
prompt_tokens_details=prompt_tokens_details
)
prompt_cost, completion_cost = dashscope_cost_per_token(
model="qwen3-coder-plus",
usage=usage
)
# Expected cost calculation:
# Regular tokens: 40,000 falls in tier 2 (32K-128K), so all charged at tier 2 rate
# - Regular: 40,000 * $1.8e-6 = $0.072
# Cached tokens: 10,000 falls in tier 1 (0-32K), so charged at tier 1 cached rate
# - Cached: 10,000 * $1e-7 = $0.001
# Total input cost = $0.072 + $0.001 = $0.073
regular_tokens = 40000
cached_tokens = 10000
expected_regular_cost = regular_tokens * 1.8e-6 # Tier 2 rate
expected_cached_cost = cached_tokens * 1e-7 # Tier 1 cached rate
expected_prompt_cost = expected_regular_cost + expected_cached_cost
expected_completion_cost = 1000 * 5e-6 # Tier 1 rate
assert math.isclose(prompt_cost, expected_prompt_cost, rel_tol=1e-10)
assert math.isclose(completion_cost, expected_completion_cost, rel_tol=1e-10)
def test_tiered_pricing_highest_tier(self):
"""Test tiered pricing when tokens exceed highest tier range."""
usage = Usage(
prompt_tokens=2000000, # Exceeds tier 4 max (1M), should use tier 4 rate
completion_tokens=5000,
total_tokens=2005000
)
prompt_cost, completion_cost = dashscope_cost_per_token(
model="qwen3-coder-plus",
usage=usage
)
# Expected cost calculation:
# 2,000,000 tokens exceeds tier 4 (256K-1M), so use tier 4 rate for all tokens
# Input: 2,000,000 tokens * $6e-6 = $12.0
# Output: 5,000 tokens falls in tier 1 (0-32K), so charged at tier 1 rate
# Output: 5,000 tokens * $5e-6 = $0.025
expected_prompt_cost = 2000000 * 6e-6 # Tier 4 rate (highest tier)
expected_completion_cost = 5000 * 5e-6 # Tier 1 rate
assert math.isclose(prompt_cost, expected_prompt_cost, rel_tol=1e-10)
assert math.isclose(completion_cost, expected_completion_cost, rel_tol=1e-10)

View file

@ -476,3 +476,176 @@ def test_create_file_for_each_model(
openai_call_found = True
break
assert openai_call_found, "OpenAI call not found with expected parameters"
def test_get_files_provider_config_vertex_ai_with_model_list():
"""
Test that get_files_provider_config correctly extracts Vertex AI config from model_list
This test verifies the fix for the proxy file upload issue
"""
from litellm.proxy.openai_files_endpoints.files_endpoints import get_files_provider_config, files_config
from litellm.proxy.proxy_server import proxy_config
# Mock the proxy_config with a model_list containing Vertex AI configuration
mock_config = {
'model_list': [
{
'model_name': 'gemini-2.5-flash',
'litellm_params': {
'model': 'vertex_ai/gemini-2.5-flash',
'vertex_project': 'test-project-123',
'vertex_location': 'us-central1',
'vertex_credentials': '/path/to/service_account.json'
}
},
{
'model_name': 'gpt-3.5-turbo',
'litellm_params': {
'model': 'openai/gpt-3.5-turbo',
'api_key': 'test-key'
}
}
]
}
# Mock proxy_config.config
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = mock_config
# Mock files_config to avoid ValueError for non-vertex_ai providers
original_files_config = files_config
import litellm.proxy.openai_files_endpoints.files_endpoints
litellm.proxy.openai_files_endpoints.files_endpoints.files_config = []
try:
# Test that vertex_ai provider returns the correct config
result = get_files_provider_config('vertex_ai')
assert result is not None, "get_files_provider_config should return config for vertex_ai"
assert result['vertex_project'] == 'test-project-123'
assert result['vertex_location'] == 'us-central1'
assert result['vertex_credentials'] == '/path/to/service_account.json'
# Test that non-vertex_ai providers still work as before
result_openai = get_files_provider_config('openai')
assert result_openai is None # Should return None when files_config is empty
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')
# Restore original files_config
litellm.proxy.openai_files_endpoints.files_endpoints.files_config = original_files_config
def test_get_files_provider_config_vertex_ai_no_model_list():
"""
Test that get_files_provider_config returns None when no model_list is available
This ensures graceful handling when proxy_config is not properly initialized
"""
from litellm.proxy.openai_files_endpoints.files_endpoints import get_files_provider_config
from litellm.proxy.proxy_server import proxy_config
# Mock proxy_config without model_list
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = {}
try:
result = get_files_provider_config('vertex_ai')
assert result is None, "get_files_provider_config should return None when no model_list"
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')
def test_get_files_provider_config_vertex_ai_no_vertex_models():
"""
Test that get_files_provider_config returns None when no vertex_ai models are in model_list
This ensures the function handles cases where only non-vertex models are configured
"""
from litellm.proxy.openai_files_endpoints.files_endpoints import get_files_provider_config
from litellm.proxy.proxy_server import proxy_config
# Mock the proxy_config with a model_list containing only non-Vertex AI models
mock_config = {
'model_list': [
{
'model_name': 'gpt-3.5-turbo',
'litellm_params': {
'model': 'openai/gpt-3.5-turbo',
'api_key': 'test-key'
}
},
{
'model_name': 'claude-3',
'litellm_params': {
'model': 'anthropic/claude-3',
'api_key': 'test-key'
}
}
]
}
# Mock proxy_config.config
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = mock_config
try:
result = get_files_provider_config('vertex_ai')
assert result is None, "get_files_provider_config should return None when no vertex_ai models in model_list"
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')
def test_get_files_provider_config_vertex_ai_partial_config():
"""
Test that get_files_provider_config handles partial Vertex AI configuration gracefully
This ensures the function works even when some vertex_ai parameters are missing
"""
from litellm.proxy.openai_files_endpoints.files_endpoints import get_files_provider_config
from litellm.proxy.proxy_server import proxy_config
# Mock the proxy_config with partial Vertex AI configuration
mock_config = {
'model_list': [
{
'model_name': 'gemini-2.5-flash',
'litellm_params': {
'model': 'vertex_ai/gemini-2.5-flash',
'vertex_project': 'test-project-123',
# Missing vertex_location and vertex_credentials
}
}
]
}
# Mock proxy_config.config
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = mock_config
try:
result = get_files_provider_config('vertex_ai')
assert result is not None, "get_files_provider_config should return config even with partial vertex_ai params"
assert result['vertex_project'] == 'test-project-123'
assert 'vertex_location' not in result
assert 'vertex_credentials' not in result
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')

View file

@ -0,0 +1,271 @@
"""
Regression tests for Vertex AI file upload functionality in the proxy.
This module contains tests to ensure that the fix for Vertex AI file uploads
in the proxy server continues to work and prevents regression of the issue
where get_files_provider_config returned None for vertex_ai provider.
"""
import pytest
from unittest.mock import Mock, patch
from litellm.proxy.openai_files_endpoints.files_endpoints import get_files_provider_config
def test_vertex_ai_files_provider_config_never_returns_none_when_configured():
"""
Regression test: Ensure that get_files_provider_config never returns None
for vertex_ai when properly configured in model_list.
This test prevents regression of the bug where vertex_ai provider
always returned None, causing "Could not resolve project_id" errors.
"""
from litellm.proxy.proxy_server import proxy_config
# Mock the proxy_config with a proper Vertex AI configuration
mock_config = {
'model_list': [
{
'model_name': 'gemini-2.5-flash',
'litellm_params': {
'model': 'vertex_ai/gemini-2.5-flash',
'vertex_project': 'test-project-123',
'vertex_location': 'us-central1',
'vertex_credentials': '/path/to/service_account.json'
}
}
]
}
# Mock proxy_config.config
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = mock_config
try:
result = get_files_provider_config('vertex_ai')
# This should NEVER be None when vertex_ai is properly configured
assert result is not None, (
"CRITICAL REGRESSION: get_files_provider_config returned None for vertex_ai "
"when it should return configuration. This would cause 'Could not resolve project_id' errors."
)
# Verify all expected parameters are present
assert 'vertex_project' in result
assert 'vertex_location' in result
assert 'vertex_credentials' in result
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')
def test_vertex_ai_files_provider_config_handles_multiple_vertex_models():
"""
Test that get_files_provider_config correctly handles multiple Vertex AI models
in the model_list and returns configuration from the first one found.
"""
from litellm.proxy.proxy_server import proxy_config
# Mock the proxy_config with multiple Vertex AI models
mock_config = {
'model_list': [
{
'model_name': 'gemini-1.5-flash',
'litellm_params': {
'model': 'vertex_ai/gemini-1.5-flash',
'vertex_project': 'project-1',
'vertex_location': 'us-east1',
'vertex_credentials': '/path/to/creds1.json'
}
},
{
'model_name': 'gemini-2.5-flash',
'litellm_params': {
'model': 'vertex_ai/gemini-2.5-flash',
'vertex_project': 'project-2',
'vertex_location': 'us-central1',
'vertex_credentials': '/path/to/creds2.json'
}
}
]
}
# Mock proxy_config.config
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = mock_config
try:
result = get_files_provider_config('vertex_ai')
assert result is not None, "Should return config when multiple vertex_ai models are present"
# Should return config from the first vertex_ai model found
assert result['vertex_project'] == 'project-1'
assert result['vertex_location'] == 'us-east1'
assert result['vertex_credentials'] == '/path/to/creds1.json'
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')
def test_vertex_ai_files_provider_config_ignores_non_vertex_models():
"""
Test that get_files_provider_config correctly identifies vertex_ai models
and ignores other model types when searching for configuration.
"""
from litellm.proxy.proxy_server import proxy_config
# Mock the proxy_config with mixed model types
mock_config = {
'model_list': [
{
'model_name': 'gpt-3.5-turbo',
'litellm_params': {
'model': 'openai/gpt-3.5-turbo',
'api_key': 'test-key'
}
},
{
'model_name': 'gemini-2.5-flash',
'litellm_params': {
'model': 'vertex_ai/gemini-2.5-flash',
'vertex_project': 'test-project',
'vertex_location': 'us-central1',
'vertex_credentials': '/path/to/creds.json'
}
},
{
'model_name': 'claude-3',
'litellm_params': {
'model': 'anthropic/claude-3',
'api_key': 'test-key'
}
}
]
}
# Mock proxy_config.config
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = mock_config
try:
result = get_files_provider_config('vertex_ai')
assert result is not None, "Should find vertex_ai config even with mixed model types"
assert result['vertex_project'] == 'test-project'
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')
def test_vertex_ai_files_provider_config_handles_malformed_model_list():
"""
Test that get_files_provider_config gracefully handles malformed model_list entries
without crashing.
"""
from litellm.proxy.proxy_server import proxy_config
# Mock the proxy_config with malformed entries
mock_config = {
'model_list': [
# Missing litellm_params
{
'model_name': 'gemini-2.5-flash'
},
# Missing model field
{
'model_name': 'gemini-1.5-flash',
'litellm_params': {
'vertex_project': 'test-project'
}
},
# Valid vertex_ai model
{
'model_name': 'gemini-2.0-flash',
'litellm_params': {
'model': 'vertex_ai/gemini-2.0-flash',
'vertex_project': 'test-project',
'vertex_location': 'us-central1',
'vertex_credentials': '/path/to/creds.json'
}
}
]
}
# Mock proxy_config.config
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = mock_config
try:
result = get_files_provider_config('vertex_ai')
# Should still work and find the valid vertex_ai model
assert result is not None, "Should handle malformed entries and find valid vertex_ai model"
assert result['vertex_project'] == 'test-project'
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')
def test_vertex_ai_files_provider_config_old_behavior_regression():
"""
Regression test: Ensure that the old behavior of always returning None
for vertex_ai provider is completely eliminated.
This test specifically checks that the function no longer has the old
hardcoded return None for vertex_ai.
"""
from litellm.proxy.proxy_server import proxy_config
# Mock the proxy_config with a minimal but valid Vertex AI configuration
mock_config = {
'model_list': [
{
'model_name': 'gemini-2.5-flash',
'litellm_params': {
'model': 'vertex_ai/gemini-2.5-flash',
'vertex_project': 'minimal-project'
}
}
]
}
# Mock proxy_config.config
original_config = getattr(proxy_config, 'config', None)
proxy_config.config = mock_config
try:
result = get_files_provider_config('vertex_ai')
# The old behavior would always return None here
# The new behavior should return the configuration
assert result is not None, (
"REGRESSION DETECTED: The old behavior of returning None for vertex_ai "
"has returned. This indicates the fix has been reverted."
)
# Verify we get the expected configuration
assert isinstance(result, dict), "Result should be a dictionary"
assert 'vertex_project' in result, "Should contain vertex_project"
finally:
# Restore original config
if original_config is not None:
proxy_config.config = original_config
else:
delattr(proxy_config, 'config')

View file

@ -18,7 +18,9 @@ import litellm
from litellm.proxy._types import SpendLogsPayload
from litellm.proxy.hooks.proxy_track_cost_callback import _ProxyDBLogger
from litellm.proxy.proxy_server import app, prisma_client
from litellm.proxy.spend_tracking import spend_management_endpoints
from litellm.router import Router
from litellm.types.utils import BudgetConfig
ignored_keys = [
"request_id",
@ -32,6 +34,18 @@ ignored_keys = [
"metadata.cold_storage_object_key",
]
MODEL_LIST = [
{
"model_name": "azure-gpt-4o",
"litellm_params": {
"model": "azure/gpt-4o-mini",
"mock_response": "Hello, world!",
"tags": ["default"],
"base_model": "gpt-4o-mini",
},
},
]
@pytest.fixture
def client():
@ -43,6 +57,19 @@ def add_anthropic_api_key_to_env(monkeypatch):
monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant-api03-1234567890")
@pytest.fixture
def disable_budget_sync(monkeypatch):
"""Disable periodic sync during tests"""
async def noop(*a, **k):
return None
monkeypatch.setattr(
"litellm.router_strategy.budget_limiter.RouterBudgetLimiting.periodic_sync_in_memory_spend_with_redis",
noop,
)
@pytest.mark.asyncio
async def test_ui_view_spend_logs_with_user_id(client, monkeypatch):
# Mock data for the test
@ -1318,3 +1345,70 @@ async def test_view_spend_tags_no_database(client, monkeypatch):
# Check the actual error message structure
assert "error" in data
assert "Database not connected" in data["error"]["message"]
@pytest.mark.asyncio
async def test_provider_budget_under(disable_budget_sync):
"""Test that router allows completion when under budget"""
provider_budget_config = {
"azure": BudgetConfig(max_budget=0.01, budget_duration="10d")
}
router = Router(
enable_pre_call_checks=True,
provider_budget_config=provider_budget_config,
model_list=MODEL_LIST,
)
response = await router.acompletion(
model="azure-gpt-4o",
messages=[{"role": "user", "content": "Hello, world!"}],
)
assert response is not None
@pytest.mark.asyncio
async def test_provider_budget_over(disable_budget_sync):
"""Test that router allows completion when over budget"""
provider_budget_config = {
"azure": BudgetConfig(max_budget=-0.01, budget_duration="10d")
}
router = Router(
num_retries=0,
enable_pre_call_checks=True,
provider_budget_config=provider_budget_config,
model_list=MODEL_LIST,
)
with pytest.raises(Exception) as e:
response = await router.acompletion(
model="azure-gpt-4o",
messages=[{"role": "user", "content": "Hello, world!"}],
)
assert "Exceeded budget for provider" in str(e.value)
@pytest.mark.asyncio
async def test_provider_budget_provider_budgets(disable_budget_sync):
"""Test that provider_budgets() returns correct values"""
provider = "azure"
max_budget = -0.01
budget_duration = "10d"
provider_budget_config = {
provider: BudgetConfig(max_budget=max_budget, budget_duration=budget_duration)
}
router = Router(
num_retries=0,
enable_pre_call_checks=True,
provider_budget_config=provider_budget_config,
model_list=MODEL_LIST,
)
with patch("litellm.proxy.proxy_server.llm_router", router):
response = await spend_management_endpoints.provider_budgets()
provider_budget_response = response.providers[provider]
assert provider_budget_response.budget_limit == max_budget
assert provider_budget_response.time_period == budget_duration

View file

@ -84,6 +84,15 @@ def test_get_optional_params_image_gen_vertex_ai_size():
assert optional_params["sampleCount"] == 1
def test_get_optional_params_image_gen_filters_empty_values():
optional_params = get_optional_params_image_gen(
model="gpt-image-1",
custom_llm_provider="openai",
extra_body={},
)
assert optional_params == {}
def test_all_model_configs():
from litellm.llms.vertex_ai.vertex_ai_partner_models.ai21.transformation import (
VertexAIAi21Config,
@ -643,6 +652,26 @@ def test_aaamodel_prices_and_context_window_json_is_valid():
},
},
"supports_native_streaming": {"type": "boolean"},
"tiered_pricing": {
"type": "array",
"items": {
"type": "object",
"properties": {
"range": {
"type": "array",
"items": {"type": "number"},
"minItems": 2,
"maxItems": 2
},
"input_cost_per_token": {"type": "number"},
"output_cost_per_token": {"type": "number"},
"cache_read_input_token_cost": {"type": "number"},
"output_cost_per_reasoning_token": {"type": "number"}
},
"required": ["range"],
"additionalProperties": False
}
},
},
"additionalProperties": False,
},

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
2:I[19107,[],"ClientPageRoot"]
3:I[75832,["665","static/chunks/3014691f-b7b79b78e27792f3.js","990","static/chunks/13b76428-ebdf3012af0e4489.js","50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","866","static/chunks/866-3523e0e07cf314f6.js","220","static/chunks/220-1c8d82f7ce7658c4.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-714ca0ed10a07f66.js","172","static/chunks/172-0f7049c565983c4d.js","931","static/chunks/app/page-8dc8d9524a1f3965.js"],"default",1]
3:I[30628,["665","static/chunks/3014691f-b7b79b78e27792f3.js","990","static/chunks/13b76428-ebdf3012af0e4489.js","50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","866","static/chunks/866-9e1803a09e9ae8da.js","220","static/chunks/220-5061c4cea850d728.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-4e7640b4d68e1ae4.js","172","static/chunks/172-0f7049c565983c4d.js","931","static/chunks/app/page-127adcf8da2b5294.js"],"default",1]
4:I[4707,[],""]
5:I[36423,[],""]
0:["0GF-OyXnYlAPMWfyPAZSs",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/060d5ddee53e45ce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
0:["FMlZjJYLUentCU02Wj6R_",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/c528590c6415a94c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"LiteLLM Dashboard"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","link","5",{"rel":"icon","href":"./favicon.ico"}],["$","meta","6",{"name":"next-size-adjust"}]]
1:null

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
2:I[19107,[],"ClientPageRoot"]
3:I[52829,["50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-714ca0ed10a07f66.js","418","static/chunks/app/model_hub/page-d6e5fb7de2cedde9.js"],"default",1]
3:I[52829,["50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-4e7640b4d68e1ae4.js","418","static/chunks/app/model_hub/page-d6e5fb7de2cedde9.js"],"default",1]
4:I[4707,[],""]
5:I[36423,[],""]
0:["0GF-OyXnYlAPMWfyPAZSs",[[["",{"children":["model_hub",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["model_hub",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","model_hub","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/060d5ddee53e45ce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
0:["FMlZjJYLUentCU02Wj6R_",[[["",{"children":["model_hub",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["model_hub",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","model_hub","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/c528590c6415a94c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"LiteLLM Dashboard"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","link","5",{"rel":"icon","href":"./favicon.ico"}],["$","meta","6",{"name":"next-size-adjust"}]]
1:null

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
2:I[19107,[],"ClientPageRoot"]
3:I[22775,["50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","866","static/chunks/866-3523e0e07cf314f6.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-714ca0ed10a07f66.js","172","static/chunks/172-0f7049c565983c4d.js","25","static/chunks/app/model_hub_table/page-e06e934de1021ee4.js"],"default",1]
3:I[22775,["50","static/chunks/50-fe160ecfa8bc4059.js","521","static/chunks/521-d97d355792d44830.js","866","static/chunks/866-9e1803a09e9ae8da.js","154","static/chunks/154-fff436ed72b19a24.js","162","static/chunks/162-4e7640b4d68e1ae4.js","172","static/chunks/172-0f7049c565983c4d.js","25","static/chunks/app/model_hub_table/page-e06e934de1021ee4.js"],"default",1]
4:I[4707,[],""]
5:I[36423,[],""]
0:["0GF-OyXnYlAPMWfyPAZSs",[[["",{"children":["model_hub_table",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["model_hub_table",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","model_hub_table","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/060d5ddee53e45ce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
0:["FMlZjJYLUentCU02Wj6R_",[[["",{"children":["model_hub_table",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["model_hub_table",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","model_hub_table","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/c528590c6415a94c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"LiteLLM Dashboard"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","link","5",{"rel":"icon","href":"./favicon.ico"}],["$","meta","6",{"name":"next-size-adjust"}]]
1:null

File diff suppressed because one or more lines are too long

View file

@ -2,6 +2,6 @@
3:I[12011,["665","static/chunks/3014691f-b7b79b78e27792f3.js","50","static/chunks/50-fe160ecfa8bc4059.js","154","static/chunks/154-fff436ed72b19a24.js","461","static/chunks/app/onboarding/page-3c5840c907b0a5c8.js"],"default",1]
4:I[4707,[],""]
5:I[36423,[],""]
0:["0GF-OyXnYlAPMWfyPAZSs",[[["",{"children":["onboarding",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["onboarding",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","onboarding","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/060d5ddee53e45ce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
0:["FMlZjJYLUentCU02Wj6R_",[[["",{"children":["onboarding",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["onboarding",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","onboarding","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/31b7f215e119031e.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/css/c528590c6415a94c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_b0dd8a","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"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"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"LiteLLM Dashboard"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","link","5",{"rel":"icon","href":"./favicon.ico"}],["$","meta","6",{"name":"next-size-adjust"}]]
1:null

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -206,6 +206,22 @@ const PROVIDER_CREDENTIAL_FIELDS: Record<Providers, ProviderCredentialField[]> =
required: true
}
],
[Providers.Dashscope]: [
{
key: "api_key",
label: "Dashscope API Key",
type: "password",
required: true
},
{
key: "api_base",
label: "API Base",
placeholder: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
defaultValue: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
required: true,
tooltip: "The base URL for your Dashscope server. Defaults to https://dashscope-intl.aliyuncs.com/compatible-mode/v1 if not specified."
}
],
[Providers.OpenAI_Text_Compatible]: [
{
key: "api_base",

View file

@ -11,8 +11,9 @@ export enum Providers {
Azure = "Azure",
Azure_AI_Studio = "Azure AI Foundry (Studio)",
Cerebras = "Cerebras",
Cohere = "Cohere",
Databricks = "Databricks",
Cohere = "Cohere",
Dashscope = "Dashscope",
Databricks = "Databricks (Qwen API)",
DeepInfra = "DeepInfra",
Deepgram = "Deepgram",
Deepseek = "Deepseek",
@ -37,7 +38,7 @@ export enum Providers {
Vertex_AI = "Vertex AI (Anthropic, Gemini, etc.)",
VolcEngine = "VolcEngine",
Voyage = "Voyage AI",
xAI = "xAI",
xAI = "xAI",
}
export const provider_map: Record<string, string> = {
@ -56,6 +57,7 @@ export const provider_map: Record<string, string> = {
OpenAI_Text_Compatible: "text-completion-openai",
Vertex_AI: "vertex_ai",
Databricks: "databricks",
Dashscope: "dashscope",
xAI: "xai",
Deepseek: "deepseek",
Ollama: "ollama",
@ -91,6 +93,7 @@ export const providerLogoMap: Record<string, string> = {
[Providers.Cerebras]: `${asset_logos_folder}cerebras.svg`,
[Providers.Cohere]: `${asset_logos_folder}cohere.svg`,
[Providers.Databricks]: `${asset_logos_folder}databricks.svg`,
[Providers.Dashscope]: `${asset_logos_folder}dashscope.svg`,
[Providers.Deepseek]: `${asset_logos_folder}deepseek.svg`,
[Providers.FireworksAI]: `${asset_logos_folder}fireworks.svg`,
[Providers.Groq]: `${asset_logos_folder}groq.svg`,