Guide de migration des modifications destructives de l'API Interactions (mai 2026)

L'API Interactions v1beta introduit des modifications destructives qui restructurent la forme de l'API pour prendre en charge de futures fonctionnalités telles que le pilotage en cours de vol et les appels d'outils asynchrones. Cette page explique les modifications et fournit des exemples de code avant et après pour vous aider à effectuer la migration. Il existe deux catégories de modifications :

  1. Schéma des étapes : un nouveau tableau steps remplace le tableau outputs, fournissant une chronologie structurée de chaque tour d'interaction.
  2. Configuration du format de sortie : un nouveau polymorphe response_format consolide tous les contrôles de format de sortie et supprime response_mime_type.

Suivez les étapes décrites dans Migrer vers le nouveau schéma pour mettre à jour votre intégration.

Modification principale : outputs vers steps

Le nouveau schéma remplace le tableau outputs par un tableau steps.

  • Ancien : les réponses renvoyaient un tableau outputs plat contenant uniquement le contenu généré par le modèle.
  • Nouveau schéma : les réponses renvoient un tableau steps qui inclut à la fois les entrées utilisateur répétées et les sorties du modèle, fournissant une chronologie complète du tour d'interaction.

Les réponses unaires (non diffusées en streaming) répètent votre entrée comme première étape du tableau steps. Les réponses diffusées en streaming ignorent l'étape d'entrée et n'émettent que des deltas de contenu généré.

Entrée/sortie de base (unaire)

Avant (ancien)

Python

# Request
interaction = client.interactions.create(
    model="gemini-3-flash-preview", input="Tell me a joke."
)

# Response access
print(interaction.outputs[0].text)

JavaScript

// Request
const interaction = await client.interactions.create({
    model: 'gemini-3-flash-preview',
    input: 'Tell me a joke.'
});

// Response access
console.log(interaction.outputs[0].text);

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Tell me a joke."
}

// Response
{
  "id": "int_123",
  "role": "model",
  "outputs": [
    {
      "type": "text",
      "text": "Why did the chicken cross the road?"
    }
  ]
}

Après (nouveau schéma)

Python

# Request
interaction = client.interactions.create(
    model="gemini-3-flash-preview", input="Tell me a joke."
)

# Response access
print(interaction.steps[-1].content[0].text)  # CHANGED: steps instead of outputs

JavaScript

// Request
const interaction = await client.interactions.create({
    model: 'gemini-3-flash-preview',
    input: 'Tell me a joke.'
});

// Response access
console.log(interaction.steps.at(-1).content[0].text);

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Tell me a joke."
}

// Response
{
  "id": "int_123",
  "steps": [
    {
      "type": "user_input",
      "status": "done",
      "content": [
        {
          "type": "text",
          "text": "Tell me a joke."
        }
      ]
    },
    {
      "type": "model_output",
      "status": "done",
      "content": [
        {
          "type": "text",
          "text": "Why did the chicken cross the road?"
        }
      ]
    }
  ]
}

Appel de fonction

La structure de la requête reste inchangée, mais la réponse remplace le contenu outputs plat par des étapes structurées.

Avant (ancien)

Python

# Accessing function call in legacy schema
for output in interaction.outputs:
    if output.type == "function_call":
        print(f"Calling {output.name} with {output.arguments}")

JavaScript

// Accessing function call in legacy schema
for (const output of interaction.outputs) {
    if (output.type === 'function_call') {
        console.log(`Calling {output.name} with {JSON.stringify(output.arguments)}`);
    }
}

REST

// Response
{
  "id": "int_001",
  "role": "model",
  "status": "requires_action",
  "outputs": [
    {
      "type": "thought",
      "signature": "abc123..."
    },
    {
      "type": "function_call",
      "id": "fc_1",
      "name": "get_weather",
      "arguments": { "location": "Boston, MA" }
    }
  ]
}

Après (nouveau schéma)

Python

# Accessing function call in new steps schema
for step in interaction.steps:
    if step.type == "function_call":
        print(f"Calling {step.name} with {step.arguments}")

JavaScript

// Accessing function call in new steps schema
for (const step of interaction.steps) {
    if (step.type === 'function_call') {
        console.log(`Calling {step.name} with {JSON.stringify(step.arguments)}`);
    }
}

REST

// Response
{
  "id": "int_001",
  "status": "requires_action",
  "steps": [
    {
      "type": "user_input",
      "status": "done",
      "content": [
        { "type": "text", "text": "What's the weather in Boston?" }
      ]
    },
    {
      "type": "thought",
      "status": "done",
      "signature": "abc123..."
    },
    {
      "type": "function_call",
      "status": "waiting",
      "id": "fc_1",
      "name": "get_weather",
      "arguments": { "location": "Boston, MA" }
    }
  ]
}

