fix(oci): preserve all Gemini system instructions (#48813) (#49458)

This commit is contained in:
ishaan-j-berri 2026-10-31 10:49:53 -07:00 • committed by GitHub
parent 6e27da8af9
commit 54892d6a62
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 86 additions and 4 deletions

View file

@ -20,7 +20,11 @@ import litellm
from litellm._logging import verbose_logger
from litellm.constants import DEFAULT_OCI_CHAT_MAX_TOKENS
from litellm.litellm_core_utils.logging_utils import track_llm_api_timing
from litellm.litellm_core_utils.prompt_templates.common_utils import messages_with_file_parts_as_image_urls
from litellm.litellm_core_utils.prompt_templates.common_utils import (
merge_consecutive_system_messages,
messages_with_file_parts_as_image_urls,
system_messages_first,
)
from litellm.litellm_core_utils.reasoning_effort_capability import declared_reasoning_efforts_for_model
from litellm.litellm_core_utils.reasoning_effort_utils import warn_dropped_reasoning
from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper
@ -693,14 +697,18 @@ class OCIChatConfig(BaseConfig):
chatRequest=chat_request,
)
else:
generic_messages: Final = list(messages_with_file_parts_as_image_urls(messages))
normalized_messages: Final = (
merge_consecutive_system_messages(system_messages_first(generic_messages))
if model.lower().removeprefix("oci/").startswith("google.gemini")
else generic_messages
)
data = OCICompletionPayload(
compartmentId=oci_compartment_id,
servingMode=serving_mode,
chatRequest=OCIChatRequestPayload(
apiFormat=vendor.value,
messages=adapt_messages_to_generic_oci_standard(
list(messages_with_file_parts_as_image_urls(messages))
),
messages=adapt_messages_to_generic_oci_standard(normalized_messages),
**self._get_optional_params(vendor, optional_params, model),
),
)

View file

@ -1,4 +1,5 @@
import datetime
import copy
import logging
from typing import Final
import httpx
@ -16,6 +17,8 @@ from litellm.llms.oci.chat.transformation import (
OCIRequestWrapper,
version,
)
from litellm.types.llms.oci import OCIChatRequestPayload, OCICompletionPayload
from litellm.types.llms.openai import AllMessageValues
TEST_MODEL_NAME = "xai.grok-4"
TEST_MODEL = f"oci/{TEST_MODEL_NAME}"
@ -2205,3 +2208,74 @@ def test_transform_request_sends_a_pdf_file_part_as_an_image_data_url() -> None:
],
}
]
@pytest.mark.parametrize("model", ["google.gemini-2.5-flash", "oci/google.gemini-2.5-flash"])
@pytest.mark.parametrize("multipart", [False, True])
@pytest.mark.parametrize("interleaved", [False, True])
def test_gemini_preserves_all_system_instructions(model: str, multipart: bool, interleaved: bool) -> None:
first: Final = "End every answer with PINEAPPLE."
second: Final = "Start every answer with BANANA."
conversation: Final[list[AllMessageValues]] = [
{"role": "user", "content": "What is 2+2?"},
{"role": "assistant", "content": "Four."},
]
messages: Final[list[AllMessageValues]] = [
{"role": "system", "content": first},
*(conversation if interleaved else []),
{"role": "system", "content": [{"type": "text", "text": second}] if multipart else second},
*(conversation if not interleaved else []),
{"role": "user", "content": "Repeat it."},
]
original: Final = copy.deepcopy(messages)
payload: Final = OCICompletionPayload.model_validate(
OCIChatConfig().transform_request(
model=model,
messages=messages,
optional_params={"oci_compartment_id": TEST_COMPARTMENT_ID},
litellm_params={},
headers={},
)
)
chat: Final = payload.chatRequest
assert isinstance(chat, OCIChatRequestPayload)
assert [message.role for message in chat.messages] == ["SYSTEM", "USER", "ASSISTANT", "USER"]
assert chat.messages[0].model_dump(exclude_none=True) == {
"role": "SYSTEM",
"content": (
[{"type": "TEXT", "text": first}, {"type": "TEXT", "text": second}]
if multipart
else [{"type": "TEXT", "text": f"{first}\n\n{second}"}]
),
}
assert [message.model_dump(exclude_none=True) for message in chat.messages[1:]] == [
{"role": "USER", "content": [{"type": "TEXT", "text": "What is 2+2?"}]},
{"role": "ASSISTANT", "content": [{"type": "TEXT", "text": "Four."}]},
{"role": "USER", "content": [{"type": "TEXT", "text": "Repeat it."}]},
]
assert messages == original
@pytest.mark.parametrize("model", ["xai.grok-4", "meta.llama-4-maverick"])
def test_other_oci_models_preserve_system_message_positions(model: str) -> None:
messages: Final[list[AllMessageValues]] = [
{"role": "system", "content": "Agent prompt."},
{"role": "user", "content": "Hello."},
{"role": "system", "content": "Conversation summary."},
]
payload: Final = OCICompletionPayload.model_validate(
OCIChatConfig().transform_request(
model=model,
messages=messages,
optional_params={"oci_compartment_id": TEST_COMPARTMENT_ID},
litellm_params={},
headers={},
)
)
chat: Final = payload.chatRequest
assert isinstance(chat, OCIChatRequestPayload)
assert [message.model_dump(exclude_none=True) for message in chat.messages] == [
{"role": "SYSTEM", "content": [{"type": "TEXT", "text": "Agent prompt."}]},
{"role": "USER", "content": [{"type": "TEXT", "text": "Hello."}]},
{"role": "SYSTEM", "content": [{"type": "TEXT", "text": "Conversation summary."}]},
]