feat(providers): add Pareto Inference as OpenAI-compatible provider

Registers pareto through the JSON provider registry, so pareto/z-ai/glm-5.3-flash
resolves to https://api.paretoinference.com/v1 with PARETO_API_KEY and an optional
PARETO_API_BASE override. Adds LlmProviders.PARETO, the constants.py provider and
endpoint lists so an api_base pointing at Pareto also resolves to the provider, the
provider endpoints matrix, the Add Model provider fields, per-token pricing for
pareto/z-ai/glm-5.3-flash in both cost maps, and tests.
This commit is contained in:
dylanvu 2026-09-23 14:19:32 -04:00
parent eacb670b6e
commit f67d164484
9 changed files with 200 additions and 0 deletions

View file

@ -1095,6 +1095,7 @@ openai_compatible_endpoints: Final[list[str]] = [
"https://api.prisminference.com/v1",
"https://api.reka.ai/v1",
"https://inference.runanywhere.ai/v1",
"https://api.paretoinference.com/v1",
"https://gigachat.devices.sberbank.ru/api/v1",
"https://api.openinfer.ai/v1",
"https://vanchin.streamlake.ai/api/gateway/v1/endpoints",
@ -1183,6 +1184,7 @@ openai_compatible_providers: Final[list[str]] = [
"reka",
"streamlake",
"wally",
"pareto",
]
OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS: Final = frozenset({"openai"} | frozenset(openai_compatible_providers))

View file

@ -314,5 +314,10 @@
"supports_function_calling": true,
"supports_reasoning": true
}
},
"pareto": {
"base_url": "https://api.paretoinference.com/v1",
"api_key_env": "PARETO_API_KEY",
"api_base_env": "PARETO_API_BASE"
}
}

View file