Outils côté serveur

Les outils côté serveur (comme la recherche Google ou l'exécution de code) génèrent désormais des types d'étapes spécifiques dans le tableau steps. Alors que l'ancien schéma renvoyait ces opérations en tant que types de contenu spécifiques dans le tableau outputs, le nouveau schéma les déplace dans le tableau steps. L'exemple suivant utilise la recherche Google.

Avant (ancien)

Python

# Accessing search results in legacy schema
for output in interaction.outputs:
    if output.type == "google_search_call":
        print(f"Searched for: {output.arguments.queries}")
    elif output.type == "google_search_result":
        print(f"Found results: {output.result.rendered_content}")

JavaScript

// Accessing search results in legacy schema
for (const output of interaction.outputs) {
    if (output.type === 'google_search_call') {
        console.log(`Searched for: {output.arguments.queries}`);
    } else if (output.type === 'google_search_result') {
        console.log(`Found results: {output.result.renderedContent}`);
    }
}

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Who won the last Super Bowl?",
  "tools": [
    { "type": "google_search" }
  ]
}

// Response
{
  "id": "int_456",
  "outputs": [
    {
      "type": "google_search_call",
      "id": "gs_1",
      "arguments": { "queries": ["last Super Bowl winner"] }
    },
    {
      "type": "google_search_result",
      "call_id": "gs_1",
      "result": {
        "rendered_content": "<div>...</div>",
        "url": "https://www.nfl.com/super-bowl"
      }
    },
    {
      "type": "text",
      "text": "The Kansas City Chiefs won the last Super Bowl.",
      "annotations": [
        {
          "start_index": 4,
          "end_index": 22,
          "source": "https://www.nfl.com/super-bowl"
        }
      ]
    }
  ],
  "status": "completed"
}

Après (nouveau schéma)

Python

# Accessing search results in new steps schema
for step in interaction.steps:
    if step.type == "google_search_call":
        print(f"Searched for: {step.arguments.queries}")
    elif step.type == "google_search_result":
        print(f"Found results: {step.result.search_suggestions}")

JavaScript

// Accessing search results in new steps schema
for (const step of interaction.steps) {
    if (step.type === 'google_search_call') {
        console.log(`Searched for: {step.arguments.queries}`);
    } else if (step.type === 'google_search_result') {
        console.log(`Found results: {step.result.searchSuggestions}`);
    }
}

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Who won the last Super Bowl?",
  "tools": [
    { "type": "google_search" }
  ]
}

// Response
{
  "id": "int_456",
  "steps": [
    {
      "type": "user_input",
      "status": "done",
      "content": [
        { "type": "text", "text": "Who won the last Super Bowl?" }
      ]
    },
    {
      "type": "google_search_call",
      "status": "done",
      "id": "gs_1",
      "arguments": { "queries": ["last Super Bowl winner"] },
      "signature": "abc123..."
    },
    {
      "type": "google_search_result",
      "status": "done",
      "call_id": "gs_1",
      "result": {
        "search_suggestions": "<div>...</div>"
      },
      "signature": "abc123..."
    },
    {
      "type": "model_output",
      "status": "done",
      "content": [
        {
          "type": "text",
          "text": "The Kansas City Chiefs won the last Super Bowl.",
          "annotations": [
            {
              "type": "url_citation",
              "url": "https://www.nfl.com/super-bowl",
              "title": "NFL.com",
              "start_index": 4,
              "end_index": 22
            }
          ]
        }
      ]
    }
  ],
  "status": "completed"
}

Streaming

Le streaming expose de nouveaux types d'événements :

Nouveaux types d'événements

  • interaction.created
  • interaction.status_update : couvre désormais tous les états du cycle de vie, y compris la finalisation et les erreurs (voir les états ci-dessous)
  • step.start
  • step.delta
  • step.stop
États interaction.status_update
  • in_progress
  • active
  • completed
  • interrupted
  • requires_action
  • error

Types d'événements obsolètes

Les types d'événements hérités suivants sont remplacés par les nouveaux événements listés ci-dessus :

  • interaction.startinteraction.created
  • content.startstep.start
  • content.deltastep.delta
  • content.stopstep.stop
  • interaction.completeinteraction.status_update avec status: "completed"
  • errorinteraction.status_update avec status: "error"
  • interaction.status_updateinteraction.status_update (inchangé, mais couvre désormais des états supplémentaires)

