Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions litellm/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,7 @@
"https://api.meta.ai/v1",
"https://api.cognition.ai/v1",
"https://api.scx.ai/v1",
"https://api.paretoinference.com/v1",
"https://gigachat.devices.sberbank.ru/api/v1",
]

Expand Down Expand Up @@ -1010,6 +1011,7 @@
"meta", # Meta Model API (Muse Spark) - JSON-configured provider
"cognition",
"scx-ai",
"pareto",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Chat Provider Enables Transcription

Adding Pareto to openai_compatible_providers also adds it to OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS. As a result, transcription(model="pareto/...") selects the OpenAI transcription transport and sends a request to Pareto's /audio/transcriptions endpoint, even though the new capability map declares audio transcription unsupported. This should be gated by the declared capability or otherwise excluded so unsupported calls are rejected locally instead of being sent upstream.

Knowledge Base Used: Provider adapters and capabilities

]

OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS: Final = frozenset({"openai"} | frozenset(openai_compatible_providers))
Expand Down
5 changes: 5 additions & 0 deletions litellm/llms/openai_like/providers.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,5 +200,10 @@
"temperature_max": 1.99
},
"supported_endpoints": ["/v1/chat/completions"]
},
"pareto": {
"base_url": "https://api.paretoinference.com/v1",
"api_key_env": "PARETO_API_KEY",
"api_base_env": "PARETO_API_BASE"
}
}
8 changes: 8 additions & 0 deletions litellm/model_prices_and_context_window_backup.json
Original file line number Diff line number Diff line change
Expand Up @@ -57905,6 +57905,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,
"input_cost_per_token": 1.25e-06,
Expand Down
17 changes: 17 additions & 0 deletions litellm/provider_endpoints_support_backup.json
Original file line number Diff line number Diff line change
Expand Up @@ -1837,6 +1837,23 @@
"search": true
}
},
"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",
Expand Down
28 changes: 28 additions & 0 deletions litellm/proxy/public_endpoints/provider_create_fields.json
Original file line number Diff line number Diff line change
Expand Up @@ -2735,6 +2735,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",
Expand Down
1 change: 1 addition & 0 deletions litellm/types/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4297,6 +4297,7 @@ class LlmProviders(str, Enum):
PINSTRIPES = "pinstripes"
COGNITION = "cognition"
SCX_AI = "scx-ai"
PARETO = "pareto"
DARKBLOOM = "darkbloom"
META = "meta"
LITELLM_AGENT = "litellm_agent"
Expand Down
8 changes: 8 additions & 0 deletions model_prices_and_context_window.json
Original file line number Diff line number Diff line change
Expand Up @@ -57905,6 +57905,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,
"input_cost_per_token": 1.25e-06,
Expand Down
17 changes: 17 additions & 0 deletions provider_endpoints_support.json
Original file line number Diff line number Diff line change
Expand Up @@ -2020,6 +2020,23 @@
"a2a": 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",
Expand Down
114 changes: 114 additions & 0 deletions tests/test_litellm/llms/openai_like/test_pareto_provider.py
Original file line number Diff line number Diff line change
@@ -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)
Loading