Merge pull request #19661 from Chesars/fix/oci-image-url-format

fix(oci): serialize imageUrl as object for OCI GenAI API
This commit is contained in:
Sameer Kankute 2026-01-28 15:26:50 +05:30 committed by GitHub
commit 4f7425df0c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 45 additions and 4 deletions

View file

@ -32,6 +32,7 @@ from litellm.types.llms.oci import (
OCICompletionResponse,
OCIContentPartUnion,
OCIImageContentPart,
OCIImageUrl,
OCIMessage,
OCIRoles,
OCIServingMode,
@ -1129,7 +1130,7 @@ def adapt_messages_to_generic_oci_standard_content_message(
image_url = image_url.get("url")
if not isinstance(image_url, str):
raise Exception("Prop `image_url` must be a string or an object with a `url` property")
new_content.append(OCIImageContentPart(imageUrl=image_url))
new_content.append(OCIImageContentPart(imageUrl=OCIImageUrl(url=image_url)))
return OCIMessage(
role=open_ai_to_generic_oci_role_map[role],

View file

@ -35,11 +35,18 @@ class OCITextContentPart(OCIContentPart):
text: str
class OCIImageUrl(BaseModel):
"""ImageUrl object for OCI API. See: https://docs.oracle.com/en-us/iaas/tools/python/latest/api/generative_ai_inference/models/oci.generative_ai_inference.models.ImageUrl.html"""
url: str
detail: Optional[Literal["AUTO", "HIGH", "LOW"]] = None
class OCIImageContentPart(OCIContentPart):
"""Image content part for the OCI API."""
type: Literal["IMAGE"] = "IMAGE"
imageUrl: str
imageUrl: OCIImageUrl
OCIContentPartUnion = Union[OCITextContentPart, OCIImageContentPart]

View file

@ -203,6 +203,7 @@ class TestOCIImageUrlTransformation:
"""Tests for OCI image_url format handling in multimodal messages.
Fixes: https://github.com/BerriAI/litellm/issues/18270
Fixes: https://github.com/BerriAI/litellm/issues/19589
"""
def test_image_url_as_string(self):
@ -224,7 +225,8 @@ class TestOCIImageUrlTransformation:
assert len(result) == 1
assert result[0].role == "USER"
assert len(result[0].content) == 2
assert result[0].content[1].imageUrl == "https://example.com/image.png"
# imageUrl is now an OCIImageUrl object with a 'url' property
assert result[0].content[1].imageUrl.url == "https://example.com/image.png"
def test_image_url_as_openai_object(self):
"""Test that image_url as OpenAI-style object {"url": "..."} works."""
@ -245,7 +247,38 @@ class TestOCIImageUrlTransformation:
assert len(result) == 1
assert result[0].role == "USER"
assert len(result[0].content) == 2
assert result[0].content[1].imageUrl == "https://example.com/image.png"
# imageUrl is now an OCIImageUrl object with a 'url' property
assert result[0].content[1].imageUrl.url == "https://example.com/image.png"
def test_image_url_serializes_as_object(self):
"""Test that imageUrl serializes as {"url": "..."} for OCI API.
Fixes: https://github.com/BerriAI/litellm/issues/19589
OCI expects imageUrl to be an object with a 'url' property, not a plain string.
"""
from litellm.llms.oci.chat.transformation import adapt_messages_to_generic_oci_standard
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image."},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,ABC123"}},
],
}
]
result = adapt_messages_to_generic_oci_standard(messages)
image_part = result[0].content[1]
# Serialize as OCI would receive it (with exclude_none=True)
serialized = image_part.model_dump(exclude_none=True)
# Verify the structure matches OCI's expected format
assert serialized == {
"type": "IMAGE",
"imageUrl": {"url": "data:image/png;base64,ABC123"}
}
def test_image_url_invalid_type_raises_error(self):
"""Test that invalid image_url type raises an error."""