on outputs is unsafe. Create an adapter that normalizes the response structure, prioritizing the new schema while supporting the legacy format during the transition window.
interface GeminiStep {
type: 'model_output' | 'function_call' | 'user_input' | 'thought';
content?: Array<{ type: 'text'; text: string }>;
name?: string;
arguments?: Record<string, unknown>;
summary?: Array<{ type: 'text'; text: string }>;
}
interface GeminiInteractionPayload {
id: string;
status: string;
// New schema fields
steps?: GeminiStep[];
// Legacy fallback fields
outputs?: Array<{ type: string; text?: string }>;
}
class InteractionResponseAdapter {
private payload: GeminiInteractionPayload;
constructor(raw: GeminiInteractionPayload) {
this.payload = raw;
}
extractFinalText(): string {
// Prefer new schema structure
if (this.payload.steps) {
const lastStep = this.payload.steps[this.payload.steps.length - 1];
if (lastStep?.type === 'model_output' && lastStep.content?.[0]?.text) {
return lastStep.content[0].text;
}
}
// Fallback for legacy payload during transition
if (this.payload.outputs?.length) {
const lastOutput = this.payload.outputs[this.payload.outputs.length - 1];
return lastOutput.text || '';
}
return '';
}
extractToolCalls(): Array<{ name: string; args: Record<string, unknown> }> {
const targetArray = this.payload.steps || this.payload.outputs || [];
return targetArray
.filter((item: any) => item.type === 'function_call')
.map((item: any) => ({
name: item.name,
args: item.arguments || {}
}));
}
}
Rationale: This adapter isolates schema volatility. By checking steps first, you align with the post-May 26 default. The fallback ensures continuity if you temporarily pin the legacy header.
2. Refactor Request Builders for Polymorphic Formats
The response_mime_type field is deprecated at the top level. All format specifications must move into the response_format object. This applies to JSON mode and image generation.
function constructGenerationRequest(
model: string,
prompt: string,
options: { isJsonMode?: boolean; aspectRatio?: string }
) {
const baseRequest = { model, input: prompt };
if (options.isJsonMode) {
return {
...baseRequest,
response_format: {
type: 'text',
mime_type: 'application/json',
schema: {
type: 'object',
properties: {
summary: { type: 'string' },
confidence_score: { type: 'number' }
},
required: ['summary']
}
}
};
}
if (options.aspectRatio) {
return {
...baseRequest,
response_format: {
type: 'image',
mime_type: 'image/jpeg',
aspect_ratio: options.aspectRatio,
image_size: '1K'
}
};
}
return baseRequest;
}
Rationale: Consolidating format configuration into response_format prevents the server from silently ignoring parameters. The type discriminator ensures the model interprets the request correctly.
3. Update Streaming Event Subscriptions
Server-Sent Events (SSE) have been renamed. Subscribers listening to content.delta or interaction.start will receive no data. Update your event source handlers immediately.
function initializeStreamConnection(
endpoint: string,
handlers: { onToken: (chunk: string) => void; onComplete: () => void }
): EventSource {
const source = new EventSource(endpoint);
// New event names
source.addEventListener('step.delta', (event: MessageEvent) => {
const payload = JSON.parse(event.data);
if (payload.delta?.text) {
handlers.onToken(payload.delta.text);
}
});
source.addEventListener('interaction.completed', () => {
handlers.onComplete();
source.close();
});
source.addEventListener('error', () => {
console.error('Stream connection failed');
source.close();
});
return source;
}
Rationale: The renaming aligns streaming events with the steps terminology. Failing to update listeners results in "hanging" UIs where the stream completes but the client never receives the termination signal.
Pitfall Guide
| Pitfall Name | Explanation | Fix |
|---|
| The Undefined Read | Code accesses interaction.outputs[-1].text. Post-flip, outputs is undefined, causing runtime errors or empty renders. | Use the InteractionResponseAdapter or guard clauses checking for steps existence. |
| Silent JSON Mode Loss | Request includes top-level response_mime_type: "application/json". Server ignores this field; model returns unstructured text. | Move mime_type and schema into response_format. Remove top-level response_mime_type. |
| Image Aspect Drift | generation_config.image_config is used. Server ignores this block; images generate with default aspect ratios. | Move aspect_ratio and image_size into response_format with type: "image". |
| Streaming Deadlock | Event listeners subscribe to content.delta. Events fire as step.delta; listeners never trigger. | Update all addEventListener calls to use new event names (step.*, interaction.created, interaction.completed). |
| Tool Loop Stalls | Agent iterates outputs to find function_call types. outputs is empty/undefined; tools are never dispatched. | Iterate steps for tool calls. Ensure the dispatch loop checks steps array. |
| Thought Context Loss | Code round-trips thought steps but drops the new summary field. Model loses reasoning context in stateless flows. | Preserve the full thought object, including summary, when constructing history payloads. |
| Header Confusion | Using Api-Revision: 2026-05-07 to opt-in to new schema. This header is for opting out. | Use Api-Revision: 2026-05-20 to opt-in to the new schema. Use 2026-05-07 only for temporary legacy support. |
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Modern Microservices | Upgrade SDK to β₯2.0.0 | SDK handles schema translation; minimal code changes. | Low (Refactor effort) |
| Legacy Monolith | Pin Api-Revision: 2026-05-07 | Buys time until June 8; avoids immediate breakage. | Medium (Tech debt) |
| Ad-Hoc Scripts | Add Api-Revision: 2026-05-20 | Quick fix for isolated integrations. | Low (Manual update) |
| Critical Agent Systems | Implement Adapter Pattern | Decouples business logic from API volatility. | High (Initial dev) |
Configuration Template
Use this template to configure your HTTP client or SDK to opt-in to the new schema immediately.
# cURL Example with Opt-In Header
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$API_KEY" \
-H "Content-Type: application/json" \
-H "Api-Revision: 2026-05-20" \
-d '{
"model": "gemini-3-flash-preview",
"input": "Generate a summary.",
"response_format": {
"type": "text",
"mime_type": "application/json",
"schema": {
"type": "object",
"properties": { "summary": { "type": "string" } }
}
}
}'
Quick Start Guide
- Update Dependencies: Upgrade your Gemini SDK to version
2.0.0 or later.
- Enable Opt-In: Add the
Api-Revision: 2026-05-20 header to your test environment configuration.
- Run Test Suite: Execute integration tests. Failures here indicate code paths requiring migration.
- Apply Fixes: Refactor response parsers, request builders, and stream listeners based on the Core Solution steps.
- Deploy: Roll out changes to production. Remove the opt-in header once the default flip occurs on May 26, 2026.