mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-13 08:52:02 +00:00
Merge 75f7ccc8b1 into 3f38730d2c
This commit is contained in:
commit
8abd4c480e
2 changed files with 39 additions and 8 deletions
|
|
@ -73,7 +73,6 @@ from litellm.types.utils import (
|
|||
ModelResponse,
|
||||
ModelResponseStream,
|
||||
)
|
||||
from litellm.utils import supports_reasoning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj
|
||||
|
|
@ -96,16 +95,15 @@ def _model_uses_max_completion_tokens(model: str) -> bool:
|
|||
and accept ``maxCompletionTokens`` everywhere, so route the whole vendor
|
||||
prefix to it rather than chasing each new release in
|
||||
``model_prices_and_context_window.json``. The ``openai.gpt-oss-*`` open
|
||||
weights are served by OCI's own stack and keep ``maxTokens``. Any other
|
||||
vendor falls back to the catalog's ``supports_reasoning`` flag.
|
||||
weights are served by OCI's own stack and keep ``maxTokens``, as does every
|
||||
other vendor whatever its catalog reasoning flag: OCI's Gemini models ignore
|
||||
``maxCompletionTokens`` and fall back to a default of about 4K output tokens.
|
||||
"""
|
||||
if not model:
|
||||
return False
|
||||
name: Final = model[4:] if model.lower().startswith("oci/") else model
|
||||
lowered: Final = name.lower()
|
||||
if lowered.startswith("openai."):
|
||||
return not lowered.startswith("openai.gpt-oss")
|
||||
return supports_reasoning(model=name, custom_llm_provider="oci")
|
||||
return lowered.startswith("openai.") and not lowered.startswith("openai.gpt-oss")
|
||||
|
||||
|
||||
def _iter_sse_events(stream: Iterator[str]) -> Iterator[str]:
|
||||
|
|
@ -572,8 +570,7 @@ class OCIChatConfig(BaseConfig):
|
|||
|
||||
# OpenAI reasoning models on OCI (e.g. GPT-5 family) reject "maxTokens"
|
||||
# and require "maxCompletionTokens" per OCI's /20231130/Chat schema.
|
||||
# Driven by the supports_reasoning flag in the model catalog. Cohere's
|
||||
# endpoint uses "maxTokens" regardless, so the override is GENERIC-only.
|
||||
# Cohere's endpoint uses "maxTokens" regardless, so the override is GENERIC-only.
|
||||
max_tokens_key: Final = (
|
||||
"maxCompletionTokens"
|
||||
if vendor != OCIVendors.COHERE and model and _model_uses_max_completion_tokens(model)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from unittest.mock import MagicMock
|
|||
import httpx
|
||||
|
||||
from litellm import ModelResponse
|
||||
from litellm.constants import DEFAULT_OCI_CHAT_MAX_TOKENS
|
||||
from litellm.llms.oci.chat.generic import (
|
||||
adapt_messages_to_generic_oci_standard,
|
||||
adapt_messages_to_generic_oci_standard_content_message,
|
||||
|
|
@ -369,6 +370,27 @@ def _register_oci_gpt5_in_catalog():
|
|||
litellm.model_cost.pop(key, None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _flag_oci_gemini_as_reasoning_in_catalog():
|
||||
"""Mark OCI's Gemini models as reasoning models, as the bundled catalog has done since #41902,
|
||||
whichever map ``litellm.model_cost`` was populated from."""
|
||||
import litellm
|
||||
|
||||
keys = ("oci/google.gemini-2.5-pro", "oci/google.gemini-2.5-flash")
|
||||
originals = {key: litellm.model_cost.get(key) for key in keys}
|
||||
for key in keys:
|
||||
litellm.model_cost[key] = {
|
||||
**(originals[key] or {"litellm_provider": "oci", "mode": "chat"}),
|
||||
"supports_reasoning": True,
|
||||
}
|
||||
yield
|
||||
for key, original in originals.items():
|
||||
if original is None:
|
||||
litellm.model_cost.pop(key, None)
|
||||
else:
|
||||
litellm.model_cost[key] = original
|
||||
|
||||
|
||||
class TestGpt5MaxCompletionTokens:
|
||||
def test_helper_detects_gpt5_family(self, _register_oci_gpt5_in_catalog):
|
||||
assert _model_uses_max_completion_tokens("openai.gpt-5") is True
|
||||
|
|
@ -441,6 +463,18 @@ class TestGpt5MaxCompletionTokens:
|
|||
assert out.get("maxTokens") == 64
|
||||
assert "maxCompletionTokens" not in out
|
||||
|
||||
@pytest.mark.parametrize("model", ["google.gemini-2.5-pro", "oci/google.gemini-2.5-flash"])
|
||||
@pytest.mark.parametrize(("params", "expected"), [({"max_tokens": 64}, 64), ({}, DEFAULT_OCI_CHAT_MAX_TOKENS)])
|
||||
def test_gemini_reasoning_models_keep_max_tokens(
|
||||
self, model, params, expected, _flag_oci_gemini_as_reasoning_in_catalog
|
||||
):
|
||||
"""Regression: OCI's Gemini models ignore maxCompletionTokens and fall back to a default of
|
||||
about 4K output tokens (verified against live OCI on 2026-09-28), so a reasoning flag in the
|
||||
catalog must not move the limit off maxTokens."""
|
||||
out = OCIChatConfig()._get_optional_params(OCIVendors.GENERIC, params, model=model)
|
||||
assert out.get("maxTokens") == expected
|
||||
assert "maxCompletionTokens" not in out
|
||||
|
||||
def test_cohere_reasoning_model_keeps_max_tokens(self):
|
||||
cfg = OCIChatConfig()
|
||||
out = cfg._get_optional_params(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue