diff --git a/tests/integration/translation/chat_completions/params/__init__.py b/tests/integration/translation/chat_completions/params/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/integration/translation/chat_completions/params/test_chat_completions_params_anthropic.py b/tests/integration/translation/chat_completions/params/test_chat_completions_params_anthropic.py new file mode 100644 index 00000000000..f909bbb9de0 --- /dev/null +++ b/tests/integration/translation/chat_completions/params/test_chat_completions_params_anthropic.py @@ -0,0 +1,53 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.chat_completions.bases.anthropic import CLAUDE_SONNET_4_6_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="temperature", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field(CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("temperature",), 0.37), +) +CLAUDE_SONNET_4_6_TOP_P_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="top_p", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field(CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("top_p",), 0.83), +) +CLAUDE_SONNET_4_6_STOP_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="stop", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "stop": ["<>"]}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("stop_sequences",), ["<>"] + ), +) +CLAUDE_SONNET_4_6_USER_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="user", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "user": "user-sentinel-01"}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("metadata", "user_id"), "user-sentinel-01" + ), +) + +CASES: Final = ( + CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE, + CLAUDE_SONNET_4_6_TOP_P_TEST_CASE, + CLAUDE_SONNET_4_6_STOP_TEST_CASE, + CLAUDE_SONNET_4_6_USER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_chat_completions_params_anthropic( + case: TranslationTestCase, gateway: Gateway, provider: SharedProvider +) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/chat_completions/params/test_chat_completions_params_azure.py b/tests/integration/translation/chat_completions/params/test_chat_completions_params_azure.py new file mode 100644 index 00000000000..315200e7867 --- /dev/null +++ b/tests/integration/translation/chat_completions/params/test_chat_completions_params_azure.py @@ -0,0 +1,93 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.chat_completions.bases.azure import GPT_5_4_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GPT_5_4_TEMPERATURE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="temperature", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("temperature",), 0.37), +) +GPT_5_4_TOP_P_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="top_p", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("top_p",), 0.83), +) +GPT_5_4_N_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="n", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "n": 2}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("n",), 2), +) +GPT_5_4_SEED_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="seed", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "seed": 4242}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("seed",), 4242), +) +GPT_5_4_USER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="user", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "user": "user-sentinel-01"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("user",), "user-sentinel-01"), +) +GPT_5_4_SERVICE_TIER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="service_tier", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "service_tier": "flex"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("service_tier",), "flex"), +) +GPT_5_4_PROMPT_CACHE_KEY_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="prompt_cache_key", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "prompt_cache_key": "pck-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("prompt_cache_key",), "pck-sentinel-01" + ), +) +GPT_5_4_SAFETY_IDENTIFIER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="safety_identifier", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "safety_identifier": "safety-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("safety_identifier",), "safety-sentinel-01" + ), +) +GPT_5_4_STORE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="store", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "store": False}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("store",), False), +) +GPT_5_4_VERBOSITY_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="verbosity", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "verbosity": "low"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("verbosity",), "low"), +) + +CASES: Final = ( + GPT_5_4_TEMPERATURE_TEST_CASE, + GPT_5_4_TOP_P_TEST_CASE, + GPT_5_4_N_TEST_CASE, + GPT_5_4_SEED_TEST_CASE, + GPT_5_4_USER_TEST_CASE, + GPT_5_4_SERVICE_TIER_TEST_CASE, + GPT_5_4_PROMPT_CACHE_KEY_TEST_CASE, + GPT_5_4_SAFETY_IDENTIFIER_TEST_CASE, + GPT_5_4_STORE_TEST_CASE, + GPT_5_4_VERBOSITY_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_chat_completions_params_azure(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/chat_completions/params/test_chat_completions_params_bedrock_converse.py b/tests/integration/translation/chat_completions/params/test_chat_completions_params_bedrock_converse.py new file mode 100644 index 00000000000..b5286904255 --- /dev/null +++ b/tests/integration/translation/chat_completions/params/test_chat_completions_params_bedrock_converse.py @@ -0,0 +1,57 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.chat_completions.bases.bedrock_converse import CLAUDE_SONNET_4_6_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="temperature", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inferenceConfig", "temperature"), 0.37 + ), +) +CLAUDE_SONNET_4_6_TOP_P_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="top_p", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inferenceConfig", "topP"), 0.83 + ), +) +CLAUDE_SONNET_4_6_STOP_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="stop", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "stop": ["<>"]}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inferenceConfig", "stopSequences"), ["<>"] + ), +) +CLAUDE_SONNET_4_6_SERVICE_TIER_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="service_tier", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "service_tier": "flex"}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("serviceTier", "type"), "flex" + ), +) + +CASES: Final = ( + CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE, + CLAUDE_SONNET_4_6_TOP_P_TEST_CASE, + CLAUDE_SONNET_4_6_STOP_TEST_CASE, + CLAUDE_SONNET_4_6_SERVICE_TIER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_chat_completions_params_bedrock_converse( + case: TranslationTestCase, gateway: Gateway, provider: SharedProvider +) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/chat_completions/params/test_chat_completions_params_gemini.py b/tests/integration/translation/chat_completions/params/test_chat_completions_params_gemini.py new file mode 100644 index 00000000000..cac7b9ee9c1 --- /dev/null +++ b/tests/integration/translation/chat_completions/params/test_chat_completions_params_gemini.py @@ -0,0 +1,73 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.chat_completions.bases.gemini import GEMINI_3_5_FLASH_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GEMINI_3_5_FLASH_TEMPERATURE_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="temperature", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "temperature"), 0.37 + ), +) +GEMINI_3_5_FLASH_TOP_P_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="top_p", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "top_p"), 0.83 + ), +) +GEMINI_3_5_FLASH_N_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="n", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "n": 2}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "candidate_count"), 2 + ), +) +GEMINI_3_5_FLASH_STOP_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="stop", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "stop": ["<>"]}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "stop_sequences"), ["<>"] + ), +) +GEMINI_3_5_FLASH_SEED_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="seed", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "seed": 4242}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "seed"), 4242 + ), +) +GEMINI_3_5_FLASH_SERVICE_TIER_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="service_tier", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "service_tier": "flex"}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("serviceTier",), "flex" + ), +) + +CASES: Final = ( + GEMINI_3_5_FLASH_TEMPERATURE_TEST_CASE, + GEMINI_3_5_FLASH_TOP_P_TEST_CASE, + GEMINI_3_5_FLASH_N_TEST_CASE, + GEMINI_3_5_FLASH_STOP_TEST_CASE, + GEMINI_3_5_FLASH_SEED_TEST_CASE, + GEMINI_3_5_FLASH_SERVICE_TIER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_chat_completions_params_gemini(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/chat_completions/params/test_chat_completions_params_openai.py b/tests/integration/translation/chat_completions/params/test_chat_completions_params_openai.py new file mode 100644 index 00000000000..09d5faeed8f --- /dev/null +++ b/tests/integration/translation/chat_completions/params/test_chat_completions_params_openai.py @@ -0,0 +1,93 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.chat_completions.bases.openai import GPT_5_4_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GPT_5_4_TEMPERATURE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="temperature", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("temperature",), 0.37), +) +GPT_5_4_TOP_P_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="top_p", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("top_p",), 0.83), +) +GPT_5_4_N_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="n", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "n": 2}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("n",), 2), +) +GPT_5_4_SEED_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="seed", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "seed": 4242}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("seed",), 4242), +) +GPT_5_4_USER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="user", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "user": "user-sentinel-01"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("user",), "user-sentinel-01"), +) +GPT_5_4_SERVICE_TIER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="service_tier", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "service_tier": "flex"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("service_tier",), "flex"), +) +GPT_5_4_PROMPT_CACHE_KEY_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="prompt_cache_key", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "prompt_cache_key": "pck-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("prompt_cache_key",), "pck-sentinel-01" + ), +) +GPT_5_4_SAFETY_IDENTIFIER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="safety_identifier", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "safety_identifier": "safety-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("safety_identifier",), "safety-sentinel-01" + ), +) +GPT_5_4_STORE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="store", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "store": False}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("store",), False), +) +GPT_5_4_VERBOSITY_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="verbosity", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "verbosity": "low"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("verbosity",), "low"), +) + +CASES: Final = ( + GPT_5_4_TEMPERATURE_TEST_CASE, + GPT_5_4_TOP_P_TEST_CASE, + GPT_5_4_N_TEST_CASE, + GPT_5_4_SEED_TEST_CASE, + GPT_5_4_USER_TEST_CASE, + GPT_5_4_SERVICE_TIER_TEST_CASE, + GPT_5_4_PROMPT_CACHE_KEY_TEST_CASE, + GPT_5_4_SAFETY_IDENTIFIER_TEST_CASE, + GPT_5_4_STORE_TEST_CASE, + GPT_5_4_VERBOSITY_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_chat_completions_params_openai(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/chat_completions/params/test_chat_completions_params_openai_responses.py b/tests/integration/translation/chat_completions/params/test_chat_completions_params_openai_responses.py new file mode 100644 index 00000000000..85633f53b02 --- /dev/null +++ b/tests/integration/translation/chat_completions/params/test_chat_completions_params_openai_responses.py @@ -0,0 +1,69 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.chat_completions.bases.openai_responses import GPT_5_6_SOL_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GPT_5_6_SOL_USER_TEST_CASE: Final = replace( + GPT_5_6_SOL_TEST_CASE, + scenario="user", + litellm_request={**GPT_5_6_SOL_TEST_CASE.litellm_request, "user": "user-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_6_SOL_TEST_CASE.expected_provider_request, ("user",), "user-sentinel-01" + ), +) +GPT_5_6_SOL_SERVICE_TIER_TEST_CASE: Final = replace( + GPT_5_6_SOL_TEST_CASE, + scenario="service_tier", + litellm_request={**GPT_5_6_SOL_TEST_CASE.litellm_request, "service_tier": "flex"}, + expected_provider_request=with_field(GPT_5_6_SOL_TEST_CASE.expected_provider_request, ("service_tier",), "flex"), +) +GPT_5_6_SOL_PROMPT_CACHE_KEY_TEST_CASE: Final = replace( + GPT_5_6_SOL_TEST_CASE, + scenario="prompt_cache_key", + litellm_request={**GPT_5_6_SOL_TEST_CASE.litellm_request, "prompt_cache_key": "pck-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_6_SOL_TEST_CASE.expected_provider_request, ("prompt_cache_key",), "pck-sentinel-01" + ), +) +GPT_5_6_SOL_SAFETY_IDENTIFIER_TEST_CASE: Final = replace( + GPT_5_6_SOL_TEST_CASE, + scenario="safety_identifier", + litellm_request={**GPT_5_6_SOL_TEST_CASE.litellm_request, "safety_identifier": "safety-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_6_SOL_TEST_CASE.expected_provider_request, ("safety_identifier",), "safety-sentinel-01" + ), +) +GPT_5_6_SOL_STORE_TEST_CASE: Final = replace( + GPT_5_6_SOL_TEST_CASE, + scenario="store", + litellm_request={**GPT_5_6_SOL_TEST_CASE.litellm_request, "store": False}, + expected_provider_request=with_field(GPT_5_6_SOL_TEST_CASE.expected_provider_request, ("store",), False), +) +GPT_5_6_SOL_VERBOSITY_TEST_CASE: Final = replace( + GPT_5_6_SOL_TEST_CASE, + scenario="verbosity", + litellm_request={**GPT_5_6_SOL_TEST_CASE.litellm_request, "verbosity": "low"}, + expected_provider_request=with_field(GPT_5_6_SOL_TEST_CASE.expected_provider_request, ("text", "verbosity"), "low"), +) + +CASES: Final = ( + GPT_5_6_SOL_USER_TEST_CASE, + GPT_5_6_SOL_SERVICE_TIER_TEST_CASE, + GPT_5_6_SOL_PROMPT_CACHE_KEY_TEST_CASE, + GPT_5_6_SOL_SAFETY_IDENTIFIER_TEST_CASE, + GPT_5_6_SOL_STORE_TEST_CASE, + GPT_5_6_SOL_VERBOSITY_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_chat_completions_params_openai_responses( + case: TranslationTestCase, gateway: Gateway, provider: SharedProvider +) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/messages/params/__init__.py b/tests/integration/translation/messages/params/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/integration/translation/messages/params/test_messages_params_anthropic.py b/tests/integration/translation/messages/params/test_messages_params_anthropic.py new file mode 100644 index 00000000000..47649fb7197 --- /dev/null +++ b/tests/integration/translation/messages/params/test_messages_params_anthropic.py @@ -0,0 +1,85 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.messages.bases.anthropic import CLAUDE_SONNET_4_6_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="temperature", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field(CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("temperature",), 0.37), +) +CLAUDE_SONNET_4_6_TOP_P_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="top_p", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field(CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("top_p",), 0.83), +) +CLAUDE_SONNET_4_6_TOP_K_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="top_k", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "top_k": 7}, + expected_provider_request=with_field(CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("top_k",), 7), +) +CLAUDE_SONNET_4_6_STOP_SEQUENCES_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="stop_sequences", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "stop_sequences": ["<>"]}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("stop_sequences",), ["<>"] + ), +) +CLAUDE_SONNET_4_6_METADATA_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="metadata", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "metadata": {"user_id": "meta-sentinel-01"}}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("metadata", "user_id"), "meta-sentinel-01" + ), +) +CLAUDE_SONNET_4_6_SERVICE_TIER_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="service_tier", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "service_tier": "auto"}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("service_tier",), "auto" + ), +) +CLAUDE_SONNET_4_6_INFERENCE_GEO_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="inference_geo", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "inference_geo": "us"}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inference_geo",), "us" + ), +) +CLAUDE_SONNET_4_6_CONTAINER_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="container", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "container": "container_sentinel01"}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("container",), "container_sentinel01" + ), +) + +CASES: Final = ( + CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE, + CLAUDE_SONNET_4_6_TOP_P_TEST_CASE, + CLAUDE_SONNET_4_6_TOP_K_TEST_CASE, + CLAUDE_SONNET_4_6_STOP_SEQUENCES_TEST_CASE, + CLAUDE_SONNET_4_6_METADATA_TEST_CASE, + CLAUDE_SONNET_4_6_SERVICE_TIER_TEST_CASE, + CLAUDE_SONNET_4_6_INFERENCE_GEO_TEST_CASE, + CLAUDE_SONNET_4_6_CONTAINER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_messages_params_anthropic(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/messages/params/test_messages_params_azure.py b/tests/integration/translation/messages/params/test_messages_params_azure.py new file mode 100644 index 00000000000..73da50a86f2 --- /dev/null +++ b/tests/integration/translation/messages/params/test_messages_params_azure.py @@ -0,0 +1,47 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.messages.bases.azure import GPT_5_4_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GPT_5_4_TEMPERATURE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="temperature", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("temperature",), 0.37), +) +GPT_5_4_TOP_P_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="top_p", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("top_p",), 0.83), +) +GPT_5_4_METADATA_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="metadata", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "metadata": {"user_id": "meta-sentinel-01"}}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("user",), "meta-sentinel-01"), +) +GPT_5_4_SERVICE_TIER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="service_tier", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "service_tier": "auto"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("service_tier",), "auto"), +) + +CASES: Final = ( + GPT_5_4_TEMPERATURE_TEST_CASE, + GPT_5_4_TOP_P_TEST_CASE, + GPT_5_4_METADATA_TEST_CASE, + GPT_5_4_SERVICE_TIER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_messages_params_azure(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/messages/params/test_messages_params_bedrock_converse.py b/tests/integration/translation/messages/params/test_messages_params_bedrock_converse.py new file mode 100644 index 00000000000..33efbc6ef15 --- /dev/null +++ b/tests/integration/translation/messages/params/test_messages_params_bedrock_converse.py @@ -0,0 +1,66 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.messages.bases.bedrock_converse import CLAUDE_SONNET_4_6_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="temperature", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inferenceConfig", "temperature"), 0.37 + ), +) +CLAUDE_SONNET_4_6_TOP_P_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="top_p", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inferenceConfig", "topP"), 0.83 + ), +) +CLAUDE_SONNET_4_6_TOP_K_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="top_k", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "top_k": 7}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("additionalModelRequestFields", "top_k"), 7 + ), +) +CLAUDE_SONNET_4_6_STOP_SEQUENCES_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="stop_sequences", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "stop_sequences": ["<>"]}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inferenceConfig", "stopSequences"), ["<>"] + ), +) +CLAUDE_SONNET_4_6_INFERENCE_GEO_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="inference_geo", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "inference_geo": "us"}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("additionalModelRequestFields", "inference_geo"), "us" + ), +) + +CASES: Final = ( + CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE, + CLAUDE_SONNET_4_6_TOP_P_TEST_CASE, + CLAUDE_SONNET_4_6_TOP_K_TEST_CASE, + CLAUDE_SONNET_4_6_STOP_SEQUENCES_TEST_CASE, + CLAUDE_SONNET_4_6_INFERENCE_GEO_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_messages_params_bedrock_converse( + case: TranslationTestCase, gateway: Gateway, provider: SharedProvider +) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/messages/params/test_messages_params_gemini.py b/tests/integration/translation/messages/params/test_messages_params_gemini.py new file mode 100644 index 00000000000..a77b576015a --- /dev/null +++ b/tests/integration/translation/messages/params/test_messages_params_gemini.py @@ -0,0 +1,55 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.messages.bases.gemini import GEMINI_3_5_FLASH_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GEMINI_3_5_FLASH_TEMPERATURE_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="temperature", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "temperature"), 0.37 + ), +) +GEMINI_3_5_FLASH_TOP_P_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="top_p", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "top_p"), 0.83 + ), +) +GEMINI_3_5_FLASH_TOP_K_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="top_k", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "top_k": 7}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "top_k"), 7 + ), +) +GEMINI_3_5_FLASH_STOP_SEQUENCES_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="stop_sequences", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "stop_sequences": ["<>"]}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "stop_sequences"), ["<>"] + ), +) + +CASES: Final = ( + GEMINI_3_5_FLASH_TEMPERATURE_TEST_CASE, + GEMINI_3_5_FLASH_TOP_P_TEST_CASE, + GEMINI_3_5_FLASH_TOP_K_TEST_CASE, + GEMINI_3_5_FLASH_STOP_SEQUENCES_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_messages_params_gemini(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/messages/params/test_messages_params_openai.py b/tests/integration/translation/messages/params/test_messages_params_openai.py new file mode 100644 index 00000000000..d1df0c1c912 --- /dev/null +++ b/tests/integration/translation/messages/params/test_messages_params_openai.py @@ -0,0 +1,47 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.messages.bases.openai import GPT_5_4_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GPT_5_4_TEMPERATURE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="temperature", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("temperature",), 0.37), +) +GPT_5_4_TOP_P_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="top_p", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("top_p",), 0.83), +) +GPT_5_4_METADATA_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="metadata", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "metadata": {"user_id": "meta-sentinel-01"}}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("user",), "meta-sentinel-01"), +) +GPT_5_4_SERVICE_TIER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="service_tier", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "service_tier": "auto"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("service_tier",), "auto"), +) + +CASES: Final = ( + GPT_5_4_TEMPERATURE_TEST_CASE, + GPT_5_4_TOP_P_TEST_CASE, + GPT_5_4_METADATA_TEST_CASE, + GPT_5_4_SERVICE_TIER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_messages_params_openai(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/params.py b/tests/integration/translation/params.py new file mode 100644 index 00000000000..30681d3aa71 --- /dev/null +++ b/tests/integration/translation/params.py @@ -0,0 +1,13 @@ +from collections.abc import Mapping, Sequence +from typing import Final + +from pydantic import JsonValue + + +def with_field(mapping: Mapping[str, JsonValue], path: Sequence[str], value: JsonValue) -> Mapping[str, JsonValue]: + """Return a copy of `mapping` with the nested key `path` set to `value`, creating intermediate objects.""" + head: Final = path[0] + if len(path) == 1: + return {**mapping, head: value} + inner: Final = mapping.get(head) + return {**mapping, head: with_field(inner if isinstance(inner, dict) else {}, path[1:], value)} diff --git a/tests/integration/translation/responses/params/__init__.py b/tests/integration/translation/responses/params/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/integration/translation/responses/params/test_responses_params_anthropic.py b/tests/integration/translation/responses/params/test_responses_params_anthropic.py new file mode 100644 index 00000000000..b5c79e8f736 --- /dev/null +++ b/tests/integration/translation/responses/params/test_responses_params_anthropic.py @@ -0,0 +1,45 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.responses.bases.anthropic import CLAUDE_SONNET_4_6_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="temperature", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field(CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("temperature",), 0.37), + expected_litellm_response={**CLAUDE_SONNET_4_6_TEST_CASE.expected_litellm_response, "temperature": 0.37}, +) +CLAUDE_SONNET_4_6_TOP_P_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="top_p", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field(CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("top_p",), 0.83), + expected_litellm_response={**CLAUDE_SONNET_4_6_TEST_CASE.expected_litellm_response, "top_p": 0.83}, +) +CLAUDE_SONNET_4_6_USER_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="user", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "user": "user-sentinel-01"}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("metadata", "user_id"), "user-sentinel-01" + ), + expected_litellm_response={**CLAUDE_SONNET_4_6_TEST_CASE.expected_litellm_response, "user": "user-sentinel-01"}, +) + +CASES: Final = ( + CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE, + CLAUDE_SONNET_4_6_TOP_P_TEST_CASE, + CLAUDE_SONNET_4_6_USER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_responses_params_anthropic(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/responses/params/test_responses_params_bedrock_converse.py b/tests/integration/translation/responses/params/test_responses_params_bedrock_converse.py new file mode 100644 index 00000000000..4937877721b --- /dev/null +++ b/tests/integration/translation/responses/params/test_responses_params_bedrock_converse.py @@ -0,0 +1,50 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.responses.bases.bedrock_converse import CLAUDE_SONNET_4_6_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="temperature", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inferenceConfig", "temperature"), 0.37 + ), + expected_litellm_response={**CLAUDE_SONNET_4_6_TEST_CASE.expected_litellm_response, "temperature": 0.37}, +) +CLAUDE_SONNET_4_6_TOP_P_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="top_p", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("inferenceConfig", "topP"), 0.83 + ), + expected_litellm_response={**CLAUDE_SONNET_4_6_TEST_CASE.expected_litellm_response, "top_p": 0.83}, +) +CLAUDE_SONNET_4_6_SERVICE_TIER_TEST_CASE: Final = replace( + CLAUDE_SONNET_4_6_TEST_CASE, + scenario="service_tier", + litellm_request={**CLAUDE_SONNET_4_6_TEST_CASE.litellm_request, "service_tier": "flex"}, + expected_provider_request=with_field( + CLAUDE_SONNET_4_6_TEST_CASE.expected_provider_request, ("serviceTier", "type"), "flex" + ), +) + +CASES: Final = ( + CLAUDE_SONNET_4_6_TEMPERATURE_TEST_CASE, + CLAUDE_SONNET_4_6_TOP_P_TEST_CASE, + CLAUDE_SONNET_4_6_SERVICE_TIER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_responses_params_bedrock_converse( + case: TranslationTestCase, gateway: Gateway, provider: SharedProvider +) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/responses/params/test_responses_params_gemini.py b/tests/integration/translation/responses/params/test_responses_params_gemini.py new file mode 100644 index 00000000000..c5547302d35 --- /dev/null +++ b/tests/integration/translation/responses/params/test_responses_params_gemini.py @@ -0,0 +1,48 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.responses.bases.gemini import GEMINI_3_5_FLASH_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GEMINI_3_5_FLASH_TEMPERATURE_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="temperature", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "temperature"), 0.37 + ), + expected_litellm_response={**GEMINI_3_5_FLASH_TEST_CASE.expected_litellm_response, "temperature": 0.37}, +) +GEMINI_3_5_FLASH_TOP_P_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="top_p", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("generationConfig", "top_p"), 0.83 + ), + expected_litellm_response={**GEMINI_3_5_FLASH_TEST_CASE.expected_litellm_response, "top_p": 0.83}, +) +GEMINI_3_5_FLASH_SERVICE_TIER_TEST_CASE: Final = replace( + GEMINI_3_5_FLASH_TEST_CASE, + scenario="service_tier", + litellm_request={**GEMINI_3_5_FLASH_TEST_CASE.litellm_request, "service_tier": "flex"}, + expected_provider_request=with_field( + GEMINI_3_5_FLASH_TEST_CASE.expected_provider_request, ("serviceTier",), "flex" + ), +) + +CASES: Final = ( + GEMINI_3_5_FLASH_TEMPERATURE_TEST_CASE, + GEMINI_3_5_FLASH_TOP_P_TEST_CASE, + GEMINI_3_5_FLASH_SERVICE_TIER_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_responses_params_gemini(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider) diff --git a/tests/integration/translation/responses/params/test_responses_params_openai.py b/tests/integration/translation/responses/params/test_responses_params_openai.py new file mode 100644 index 00000000000..8fc6235c008 --- /dev/null +++ b/tests/integration/translation/responses/params/test_responses_params_openai.py @@ -0,0 +1,120 @@ +from dataclasses import replace +from typing import Final + +import pytest +from integration._support.client import Gateway +from integration._support.provider import SharedProvider +from integration.translation.case import TranslationTestCase +from integration.translation.responses.bases.openai import GPT_5_4_TEST_CASE +from integration.translation.params import with_field +from integration.translation.runner import assert_translation + +GPT_5_4_TEMPERATURE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="temperature", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "temperature": 0.37}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("temperature",), 0.37), +) +GPT_5_4_TOP_P_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="top_p", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "top_p": 0.83}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("top_p",), 0.83), +) +GPT_5_4_METADATA_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="metadata", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "metadata": {"trace_id": "meta-sentinel-01"}}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("metadata", "trace_id"), "meta-sentinel-01" + ), +) +GPT_5_4_USER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="user", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "user": "user-sentinel-01"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("user",), "user-sentinel-01"), +) +GPT_5_4_SAFETY_IDENTIFIER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="safety_identifier", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "safety_identifier": "safety-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("safety_identifier",), "safety-sentinel-01" + ), +) +GPT_5_4_PROMPT_CACHE_KEY_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="prompt_cache_key", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "prompt_cache_key": "pck-sentinel-01"}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("prompt_cache_key",), "pck-sentinel-01" + ), +) +GPT_5_4_TEXT_VERBOSITY_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="text_verbosity", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "text": {"verbosity": "low"}}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("text", "verbosity"), "low"), +) +GPT_5_4_STORE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="store", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "store": False}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("store",), False), +) +GPT_5_4_INCLUDE_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="include", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "include": ["reasoning.encrypted_content"]}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("include",), ["reasoning.encrypted_content"] + ), +) +GPT_5_4_TRUNCATION_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="truncation", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "truncation": "auto"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("truncation",), "auto"), +) +GPT_5_4_SERVICE_TIER_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="service_tier", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "service_tier": "flex"}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("service_tier",), "flex"), +) +GPT_5_4_TOP_LOGPROBS_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="top_logprobs", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "top_logprobs": 3}, + expected_provider_request=with_field(GPT_5_4_TEST_CASE.expected_provider_request, ("top_logprobs",), 3), +) +GPT_5_4_PROMPT_CACHE_RETENTION_TEST_CASE: Final = replace( + GPT_5_4_TEST_CASE, + scenario="prompt_cache_retention", + litellm_request={**GPT_5_4_TEST_CASE.litellm_request, "prompt_cache_retention": "24h"}, + expected_provider_request=with_field( + GPT_5_4_TEST_CASE.expected_provider_request, ("prompt_cache_retention",), "24h" + ), +) + +CASES: Final = ( + GPT_5_4_TEMPERATURE_TEST_CASE, + GPT_5_4_TOP_P_TEST_CASE, + GPT_5_4_METADATA_TEST_CASE, + GPT_5_4_USER_TEST_CASE, + GPT_5_4_SAFETY_IDENTIFIER_TEST_CASE, + GPT_5_4_PROMPT_CACHE_KEY_TEST_CASE, + GPT_5_4_TEXT_VERBOSITY_TEST_CASE, + GPT_5_4_STORE_TEST_CASE, + GPT_5_4_INCLUDE_TEST_CASE, + GPT_5_4_TRUNCATION_TEST_CASE, + GPT_5_4_SERVICE_TIER_TEST_CASE, + GPT_5_4_TOP_LOGPROBS_TEST_CASE, + GPT_5_4_PROMPT_CACHE_RETENTION_TEST_CASE, +) + + +@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id) +def test_responses_params_openai(case: TranslationTestCase, gateway: Gateway, provider: SharedProvider) -> None: + assert_translation(case, gateway, provider)