Appels de fonction en streaming : lorsque vous utilisez le streaming avec l'appel de fonction, l'événement step.start fournit le nom de la fonction, et les événements step.delta diffusent les arguments en tant que chaînes JSON partielles (à l'aide de arguments_delta). Vous devez cumuler ces deltas pour obtenir les arguments complets. Cela diffère des appels unaires, où vous recevez l'objet d'appel de fonction complet en une seule fois.

Exemples

Avant (ancien)

Python

# Legacy streaming used content.delta
stream = client.interactions.create(
    model="gemini-3-flash-preview",
    input="Explain quantum entanglement in simple terms.",
    stream=True,
)

for chunk in stream:
    if chunk.event_type == "content.delta":
        if chunk.delta.type == "text":
            print(chunk.delta.text, end="", flush=True)

JavaScript

// Legacy streaming used content.delta
const stream = await client.interactions.create({
    model: 'gemini-3-flash-preview',
    input: 'Explain quantum entanglement in simple terms.',
    stream: true,
});

for await (const chunk of stream) {
    if (chunk.event_type === 'content.delta') {
        if (chunk.delta.type === 'text') {
            process.stdout.write(chunk.delta.text);
        }
    }
}

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Explain quantum entanglement in simple terms.",
  "stream": true
}

// Response (SSE Lines)
// event: interaction.start
// data: {"id": "int_123", "status": "in_progress"}
//
// event: content.start
// data: {"index": 0, "type": "text"}
//
// event: content.delta
// data: {"delta": {"type": "text", "text": "Quantum entanglement is..."}}
//
// event: content.stop
// data: {"index": 0}
//
// event: interaction.complete
// data: {"id": "int_123", "status": "done", "usage": {"total_tokens": 42}}
Après (nouveau schéma)

Python

# Consuming stream and handling new event types
for event in client.interactions.create(
    model="gemini-3-flash-preview",
    input="Tell me a story.",
    stream=True,
):
    if event.type == "step.delta":  # CHANGED: step.delta instead of content.delta
        if event.delta.type == "text":
            print(event.delta.text, end="")

JavaScript

// Consuming stream and handling new event types
const stream = await client.interactions.create({
    model: 'gemini-3-flash-preview',
    input: 'Tell me a story.',
    stream: true,
});

for await (const event of stream) {
    if (event.type === 'step.delta') {  // CHANGED: step.delta instead of content.delta
        if (event.delta.type === 'text') {
            process.stdout.write(event.delta.text);
        }
    }
}

REST

 // Request: POST /v1beta/interactions
 // Accept: text/event-stream
 {
   "model": "gemini-3-flash-preview",
   "input": "Tell me a story."
 }

 // Response (SSE Lines)
 // event: interaction.created
 // data: {"type": "interaction.created", "interaction": {"id": "int_xyz", "status": "created"}} // CHANGED: 'type' instead of 'event_type'
 //
 // event: interaction.status_update
 // data: {"type": "interaction.status_update", "status": "in_progress"} // NEW: Lifecycle status updates in stream (postpone until Sessions launch dependency)
 //
 // event: step.start
 // data: {"type": "step.start", "index": 0, "step": {"type": "thought"}} // NEW: Replaces content.start, 'step' instead of 'content'
 //
 // event: step.delta
 // data: {"type": "step.delta", "index": 0, "delta": {"type": "thought", "text": "User wants an explanation."}} // NEW: Delta type matches step type
 //
 // event: step.stop
 // data: {"type": "step.stop", "index": 0, "status": "done"} // NEW: Includes status
 //
 // event: step.start
 // data: {"type": "step.start", "index": 1, "step": {"type": "model_output"}} // NEW: Step wrapper for output
 //
 // event: step.delta
 // data: {"type": "step.delta", "index": 1, "delta": {"type": "text", "text": "Hello"}}
 //
 // event: step.stop
 // data: {"type": "step.stop", "index": 1, "status": "done"}
 //
 // event: interaction.complete
 // data: {"type": "interaction.complete", "interaction": {"id": "int_xyz", "status": "completed", "usage": {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15}}} // NEW: End of stream event with interaction details

Historique des conversations sans état

Si vous gérez manuellement l'historique des conversations côté client (cas d'utilisation sans état), vous devez modifier la façon dont vous enchaînez les tours précédents.

  • Ancien : les développeurs collectaient souvent le tableau outputs à partir des réponses et les renvoyaient dans le champ input au tour suivant.
  • Nouveau schéma : vous devez maintenant collecter le tableau steps à partir de la réponse et le transmettre dans le champ input de la requête suivante, en ajoutant votre nouveau tour d'utilisateur en tant qu'étape user_input.

