diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index dd367e875de..2e19860bb95 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -10113,13 +10113,13 @@ "supports_web_search": true }, "azure_ai/jais-30b-chat": { - "input_cost_per_token": 0.0032, + "input_cost_per_token": 3.2e-06, "litellm_provider": "azure_ai", "max_input_tokens": 8192, "max_output_tokens": 8192, "max_tokens": 8192, "mode": "chat", - "output_cost_per_token": 0.00971, + "output_cost_per_token": 9.71e-06, "source": "https://azure.microsoft.com/en-us/products/ai-services/ai-foundry/models/jais-30b-chat" }, "azure_ai/jamba-instruct": { @@ -43044,8 +43044,8 @@ "max_tokens": 131072, "max_input_tokens": 131072, "max_output_tokens": 131072, - "input_cost_per_token": 0.015, - "output_cost_per_token": 0.06, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 6e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43053,8 +43053,8 @@ "max_tokens": 131072, "max_input_tokens": 131072, "max_output_tokens": 131072, - "input_cost_per_token": 0.005, - "output_cost_per_token": 0.02, + "input_cost_per_token": 5e-08, + "output_cost_per_token": 2e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43062,8 +43062,8 @@ "max_tokens": 131072, "max_input_tokens": 131072, "max_output_tokens": 131072, - "input_cost_per_token": 0.055, - "output_cost_per_token": 0.2, + "input_cost_per_token": 5.5e-07, + "output_cost_per_token": 2e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43071,8 +43071,8 @@ "max_tokens": 262144, "max_input_tokens": 262144, "max_output_tokens": 262144, - "input_cost_per_token": 0.01, - "output_cost_per_token": 0.01, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 1e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43080,8 +43080,8 @@ "max_tokens": 262144, "max_input_tokens": 262144, "max_output_tokens": 262144, - "input_cost_per_token": 0.1, - "output_cost_per_token": 0.15, + "input_cost_per_token": 1e-06, + "output_cost_per_token": 1.5e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43089,8 +43089,8 @@ "max_tokens": 262144, "max_input_tokens": 262144, "max_output_tokens": 262144, - "input_cost_per_token": 0.01, - "output_cost_per_token": 0.01, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 1e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43135,8 +43135,8 @@ "max_tokens": 128000, "max_input_tokens": 128000, "max_output_tokens": 128000, - "input_cost_per_token": 0.022, - "output_cost_per_token": 0.022, + "input_cost_per_token": 2.2e-07, + "output_cost_per_token": 2.2e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43144,8 +43144,8 @@ "max_tokens": 128000, "max_input_tokens": 128000, "max_output_tokens": 128000, - "input_cost_per_token": 0.055, - "output_cost_per_token": 0.165, + "input_cost_per_token": 5.5e-07, + "output_cost_per_token": 1.65e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43153,8 +43153,8 @@ "max_tokens": 161000, "max_input_tokens": 161000, "max_output_tokens": 161000, - "input_cost_per_token": 0.135, - "output_cost_per_token": 0.54, + "input_cost_per_token": 1.35e-06, + "output_cost_per_token": 5.4e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43162,8 +43162,8 @@ "max_tokens": 161000, "max_input_tokens": 161000, "max_output_tokens": 161000, - "input_cost_per_token": 0.114, - "output_cost_per_token": 0.275, + "input_cost_per_token": 1.14e-06, + "output_cost_per_token": 2.75e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43171,8 +43171,8 @@ "max_tokens": 128000, "max_input_tokens": 128000, "max_output_tokens": 128000, - "input_cost_per_token": 0.071, - "output_cost_per_token": 0.071, + "input_cost_per_token": 7.1e-07, + "output_cost_per_token": 7.1e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43180,8 +43180,8 @@ "max_tokens": 64000, "max_input_tokens": 64000, "max_output_tokens": 64000, - "input_cost_per_token": 0.017, - "output_cost_per_token": 0.066, + "input_cost_per_token": 1.7e-07, + "output_cost_per_token": 6.6e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43189,8 +43189,8 @@ "max_tokens": 128000, "max_input_tokens": 128000, "max_output_tokens": 128000, - "input_cost_per_token": 0.008, - "output_cost_per_token": 0.035, + "input_cost_per_token": 8e-08, + "output_cost_per_token": 3.5e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43234,8 +43234,8 @@ "max_tokens": 8192, "max_input_tokens": 8192, "max_output_tokens": 8192, - "input_cost_per_token": 0.0005, - "output_cost_per_token": 0.002, + "input_cost_per_token": 1.8e-06, + "output_cost_per_token": 1.8e-06, "litellm_provider": "watsonx", "mode": "chat", "supports_function_calling": false, @@ -43246,8 +43246,8 @@ "max_tokens": 8192, "max_input_tokens": 8192, "max_output_tokens": 8192, - "input_cost_per_token": 0.0005, - "output_cost_per_token": 0.002, + "input_cost_per_token": 1.8e-06, + "output_cost_per_token": 1.8e-06, "litellm_provider": "watsonx", "mode": "chat", "supports_function_calling": false, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index dd367e875de..2e19860bb95 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -10113,13 +10113,13 @@ "supports_web_search": true }, "azure_ai/jais-30b-chat": { - "input_cost_per_token": 0.0032, + "input_cost_per_token": 3.2e-06, "litellm_provider": "azure_ai", "max_input_tokens": 8192, "max_output_tokens": 8192, "max_tokens": 8192, "mode": "chat", - "output_cost_per_token": 0.00971, + "output_cost_per_token": 9.71e-06, "source": "https://azure.microsoft.com/en-us/products/ai-services/ai-foundry/models/jais-30b-chat" }, "azure_ai/jamba-instruct": { @@ -43044,8 +43044,8 @@ "max_tokens": 131072, "max_input_tokens": 131072, "max_output_tokens": 131072, - "input_cost_per_token": 0.015, - "output_cost_per_token": 0.06, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 6e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43053,8 +43053,8 @@ "max_tokens": 131072, "max_input_tokens": 131072, "max_output_tokens": 131072, - "input_cost_per_token": 0.005, - "output_cost_per_token": 0.02, + "input_cost_per_token": 5e-08, + "output_cost_per_token": 2e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43062,8 +43062,8 @@ "max_tokens": 131072, "max_input_tokens": 131072, "max_output_tokens": 131072, - "input_cost_per_token": 0.055, - "output_cost_per_token": 0.2, + "input_cost_per_token": 5.5e-07, + "output_cost_per_token": 2e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43071,8 +43071,8 @@ "max_tokens": 262144, "max_input_tokens": 262144, "max_output_tokens": 262144, - "input_cost_per_token": 0.01, - "output_cost_per_token": 0.01, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 1e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43080,8 +43080,8 @@ "max_tokens": 262144, "max_input_tokens": 262144, "max_output_tokens": 262144, - "input_cost_per_token": 0.1, - "output_cost_per_token": 0.15, + "input_cost_per_token": 1e-06, + "output_cost_per_token": 1.5e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43089,8 +43089,8 @@ "max_tokens": 262144, "max_input_tokens": 262144, "max_output_tokens": 262144, - "input_cost_per_token": 0.01, - "output_cost_per_token": 0.01, + "input_cost_per_token": 1e-07, + "output_cost_per_token": 1e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43135,8 +43135,8 @@ "max_tokens": 128000, "max_input_tokens": 128000, "max_output_tokens": 128000, - "input_cost_per_token": 0.022, - "output_cost_per_token": 0.022, + "input_cost_per_token": 2.2e-07, + "output_cost_per_token": 2.2e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43144,8 +43144,8 @@ "max_tokens": 128000, "max_input_tokens": 128000, "max_output_tokens": 128000, - "input_cost_per_token": 0.055, - "output_cost_per_token": 0.165, + "input_cost_per_token": 5.5e-07, + "output_cost_per_token": 1.65e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43153,8 +43153,8 @@ "max_tokens": 161000, "max_input_tokens": 161000, "max_output_tokens": 161000, - "input_cost_per_token": 0.135, - "output_cost_per_token": 0.54, + "input_cost_per_token": 1.35e-06, + "output_cost_per_token": 5.4e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43162,8 +43162,8 @@ "max_tokens": 161000, "max_input_tokens": 161000, "max_output_tokens": 161000, - "input_cost_per_token": 0.114, - "output_cost_per_token": 0.275, + "input_cost_per_token": 1.14e-06, + "output_cost_per_token": 2.75e-06, "litellm_provider": "wandb", "mode": "chat" }, @@ -43171,8 +43171,8 @@ "max_tokens": 128000, "max_input_tokens": 128000, "max_output_tokens": 128000, - "input_cost_per_token": 0.071, - "output_cost_per_token": 0.071, + "input_cost_per_token": 7.1e-07, + "output_cost_per_token": 7.1e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43180,8 +43180,8 @@ "max_tokens": 64000, "max_input_tokens": 64000, "max_output_tokens": 64000, - "input_cost_per_token": 0.017, - "output_cost_per_token": 0.066, + "input_cost_per_token": 1.7e-07, + "output_cost_per_token": 6.6e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43189,8 +43189,8 @@ "max_tokens": 128000, "max_input_tokens": 128000, "max_output_tokens": 128000, - "input_cost_per_token": 0.008, - "output_cost_per_token": 0.035, + "input_cost_per_token": 8e-08, + "output_cost_per_token": 3.5e-07, "litellm_provider": "wandb", "mode": "chat" }, @@ -43234,8 +43234,8 @@ "max_tokens": 8192, "max_input_tokens": 8192, "max_output_tokens": 8192, - "input_cost_per_token": 0.0005, - "output_cost_per_token": 0.002, + "input_cost_per_token": 1.8e-06, + "output_cost_per_token": 1.8e-06, "litellm_provider": "watsonx", "mode": "chat", "supports_function_calling": false, @@ -43246,8 +43246,8 @@ "max_tokens": 8192, "max_input_tokens": 8192, "max_output_tokens": 8192, - "input_cost_per_token": 0.0005, - "output_cost_per_token": 0.002, + "input_cost_per_token": 1.8e-06, + "output_cost_per_token": 1.8e-06, "litellm_provider": "watsonx", "mode": "chat", "supports_function_calling": false, diff --git a/tests/test_litellm/test_cost_calculator.py b/tests/test_litellm/test_cost_calculator.py index 8fce9ba080c..8d0b404a688 100644 --- a/tests/test_litellm/test_cost_calculator.py +++ b/tests/test_litellm/test_cost_calculator.py @@ -172,9 +172,26 @@ def test_baseten_model_api_pricing_entries(_local_model_cost_map): def test_wandb_model_api_pricing_entries(_local_model_cost_map): + # W&B publishes per 1M tokens (https://wandb.ai/site/pricing/inference); these are + # those figures divided by 1e6. Entries added before this was checked carried the + # published number scaled by 1e5 too little, billing $15,000 per 1M tokens instead + # of $0.15. expected_pricing = { "wandb/moonshotai/Kimi-K2.5": (6e-07, 3e-06), "wandb/MiniMaxAI/MiniMax-M2.5": (3e-07, 1.2e-06), + "wandb/openai/gpt-oss-120b": (1.5e-07, 6e-07), + "wandb/openai/gpt-oss-20b": (5e-08, 2e-07), + "wandb/zai-org/GLM-4.5": (5.5e-07, 2e-06), + "wandb/Qwen/Qwen3-235B-A22B-Instruct-2507": (1e-07, 1e-07), + "wandb/Qwen/Qwen3-235B-A22B-Thinking-2507": (1e-07, 1e-07), + "wandb/Qwen/Qwen3-Coder-480B-A35B-Instruct": (1e-06, 1.5e-06), + "wandb/meta-llama/Llama-3.1-8B-Instruct": (2.2e-07, 2.2e-07), + "wandb/meta-llama/Llama-3.3-70B-Instruct": (7.1e-07, 7.1e-07), + "wandb/meta-llama/Llama-4-Scout-17B-16E-Instruct": (1.7e-07, 6.6e-07), + "wandb/deepseek-ai/DeepSeek-V3.1": (5.5e-07, 1.65e-06), + "wandb/deepseek-ai/DeepSeek-V3-0324": (1.14e-06, 2.75e-06), + "wandb/deepseek-ai/DeepSeek-R1-0528": (1.35e-06, 5.4e-06), + "wandb/microsoft/Phi-4-mini-instruct": (8e-08, 3.5e-07), } for model_name, (input_cost, output_cost) in expected_pricing.items(): diff --git a/tests/test_litellm/test_model_prices_schema.py b/tests/test_litellm/test_model_prices_schema.py index 6114d1d8aba..564dc6678e8 100644 --- a/tests/test_litellm/test_model_prices_schema.py +++ b/tests/test_litellm/test_model_prices_schema.py @@ -173,3 +173,52 @@ def test_dated_variants_carry_base_alias_service_tier_pricing(prices: dict): "sync the tier keys so service-tier requests against pinned snapshots are not " "billed at standard rates:\n" + "\n".join(drifted) ) + + +# Fields quoting USD per token, including the audio/image/reasoning token variants and the +# tier and threshold suffixes ("_flex", "_batches", "_above_200k_tokens"). Deliberately +# excludes per-character/per-second/per-1k fields, whose "_above_128k_tokens" suffix names +# a threshold rather than the unit, and Databricks' DBU fields, which are not dollars. +PER_TOKEN_COST_FIELD = re.compile(r"(?:per_token|token_cost)(?:_|$)|_token$") + +# $1000 per million tokens. The priciest model in the map is o1-pro at $600 per million +# output tokens, so this leaves room for a genuinely expensive future model while still +# being far below what a per-1k or per-million figure looks like once it lands in a +# per-token field. +MAX_USD_PER_TOKEN = 1e-3 + + +def per_token_costs(entry: dict) -> list[tuple[str, float]]: + return [ + (field, value) + for field, value in entry.items() + if "dbu" not in field + and PER_TOKEN_COST_FIELD.search(field) + and isinstance(value, (int, float)) + and not isinstance(value, bool) + ] + + +@pytest.mark.parametrize("path", (PRICES_PATH, BACKUP_PRICES_PATH), ids=("main", "backup")) +def test_per_token_costs_are_priced_per_token(path: Path): + """Catch a vendor's per-1k or per-million price landing in a per-token field. + + Vendors quote prices per 1,000 or per 1,000,000 tokens, litellm stores dollars per + single token, and pasting the quoted number straight in overcharges by 3 to 6 orders + of magnitude on every request through that model. Spend logs, budgets and the + x-litellm-response-cost header all read these fields, so a budget trips on the first + call instead of the ten-thousandth. + """ + mispriced = [ + f"{name}.{field}={value} (${value * 1_000_000:,.2f} per 1M tokens)" + for name, entry in json.loads(path.read_text()).items() + if isinstance(entry, dict) and name not in ("sample_spec", "fallback_generalizations") + for field, value in per_token_costs(entry) + if value > MAX_USD_PER_TOKEN + ] + assert mispriced == [], ( + f"{path.name} prices these above ${MAX_USD_PER_TOKEN} per token, which is what a " + "price quoted per 1k or per 1M tokens looks like when it is copied into a per-token " + "field. Divide by the vendor's unit, or raise MAX_USD_PER_TOKEN if a model really is " + "this expensive:\n" + "\n".join(mispriced) + )