mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
Merge branch 'BerriAI:main' into LangfuseUsageDetails
This commit is contained in:
commit
dae5b0f0f3
64 changed files with 1842 additions and 128 deletions
|
|
@ -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**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
litellm/proxy/_experimental/out/assets/logos/qwen.png
Normal file
BIN
litellm/proxy/_experimental/out/assets/logos/qwen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
File diff suppressed because one or more lines are too long
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
1
litellm/proxy/_experimental/out/onboarding.html
Normal file
1
litellm/proxy/_experimental/out/onboarding.html
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ class Schema(TypedDict, total=False):
|
|||
pattern: str
|
||||
example: Any
|
||||
anyOf: List["Schema"]
|
||||
additionalProperties: Any
|
||||
|
||||
|
||||
class FunctionDeclaration(TypedDict, total=False):
|
||||
|
|
|
|||
|
|
@ -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[
|
||||
|
|
|
|||
|
|
@ -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
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"model": "gpt-image-1",
|
||||
"prompt": "test prompt"
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
ui/litellm-dashboard/out/assets/logos/qwen.png
Normal file
BIN
ui/litellm-dashboard/out/assets/logos/qwen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
File diff suppressed because one or more lines are too long
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
BIN
ui/litellm-dashboard/public/assets/logos/qwen.png
Normal file
BIN
ui/litellm-dashboard/public/assets/logos/qwen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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`,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue