mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
fix(fireworks): add glm-5p1 metadata and parallel_tool_calls (#26069)
This commit is contained in:
parent
67e6a95cb0
commit
e3b3f12777
4 changed files with 135 additions and 35 deletions
|
|
@ -116,6 +116,7 @@ class FireworksAIConfig(OpenAIGPTConfig):
|
|||
# Only add tool_choice for models that explicitly support it
|
||||
if supports_tool_choice(model=model, custom_llm_provider="fireworks_ai"):
|
||||
supported_params.append("tool_choice")
|
||||
supported_params.append("parallel_tool_calls")
|
||||
|
||||
# Only add reasoning_effort for models that support it
|
||||
if supports_reasoning(model=model, custom_llm_provider="fireworks_ai"):
|
||||
|
|
@ -248,34 +249,24 @@ class FireworksAIConfig(OpenAIGPTConfig):
|
|||
|
||||
return messages
|
||||
|
||||
def _get_model_cost_capability(self, model: str, capability: str) -> Optional[bool]:
|
||||
candidate_keys = [model]
|
||||
if not model.startswith("fireworks_ai/"):
|
||||
candidate_keys.append(f"fireworks_ai/{model}")
|
||||
|
||||
for candidate_key in candidate_keys:
|
||||
model_info = litellm.model_cost.get(candidate_key)
|
||||
if model_info is not None and model_info.get(capability) is not None:
|
||||
return cast(Optional[bool], model_info.get(capability))
|
||||
|
||||
return None
|
||||
|
||||
def get_provider_info(self, model: str) -> ProviderSpecificModelInfo:
|
||||
# Models that support reasoning_effort
|
||||
reasoning_supported_models = [
|
||||
"qwen3-8b",
|
||||
"qwen3-32b",
|
||||
"qwen3-coder-480b-a35b-instruct",
|
||||
"deepseek-v3p1",
|
||||
"deepseek-v3p2",
|
||||
"glm-4p5",
|
||||
"glm-4p5-air",
|
||||
"glm-4p6",
|
||||
"gpt-oss-120b",
|
||||
"gpt-oss-20b",
|
||||
]
|
||||
|
||||
# Normalize model name - remove prefix if present
|
||||
normalized_model = model
|
||||
if model.startswith("fireworks_ai/"):
|
||||
normalized_model = model.replace("fireworks_ai/", "")
|
||||
if normalized_model.startswith("accounts/fireworks/models/"):
|
||||
normalized_model = normalized_model.replace(
|
||||
"accounts/fireworks/models/", ""
|
||||
)
|
||||
|
||||
# Check if model supports reasoning
|
||||
supports_reasoning_value = any(
|
||||
reasoning_model in normalized_model
|
||||
for reasoning_model in reasoning_supported_models
|
||||
supports_function_calling_value = self._get_model_cost_capability(
|
||||
model=model, capability="supports_function_calling"
|
||||
)
|
||||
supports_reasoning_value = self._get_model_cost_capability(
|
||||
model=model, capability="supports_reasoning"
|
||||
)
|
||||
|
||||
provider_specific_model_info: ProviderSpecificModelInfo = {
|
||||
|
|
@ -285,9 +276,16 @@ class FireworksAIConfig(OpenAIGPTConfig):
|
|||
"supports_vision": True, # via document inlining
|
||||
}
|
||||
|
||||
if supports_function_calling_value is not None:
|
||||
provider_specific_model_info["supports_function_calling"] = (
|
||||
supports_function_calling_value
|
||||
)
|
||||
|
||||
# Only include supports_reasoning if True
|
||||
if supports_reasoning_value:
|
||||
provider_specific_model_info["supports_reasoning"] = True
|
||||
if supports_reasoning_value is not None:
|
||||
provider_specific_model_info["supports_reasoning"] = (
|
||||
supports_reasoning_value
|
||||
)
|
||||
|
||||
return provider_specific_model_info
|
||||
|
||||
|
|
|
|||
|
|
@ -13219,6 +13219,21 @@
|
|||
"supports_response_schema": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"fireworks_ai/accounts/fireworks/models/glm-5p1": {
|
||||
"cache_read_input_token_cost": 2.6e-07,
|
||||
"input_cost_per_token": 1.4e-06,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
"max_input_tokens": 202800,
|
||||
"max_output_tokens": 202800,
|
||||
"max_tokens": 202800,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"source": "https://fireworks.ai/models/fireworks/glm-5p1",
|
||||
"supports_function_calling": false,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": false,
|
||||
"supports_tool_choice": false
|
||||
},
|
||||
"fireworks_ai/accounts/fireworks/models/gpt-oss-120b": {
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
|
|
@ -13485,6 +13500,21 @@
|
|||
"supports_response_schema": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"fireworks_ai/glm-5p1": {
|
||||
"cache_read_input_token_cost": 2.6e-07,
|
||||
"input_cost_per_token": 1.4e-06,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
"max_input_tokens": 202800,
|
||||
"max_output_tokens": 202800,
|
||||
"max_tokens": 202800,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"source": "https://fireworks.ai/models/fireworks/glm-5p1",
|
||||
"supports_function_calling": false,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": false,
|
||||
"supports_tool_choice": false
|
||||
},
|
||||
"fireworks_ai/kimi-k2p5": {
|
||||
"cache_read_input_token_cost": 1e-07,
|
||||
"input_cost_per_token": 6e-07,
|
||||
|
|
|
|||
|
|
@ -13219,6 +13219,21 @@
|
|||
"supports_response_schema": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"fireworks_ai/accounts/fireworks/models/glm-5p1": {
|
||||
"cache_read_input_token_cost": 2.6e-07,
|
||||
"input_cost_per_token": 1.4e-06,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
"max_input_tokens": 202800,
|
||||
"max_output_tokens": 202800,
|
||||
"max_tokens": 202800,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"source": "https://fireworks.ai/models/fireworks/glm-5p1",
|
||||
"supports_function_calling": false,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": false,
|
||||
"supports_tool_choice": false
|
||||
},
|
||||
"fireworks_ai/accounts/fireworks/models/gpt-oss-120b": {
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
|
|
@ -13485,6 +13500,21 @@
|
|||
"supports_response_schema": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"fireworks_ai/glm-5p1": {
|
||||
"cache_read_input_token_cost": 2.6e-07,
|
||||
"input_cost_per_token": 1.4e-06,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
"max_input_tokens": 202800,
|
||||
"max_output_tokens": 202800,
|
||||
"max_tokens": 202800,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"source": "https://fireworks.ai/models/fireworks/glm-5p1",
|
||||
"supports_function_calling": false,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": false,
|
||||
"supports_tool_choice": false
|
||||
},
|
||||
"fireworks_ai/kimi-k2p5": {
|
||||
"cache_read_input_token_cost": 1e-07,
|
||||
"input_cost_per_token": 6e-07,
|
||||
|
|
|
|||
|
|
@ -10,12 +10,23 @@ sys.path.insert(
|
|||
0, os.path.abspath("../../../../..")
|
||||
) # Adds the parent directory to the system path
|
||||
|
||||
from litellm import supports_reasoning
|
||||
from litellm import get_model_info, supports_reasoning
|
||||
from litellm.llms.fireworks_ai.chat.transformation import FireworksAIConfig
|
||||
from litellm.types.llms.openai import ChatCompletionToolCallFunctionChunk
|
||||
from litellm.types.utils import ChatCompletionMessageToolCall, Function, Message
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def force_local_model_cost(monkeypatch):
|
||||
"""Force local model cost map usage for all tests in this file."""
|
||||
monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True")
|
||||
# Refresh model_cost from local map
|
||||
import litellm
|
||||
from litellm.litellm_core_utils.get_model_cost_map import get_model_cost_map
|
||||
|
||||
litellm.model_cost = get_model_cost_map(url=litellm.model_cost_map_url)
|
||||
|
||||
|
||||
def test_handle_message_content_with_tool_calls():
|
||||
config = FireworksAIConfig()
|
||||
message = Message(
|
||||
|
|
@ -62,7 +73,6 @@ def test_handle_message_content_with_tool_calls():
|
|||
|
||||
def test_supports_reasoning_effort():
|
||||
"""Test that reasoning_effort is only supported for specific Fireworks AI models."""
|
||||
# Models that support reasoning_effort
|
||||
supported_models = [
|
||||
"fireworks_ai/accounts/fireworks/models/qwen3-8b",
|
||||
"fireworks_ai/accounts/fireworks/models/qwen3-32b",
|
||||
|
|
@ -72,11 +82,13 @@ def test_supports_reasoning_effort():
|
|||
"fireworks_ai/accounts/fireworks/models/glm-4p5",
|
||||
"fireworks_ai/accounts/fireworks/models/glm-4p5-air",
|
||||
"fireworks_ai/accounts/fireworks/models/glm-4p6",
|
||||
"fireworks_ai/accounts/fireworks/models/glm-4p7",
|
||||
"fireworks_ai/accounts/fireworks/models/glm-5p1",
|
||||
"fireworks_ai/accounts/fireworks/models/gpt-oss-120b",
|
||||
"fireworks_ai/accounts/fireworks/models/gpt-oss-20b",
|
||||
"fireworks_ai/glm-5p1",
|
||||
]
|
||||
|
||||
# Models that don't support reasoning_effort
|
||||
unsupported_models = [
|
||||
"fireworks_ai/accounts/fireworks/models/llama-v3-70b-instruct",
|
||||
"fireworks_ai/accounts/fireworks/models/mixtral-8x7b-instruct",
|
||||
|
|
@ -97,19 +109,41 @@ def test_get_supported_openai_params_reasoning_effort():
|
|||
"""Test that reasoning_effort is only included in supported params for models that support it."""
|
||||
config = FireworksAIConfig()
|
||||
|
||||
# Model that supports reasoning_effort
|
||||
supported_params = config.get_supported_openai_params(
|
||||
"fireworks_ai/accounts/fireworks/models/qwen3-8b"
|
||||
"fireworks_ai/accounts/fireworks/models/glm-5p1"
|
||||
)
|
||||
assert "reasoning_effort" in supported_params
|
||||
|
||||
# Model that doesn't support reasoning_effort
|
||||
unsupported_params = config.get_supported_openai_params(
|
||||
"fireworks_ai/accounts/fireworks/models/llama-v3-70b-instruct"
|
||||
)
|
||||
assert "reasoning_effort" not in unsupported_params
|
||||
|
||||
|
||||
def test_get_supported_openai_params_parallel_tool_calls():
|
||||
"""Test that parallel_tool_calls is included for models that support tool_choice."""
|
||||
config = FireworksAIConfig()
|
||||
|
||||
supported_params = config.get_supported_openai_params(
|
||||
"fireworks_ai/accounts/fireworks/models/glm-4p6"
|
||||
)
|
||||
assert "parallel_tool_calls" in supported_params
|
||||
|
||||
unsupported_params = config.get_supported_openai_params(
|
||||
"fireworks_ai/accounts/fireworks/models/glm-5p1"
|
||||
)
|
||||
assert "parallel_tool_calls" not in unsupported_params
|
||||
|
||||
|
||||
def test_get_model_info_respects_explicit_fireworks_capabilities():
|
||||
"""Test that get_model_info preserves explicit capability flags from the model map."""
|
||||
model_info = get_model_info("fireworks_ai/accounts/fireworks/models/glm-5p1")
|
||||
|
||||
assert model_info["supports_function_calling"] is False
|
||||
assert model_info["supports_reasoning"] is True
|
||||
assert model_info["supports_tool_choice"] is False
|
||||
|
||||
|
||||
def test_add_transform_inline_image_block_skips_data_urls():
|
||||
"""
|
||||
data: URLs must not have #transform=inline appended — doing so corrupts the
|
||||
|
|
@ -232,3 +266,11 @@ def test_transform_messages_helper_removes_provider_specific_fields():
|
|||
)
|
||||
for msg in out:
|
||||
assert "provider_specific_fields" not in msg
|
||||
|
||||
|
||||
def test_unmapped_model_fallback_function_calling():
|
||||
"""Test that a model not in model_cost still defaults to supporting function calling for Fireworks."""
|
||||
config = FireworksAIConfig()
|
||||
model = "fireworks_ai/unmapped-future-model"
|
||||
info = config.get_provider_info(model)
|
||||
assert info["supports_function_calling"] is True
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue