mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
fix(apodex): isolate chat routing
This commit is contained in:
parent
190a3e01ec
commit
42dcfa12a2
3 changed files with 42 additions and 13 deletions
|
|
@ -14,6 +14,7 @@ Ref: https://platform.apodex.ai/docs/chat-completions
|
|||
from collections.abc import Mapping
|
||||
from typing import Final
|
||||
|
||||
import litellm
|
||||
from litellm.llms.openai.chat.gpt_transformation import OpenAIGPTConfig
|
||||
from litellm.types.llms.openai import AllMessageValues
|
||||
|
||||
|
|
@ -22,6 +23,7 @@ from ..common_utils import (
|
|||
get_apodex_api_base,
|
||||
get_apodex_api_key,
|
||||
is_deep_research_model,
|
||||
is_responses_only_model,
|
||||
)
|
||||
|
||||
_DEEP_RESEARCH_PARAMS: Final = (
|
||||
|
|
@ -87,6 +89,13 @@ class ApodexChatConfig(OpenAIGPTConfig):
|
|||
model: str,
|
||||
drop_params: bool,
|
||||
) -> dict: # mutable-ok: matches the base-class signature
|
||||
if is_responses_only_model(model):
|
||||
raise litellm.BadRequestError(
|
||||
message=f"apodex model {model} is only available through /v1/responses",
|
||||
model=model,
|
||||
llm_provider="apodex",
|
||||
)
|
||||
|
||||
mapped: Final = super().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
|
|
@ -94,7 +103,6 @@ class ApodexChatConfig(OpenAIGPTConfig):
|
|||
drop_params=drop_params,
|
||||
)
|
||||
|
||||
# Apodex documents max_tokens only.
|
||||
renamed: Final = (
|
||||
mapped
|
||||
if "max_completion_tokens" not in mapped
|
||||
|
|
@ -109,18 +117,9 @@ class ApodexChatConfig(OpenAIGPTConfig):
|
|||
if renamed.get("stream"):
|
||||
return renamed
|
||||
|
||||
# The OpenAI chat handler pops `stream` out of the params it forwards
|
||||
# (litellm/llms/openai/openai.py), which would leave the Deep Research tiers
|
||||
# on their streaming default. extra_body is merged into the request body
|
||||
# further down, so it survives that pop.
|
||||
requested_extra_body: Final = renamed.get("extra_body")
|
||||
extra_body: Final = (
|
||||
requested_extra_body if isinstance(requested_extra_body, Mapping) else {} # mutable-ok: JSON request body
|
||||
)
|
||||
return { # mutable-ok: JSON request body
|
||||
**renamed,
|
||||
_PIN_NON_STREAMING: True,
|
||||
"extra_body": {**extra_body, "stream": False}, # mutable-ok: JSON request body
|
||||
}
|
||||
|
||||
def transform_request(
|
||||
|
|
@ -131,12 +130,12 @@ class ApodexChatConfig(OpenAIGPTConfig):
|
|||
litellm_params: dict, # mutable-ok: matches the base-class signature
|
||||
headers: dict, # mutable-ok: matches the base-class signature
|
||||
) -> dict: # mutable-ok: JSON request body
|
||||
"""Apply the non-streaming pin after LiteLLM merges caller ``extra_body``."""
|
||||
pin_non_streaming: Final = bool(optional_params.pop(_PIN_NON_STREAMING, False))
|
||||
pin_non_streaming: Final = bool(optional_params.get(_PIN_NON_STREAMING, False))
|
||||
forwarded_params: Final = {key: value for key, value in optional_params.items() if key != _PIN_NON_STREAMING}
|
||||
transformed: Final = super().transform_request(
|
||||
model=model,
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
optional_params=forwarded_params,
|
||||
litellm_params=litellm_params,
|
||||
headers=headers,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from litellm.secret_managers.main import get_secret_str
|
|||
APODEX_API_BASE_URL: Final = "https://api.apodex.ai/v1"
|
||||
|
||||
_DEEP_RESEARCH_MARKER: Final = "-deep-"
|
||||
_RESPONSES_ONLY_MODELS: Final = frozenset({"apodex-1-1-deep-discover"})
|
||||
|
||||
|
||||
def strip_provider_prefix(model: str) -> str:
|
||||
|
|
@ -28,6 +29,10 @@ def is_deep_research_model(model: str) -> bool:
|
|||
return _DEEP_RESEARCH_MARKER in strip_provider_prefix(model)
|
||||
|
||||
|
||||
def is_responses_only_model(model: str) -> bool:
|
||||
return strip_provider_prefix(model) in _RESPONSES_ONLY_MODELS
|
||||
|
||||
|
||||
def get_apodex_api_key(api_key: str | None = None) -> str | None:
|
||||
return api_key or get_secret_str("APODEX_API_KEY")
|
||||
|
||||
|
|
|
|||
|
|
@ -167,8 +167,33 @@ class TestStreamDefault:
|
|||
|
||||
assert captured["body"]["stream"] is False
|
||||
|
||||
def test_transform_does_not_mutate_optional_params(self):
|
||||
config = _chat_config("apodex-1.1")
|
||||
optional_params = config.map_openai_params(
|
||||
non_default_params={}, optional_params={}, model="apodex-1.1", drop_params=False
|
||||
)
|
||||
original = optional_params.copy()
|
||||
|
||||
config.transform_request(
|
||||
model="apodex-1.1",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
optional_params=optional_params,
|
||||
litellm_params={"custom_llm_provider": "apodex"},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert optional_params == original
|
||||
|
||||
|
||||
class TestSupportedParams:
|
||||
def test_responses_only_model_rejects_chat_completions(self):
|
||||
with pytest.raises(litellm.BadRequestError, match="only available through /v1/responses"):
|
||||
litellm.completion(
|
||||
model="apodex/apodex-1-1-deep-discover",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
client=_client({}),
|
||||
)
|
||||
|
||||
def test_core_models_support_tools(self):
|
||||
supported = _chat_config("apodex-1.1").get_supported_openai_params("apodex-1.1")
|
||||
assert "tools" in supported
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue