From 239bcbc21423ee09bc8e58966e9d34a29a5bb6cb Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 13 Sep 2026 00:44:30 +0000 Subject: [PATCH 1/5] fix(fireworks): resolve short model names to long cost map keys Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/utils.py | 5 +++ tests/test_litellm/test_utils.py | 69 ++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/litellm/utils.py b/litellm/utils.py index 394ab4b4094..4a92f9b1244 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -5556,6 +5556,11 @@ def _get_potential_model_names(model: str, custom_llm_provider: str | None) -> P split_model = strip_bedrock_routing_prefix(split_model) + if custom_llm_provider == "fireworks_ai": + from litellm.llms.fireworks_ai.common_utils import resolve_fireworks_resource_name + + provider_prefixed_model_name = f"fireworks_ai/{resolve_fireworks_resource_name(split_model)}" + return PotentialModelNamesAndCustomLLMProvider( split_model=split_model, combined_model_name=combined_model_name, diff --git a/tests/test_litellm/test_utils.py b/tests/test_litellm/test_utils.py index 835e87aff88..02e2eeec467 100644 --- a/tests/test_litellm/test_utils.py +++ b/tests/test_litellm/test_utils.py @@ -4448,6 +4448,75 @@ def test_fireworks_models_in_backup_cost_map(): ), f"short-form {short_key} does not match long-form {long_key}" +@pytest.fixture +def fireworks_short_model_cost_map(monkeypatch: pytest.MonkeyPatch) -> Iterator[None]: + monkeypatch.setattr( + litellm, + "model_cost", + { + "fireworks_ai/accounts/fireworks/models/glm-5p3": { + "input_cost_per_token": 1e-6, + "output_cost_per_token": 2e-6, + "litellm_provider": "fireworks_ai", + "mode": "chat", + "max_tokens": 100, + }, + "fireworks_ai/accounts/fireworks/routers/glm-5p3-fast": { + "input_cost_per_token": 2.1e-6, + "output_cost_per_token": 6.6e-6, + "litellm_provider": "fireworks_ai", + "mode": "chat", + }, + "fireworks_ai/nomic-ai/nomic-embed-text-v1.5": { + "input_cost_per_token": 8e-9, + "output_cost_per_token": 0.0, + "litellm_provider": "fireworks_ai", + "mode": "embedding", + }, + }, + ) + litellm.get_model_info.cache_clear() + yield + litellm.get_model_info.cache_clear() + + +def test_fireworks_short_model_names_resolve_to_long_cost_map_keys(fireworks_short_model_cost_map: None) -> None: + model_info = litellm.get_model_info("fireworks_ai/glm-5p3") + assert model_info["key"] == "fireworks_ai/accounts/fireworks/models/glm-5p3" + assert model_info["input_cost_per_token"] == 1e-6 + assert model_info["max_tokens"] == 100 + + model_info = litellm.get_model_info("glm-5p3", custom_llm_provider="fireworks_ai") + assert model_info["key"] == "fireworks_ai/accounts/fireworks/models/glm-5p3" + + model_info = litellm.get_model_info("fireworks_ai/glm-5p3-fast") + assert model_info["key"] == "fireworks_ai/accounts/fireworks/routers/glm-5p3-fast" + assert model_info["input_cost_per_token"] == 2.1e-6 + + model_info = litellm.get_model_info("fireworks_ai/nomic-ai/nomic-embed-text-v1.5") + assert model_info["key"] == "fireworks_ai/nomic-ai/nomic-embed-text-v1.5" + + with pytest.raises(Exception, match="isn't mapped"): + litellm.get_model_info("fireworks_ai/does-not-exist") + + +def test_fireworks_short_model_names_price_with_completion_cost(fireworks_short_model_cost_map: None) -> None: + from litellm.types.utils import ModelResponse + + response = ModelResponse( + model="fireworks_ai/glm-5p3", + usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15), + ) + + cost = litellm.completion_cost( + completion_response=response, + model="fireworks_ai/glm-5p3", + custom_llm_provider="fireworks_ai", + ) + + assert cost == pytest.approx(10 * 1e-6 + 5 * 2e-6) + + class TestBedrockBaseModelLabelKeepsTools: """Regression for #29618: a Bedrock deployment whose ``base_model`` is a friendly label must not silently drop ``tools``/``tool_choice`` under ``drop_params``.""" From 0904051fda4e3f07c59ecca731eb3c5b94b92817 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 13 Sep 2026 03:24:23 +0000 Subject: [PATCH 2/5] refactor(fireworks): move cost map key construction under llms/ Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/llms/fireworks_ai/common_utils.py | 4 ++++ litellm/utils.py | 4 ++-- .../test_fireworks_ai_common_utils.py | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/litellm/llms/fireworks_ai/common_utils.py b/litellm/llms/fireworks_ai/common_utils.py index 21a630a76d7..b5552583862 100644 --- a/litellm/llms/fireworks_ai/common_utils.py +++ b/litellm/llms/fireworks_ai/common_utils.py @@ -72,6 +72,10 @@ def resolve_fireworks_resource_name(model: str) -> str: return f"accounts/fireworks/models/{stripped}" +def fireworks_cost_map_key(model: str) -> str: + return f"fireworks_ai/{resolve_fireworks_resource_name(model)}" + + class FireworksAIMixin: """ Common Base Config functions across Fireworks AI Endpoints diff --git a/litellm/utils.py b/litellm/utils.py index 4a92f9b1244..d088ae7264f 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -5557,9 +5557,9 @@ def _get_potential_model_names(model: str, custom_llm_provider: str | None) -> P split_model = strip_bedrock_routing_prefix(split_model) if custom_llm_provider == "fireworks_ai": - from litellm.llms.fireworks_ai.common_utils import resolve_fireworks_resource_name + from litellm.llms.fireworks_ai.common_utils import fireworks_cost_map_key - provider_prefixed_model_name = f"fireworks_ai/{resolve_fireworks_resource_name(split_model)}" + provider_prefixed_model_name = fireworks_cost_map_key(split_model) return PotentialModelNamesAndCustomLLMProvider( split_model=split_model, diff --git a/tests/test_litellm/llms/fireworks_ai/test_fireworks_ai_common_utils.py b/tests/test_litellm/llms/fireworks_ai/test_fireworks_ai_common_utils.py index 16226a3ce74..5aa1429f2e7 100644 --- a/tests/test_litellm/llms/fireworks_ai/test_fireworks_ai_common_utils.py +++ b/tests/test_litellm/llms/fireworks_ai/test_fireworks_ai_common_utils.py @@ -1,8 +1,6 @@ - import pytest - -from litellm.llms.fireworks_ai.common_utils import resolve_fireworks_resource_name +from litellm.llms.fireworks_ai.common_utils import fireworks_cost_map_key, resolve_fireworks_resource_name @pytest.mark.parametrize( @@ -43,3 +41,15 @@ from litellm.llms.fireworks_ai.common_utils import resolve_fireworks_resource_na ) def test_resolve_fireworks_resource_name(model, expected): assert resolve_fireworks_resource_name(model) == expected + + +@pytest.mark.parametrize( + "model, expected", + [ + ("deepseek-r1", "fireworks_ai/accounts/fireworks/models/deepseek-r1"), + ("glm-5p3-fast", "fireworks_ai/accounts/fireworks/routers/glm-5p3-fast"), + ("accounts/fireworks/models/deepseek-r1", "fireworks_ai/accounts/fireworks/models/deepseek-r1"), + ], +) +def test_fireworks_cost_map_key(model: str, expected: str) -> None: + assert fireworks_cost_map_key(model) == expected From a519d805bb35abad5ba736d0e785aebe813cca26 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 13 Sep 2026 03:29:11 +0000 Subject: [PATCH 3/5] refactor(fireworks): resolve cost map key through a provider config hook Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/llms/base_llm/base_utils.py | 6 ++++++ litellm/llms/fireworks_ai/chat/transformation.py | 3 +++ litellm/llms/fireworks_ai/common_utils.py | 4 ---- litellm/utils.py | 14 +++++++++----- .../test_fireworks_ai_chat_transformation.py | 12 ++++++++++++ .../test_fireworks_ai_common_utils.py | 16 +++------------- 6 files changed, 33 insertions(+), 22 deletions(-) diff --git a/litellm/llms/base_llm/base_utils.py b/litellm/llms/base_llm/base_utils.py index c5290b41f7b..c9ef7d77ed8 100644 --- a/litellm/llms/base_llm/base_utils.py +++ b/litellm/llms/base_llm/base_utils.py @@ -50,6 +50,12 @@ class BaseLLMModelInfo(ABC): """ return None + def get_model_cost_key(self, model: str) -> str | None: + """ + Extra `litellm.model_cost` key to try for this provider's spelling of `model`, after the exact keys miss. + """ + return None + @abstractmethod def get_models(self, api_key: str | None = None, api_base: str | None = None) -> list[str]: """ diff --git a/litellm/llms/fireworks_ai/chat/transformation.py b/litellm/llms/fireworks_ai/chat/transformation.py index b4e1856f499..05160d83c12 100644 --- a/litellm/llms/fireworks_ai/chat/transformation.py +++ b/litellm/llms/fireworks_ai/chat/transformation.py @@ -602,6 +602,9 @@ class FireworksAIConfig(FireworksAIMixin, OpenAIGPTConfig): return None return max(matches, key=lambda match: len(match[0]))[1] + def get_model_cost_key(self, model: str) -> str: + return f"fireworks_ai/{resolve_fireworks_resource_name(model)}" + def get_provider_info(self, model: str) -> ProviderSpecificModelInfo: supports_function_calling_value: Final = self._get_model_cost_capability( model=model, capability="supports_function_calling" diff --git a/litellm/llms/fireworks_ai/common_utils.py b/litellm/llms/fireworks_ai/common_utils.py index b5552583862..21a630a76d7 100644 --- a/litellm/llms/fireworks_ai/common_utils.py +++ b/litellm/llms/fireworks_ai/common_utils.py @@ -72,10 +72,6 @@ def resolve_fireworks_resource_name(model: str) -> str: return f"accounts/fireworks/models/{stripped}" -def fireworks_cost_map_key(model: str) -> str: - return f"fireworks_ai/{resolve_fireworks_resource_name(model)}" - - class FireworksAIMixin: """ Common Base Config functions across Fireworks AI Endpoints diff --git a/litellm/utils.py b/litellm/utils.py index d088ae7264f..edfdde55699 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -5556,17 +5556,21 @@ def _get_potential_model_names(model: str, custom_llm_provider: str | None) -> P split_model = strip_bedrock_routing_prefix(split_model) - if custom_llm_provider == "fireworks_ai": - from litellm.llms.fireworks_ai.common_utils import fireworks_cost_map_key - - provider_prefixed_model_name = fireworks_cost_map_key(split_model) + provider_model_info: Final = ( + ProviderConfigManager.get_provider_model_info(model=split_model, provider=LlmProviders(custom_llm_provider)) + if custom_llm_provider in LlmProvidersSet + else None + ) + provider_cost_key: Final = ( + provider_model_info.get_model_cost_key(split_model) if provider_model_info is not None else None + ) return PotentialModelNamesAndCustomLLMProvider( split_model=split_model, combined_model_name=combined_model_name, stripped_model_name=stripped_model_name, combined_stripped_model_name=combined_stripped_model_name, - provider_prefixed_model_name=provider_prefixed_model_name, + provider_prefixed_model_name=provider_cost_key or provider_prefixed_model_name, custom_llm_provider=cast(str, custom_llm_provider), ) diff --git a/tests/test_litellm/llms/fireworks_ai/chat/test_fireworks_ai_chat_transformation.py b/tests/test_litellm/llms/fireworks_ai/chat/test_fireworks_ai_chat_transformation.py index 8479397efa7..fb0311ef39b 100644 --- a/tests/test_litellm/llms/fireworks_ai/chat/test_fireworks_ai_chat_transformation.py +++ b/tests/test_litellm/llms/fireworks_ai/chat/test_fireworks_ai_chat_transformation.py @@ -1813,3 +1813,15 @@ def test_streaming_preserves_selected_model_for_private_accounting(): completion_response=assembled, custom_llm_provider="fireworks_ai", ) == pytest.approx(expected_cost) + + +@pytest.mark.parametrize( + "model, expected", + [ + ("deepseek-r1", "fireworks_ai/accounts/fireworks/models/deepseek-r1"), + ("glm-5p3-fast", "fireworks_ai/accounts/fireworks/routers/glm-5p3-fast"), + ("accounts/fireworks/models/deepseek-r1", "fireworks_ai/accounts/fireworks/models/deepseek-r1"), + ], +) +def test_get_model_cost_key_resolves_short_names_to_long_keys(model: str, expected: str) -> None: + assert FireworksAIConfig().get_model_cost_key(model) == expected diff --git a/tests/test_litellm/llms/fireworks_ai/test_fireworks_ai_common_utils.py b/tests/test_litellm/llms/fireworks_ai/test_fireworks_ai_common_utils.py index 5aa1429f2e7..16226a3ce74 100644 --- a/tests/test_litellm/llms/fireworks_ai/test_fireworks_ai_common_utils.py +++ b/tests/test_litellm/llms/fireworks_ai/test_fireworks_ai_common_utils.py @@ -1,6 +1,8 @@ + import pytest -from litellm.llms.fireworks_ai.common_utils import fireworks_cost_map_key, resolve_fireworks_resource_name + +from litellm.llms.fireworks_ai.common_utils import resolve_fireworks_resource_name @pytest.mark.parametrize( @@ -41,15 +43,3 @@ from litellm.llms.fireworks_ai.common_utils import fireworks_cost_map_key, resol ) def test_resolve_fireworks_resource_name(model, expected): assert resolve_fireworks_resource_name(model) == expected - - -@pytest.mark.parametrize( - "model, expected", - [ - ("deepseek-r1", "fireworks_ai/accounts/fireworks/models/deepseek-r1"), - ("glm-5p3-fast", "fireworks_ai/accounts/fireworks/routers/glm-5p3-fast"), - ("accounts/fireworks/models/deepseek-r1", "fireworks_ai/accounts/fireworks/models/deepseek-r1"), - ], -) -def test_fireworks_cost_map_key(model: str, expected: str) -> None: - assert fireworks_cost_map_key(model) == expected From f1fe61af06ddefcf086ec831cc172107c6e8c886 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 13 Sep 2026 03:36:00 +0000 Subject: [PATCH 4/5] docs(fireworks): explain what get_model_cost_key is for Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/llms/base_llm/base_utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/litellm/llms/base_llm/base_utils.py b/litellm/llms/base_llm/base_utils.py index c9ef7d77ed8..32f98fbc933 100644 --- a/litellm/llms/base_llm/base_utils.py +++ b/litellm/llms/base_llm/base_utils.py @@ -52,7 +52,10 @@ class BaseLLMModelInfo(ABC): def get_model_cost_key(self, model: str) -> str | None: """ - Extra `litellm.model_cost` key to try for this provider's spelling of `model`, after the exact keys miss. + Maps the model name a user sends to the key `litellm.model_cost` stores it under, when the two differ. + `get_model_info` tries this key once the exact `model` and `provider/model` keys miss. The default None means + the provider's user-facing names already match the cost map, so there is nothing extra to try. Fireworks + overrides it: `deepseek-r1` -> `fireworks_ai/accounts/fireworks/models/deepseek-r1`. """ return None From 7a0ea9867df1573f3847b6cd227dd39be7c2a8fa Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 13 Sep 2026 03:38:14 +0000 Subject: [PATCH 5/5] docs(fireworks): drop provider example from get_model_cost_key docstring Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/llms/base_llm/base_utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/litellm/llms/base_llm/base_utils.py b/litellm/llms/base_llm/base_utils.py index 32f98fbc933..a446a721307 100644 --- a/litellm/llms/base_llm/base_utils.py +++ b/litellm/llms/base_llm/base_utils.py @@ -54,8 +54,7 @@ class BaseLLMModelInfo(ABC): """ Maps the model name a user sends to the key `litellm.model_cost` stores it under, when the two differ. `get_model_info` tries this key once the exact `model` and `provider/model` keys miss. The default None means - the provider's user-facing names already match the cost map, so there is nothing extra to try. Fireworks - overrides it: `deepseek-r1` -> `fireworks_ai/accounts/fireworks/models/deepseek-r1`. + the provider's user-facing names already match the cost map, so there is nothing extra to try. """ return None