Skip to content

Conversation

@tinyc0der
Copy link

Summary

  • Adds missing index field to image objects in OpenAI-compatible responses
  • Fixes LiteLLM Pydantic validation error: "images.0.index Field required"

Test plan

  • Verify image generation responses include index field
  • Test with LiteLLM client to confirm validation passes

LiteLLM's Pydantic model requires an index field in each image object.
Without it, responses fail validation with "images.0.index Field required".
@gemini-code-assist
Copy link

Summary of Changes

Hello @tinyc0der, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a compatibility issue with LiteLLM by enhancing the structure of OpenAI-compatible image responses. It introduces an index field to each image object, which is crucial for LiteLLM's Pydantic validation, thereby preventing errors and ensuring seamless integration.

Highlights

  • LiteLLM Compatibility: Adds the necessary index field to image objects within OpenAI-compatible responses to ensure proper validation with LiteLLM.
  • Pydantic Validation Fix: Resolves a Pydantic validation error in LiteLLM clients that specifically complained about a missing index field in image responses.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly adds the index field to image objects in OpenAI-compatible responses, which resolves the Pydantic validation error in LiteLLM. The implementation is straightforward and addresses the issue described. My review focuses on improving the maintainability of the changes. The logic for creating the image payload has been duplicated in four different places across three files. I've left comments suggesting a refactoring to a shared helper function to reduce this duplication, which will make the code easier to maintain in the future. I've also suggested using a struct for JSON marshaling for better type safety and readability, and adding logging for marshaling errors where a logger is available.

Comment on lines +189 to +201
imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())
imagePayload, err := json.Marshal(map[string]any{
"index": imageIndex,
"type": "image_url",
"image_url": map[string]string{
"url": imageURL,
},
})
if err != nil {
continue
}
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", imagePayload)
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code for creating and appending an image payload is duplicated in other response translator files (gemini-cli_openai_response.go, gemini_openai_response.go). To improve maintainability and reduce redundancy, consider extracting this logic into a single, reusable helper function in a shared package.

For better type safety and readability, it's also recommended to use a struct for JSON marshaling instead of a map[string]any.

Finally, it would be beneficial to log the error from json.Marshal to aid in debugging, as it's currently being silently ignored.

				imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())

				type imagePayload struct {
					Index    int               `json:"index"`
					Type     string            `json:"type"`
					ImageURL map[string]string `json:"image_url"`
				}

				payload := imagePayload{
					Index: imageIndex,
					Type:  "image_url",
					ImageURL: map[string]string{
						"url": imageURL,
					},
				}

				imagePayloadBytes, err := json.Marshal(payload)
				if err != nil {
					log.Warnf("antigravity openai response: failed to marshal image payload: %v", err)
					continue
				}
				template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
				template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayloadBytes))

Comment on lines +178 to +190
imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())
imagePayload, err := json.Marshal(map[string]any{
"index": imageIndex,
"type": "image_url",
"image_url": map[string]string{
"url": imageURL,
},
})
if err != nil {
continue
}
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", imagePayload)
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code for creating and appending an image payload is duplicated in other response translator files (antigravity_openai_response.go, gemini_openai_response.go). To improve maintainability and reduce redundancy, consider extracting this logic into a single, reusable helper function in a shared package.

Additionally, for better type safety and readability, it's recommended to use a struct for JSON marshaling instead of a map[string]any.

				imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())

				type imagePayload struct {
					Index    int               `json:"index"`
					Type     string            `json:"type"`
					ImageURL map[string]string `json:"image_url"`
				}

				payload := imagePayload{
					Index: imageIndex,
					Type:  "image_url",
					ImageURL: map[string]string{
						"url": imageURL,
					},
				}

				imagePayloadBytes, err := json.Marshal(payload)
				if err != nil {
					continue
				}
				template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
				template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayloadBytes))

Comment on lines +190 to +202
imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())
imagePayload, err := json.Marshal(map[string]any{
"index": imageIndex,
"type": "image_url",
"image_url": map[string]string{
"url": imageURL,
},
})
if err != nil {
continue
}
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", imagePayload)
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code for creating and appending an image payload is duplicated elsewhere in this file and in other response translator files. To improve maintainability and reduce redundancy, consider extracting this logic into a single, reusable helper function.

For better type safety and readability, it's also recommended to use a struct for JSON marshaling instead of a map[string]any.

Finally, it would be beneficial to log the error from json.Marshal to aid in debugging.

				imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())

				type imagePayload struct {
					Index    int               `json:"index"`
					Type     string            `json:"type"`
					ImageURL map[string]string `json:"image_url"`
				}

				payload := imagePayload{
					Index: imageIndex,
					Type:  "image_url",
					ImageURL: map[string]string{
						"url": imageURL,
					},
				}

				imagePayloadBytes, err := json.Marshal(payload)
				if err != nil {
					log.Warnf("gemini openai response: failed to marshal image payload in streaming: %v", err)
					continue
				}
				template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
				template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayloadBytes))

Comment on lines +333 to +345
imageIndex := len(gjson.Get(template, "choices.0.message.images").Array())
imagePayload, err := json.Marshal(map[string]any{
"index": imageIndex,
"type": "image_url",
"image_url": map[string]string{
"url": imageURL,
},
})
if err != nil {
continue
}
template, _ = sjson.Set(template, "choices.0.message.role", "assistant")
template, _ = sjson.SetRaw(template, "choices.0.message.images.-1", imagePayload)
template, _ = sjson.SetRaw(template, "choices.0.message.images.-1", string(imagePayload))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code for creating and appending an image payload is duplicated elsewhere in this file and in other response translator files. To improve maintainability and reduce redundancy, consider extracting this logic into a single, reusable helper function.

For better type safety and readability, it's also recommended to use a struct for JSON marshaling instead of a map[string]any.

Finally, it would be beneficial to log the error from json.Marshal to aid in debugging.

				imageIndex := len(gjson.Get(template, "choices.0.message.images").Array())

				type imagePayload struct {
					Index    int               `json:"index"`
					Type     string            `json:"type"`
					ImageURL map[string]string `json:"image_url"`
				}

				payload := imagePayload{
					Index: imageIndex,
					Type:  "image_url",
					ImageURL: map[string]string{
						"url": imageURL,
					},
				}

				imagePayloadBytes, err := json.Marshal(payload)
				if err != nil {
					log.Warnf("gemini openai response: failed to marshal image payload in non-streaming: %v", err)
					continue
				}
				template, _ = sjson.Set(template, "choices.0.message.role", "assistant")
				template, _ = sjson.SetRaw(template, "choices.0.message.images.-1", string(imagePayloadBytes))

@tinyc0der tinyc0der closed this Dec 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant