How to Convert OpenAI Message Payloads to Gemini Contents
Converting from OpenAI to Gemini requires three structural changes: moving the system prompt, renaming a role, and wrapping content in a parts array. The conversation content itself transfers unchanged — only the container format changes.
Side-by-side format comparison
The same two-turn conversation in both formats:
// OpenAI format
{
"model": "gpt-4o",
"messages": [
{"role": "system", "content": "You summarise text concisely."},
{"role": "user", "content": "Summarise: The quick brown fox..."},
{"role": "assistant", "content": "A fox jumps over a lazy dog."},
{"role": "user", "content": "Make it shorter."}
]
}
// Gemini format
{
"system_instruction": {
"parts": [{"text": "You summarise text concisely."}]
},
"contents": [
{"role": "user", "parts": [{"text": "Summarise: The quick brown fox..."}]},
{"role": "model", "parts": [{"text": "A fox jumps over a lazy dog."}]},
{"role": "user", "parts": [{"text": "Make it shorter."}]}
]
}
The three changes
1. System prompt moves out of messages. Any message with "role": "system" must be removed from the messages array and its content placed in system_instruction.parts[0].text. Gemini ignores system messages left in the contents array.
2. "assistant" becomes "model". Every message with "role": "assistant" becomes "role": "model". User messages stay as "role": "user".
3. Content becomes parts array. Every "content": "text" becomes "parts": [{"text": "text"}]. This wrapping is required even for simple text messages.
The messages array key becomes contents.
Step-by-step in code
# Python — convert OpenAI payload to Gemini
def openai_to_gemini(payload):
system_texts = []
contents = []
for msg in payload.get("messages", []):
role = msg["role"]
content = msg["content"]
if role == "system":
system_texts.append(content)
else:
gemini_role = "model" if role == "assistant" else "user"
contents.append({
"role": gemini_role,
"parts": [{"text": content}]
})
result = {"contents": contents}
if system_texts:
result["system_instruction"] = {
"parts": [{"text": " ".join(system_texts)}]
}
return result
Multi-modal and multi-part content
For text-only messages, each part is a single text object. For messages with images, each part is either a text object or an inline data object. The parts array structure is Gemini's way of supporting mixed content in a single message — text plus image, for example. For text-only prompts, the parts array always has exactly one text element.
gemini-1.5-pro, gemini-1.5-flash, or the current recommended model name from Google's documentation. OpenAI model names like gpt-4o are not valid Gemini model identifiers.