@ -64400,6 +64400,14 @@
"supports_system_messages": true,
"supports_tool_choice": true
},
"pareto/z-ai/glm-5.3-flash": {
"input_cost_per_token": 3e-08,
"output_cost_per_token": 1e-07,
"cache_read_input_token_cost": 6e-09,
"litellm_provider": "pareto",
"mode": "chat",
"source": "https://docs.paretoinference.com/pricing"
},
"xai/grok-4.20-0309-non-reasoning": {
"cache_read_input_token_cost": 2e-07,
"cache_read_input_token_cost_batches": 1.6e-07,

View file

@ -3189,6 +3189,23 @@
"generateContent": false
}
},
"pareto": {
"display_name": "Pareto Inference (`pareto`)",
"url": "https://docs.litellm.ai/docs/providers/pareto",
"endpoints": {
"chat_completions": true,
"messages": false,
"responses": false,
"embeddings": false,
"image_generations": false,
"audio_transcriptions": false,
"audio_speech": false,
"moderations": false,
"batches": false,
"rerank": false,
"a2a": false
}
},
"perplexity": {
"display_name": "Perplexity AI (`perplexity`)",
"url": "https://docs.litellm.ai/docs/providers/perplexity",

View file

@ -3269,6 +3269,34 @@
],
"default_model_placeholder": "gpt-3.5-turbo"
},
{
"provider": "PARETO",
"provider_display_name": "Pareto Inference",
"litellm_provider": "pareto",
"credential_fields": [
{
"key": "api_base",
"label": "API Base",
"placeholder": "https://api.paretoinference.com/v1",
"tooltip": null,
"required": false,
"field_type": "text",
"options": null,
"default_value": null
},
{
"key": "api_key",
"label": "API Key",
"placeholder": null,
"tooltip": null,
"required": true,
"field_type": "password",
"options": null,
"default_value": null
}
],
"default_model_placeholder": "pareto/z-ai/glm-5.3-flash"
},
{
"provider": "Perplexity",
"provider_display_name": "Perplexity",

View file

@ -4785,6 +4785,7 @@ class LlmProviders(str, Enum):
INFERENCEAPIS = "inferenceapis"
HOSTINGER_ROUTER = "hostinger_router"
ZEROGPU = "zerogpu"
PARETO = "pareto"
DARKBLOOM = "darkbloom"
META = "meta"
SAIL = "sail"

View file

@ -64400,6 +64400,14 @@
"supports_system_messages": true,
"supports_tool_choice": true
},
"pareto/z-ai/glm-5.3-flash": {
"input_cost_per_token": 3e-08,
"output_cost_per_token": 1e-07,
"cache_read_input_token_cost": 6e-09,
"litellm_provider": "pareto",
"mode": "chat",
"source": "https://docs.paretoinference.com/pricing"
},
"xai/grok-4.20-0309-non-reasoning": {
"cache_read_input_token_cost": 2e-07,
"cache_read_input_token_cost_batches": 1.6e-07,

View file

@ -3189,6 +3189,23 @@
"generateContent": false
}
},
"pareto": {
"display_name": "Pareto Inference (`pareto`)",
"url": "https://docs.litellm.ai/docs/providers/pareto",
"endpoints": {
"chat_completions": true,
"messages": false,
"responses": false,
"embeddings": false,
"image_generations": false,
"audio_transcriptions": false,
"audio_speech": false,
"moderations": false,
"batches": false,
"rerank": false,
"a2a": false
}
},
"perplexity": {
"display_name": "Perplexity AI (`perplexity`)",
"url": "https://docs.litellm.ai/docs/providers/perplexity",

View file

@ -0,0 +1,114 @@
import json
from pathlib import Path
from typing import Final
import pytest
import respx
import litellm
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
from litellm.llms.openai_like.json_loader import JSONProviderRegistry, SimpleProviderConfig
MODEL: Final = "z-ai/glm-5.3-flash"
REPO_ROOT: Final = Path(__file__).parents[4]
COST_MAPS: Final = (
REPO_ROOT / "model_prices_and_context_window.json",
REPO_ROOT / "litellm" / "model_prices_and_context_window_backup.json",
)
@pytest.fixture
def pareto() -> SimpleProviderConfig:
config: Final = JSONProviderRegistry.get("pareto")
assert config is not None
return config
def test_prefixed_model_resolves_to_pareto_and_keeps_the_vendor_namespace(
pareto: SimpleProviderConfig, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.delenv("PARETO_API_BASE", raising=False)
model, provider, _, api_base = get_llm_provider(model=f"pareto/{MODEL}")
assert provider == litellm.LlmProviders.PARETO.value
assert model == MODEL
assert api_base == pareto.base_url
def test_api_key_and_base_are_read_from_pareto_env_vars(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
monkeypatch.setenv("PARETO_API_KEY", "sk-pareto-env")
monkeypatch.setenv("PARETO_API_BASE", "https://pareto.internal.example/v1")
_, provider, api_key, api_base = get_llm_provider(model=f"pareto/{MODEL}")
assert provider == "pareto"
assert api_key == "sk-pareto-env"
assert api_base == "https://pareto.internal.example/v1"
def test_default_api_base_autodetects_pareto(pareto: SimpleProviderConfig, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("PARETO_API_KEY", "sk-pareto-env")
model, provider, api_key, _ = get_llm_provider(model=MODEL, api_base=pareto.base_url)
assert provider == "pareto"
assert model == MODEL
assert api_key == "sk-pareto-env"
@respx.mock
def test_completion_posts_to_pareto_chat_completions_with_bearer_key(
pareto: SimpleProviderConfig, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.delenv("PARETO_API_BASE", raising=False)
monkeypatch.setenv("PARETO_API_KEY", "sk-pareto-env")
route: Final = respx.post(f"{pareto.base_url}/chat/completions").respond(
json={
"id": "chatcmpl-pareto",
"object": "chat.completion",
"created": 1,
"model": MODEL,
"choices": [{"index": 0, "message": {"role": "assistant", "content": "hi"}, "finish_reason": "stop"}],
"usage": {"prompt_tokens": 5, "completion_tokens": 1, "total_tokens": 6},
}
)
response: Final = litellm.completion(
model=f"pareto/{MODEL}",
messages=[{"role": "user", "content": "hello"}],
)
assert route.call_count == 1
request: Final = route.calls.last.request
assert request.headers["authorization"] == "Bearer sk-pareto-env"
assert json.loads(request.content)["model"] == MODEL
assert response.choices[0].message.content == "hi"
assert response.usage.total_tokens == 6
@pytest.fixture
def local_model_cost_map(monkeypatch: pytest.MonkeyPatch):
"""Resolve pricing against the in-repo cost map, not the remote one fetched at import."""
monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True")
monkeypatch.setattr(litellm, "model_cost", litellm.get_model_cost_map(url=""))
litellm.get_model_info.cache_clear()
yield
litellm.get_model_info.cache_clear()
def test_cost_maps_carry_the_same_pareto_entry() -> None:
main, backup = (json.loads(path.read_text())[f"pareto/{MODEL}"] for path in COST_MAPS)
assert main == backup
assert main["litellm_provider"] == "pareto"
def test_published_per_token_prices_are_used_for_cost(local_model_cost_map: None) -> None:
prompt_cost, completion_cost = litellm.cost_per_token(
model=f"pareto/{MODEL}", prompt_tokens=1_000_000, completion_tokens=1_000_000
)
assert prompt_cost == pytest.approx(0.03)
assert completion_cost == pytest.approx(0.10)