mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-26 06:03:19 +00:00
fix(friendliai): sync serverless catalog with the models API
The catalog carried only meta-llama-3.1-70b-instruct and meta-llama-3.1-8b-instruct. Both are retired; neither is served by https://api.friendli.ai/serverless/v1/models anymore, so their pricing and 8k context windows were the only FriendliAI data litellm exposed. Every field is taken from that endpoint, which is public and unauthenticated: pricing.input, pricing.output and pricing.input_cache_read map onto the token costs, context_length onto max_input_tokens, max_completion_tokens onto max_output_tokens and max_tokens, and functionality.tool_call, functionality.parallel_tool_call and functionality.structured_output onto the capability flags. Qwen3-235B-A22B-Instruct-2507 reports a deprecation_date of 2026-08-05 and carries it through. tests/test_litellm/test_friendliai_model_metadata.py pins the lineup, asserts the retired keys stay absent, and asserts the root JSON and the bundled backup never drift apart for this provider
This commit is contained in:
parent
24123269cc
commit
daa43de167
3 changed files with 318 additions and 24 deletions
|
|
@ -17198,30 +17198,116 @@
|
|||
"output_cost_per_token": 0.0,
|
||||
"source": "https://fireworks.ai/pricing"
|
||||
},
|
||||
"friendliai/meta-llama-3.1-70b-instruct": {
|
||||
"input_cost_per_token": 6e-07,
|
||||
"friendliai/LGAI-EXAONE/K-EXAONE-236B-A23B": {
|
||||
"cache_read_input_token_cost": 1e-07,
|
||||
"input_cost_per_token": 2e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 8192,
|
||||
"max_output_tokens": 8192,
|
||||
"max_tokens": 8192,
|
||||
"max_input_tokens": 262144,
|
||||
"max_output_tokens": 262144,
|
||||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 6e-07,
|
||||
"output_cost_per_token": 8e-07,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/MiniMaxAI/MiniMax-M2.5": {
|
||||
"cache_read_input_token_cost": 6e-08,
|
||||
"input_cost_per_token": 3e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 196608,
|
||||
"max_output_tokens": 196608,
|
||||
"max_tokens": 196608,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/Qwen/Qwen3-235B-A22B-Instruct-2507": {
|
||||
"deprecation_date": "2026-08-05",
|
||||
"input_cost_per_token": 2e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 262144,
|
||||
"max_output_tokens": 262144,
|
||||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 8e-07,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/meta-llama-3.1-8b-instruct": {
|
||||
"input_cost_per_token": 1e-07,
|
||||
"friendliai/deepseek-ai/DeepSeek-V3.2": {
|
||||
"cache_read_input_token_cost": 2.5e-07,
|
||||
"input_cost_per_token": 5e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 8192,
|
||||
"max_output_tokens": 8192,
|
||||
"max_tokens": 8192,
|
||||
"max_input_tokens": 163840,
|
||||
"max_output_tokens": 163840,
|
||||
"max_tokens": 163840,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 1e-07,
|
||||
"output_cost_per_token": 1.5e-06,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/google/gemma-4-31B-it": {
|
||||
"input_cost_per_token": 1.4e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 262144,
|
||||
"max_output_tokens": 262144,
|
||||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4e-07,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true,
|
||||
"supports_vision": true
|
||||
},
|
||||
"friendliai/zai-org/GLM-5.1": {
|
||||
"cache_read_input_token_cost": 2.6e-07,
|
||||
"input_cost_per_token": 1.4e-06,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 202752,
|
||||
"max_output_tokens": 202752,
|
||||
"max_tokens": 202752,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/zai-org/GLM-5.2": {
|
||||
"cache_read_input_token_cost": 2.6e-07,
|
||||
"input_cost_per_token": 1.4e-06,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 1048576,
|
||||
"max_output_tokens": 1048576,
|
||||
"max_tokens": 1048576,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
|
|
|
|||
|
|
@ -17198,30 +17198,116 @@
|
|||
"output_cost_per_token": 0.0,
|
||||
"source": "https://fireworks.ai/pricing"
|
||||
},
|
||||
"friendliai/meta-llama-3.1-70b-instruct": {
|
||||
"input_cost_per_token": 6e-07,
|
||||
"friendliai/LGAI-EXAONE/K-EXAONE-236B-A23B": {
|
||||
"cache_read_input_token_cost": 1e-07,
|
||||
"input_cost_per_token": 2e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 8192,
|
||||
"max_output_tokens": 8192,
|
||||
"max_tokens": 8192,
|
||||
"max_input_tokens": 262144,
|
||||
"max_output_tokens": 262144,
|
||||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 6e-07,
|
||||
"output_cost_per_token": 8e-07,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/MiniMaxAI/MiniMax-M2.5": {
|
||||
"cache_read_input_token_cost": 6e-08,
|
||||
"input_cost_per_token": 3e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 196608,
|
||||
"max_output_tokens": 196608,
|
||||
"max_tokens": 196608,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/Qwen/Qwen3-235B-A22B-Instruct-2507": {
|
||||
"deprecation_date": "2026-08-05",
|
||||
"input_cost_per_token": 2e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 262144,
|
||||
"max_output_tokens": 262144,
|
||||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 8e-07,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/meta-llama-3.1-8b-instruct": {
|
||||
"input_cost_per_token": 1e-07,
|
||||
"friendliai/deepseek-ai/DeepSeek-V3.2": {
|
||||
"cache_read_input_token_cost": 2.5e-07,
|
||||
"input_cost_per_token": 5e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 8192,
|
||||
"max_output_tokens": 8192,
|
||||
"max_tokens": 8192,
|
||||
"max_input_tokens": 163840,
|
||||
"max_output_tokens": 163840,
|
||||
"max_tokens": 163840,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 1e-07,
|
||||
"output_cost_per_token": 1.5e-06,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/google/gemma-4-31B-it": {
|
||||
"input_cost_per_token": 1.4e-07,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 262144,
|
||||
"max_output_tokens": 262144,
|
||||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4e-07,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true,
|
||||
"supports_vision": true
|
||||
},
|
||||
"friendliai/zai-org/GLM-5.1": {
|
||||
"cache_read_input_token_cost": 2.6e-07,
|
||||
"input_cost_per_token": 1.4e-06,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 202752,
|
||||
"max_output_tokens": 202752,
|
||||
"max_tokens": 202752,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"friendliai/zai-org/GLM-5.2": {
|
||||
"cache_read_input_token_cost": 2.6e-07,
|
||||
"input_cost_per_token": 1.4e-06,
|
||||
"litellm_provider": "friendliai",
|
||||
"max_input_tokens": 1048576,
|
||||
"max_output_tokens": 1048576,
|
||||
"max_tokens": 1048576,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_tool_choice": true
|
||||
|
|
|
|||
122
tests/test_litellm/test_friendliai_model_metadata.py
Normal file
122
tests/test_litellm/test_friendliai_model_metadata.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
"""Regression tests for the FriendliAI serverless catalog entries.
|
||||
|
||||
The catalog previously carried only ``friendliai/meta-llama-3.1-70b-instruct``
|
||||
and ``friendliai/meta-llama-3.1-8b-instruct``, both retired and no longer
|
||||
served by ``https://api.friendli.ai/serverless/v1/models``. These tests pin the
|
||||
current serverless lineup, assert the retired entries stay gone, and assert the
|
||||
root JSON and the bundled backup JSON never drift apart for this provider.
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Final, NamedTuple
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class FriendliModel(NamedTuple):
|
||||
key: str
|
||||
input_cost_per_token: float
|
||||
output_cost_per_token: float
|
||||
cache_read_input_token_cost: float | None
|
||||
max_input_tokens: int
|
||||
max_output_tokens: int
|
||||
|
||||
|
||||
EXPECTED_MODELS: Final[tuple[FriendliModel, ...]] = (
|
||||
FriendliModel(
|
||||
"friendliai/LGAI-EXAONE/K-EXAONE-236B-A23B", 2e-07, 8e-07, 1e-07, 262144, 262144
|
||||
),
|
||||
FriendliModel(
|
||||
"friendliai/MiniMaxAI/MiniMax-M2.5", 3e-07, 1.2e-06, 6e-08, 196608, 196608
|
||||
),
|
||||
FriendliModel(
|
||||
"friendliai/Qwen/Qwen3-235B-A22B-Instruct-2507", 2e-07, 8e-07, None, 262144, 262144
|
||||
),
|
||||
FriendliModel(
|
||||
"friendliai/deepseek-ai/DeepSeek-V3.2", 5e-07, 1.5e-06, 2.5e-07, 163840, 163840
|
||||
),
|
||||
FriendliModel(
|
||||
"friendliai/google/gemma-4-31B-it", 1.4e-07, 4e-07, None, 262144, 262144
|
||||
),
|
||||
FriendliModel(
|
||||
"friendliai/zai-org/GLM-5.1", 1.4e-06, 4.4e-06, 2.6e-07, 202752, 202752
|
||||
),
|
||||
FriendliModel(
|
||||
"friendliai/zai-org/GLM-5.2", 1.4e-06, 4.4e-06, 2.6e-07, 1048576, 1048576
|
||||
),
|
||||
)
|
||||
|
||||
RETIRED_KEYS: Final[tuple[str, ...]] = (
|
||||
"friendliai/meta-llama-3.1-70b-instruct",
|
||||
"friendliai/meta-llama-3.1-8b-instruct",
|
||||
)
|
||||
|
||||
_REPO_ROOT: Final[Path] = Path(__file__).resolve().parents[2]
|
||||
ROOT_PATH: Final[Path] = _REPO_ROOT / "model_prices_and_context_window.json"
|
||||
BACKUP_PATH: Final[Path] = (
|
||||
_REPO_ROOT / "litellm" / "model_prices_and_context_window_backup.json"
|
||||
)
|
||||
CATALOG_PATHS: Final[tuple[Path, ...]] = (ROOT_PATH, BACKUP_PATH)
|
||||
|
||||
|
||||
def _load(path: Path) -> dict[str, dict[str, object]]:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", CATALOG_PATHS, ids=lambda p: p.name)
|
||||
@pytest.mark.parametrize("expected", EXPECTED_MODELS, ids=lambda m: m.key)
|
||||
def test_serverless_model_pricing_and_context(path: Path, expected: FriendliModel) -> None:
|
||||
entry = _load(path).get(expected.key)
|
||||
assert entry is not None, f"{expected.key} missing from {path.name}"
|
||||
assert entry["litellm_provider"] == "friendliai"
|
||||
assert entry["mode"] == "chat"
|
||||
assert entry["input_cost_per_token"] == expected.input_cost_per_token
|
||||
assert entry["output_cost_per_token"] == expected.output_cost_per_token
|
||||
assert entry.get("cache_read_input_token_cost") == expected.cache_read_input_token_cost
|
||||
assert entry["max_input_tokens"] == expected.max_input_tokens
|
||||
assert entry["max_output_tokens"] == expected.max_output_tokens
|
||||
assert entry["max_tokens"] == expected.max_output_tokens
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", CATALOG_PATHS, ids=lambda p: p.name)
|
||||
@pytest.mark.parametrize("expected", EXPECTED_MODELS, ids=lambda m: m.key)
|
||||
def test_serverless_models_advertise_tool_calling(
|
||||
path: Path, expected: FriendliModel
|
||||
) -> None:
|
||||
entry = _load(path)[expected.key]
|
||||
assert entry["supports_function_calling"] is True
|
||||
assert entry["supports_parallel_function_calling"] is True
|
||||
assert entry["supports_response_schema"] is True
|
||||
assert entry["supports_tool_choice"] is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", CATALOG_PATHS, ids=lambda p: p.name)
|
||||
@pytest.mark.parametrize("key", RETIRED_KEYS)
|
||||
def test_retired_llama_entries_absent(path: Path, key: str) -> None:
|
||||
assert key not in _load(path), f"{key} is retired and must not be re-added"
|
||||
|
||||
|
||||
def test_prompt_caching_flag_tracks_cache_read_cost() -> None:
|
||||
catalog = _load(ROOT_PATH)
|
||||
for expected in EXPECTED_MODELS:
|
||||
entry = catalog[expected.key]
|
||||
assert entry.get("supports_prompt_caching", False) is (
|
||||
expected.cache_read_input_token_cost is not None
|
||||
), f"{expected.key} prompt-caching flag disagrees with cache_read cost"
|
||||
|
||||
|
||||
def test_deprecating_model_carries_iso_date() -> None:
|
||||
entry = _load(ROOT_PATH)["friendliai/Qwen/Qwen3-235B-A22B-Instruct-2507"]
|
||||
assert entry["deprecation_date"] == "2026-08-05"
|
||||
|
||||
|
||||
def test_root_and_backup_agree_on_every_friendliai_entry() -> None:
|
||||
root = {k: v for k, v in _load(ROOT_PATH).items() if k.startswith("friendliai/")}
|
||||
backup = {k: v for k, v in _load(BACKUP_PATH).items() if k.startswith("friendliai/")}
|
||||
assert root == backup
|
||||
|
||||
|
||||
def test_catalog_covers_exactly_the_expected_lineup() -> None:
|
||||
keys = {k for k in _load(ROOT_PATH) if k.startswith("friendliai/")}
|
||||
assert keys == {m.key for m in EXPECTED_MODELS}
|
||||
Loading…
Add table
Reference in a new issue