Configuration du format de sortie : modifications de response_format

L'API mise à jour consolide tous les contrôles de format de sortie dans un champ response_format unifié et polymorphe. Cela centralise la configuration de la sortie au niveau supérieur et permet à generation_config de se concentrer sur le comportement du modèle (comme la température, le top_p et la réflexion).

Principales modifications

  • L'API supprime response_mime_type. Vous spécifiez désormais le type MIME par entrée de format dans response_format.
  • response_format est désormais un objet (ou un tableau) polymorphe. Chaque entrée comporte un discriminateur type (text, audio, image) et des champs spécifiques au type. Pour demander plusieurs modalités de sortie, transmettez un tableau d'entrées de format.
  • image_config passe de generation_config à response_format. Vous spécifiez désormais les paramètres de sortie d'image tels que aspect_ratio et image_size dans une entrée response_format avec "type": "image".

Sortie structurée (JSON)

Le nouveau schéma supprime le champ response_mime_type. Spécifiez plutôt le type MIME et le schéma JSON dans un response_format objet avec "type": "text".

Avant (ancien)

Python

interaction = client.interactions.create(
    model="gemini-3-flash-preview",
    input="Summarize this article.",
    response_mime_type="application/json",
    response_format={
        "type": "object",
        "properties": {
            "summary": {"type": "string"}
        }
    },
)

print(interaction.outputs[0].text)

JavaScript

const interaction = await client.interactions.create({
    model: 'gemini-3-flash-preview',
    input: 'Summarize this article.',
    responseMimeType: 'application/json',
    responseFormat: {
        type: 'object',
        properties: {
            summary: { type: 'string' }
        }
    },
});

console.log(interaction.outputs[0].text);

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Summarize this article.",
  "response_mime_type": "application/json",
  "response_format": {
    "type": "object",
    "properties": {
      "summary": { "type": "string" }
    }
  }
}

Après (nouveau schéma)

Python

interaction = client.interactions.create(
    model="gemini-3-flash-preview",
    input="Summarize this article.",
    # response_mime_type is removed — specify mime_type inside response_format
    response_format={
        "type": "text",
        "mime_type": "application/json",
        "schema": {
            "type": "object",
            "properties": {
                "summary": {"type": "string"}
            }
        }
    },
)

print(interaction.steps[-1].content[0].text)

JavaScript

const interaction = await client.interactions.create({
    model: 'gemini-3-flash-preview',
    input: 'Summarize this article.',
    // responseMimeType is removed — specify mimeType inside responseFormat
    responseFormat: {
        type: 'text',
        mimeType: 'application/json',
        schema: {
            type: 'object',
            properties: {
                summary: { type: 'string' }
            }
        }
    },
});

console.log(interaction.steps.at(-1).content[0].text);

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Summarize this article.",
  // response_mime_type is removed
  "response_format": {
    "type": "text",                          // NEW: type discriminator
    "mime_type": "application/json",          // MOVED: from response_mime_type
    "schema": {                              // RENAMED: was response_format directly
      "type": "object",
      "properties": {
        "summary": { "type": "string" }
      }
    }
  }
}

Configuration des images

Le nouveau schéma supprime image_config de generation_config. Vous spécifiez désormais les paramètres de sortie d'image dans une entrée response_format avec "type": "image".

Avant (ancien)

Python

interaction = client.interactions.create(
    model="gemini-3-flash-preview",
    input="Generate an image of a sunset over the ocean.",
    generation_config={
        "image_config": {
            "aspect_ratio": "1:1",
            "image_size": "1K"
        }
    },
)

JavaScript

const interaction = await client.interactions.create({
    model: 'gemini-3-flash-preview',
    input: 'Generate an image of a sunset over the ocean.',
    generationConfig: {
        imageConfig: {
            aspectRatio: '1:1',
            imageSize: '1K'
        }
    },
});

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Generate an image of a sunset over the ocean.",
  "generation_config": {
    "image_config": {
      "aspect_ratio": "1:1",
      "image_size": "1K"
    }
  }
}

Après (nouveau schéma)

Python

interaction = client.interactions.create(
    model="gemini-3-flash-preview",
    input="Generate an image of a sunset over the ocean.",
    # image_config is removed from generation_config — use response_format
    response_format={
        "type": "image",
        "mime_type": "image/jpeg",
        "delivery": "inline",
        "aspect_ratio": "1:1",
        "image_size": "1K"
    },
)

JavaScript

