mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-02 07:13:02 +00:00
feat(gemini): expose long decode continuation capability
This commit is contained in:
parent
298911d61b
commit
736fd9cba6
9 changed files with 69 additions and 0 deletions
|
|
@ -2379,6 +2379,7 @@ if TYPE_CHECKING:
|
|||
supports_audio_input: Callable[..., bool]
|
||||
supports_video_input: Callable[..., bool]
|
||||
supports_box_questions: Callable[..., bool]
|
||||
supports_continuation: Callable[..., bool]
|
||||
supports_audio_output: Callable[..., bool]
|
||||
supports_system_messages: Callable[..., bool]
|
||||
supports_reasoning: Callable[..., bool]
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ UTILS_NAMES: Final = (
|
|||
"supports_audio_input",
|
||||
"supports_video_input",
|
||||
"supports_box_questions",
|
||||
"supports_continuation",
|
||||
"supports_audio_output",
|
||||
"supports_system_messages",
|
||||
"supports_reasoning",
|
||||
|
|
@ -497,6 +498,7 @@ _UTILS_IMPORT_MAP: Final = {
|
|||
"supports_audio_input": (".utils", "supports_audio_input"),
|
||||
"supports_video_input": (".utils", "supports_video_input"),
|
||||
"supports_box_questions": (".utils", "supports_box_questions"),
|
||||
"supports_continuation": (".utils", "supports_continuation"),
|
||||
"supports_audio_output": (".utils", "supports_audio_output"),
|
||||
"supports_system_messages": (".utils", "supports_system_messages"),
|
||||
"supports_reasoning": (".utils", "supports_reasoning"),
|
||||
|
|
|
|||
|
|
@ -76646,6 +76646,7 @@
|
|||
"supports_audio_input": true,
|
||||
"supports_audio_output": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_continuation": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_minimal_reasoning_effort": false,
|
||||
"supports_native_streaming": true,
|
||||
|
|
@ -76705,6 +76706,7 @@
|
|||
],
|
||||
"supports_audio_input": true,
|
||||
"supports_computer_use": true,
|
||||
"supports_continuation": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_minimal_reasoning_effort": false,
|
||||
"supports_native_streaming": true,
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ class ProviderSpecificModelInfo(TypedDict, total=False):
|
|||
supports_audio_input: bool | None
|
||||
supports_video_input: ReadOnly[bool | None]
|
||||
supports_box_questions: ReadOnly[bool | None]
|
||||
supports_continuation: ReadOnly[bool | None]
|
||||
supports_embedding_image_input: bool | None
|
||||
supports_audio_output: bool | None
|
||||
supports_pdf_input: bool | None
|
||||
|
|
|
|||
|
|
@ -3458,6 +3458,11 @@ def is_explicitly_disabled_factory(model: str, custom_llm_provider: str | None,
|
|||
return False
|
||||
|
||||
|
||||
def supports_continuation(model: str, custom_llm_provider: str | None = None) -> bool:
|
||||
"""Check if the model declares support for long-decode continuation."""
|
||||
return supports_factory(model=model, custom_llm_provider=custom_llm_provider, key="supports_continuation")
|
||||
|
||||
|
||||
def supports_audio_input(model: str, custom_llm_provider: str | None = None) -> bool:
|
||||
"""Check if a given model supports audio input in a chat completion call"""
|
||||
return supports_factory(model=model, custom_llm_provider=custom_llm_provider, key="supports_audio_input")
|
||||
|
|
@ -7343,6 +7348,7 @@ def get_model_info_helper(
|
|||
supports_audio_input=_model_info.get("supports_audio_input", None),
|
||||
supports_video_input=_model_info.get("supports_video_input", None),
|
||||
supports_box_questions=_model_info.get("supports_box_questions", None),
|
||||
supports_continuation=_model_info.get("supports_continuation", None),
|
||||
supports_audio_output=_model_info.get("supports_audio_output", None),
|
||||
supports_pdf_input=_model_info.get("supports_pdf_input", None),
|
||||
supports_embedding_image_input=_model_info.get("supports_embedding_image_input", None),
|
||||
|
|
@ -7505,6 +7511,7 @@ def get_model_info(
|
|||
supports_audio_input: Optional[bool]
|
||||
supports_video_input: Optional[bool]
|
||||
supports_box_questions: Optional[bool]
|
||||
supports_continuation: Optional[bool]
|
||||
supports_audio_output: Optional[bool]
|
||||
supports_pdf_input: Optional[bool]
|
||||
supports_web_search: Optional[bool]
|
||||
|
|
|
|||
|
|
@ -76646,6 +76646,7 @@
|
|||
"supports_audio_input": true,
|
||||
"supports_audio_output": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_continuation": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_minimal_reasoning_effort": false,
|
||||
"supports_native_streaming": true,
|
||||
|
|
@ -76705,6 +76706,7 @@
|
|||
],
|
||||
"supports_audio_input": true,
|
||||
"supports_computer_use": true,
|
||||
"supports_continuation": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_minimal_reasoning_effort": false,
|
||||
"supports_native_streaming": true,
|
||||
|
|
|
|||
|
|
@ -6226,6 +6226,35 @@ def test_model_info_v1_list_skips_fastapi_jsonable_encoder(monkeypatch):
|
|||
assert encoder_spy.call_count == 0
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize("route", ("/model/info", "/v1/model/info"))
|
||||
def test_model_info_exposes_continuation_and_deployment_override(
|
||||
route: str, local_model_cost_map: None, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
deployments: Final = [
|
||||
{"model_name": "default", "litellm_params": {"model": "gemini/gemini-4-argon"}},
|
||||
{
|
||||
"model_name": "override",
|
||||
"litellm_params": {"model": "vertex_ai/gemini-4-argon"},
|
||||
"model_info": {"supports_continuation": False},
|
||||
},
|
||||
]
|
||||
router: Final = litellm.Router(model_list=deployments)
|
||||
monkeypatch.setattr(proxy_server_module, "llm_router", router)
|
||||
monkeypatch.setattr(proxy_server_module, "llm_model_list", router.model_list)
|
||||
monkeypatch.setattr(proxy_server_module, "prisma_client", None)
|
||||
monkeypatch.setattr(proxy_server_module, "general_settings", {"infer_model_from_keys": False})
|
||||
monkeypatch.setattr(proxy_server_module, "user_model", None)
|
||||
monkeypatch.setitem(
|
||||
app.dependency_overrides,
|
||||
user_api_key_auth,
|
||||
lambda: UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN, api_key=MASTER_KEY, models=[], team_models=[]),
|
||||
)
|
||||
response: Final = TestClient(app).get(route)
|
||||
assert response.status_code == 200
|
||||
flags: Final = {row["model_name"]: row["model_info"]["supports_continuation"] for row in response.json()["data"]}
|
||||
assert flags == {"default": True, "override": False}
|
||||
|
||||
def test_model_info_v1_cli_model_returns_single_deployment_as_json(monkeypatch):
|
||||
"""
|
||||
A proxy started with `litellm --model <name>` answers /model/info with one deployment
|
||||
|
|
|
|||
|
|
@ -44,6 +44,16 @@ def test_azure_audio_snapshot_capabilities_match_declared_modalities(model: str,
|
|||
assert (litellm.supports_audio_input(model), litellm.supports_audio_output(model)) == expected
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model", ("gemini/gemini-4-argon", "vertex_ai/gemini-4-argon"))
|
||||
def test_gemini_long_decode_capability_is_exposed(model: str, local_model_cost_map: None) -> None:
|
||||
# Google long decode documentation, verified 2026-10-30: https://ai.google.dev/gemini-api/docs/generate-content/long-decode
|
||||
catalog: Final = TypeAdapter(dict[str, JsonValue]).validate_json(PRICES_PATH.read_bytes())
|
||||
backup: Final = TypeAdapter(dict[str, JsonValue]).validate_json(BACKUP_PRICES_PATH.read_bytes())
|
||||
assert catalog[model] == backup[model]
|
||||
assert litellm.get_model_info(model)["supports_continuation"] is True
|
||||
assert litellm.supports_continuation(model) is True
|
||||
|
||||
class _CopilotEndpointRow(BaseModel):
|
||||
model_config = ConfigDict(frozen=True, extra="ignore")
|
||||
|
||||
|
|
|
|||
|
|
@ -476,6 +476,20 @@ def test_supports_video_input_reads_its_own_cost_map_flag(
|
|||
assert litellm.get_model_info(model)["supports_video_input"] is video_input
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize("declared", (True, False, None))
|
||||
def test_continuation_capability_reads_declared_model_info(
|
||||
local_model_cost_map: None, monkeypatch: pytest.MonkeyPatch, declared: bool | None
|
||||
) -> None:
|
||||
model: Final = "openai/continuation-capability-test"
|
||||
monkeypatch.setitem(
|
||||
litellm.model_cost,
|
||||
model,
|
||||
{"litellm_provider": "openai", "mode": "chat", "supports_continuation": declared},
|
||||
)
|
||||
assert litellm.get_model_info(model)["supports_continuation"] is declared
|
||||
assert litellm.supports_continuation(model) is (declared is True)
|
||||
|
||||
def test_get_optional_params_image_gen():
|
||||
from litellm.llms.azure.image_generation import AzureGPTImageGenerationConfig
|
||||
|
||||
|
|
@ -1175,6 +1189,7 @@ _COST_MAP_ROW_SCHEMA: Final = {
|
|||
"supports_tool_search": {"type": "boolean"},
|
||||
"supports_video_input": {"type": "boolean"},
|
||||
"supports_box_questions": {"type": "boolean"},
|
||||
"supports_continuation": {"type": "boolean"},
|
||||
"supports_vision": {"type": "boolean"},
|
||||
"supports_web_search": {"type": "boolean"},
|
||||
"token_count_framing": {"type": "integer"},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue