From 161d07200b683d89d4eb3001516c31067aad7798 Mon Sep 17 00:00:00 2001 From: Subodh Sharma <10337595+sdvats@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:33:58 +1100 Subject: [PATCH] fix(cost): preserve registered Together deployment pricing --- litellm/llms/together_ai/cost_calculator.py | 7 +- tests/unit/test_cost_calculator.py | 71 +++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/litellm/llms/together_ai/cost_calculator.py b/litellm/llms/together_ai/cost_calculator.py index 6fc2c949fa6..ba31762fe1d 100644 --- a/litellm/llms/together_ai/cost_calculator.py +++ b/litellm/llms/together_ai/cost_calculator.py @@ -21,8 +21,11 @@ from litellm.types.utils import CallTypes def has_together_registry_pricing(model: str, cost_map: Mapping[str, object]) -> bool: stripped: Final = model.removeprefix("together_ai/") - entry: Final = cost_map.get(f"together_ai/{stripped}") - return isinstance(entry, Mapping) and "input_cost_per_token" in entry + for key in (f"together_ai/{stripped}", stripped): + entry: Final = cost_map.get(key) + if isinstance(entry, Mapping) and "input_cost_per_token" in entry: + return True + return False # Extract the number of billion parameters from the model name diff --git a/tests/unit/test_cost_calculator.py b/tests/unit/test_cost_calculator.py index 5d5d53d793e..96fea074983 100644 --- a/tests/unit/test_cost_calculator.py +++ b/tests/unit/test_cost_calculator.py @@ -6415,6 +6415,77 @@ def test_groq_response_cost_tracking(is_streaming): print(f"response_cost: {response_cost}") +@pytest.mark.parametrize("cache_rate", [0.0, 3e-8]) +@pytest.mark.parametrize("cached_tokens", [0, 75200]) +@pytest.mark.parametrize("custom_pricing", [False, True]) +def test_together_completion_cost_preserves_registered_rates( + monkeypatch: pytest.MonkeyPatch, + cache_rate: float, + cached_tokens: int, + custom_pricing: bool, +) -> None: + deployment_id: Final = "00000000-3b00-4000-8000-000000000001" + model: Final = "example/pricing-regression-3B" + registry_key: Final = deployment_id if custom_pricing else f"together_ai/{model}" + input_rate: Final = 1.5e-7 + output_rate: Final = 5e-7 + prompt_tokens: Final = 89536 + completion_tokens: Final = 2117 + monkeypatch.setitem( + litellm.model_cost, + "together-ai-up-to-4b", + {"input_cost_per_token": 9e-6, "output_cost_per_token": 9e-6, "litellm_provider": "together_ai"}, + ) + litellm.register_model( + model_cost={ + registry_key: { + "input_cost_per_token": input_rate, + "output_cost_per_token": output_rate, + "cache_read_input_token_cost": cache_rate, + "litellm_provider": "together_ai", + } + } + ) + response: Final = ModelResponse( + model=model, + usage=Usage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + prompt_tokens_details=PromptTokensDetailsWrapper(cached_tokens=cached_tokens), + ), + ) + + cost: Final = completion_cost( + completion_response=response, + custom_llm_provider="together_ai", + custom_pricing=custom_pricing, + router_model_id=deployment_id, + ) + + assert cost == pytest.approx( + (prompt_tokens - cached_tokens) * input_rate + cached_tokens * cache_rate + completion_tokens * output_rate + ) + + +def test_together_completion_cost_keeps_unregistered_model_size_fallback(monkeypatch: pytest.MonkeyPatch) -> None: + input_rate: Final = 2e-6 + output_rate: Final = 7e-6 + monkeypatch.setitem( + litellm.model_cost, + "together-ai-up-to-4b", + {"input_cost_per_token": input_rate, "output_cost_per_token": output_rate, "litellm_provider": "together_ai"}, + ) + response: Final = ModelResponse( + model="example/unregistered-3B", + usage=Usage(prompt_tokens=100, completion_tokens=20), + ) + + assert completion_cost( + completion_response=response, + custom_llm_provider="together_ai", + ) == pytest.approx(100 * input_rate + 20 * output_rate) + + def test_together_ai_qwen_completion_cost(): input_kwargs = { "completion_response": litellm.ModelResponse(