const interaction = await client.interactions.create({
    model: 'gemini-3-flash-preview',
    input: 'Generate an image of a sunset over the ocean.',
    // imageConfig is removed from generationConfig — use responseFormat
    responseFormat: {
        type: 'image',
        mimeType: 'image/jpeg',
        delivery: 'inline',
        aspectRatio: '1:1',
        imageSize: '1K'
    },
});

REST

// Request: POST /v1beta/interactions
{
  "model": "gemini-3-flash-preview",
  "input": "Generate an image of a sunset over the ocean.",
  // image_config removed from generation_config
  "response_format": {
    "type": "image",                         // NEW: type discriminator
    "mime_type": "image/jpeg",
    "delivery": "inline",
    "aspect_ratio": "1:1",                   // MOVED: from generation_config.image_config
    "image_size": "1K"                       // MOVED: from generation_config.image_config
  }
}

Pour demander plusieurs modalités de sortie (par exemple, du texte et de l'audio ensemble), transmettez un tableau d'entrées de format à response_format au lieu d'un seul objet.

Migrer vers le nouveau schéma

Utilisateurs du SDK

Effectuez une mise à niveau vers la dernière version du SDK (Python ≥1.76.0, JavaScript ≥1.53.0). Le SDK vous inscrit automatiquement au nouveau schéma. Aucune modification de code n'est nécessaire au-delà de la mise à jour de la façon dont vous lisez les réponses (voir les exemples ci-dessus). Notez que seul le nouveau schéma est compatible avec ces versions du SDK. Les anciennes versions du SDK (Python ≤1.73.1, JavaScript ≤1.50.1) continueront de fonctionner jusqu'à la suppression de l'ancien schéma le 6 juin 2026.

Utilisateurs de l'API REST

Ajoutez l'en-tête Api-Revision: 2026-05-20 à vos requêtes pour activer le nouveau schéma dès maintenant. Après le 20 mai, le nouveau schéma deviendra la valeur par défaut pour toutes les requêtes. Vous pouvez temporairement désactiver cette option avec Api-Revision: 2026-05-06 jusqu'au 6 juin, date à laquelle l'API supprimera définitivement l'ancien schéma.

Chronologie

Date Phase Utilisateurs du SDK Utilisateurs de l'API REST
6 mai Activer Nouvelle version majeure du SDK disponible (Python ≥2.0.0, JS ≥2.0.0). Effectuez une mise à niveau pour obtenir automatiquement le nouveau schéma. Ajoutez l'en-tête Api-Revision: 2026-05-20 pour activer le nouveau schéma. L'ancien schéma reste la valeur par défaut.
20 mai Changement de valeur par défaut Aucune action n'est requise si la mise à niveau a déjà été effectuée. Les anciens SDK (Python 1.x.x, JS 1.x.x) fonctionnent toujours, mais renvoient des réponses héritées. Le nouveau schéma est désormais la valeur par défaut. Envoyez l'en-tête Api-Revision: 2026-05-06 pour désactiver le nouveau schéma.
6 juin Coucher du soleil Les versions 1.x.x du SDK pour Python et JS ne fonctionneront plus pour les appels de l'API Interactions. L'ancien schéma est supprimé pour l'API Interactions. L'en-tête Api-Revision est ignoré.

Liste de contrôle de la migration

Schéma des étapes (steps)

  • Mettez à jour le code pour lire le contenu de la réponse à partir du tableau steps au lieu de outputs. Voir des exemples..
  • Vérifiez que votre code gère les types d'étapes user_input et model_output. Voir des exemples..
  • (Appel de fonction) Mettez à jour le code pour trouver les étapes function_call dans le tableau steps. Voir des exemples..
  • (Outils côté serveur) Mettez à jour le code pour gérer les étapes spécifiques à l'outil (par exemple, google_search_call, google_search_result). Voir des exemples.
  • (Historique sans état) Mettez à jour la gestion de l'historique pour transmettre le tableau steps dans le champ input de la requête suivante. Voir les détails.
  • (Streaming uniquement) Mettez à jour le client pour écouter les nouveaux types d'événements SSE (interaction.created, step.delta, etc.). Voir des exemples.

Configuration du format de sortie (response_format)

  • Remplacez response_mime_type par un champ mime_type dans response_format. Voir des exemples.
  • Encapsulez votre schéma JSON response_format existant dans un objet {"type": "text", "schema": ...}. Voir des exemples.
  • (Génération d'images) Déplacez image_config de generation_config vers une entrée {"type": "image", ...} dans response_format. Voir des exemples.
  • (Multimodal) Convertissez response_format d'un seul objet en tableau lorsque vous demandez plusieurs modalités de sortie.