Repository Public
1This guide helps you migrate from the `generateContent` API to the Interactions API.23The Interactions API is our simplest and best way to build with Gemini models and agents. While `generateContent` remains fully supported, we recommend the Interactions API for all new development.45> [!NOTE]6> **Automate this migration with a coding agent.** If you use7> a coding agent that supports skills (like Gemini CLI or Jules), install the8> [Gemini9> API development skill](https://ai.google.dev/gemini-api/docs/coding-agents#gemini-api-dev) and run:10>11> ```12> /gemini-api-dev migrate my app to the interactions api13> ```14>15> The skill applies the API changes described in this guide.1617### Why migrate?1819The Interactions API is our simplest and best way to build with Gemini models and agents:2021- **Server-side history management** : Simplified multi-turn flows via `previous_interaction_id`. The server enables state by default (`store=true`), but you can opt into stateless behavior by setting `store=false`.22- **Observable execution steps**: Typed steps make it easy to debug complex flows and render UI for intermediate events (like thoughts or search widgets).23- **Tool use and agentic workflows**: Native support for multi-step tool use, orchestration, and complex reasoning flows through typed execution steps.24- **Long-running and background tasks** : Supports offloading time-intensive operations like Deep Think and Deep Research to background processes using `background=true`.2526## Basic input/output2728This section shows how to migrate a simple text generation request.2930### Before (`generateContent`)3132The `generateContent` API is stateless and returns the response directly. The response structure wraps the output in a list of `candidates`, each containing `content` with a list of `parts` to parse.3334### Python3536 from google import genai3738 client = genai.Client()3940 response = client.models.generate_content(41 model="gemini-2.5-flash-lite", contents="Tell me a joke."42 )43 print(response.text)4445### JavaScript4647 import { GoogleGenAI } from '@google/genai';4849 const ai = new GoogleGenAI({});5051 const response = await ai.models.generateContent({52 model: "gemini-2.5-flash-lite",53 contents: "Tell me a joke.",54 });55 console.log(response.text);5657### Java5859 import com.google.genai.Client;60 import com.google.genai.types.GenerateContentResponse;6162 Client client = new Client();6364 GenerateContentResponse response =65 client.models.generateContent("gemini-2.5-flash-lite", "Tell me a joke.", null);66 System.out.println(response.text());6768### REST6970 # Request71 curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent" \72 -H "Content-Type: application/json" \73 -H "x-goog-api-key: $GEMINI_API_KEY" \74 -d '{75 "contents": \[{76 "parts": \[{77 "text": "Tell me a joke."78 }\]79 }\]80 }'8182 # Response83 {84 "candidates": \[85 {86 "content": {87 "parts": \[88 {89 "text": "Why did the chicken cross the road? To get to the other side!"90 }91 \],92 "role": "model"93 },94 "finishReason": "STOP",95 "index": 096 }97 \],98 "usageMetadata": {99 "promptTokenCount": 4,100 "candidatesTokenCount": 12,101 "totalTokenCount": 16102 }103 }104105The Interactions API returns a stored interaction resource with a `steps`106timeline. While you can inspect the `steps` array manually to find intermediate107events, the Google GenAI SDKs provide convenience properties108directly on the returned `Interaction` object to access the final output.109110The most common convenience property is **`.output_text`** (String), which111automatically extracts and joins consecutive `TextContent` blocks at the112end of the model's response. While this works perfectly for simple responses,113it does not include earlier text blocks separated by non-text content (such114as thoughts, images, audio, or tool calls). For complex or interleaved115multimodal responses, you must manually iterate over `steps` instead.116117> [!NOTE]118> **Note:** For details on other SDK convenience properties (including `.output_image` and `.output_audio`), see [Access outputs with SDK convenience properties](https://ai.google.dev/gemini-api/docs/interactions-overview#sdk-sugar) in the overview.119120### Python121122 from google import genai123124 client = genai.Client()125126 interaction = client.interactions.create(127 model="gemini-3.8-flash", input="Tell me a joke."128 )129130 print(interaction.output_text)131132### JavaScript133134 import { GoogleGenAI } from '@google/genai';135136 const client = new GoogleGenAI({});137138 let interaction = await client.interactions.create({139 model: 'gemini-3.8-flash',140 input: 'Tell me a joke.'141 });142143 console.log(interaction.output_text);144145### Java146147 import com.google.genai.Client;148 import com.google.genai.gaos.models.interactions.CreateModelInteraction;149 import com.google.genai.gaos.models.interactions.Interaction;150 import com.google.genai.gaos.models.interactions.InteractionsInput;151 import com.google.genai.gaos.models.interactions.Model;152 import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;153154 Client client = new Client();155156 CreateModelInteraction request =157 CreateModelInteraction.builder()158 .model(Model.of("gemini-3.8-flash"))159 .input(InteractionsInput.of("Tell me a joke."))160 .build();161162 Interaction interaction =163 client.interactions.create(CreateInteractionRequestBody.of(request)).interaction().get();164165 System.out.println(interaction.outputText().orElse(""));166167### REST168169 # Request170 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \171 -H "Content-Type: application/json" \172 -H "x-goog-api-key: $GEMINI_API_KEY" \173 -d '{174 "model": "gemini-3.8-flash",175 "input": "Tell me a joke."176 }'177178 # Response179 {180 "id": "int_123",181 "status": "completed",182 "steps": \[183 {184 "type": "user_input",185 "status": "done",186 "content": \[187 {188 "type": "text",189 "text": "Tell me a joke."190 }191 \]192 },193 {194 "type": "model_output",195 "status": "done",196 "content": \[197 {198 "type": "text",199 "text": "Why did the chicken cross the road?"200 }201 \]202 }203 \]204 }205206## Multi-turn conversations207208The Interactions API stores interactions by default, enabling server-side state management for multi-turn conversations.209210### Before (`generateContent`)211212In `generateContent`, you must manually manage conversation history using the `contents` array or a client-side chat helper.213214### Python215216**Using the chat helper (recommended)**217218 from google import genai219220 client = genai.Client()221222 chat = client.chats.create(model="gemini-2.5-flash-lite")223 response1 = chat.send_message("Hi, my name is Phil.")224 print(response1.text)225226 response2 = chat.send_message("What is my name?")227 print(response2.text)228229**Manually managing history**230231 from google import genai232 from google.genai import types233234 client = genai.Client()235236 response = client.models.generate_content(237 model="gemini-2.5-flash-lite",238 contents=[239 types.Content(240 role="user", parts=[types.Part.from_text(text="Hi, my name is Phil.")]241 ),242 types.Content(243 role="model",244 parts=[types.Part.from_text(text="Hi Phil, how can I help you?")],245 ),246 types.Content(247 role="user", parts=[types.Part.from_text(text="What is my name?")]248 ),249 ],250 )251 print(response.text)252253### JavaScript254255**Using the chat helper (recommended)**256257 import { GoogleGenAI } from '@google/genai';258259 const client = new GoogleGenAI({});260261 const chat = client.chats.create({ model: 'gemini-2.5-flash-lite' });262 let response = await chat.sendMessage({ message: 'Hi, my name is Phil.' });263 console.log(response.text);264265 response = await chat.sendMessage({ message: 'What is my name?' });266 console.log(response.text);267268**Manually managing history**269270 import { GoogleGenAI } from '@google/genai';271272 const client = new GoogleGenAI({});273274 const response = await client.models.generateContent({275 model: 'gemini-2.5-flash-lite',276 contents: [277 { role: 'user', parts: [{ text: 'Hi, my name is Phil.' }] },278 { role: 'model', parts: [{ text: 'Hi Phil, how can I help you?' }] },279 { role: 'user', parts: [{ text: 'What is my name?' }] }280 ]281 });282 console.log(response.text);283284### Java285286 import com.google.genai.Chat;287 import com.google.genai.Client;288 import com.google.genai.types.Content;289 import com.google.genai.types.GenerateContentResponse;290 import com.google.genai.types.Part;291 import java.util.Arrays;292293 Client client = new Client();294295 // Using the chat helper (recommended)296 Chat chat = client.chats.create("gemini-2.5-flash-lite");297 GenerateContentResponse response1 = chat.sendMessage("Hi, my name is Phil.");298 System.out.println(response1.text());299300 GenerateContentResponse response2 = chat.sendMessage("What is my name?");301 System.out.println(response2.text());302303 // Manually managing history304 GenerateContentResponse manualResponse =305 client.models.generateContent(306 "gemini-2.5-flash-lite",307 Arrays.asList(308 Content.builder()309 .role("user")310 .parts(Arrays.asList(Part.fromText("Hi, my name is Phil.")))311 .build(),312 Content.builder()313 .role("model")314 .parts(Arrays.asList(Part.fromText("Hi Phil, how can I help you?")))315 .build(),316 Content.builder()317 .role("user")318 .parts(Arrays.asList(Part.fromText("What is my name?")))319 .build()),320 null);321 System.out.println(manualResponse.text());322323### REST324325 # Request (the second turn requires sending the entire history)326 curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent" \327 -H "Content-Type: application/json" \328 -H "x-goog-api-key: $GEMINI_API_KEY" \329 -d '{330 "contents": \[331 {"role": "user", "parts": \[{"text": "Hi, my name is Phil."}\]},332 {"role": "model", "parts": \[{"text": "Hi Phil, how can I help you?"}\]},333 {"role": "user", "parts": \[{"text": "What is my name?"}\]}334 \]335 }'336337 # Response338 {339 "candidates": \[340 {341 "content": {342 "parts": \[343 {344 "text": "Your name is Phil."345 }346 \],347 "role": "model"348 },349 "finishReason": "STOP",350 "index": 0351 }352 \]353 }354355### After (Interactions API)356357The Interactions API manages state on the server. You continue a conversation by referencing the `previous_interaction_id`.358359### Python360361 from google import genai362363 client = genai.Client()364365 interaction1 = client.interactions.create(366 model="gemini-3.8-flash", input="Hi, my name is Phil."367 )368 print("Response 1:", interaction1.output_text)369370 interaction2 = client.interactions.create(371 model="gemini-3.8-flash",372 previous_interaction_id=interaction1.id,373 input="What is my name?",374 )375 print("Response 2:", interaction2.output_text)376377### JavaScript378379 import { GoogleGenAI } from '@google/genai';380381 const client = new GoogleGenAI({});382383 let interaction = await client.interactions.create({384 model: 'gemini-3.8-flash',385 input: 'Hi, my name is Phil.'386 });387 console.log("Response 1:", interaction.output_text);388389 interaction = await client.interactions.create({390 model: 'gemini-3.8-flash',391 previous_interaction_id: interaction.id,392 input: 'What is my name?'393 });394 console.log("Response 2:", interaction.output_text);395396### Java397398 import com.google.genai.Client;399 import com.google.genai.gaos.models.interactions.CreateModelInteraction;400 import com.google.genai.gaos.models.interactions.Interaction;401 import com.google.genai.gaos.models.interactions.InteractionsInput;402 import com.google.genai.gaos.models.interactions.Model;403 import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;404405 Client client = new Client();406407 CreateModelInteraction req1 =408 CreateModelInteraction.builder()409 .model(Model.of("gemini-3.8-flash"))410 .input(InteractionsInput.of("Hi, my name is Phil."))411 .build();412413 Interaction interaction1 =414 client.interactions.create(CreateInteractionRequestBody.of(req1)).interaction().get();415 System.out.println("Response 1: " + interaction1.outputText().orElse(""));416417 CreateModelInteraction req2 =418 CreateModelInteraction.builder()419 .model(Model.of("gemini-3.8-flash"))420 .previousInteractionId(interaction1.id().orElse(""))421 .input(InteractionsInput.of("What is my name?"))422 .build();423424 Interaction interaction2 =425 client.interactions.create(CreateInteractionRequestBody.of(req2)).interaction().get();426 System.out.println("Response 2: " + interaction2.outputText().orElse(""));427428### REST429430 # First Request431 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \432 -H "Content-Type: application/json" \433 -H "x-goog-api-key: $GEMINI_API_KEY" \434 -d '{435 "model": "gemini-3.8-flash",436 "input": "Hi, my name is Phil."437 }'438439 # Second Request (using ID from first response)440 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \441 -H "Content-Type: application/json" \442 -H "x-goog-api-key: $GEMINI_API_KEY" \443 -d '{444 "model": "gemini-3.8-flash",445 "previous_interaction_id": "int_123",446 "input": "What is my name?"447 }'448449 # Response to Second Request450 {451 "id": "int_123",452 "steps": \[453 {454 "type": "user_input",455 "status": "done",456 "content": \[{ "type": "text", "text": "Hi, my name is Phil." }\]457 },458 {459 "type": "model_output",460 "status": "done",461 "content": \[{ "type": "text", "text": "Hello Phil! How can I help you today?" }\]462 },463 {464 "type": "user_input",465 "status": "done",466 "content": \[{ "type": "text", "text": "What is my name?" }\]467 },468 {469 "type": "model_output",470 "status": "done",471 "content": \[{ "type": "text", "text": "Your name is Phil." }\]472 }473 \]474 }475476## Multimodal inputs477478Both APIs support multimodal inputs (text, images, video, etc.).479480### Before (`generateContent`)481482In `generateContent`, you pass a list of `parts` within the `contents` array. The response returns output in the `parts` of the first candidate.483484### Python485486 from google import genai487 from google.genai import types488489 client = genai.Client()490491 with open("sample.jpg", "rb") as f:492 image_bytes = f.read()493494 response = client.models.generate_content(495 model="gemini-2.5-flash-lite",496 contents=[497 types.Part.from_bytes(data=image_bytes, mime_type="image/jpeg"),498 "Describe this image.",499 ],500 )501 print(response.text)502503### JavaScript504505 import { GoogleGenAI } from '@google/genai';506 import * as fs from 'fs';507508 const client = new GoogleGenAI({});509510 const imageBytes = fs.readFileSync('sample.jpg').toString('base64');511512 const response = await client.models.generateContent({513 model: 'gemini-2.5-flash-lite',514 contents: [515 {516 inlineData: {517 data: imageBytes,518 mimeType: 'image/jpeg',519 },520 },521 'Describe this image.',522 ],523 });524 console.log(response.text);525526### Java527528 import com.google.genai.Client;529 import com.google.genai.types.Content;530 import com.google.genai.types.GenerateContentResponse;531 import com.google.genai.types.Part;532 import java.nio.file.Files;533 import java.nio.file.Paths;534535 Client client = new Client();536537 byte[] imageBytes = Files.readAllBytes(Paths.get("sample.jpg"));538539 GenerateContentResponse response =540 client.models.generateContent(541 "gemini-2.5-flash-lite",542 Content.fromParts(543 Part.fromBytes(imageBytes, "image/jpeg"), Part.fromText("Describe this image.")),544 null);545 System.out.println(response.text());546547### REST548549 # Request550 curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent" \551 -H "Content-Type: application/json" \552 -H "x-goog-api-key: $GEMINI_API_KEY" \553 -d '{554 "contents": \[{555 "parts": \[556 {557 "inlineData": {558 "mimeType": "image/jpeg",559 "data": "..."560 }561 },562 {563 "text": "Describe this image."564 }565 \]566 }\]567 }'568569 # Response570 {571 "candidates": \[572 {573 "content": {574 "parts": \[575 {576 "text": "This is a picture of a beautiful sunset."577 }578 \],579 "role": "model"580 }581 }582 \]583 }584585### After (Interactions API)586587In the Interactions API, you pass an array to the `input` field. You retrieve output content by finding the `model_output` step in the timeline.588589### Python590591 import base64592 from google import genai593594 client = genai.Client()595596 with open("sample.jpg", "rb") as f:597 image_bytes = f.read()598 image_b64 = base64.b64encode(image_bytes).decode("utf-8")599600 interaction = client.interactions.create(601 model="gemini-3.8-flash",602 input=[603 {604 "type": "image",605 "mime_type": "image/jpeg",606 "data": image_b64,607 },608 {"type": "text", "text": "Describe this image."},609 ],610 )611 print(interaction.output_text)612613### JavaScript614615 import { GoogleGenAI } from '@google/genai';616 import * as fs from 'fs';617618 const client = new GoogleGenAI({});619620 const imageBytes = fs.readFileSync('sample.jpg').toString('base64');621622 const interaction = await client.interactions.create({623 model: 'gemini-3.8-flash',624 input: [625 {626 type: 'image',627 mime_type: 'image/jpeg',628 data: imageBytes629 },630 {631 type: 'text',632 text: 'Describe this image.'633 }634 ]635 });636 console.log(interaction.output_text);637638### Java639640 import com.google.genai.Client;641 import com.google.genai.gaos.models.interactions.CreateModelInteraction;642 import com.google.genai.gaos.models.interactions.ImageContent;643 import com.google.genai.gaos.models.interactions.ImageContentMimeType;644 import com.google.genai.gaos.models.interactions.Interaction;645 import com.google.genai.gaos.models.interactions.InteractionsInput;646 import com.google.genai.gaos.models.interactions.Model;647 import com.google.genai.gaos.models.interactions.TextContent;648 import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;649 import java.nio.file.Files;650 import java.nio.file.Paths;651 import java.util.Arrays;652 import java.util.Base64;653654 Client client = new Client();655656 byte[] imageBytes = Files.readAllBytes(Paths.get("sample.jpg"));657 String base64ImageData = Base64.getEncoder().encodeToString(imageBytes);658659 CreateModelInteraction request =660 CreateModelInteraction.builder()661 .model(Model.of("gemini-3.8-flash"))662 .input(663 InteractionsInput.ofContent(664 Arrays.asList(665 ImageContent.builder()666 .mimeType(ImageContentMimeType.IMAGE_JPEG)667 .data(base64ImageData)668 .build(),669 TextContent.builder().text("Describe this image.").build())))670 .build();671672 Interaction interaction =673 client.interactions.create(CreateInteractionRequestBody.of(request)).interaction().get();674 System.out.println(interaction.outputText().orElse(""));675676### REST677678 # Request679 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \680 -H "Content-Type: application/json" \681 -H "x-goog-api-key: $GEMINI_API_KEY" \682 -d '{683 "model": "gemini-3.8-flash",684 "input": \[685 {686 "type": "image",687 "mime_type": "image/jpeg",688 "data": "..."689 },690 {691 "type": "text",692 "text": "Describe this image."693 }694 \]695 }'696697 # Response698 {699 "id": "int_multimodal",700 "steps": \[701 {702 "type": "user_input",703 "status": "done",704 "content": \[705 {706 "type": "image",707 "mime_type": "image/jpeg",708 "data": "..."709 },710 {711 "type": "text",712 "text": "Describe this image."713 }714 \]715 },716 {717 "type": "model_output",718 "status": "done",719 "content": \[720 {721 "type": "text",722 "text": "This is a picture of a beautiful sunset over the mountains."723 }724 \]725 }726 \]727 }728729## Structured output730731To make the model return JSON matching a specific schema, configure the response format.732733### Before (`generateContent`)734735In `generateContent`, you configure output format using the `response_mime_type` and `response_schema` fields nested inside the `config` (or `generationConfig`) object.736737### Python738739 from google import genai740 from google.genai import types741 from pydantic import BaseModel742743 client = genai.Client()744745 class Recipe(BaseModel):746 recipe_name: str747 ingredients: list[str]748749 response = client.models.generate_content(750 model="gemini-2.5-flash-lite",751 contents="Give me a recipe for chocolate chip cookies.",752 config=types.GenerateContentConfig(753 response_mime_type="application/json",754 response_schema=Recipe,755 ),756 )757 print(response.text)758759### JavaScript760761 import { GoogleGenAI, Type } from '@google/genai';762763 const ai = new GoogleGenAI({});764765 const response = await ai.models.generateContent({766 model: 'gemini-2.5-flash-lite',767 contents: 'Give me a recipe for chocolate chip cookies.',768 config: {769 responseMimeType: 'application/json',770 responseSchema: {771 type: Type.OBJECT,772 properties: {773 recipe_name: { type: Type.STRING },774 ingredients: {775 type: Type.ARRAY,776 items: { type: Type.STRING },777 },778 },779 required: ['recipe_name', 'ingredients'],780 },781 },782 });783 console.log(response.text);784785### Java786787 import com.google.genai.Client;788 import com.google.genai.types.GenerateContentConfig;789 import com.google.genai.types.GenerateContentResponse;790 import com.google.genai.types.Schema;791 import com.google.genai.types.Type;792 import java.util.Arrays;793 import java.util.Map;794795 Client client = new Client();796797 Schema recipeSchema =798 Schema.builder()799 .type(Type.Known.OBJECT)800 .properties(801 Map.of(802 "recipe_name", Schema.builder().type(Type.Known.STRING).build(),803 "ingredients",804 Schema.builder()805 .type(Type.Known.ARRAY)806 .items(Schema.builder().type(Type.Known.STRING).build())807 .build()))808 .required(Arrays.asList("recipe_name", "ingredients"))809 .build();810811 GenerateContentResponse response =812 client.models.generateContent(813 "gemini-2.5-flash-lite",814 "Give me a recipe for chocolate chip cookies.",815 GenerateContentConfig.builder()816 .responseMimeType("application/json")817 .responseSchema(recipeSchema)818 .build());819 System.out.println(response.text());820821### REST822823 # Request824 curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent" \825 -H "Content-Type: application/json" \826 -H "x-goog-api-key: $GEMINI_API_KEY" \827 -d '{828 "contents": \[{829 "parts": \[{830 "text": "Give me a recipe for chocolate chip cookies."831 }\]832 }\],833 "generationConfig": {834 "responseMimeType": "application/json",835 "responseSchema": {836 "type": "OBJECT",837 "properties": {838 "recipe_name": { "type": "STRING" },839 "ingredients": {840 "type": "ARRAY",841 "items": { "type": "STRING" }842 }843 },844 "required": \["recipe_name", "ingredients"\]845 }846 }847 }'848849 # Response850 {851 "candidates": \[852 {853 "content": {854 "parts": \[855 {856 "text": "{\\n \\"recipe_name\\": \\"Chocolate Chip Cookies\\",\\n \\"ingredients\\": \[\\n \\"1 cup butter\\",\\n \\"1 cup sugar\\",\\n \\"2 cups flour\\",\\n \\"1 cup chocolate chips\\"\\n \]\\n}"857 }858 \],859 "role": "model"860 }861 }862 \]863 }864865### After (Interactions API)866867In the Interactions API, output format controls move to a top-level `response_format` array.868869### Python870871 from google import genai872 from pydantic import BaseModel873874 client = genai.Client()875876 class Recipe(BaseModel):877 recipe_name: str878 ingredients: list[str]879880 interaction = client.interactions.create(881 model="gemini-3.8-flash",882 input="Give me a recipe for chocolate chip cookies.",883 response_format=[884 {885 "type": "text",886 "mime_type": "application/json",887 "schema": Recipe.model_json_schema(),888 }889 ],890 )891892 print(interaction.output_text)893894### JavaScript895896 import { GoogleGenAI } from '@google/genai';897898 const client = new GoogleGenAI({});899900 const interaction = await client.interactions.create({901 model: 'gemini-3.8-flash',902 input: 'Give me a recipe for chocolate chip cookies.',903 response_format: [904 {905 type: 'text',906 mime_type: 'application/json',907 schema: {908 type: 'object',909 properties: {910 recipe_name: { type: 'string' },911 ingredients: {912 type: 'array',913 items: { type: 'string' }914 }915 },916 required: ['recipe_name', 'ingredients']917 }918 }919 ]920 });921 console.log(interaction.output_text);922923### Java924925 import com.google.genai.Client;926 import com.google.genai.gaos.models.interactions.CreateModelInteraction;927 import com.google.genai.gaos.models.interactions.CreateModelInteractionResponseFormat;928 import com.google.genai.gaos.models.interactions.Interaction;929 import com.google.genai.gaos.models.interactions.InteractionsInput;930 import com.google.genai.gaos.models.interactions.Model;931 import com.google.genai.gaos.models.interactions.ResponseFormat;932 import com.google.genai.gaos.models.interactions.TextResponseFormat;933 import com.google.genai.gaos.models.interactions.TextResponseFormatMimeType;934 import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;935 import java.util.Arrays;936 import java.util.HashMap;937 import java.util.Map;938939 Client client = new Client();940941 Map<String, Object> properties = new HashMap<>();942 properties.put("recipe_name", Map.of("type", "string"));943 properties.put("ingredients", Map.of("type", "array", "items", Map.of("type", "string")));944945 Map<String, Object> schema = new HashMap<>();946 schema.put("type", "object");947 schema.put("properties", properties);948 schema.put("required", Arrays.asList("recipe_name", "ingredients"));949950 CreateModelInteraction request =951 CreateModelInteraction.builder()952 .model(Model.of("gemini-3.8-flash"))953 .input(InteractionsInput.of("Give me a recipe for chocolate chip cookies."))954 .responseFormat(955 CreateModelInteractionResponseFormat.of(956 Arrays.asList(957 ResponseFormat.of(958 TextResponseFormat.builder()959 .mimeType(TextResponseFormatMimeType.APPLICATION_JSON)960 .schema(schema)961 .build()))))962 .build();963964 Interaction interaction =965 client.interactions.create(CreateInteractionRequestBody.of(request)).interaction().get();966 System.out.println(interaction.outputText().orElse(""));967968### REST969970 # Request971 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \972 -H "Content-Type: application/json" \973 -H "x-goog-api-key: $GEMINI_API_KEY" \974 -d '{975 "model": "gemini-3.8-flash",976 "input": "Give me a recipe for chocolate chip cookies.",977 "response_format": \[978 {979 "type": "text",980 "mime_type": "application/json",981 "schema": {982 "type": "OBJECT",983 "properties": {984 "recipe_name": { "type": "STRING" },985 "ingredients": {986 "type": "ARRAY",987 "items": { "type": "STRING" }988 }989 },990 "required": \["recipe_name", "ingredients"\]991 }992 }993 \]994 }'995996 # Response997 {998 "id": "int_structured",999 "steps": \[1000 {1001 "type": "user_input",1002 "status": "done",1003 "content": \[{ "type": "text", "text": "Give me a recipe for chocolate chip cookies." }\]1004 },1005 {1006 "type": "model_output",1007 "status": "done",1008 "content": \[1009 {1010 "type": "text",1011 "text": "{\\n \\"recipe_name\\": \\"Chocolate Chip Cookies\\",\\n \\"ingredients\\": \[\\n \\"1 cup butter\\",\\n \\"1 cup sugar\\",\\n \\"2 cups flour\\",\\n \\"1 cup chocolate chips\\"\\n \]\\n}"1012 }1013 \]1014 }1015 \]1016 }10171018## Multimodal generation10191020When generating content in modalities beyond text (such as images or audio), the primary difference is how the response structures the generated media.10211022### Before (`generateContent`)10231024In `generateContent`, the response returns generated media directly in the `parts` of the candidate, typically as base64 data in `inlineData`.10251026 # Response structure concept1027 {1028 "candidates": \[1029 {1030 "content": {1031 "parts": \[1032 {1033 "text": "Here is your generated image:"1034 },1035 {1036 "inlineData": {1037 "mimeType": "image/jpeg",1038 "data": "...base64..."1039 }1040 }1041 \]1042 }1043 }1044 \]1045 }10461047### After (Interactions API)10481049In the Interactions API, generated media appears as distinct items within the `content` array of a `model_output` step in the timeline, maintaining the chronological flow of the interaction.10501051 # Response structure concept1052 {1053 "id": "int_123",1054 "steps": \[1055 {1056 "type": "model_output",1057 "status": "done",1058 "content": \[1059 {1060 "type": "text",1061 "text": "Here is your generated image:"1062 },1063 {1064 "type": "image",1065 "mime_type": "image/jpeg",1066 "data": "...base64..." // Or a reference URL in future1067 }1068 \]1069 }1070 \]1071 }10721073This keeps the response parsing consistent with how inputs and text outputs are handled---everything is a step in the timeline.10741075## Server-side tools10761077Gemini supports built-in server-side tools like Google Search grounding. The primary difference is how the response represents tool execution.10781079### Before (`generateContent`)10801081In `generateContent`, server-side tools are largely opaque. You enable the tool and get a final answer with a separate `groundingMetadata` object. Crucially, citations are not inline; `groundingSupports` use character indices to map text segments back to web sources in `groundingChunks`.10821083### Python10841085 from google import genai1086 from google.genai import types10871088 client = genai.Client()10891090 response = client.models.generate_content(1091 model="gemini-2.5-flash-lite",1092 contents="Who won Euro 2024?",1093 config=types.GenerateContentConfig(1094 tools=[{"google_search": {}}]1095 ),1096 )10971098 metadata = response.candidates[0].grounding_metadata1099 if metadata.search_entry_point:1100 print(f"Search Entry Point: {metadata.search_entry_point.rendered_content}")11011102 for support in metadata.grounding_supports:1103 print(f"Citation: {support.segment.text}")11041105### JavaScript11061107 import { GoogleGenAI } from '@google/genai';11081109 const client = new GoogleGenAI({});11101111 const response = await client.models.generateContent({1112 model: 'gemini-2.5-flash-lite',1113 contents: 'Who won Euro 2024?',1114 config: {1115 tools: [{ google_search: {} }]1116 }1117 });11181119 const metadata = response.candidates[0].groundingMetadata;1120 if (metadata.searchEntryPoint) {1121 console.log(`Search Entry Point: ${metadata.searchEntryPoint.renderedContent}`);1122 }1123 for (const support of metadata.groundingSupports) {1124 console.log(`Citation: ${support.segment.text}`);1125 }11261127### Java11281129 import com.google.genai.Client;1130 import com.google.genai.types.Candidate;1131 import com.google.genai.types.GenerateContentConfig;1132 import com.google.genai.types.GenerateContentResponse;1133 import com.google.genai.types.GoogleSearch;1134 import com.google.genai.types.GroundingMetadata;1135 import com.google.genai.types.GroundingSupport;1136 import com.google.genai.types.Tool;1137 import java.util.Arrays;1138 import java.util.Collections;1139 import java.util.List;1140 import java.util.Optional;11411142 Client client = new Client();11431144 GenerateContentResponse response =1145 client.models.generateContent(1146 "gemini-2.5-flash-lite",1147 "Who won Euro 2024?",1148 GenerateContentConfig.builder()1149 .tools(1150 Arrays.asList(1151 Tool.builder().googleSearch(GoogleSearch.builder().build()).build()))1152 .build());11531154 List<Candidate> candidates = response.candidates().orElse(Collections.emptyList());1155 if (!candidates.isEmpty() && candidates.get(0).groundingMetadata().isPresent()) {1156 GroundingMetadata metadata = candidates.get(0).groundingMetadata().get();1157 if (metadata.searchEntryPoint().isPresent()) {1158 System.out.println(1159 "Search Entry Point: " + metadata.searchEntryPoint().get().renderedContent().orElse(""));1160 }1161 for (GroundingSupport support : metadata.groundingSupports().orElse(Collections.emptyList())) {1162 Optional<String> segmentText = support.segment().flatMap(s -> s.text());1163 segmentText.ifPresent(text -> System.out.println("Citation: " + text));1164 }1165 }11661167### REST11681169 # Request1170 curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent" \1171 -H "Content-Type: application/json" \1172 -H "x-goog-api-key: $GEMINI_API_KEY" \1173 -d '{1174 "contents": \[{1175 "parts": \[{1176 "text": "Who won Euro 2024?"1177 }\]1178 }\],1179 "tools": \[{1180 "googleSearchRetrieval": {}1181 }\]1182 }'11831184 # Response1185 {1186 "candidates": \[1187 {1188 "content": {1189 "parts": \[1190 {1191 "text": "Spain won Euro 2024, defeating England 2-1 in the final. This victory marks Spain's record fourth European Championship title."1192 }1193 \],1194 "role": "model"1195 },1196 "groundingMetadata": {1197 "webSearchQueries": \[1198 "UEFA Euro 2024 winner",1199 "who won euro 2024"1200 \],1201 "searchEntryPoint": {1202 "renderedContent": "\<!-- HTML and CSS for the search widget --\>"1203 },1204 "groundingChunks": \[1205 {"web": {"uri": "https://vertexaisearch.cloud.google.com.....", "title": "aljazeera.com"}},1206 {"web": {"uri": "https://vertexaisearch.cloud.google.com.....", "title": "uefa.com"}}1207 \],1208 "groundingSupports": \[1209 {1210 "segment": {"startIndex": 0, "endIndex": 85, "text": "Spain won Euro 2024, defeatin..."},1211 "groundingChunkIndices": \[0\]1212 },1213 {1214 "segment": {"startIndex": 86, "endIndex": 210, "text": "This victory marks Spain's..."},1215 "groundingChunkIndices": \[0, 1\]1216 }1217 \]1218 }1219 }1220 \]1221 }12221223### After (Interactions API)12241225In the Interactions API, server-side tools provide full timeline transparency. The API records the call and result as distinct execution `steps` (`google_search_call` and `google_search_result`), exposing exactly what data the model retrieved.12261227Furthermore, the API returns citations **inline** . Instead of mapping indices from a separate metadata object, the text item within the `model_output` step contains its own `annotations` array linking directly to the source.12281229### Python12301231 from google import genai12321233 client = genai.Client()12341235 interaction = client.interactions.create(1236 model="gemini-3.8-flash",1237 input="Who won Euro 2024?",1238 tools=[{"type": "google_search"}],1239 )12401241 for step in interaction.steps:1242 if step.type == "google_search_result":1243 print(f"Search Suggestions: {step.result[0].search_suggestions}")1244 elif step.type == "model_output":1245 print(f"Answer: {step.content[0].text}")1246 if step.content[0].annotations:1247 for anno in step.content[0].annotations:1248 print(f"Citation: {anno.title} ({anno.uri})")12491250### JavaScript12511252 import { GoogleGenAI } from '@google/genai';12531254 const client = new GoogleGenAI({});12551256 const interaction = await client.interactions.create({1257 model: 'gemini-3.8-flash',1258 input: 'Who won Euro 2024?',1259 tools: [{ type: 'google_search' }]1260 });12611262 for (const step of interaction.steps) {1263 if (step.type === 'google_search_result') {1264 console.log(`Search Suggestions: ${step.result[0].search_suggestions}`);1265 } else if (step.type === 'model_output') {1266 console.log(`Answer: ${step.content[0].text}`);1267 if (step.content[0].annotations) {1268 for (const anno of step.content[0].annotations) {1269 console.log(`Citation: ${anno.title} (${anno.uri})`);1270 }1271 }1272 }1273 }12741275### Java12761277 import com.google.genai.Client;1278 import com.google.genai.gaos.models.interactions.Annotation;1279 import com.google.genai.gaos.models.interactions.Content;1280 import com.google.genai.gaos.models.interactions.CreateModelInteraction;1281 import com.google.genai.gaos.models.interactions.GoogleSearch;1282 import com.google.genai.gaos.models.interactions.GoogleSearchResult;1283 import com.google.genai.gaos.models.interactions.GoogleSearchResultStep;1284 import com.google.genai.gaos.models.interactions.Interaction;1285 import com.google.genai.gaos.models.interactions.InteractionsInput;1286 import com.google.genai.gaos.models.interactions.Model;1287 import com.google.genai.gaos.models.interactions.ModelOutputStep;1288 import com.google.genai.gaos.models.interactions.Step;1289 import com.google.genai.gaos.models.interactions.TextContent;1290 import com.google.genai.gaos.models.interactions.URLCitation;1291 import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;1292 import java.util.Arrays;1293 import java.util.Collections;12941295 Client client = new Client();12961297 CreateModelInteraction request =1298 CreateModelInteraction.builder()1299 .model(Model.of("gemini-3.8-flash"))1300 .input(InteractionsInput.of("Who won Euro 2024?"))1301 .tools(Arrays.asList(GoogleSearch.builder().build()))1302 .build();13031304 Interaction interaction =1305 client.interactions.create(CreateInteractionRequestBody.of(request)).interaction().get();13061307 for (Step step : interaction.steps().orElse(Collections.emptyList())) {1308 if (step instanceof GoogleSearchResultStep) {1309 GoogleSearchResultStep searchStep = (GoogleSearchResultStep) step;1310 for (GoogleSearchResult res : searchStep.result().orElse(Collections.emptyList())) {1311 System.out.println("Search Suggestions: " + res.searchSuggestions().orElse(""));1312 }1313 } else if (step instanceof ModelOutputStep) {1314 ModelOutputStep modelOutput = (ModelOutputStep) step;1315 for (Content contentBlock : modelOutput.content().orElse(Collections.emptyList())) {1316 if (contentBlock instanceof TextContent) {1317 TextContent textContent = (TextContent) contentBlock;1318 System.out.println("Answer: " + textContent.text().orElse(""));1319 for (Annotation anno : textContent.annotations().orElse(Collections.emptyList())) {1320 if (anno instanceof URLCitation) {1321 URLCitation cit = (URLCitation) anno;1322 System.out.println(1323 "Citation: " + cit.title().orElse("") + " (" + cit.url().orElse("") + ")");1324 }1325 }1326 }1327 }1328 }1329 }13301331### REST13321333 # Request1334 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \1335 -H "Content-Type: application/json" \1336 -H "x-goog-api-key: $GEMINI_API_KEY" \1337 -d '{1338 "model": "gemini-3.8-flash",1339 "input": "Who won Euro 2024?",1340 "tools": \[{"type": "google_search"}\]1341 }'13421343 # Response (showing grounding)1344 {1345 "id": "int_grounded",1346 "steps": \[1347 {1348 "type": "user_input",1349 "status": "done",1350 "content": \[{ "type": "text", "text": "Who won Euro 2024?" }\]1351 },1352 {1353 "type": "google_search_call",1354 "status": "done",1355 "content": \[{ "type": "text", "text": "UEFA Euro 2024 winner" }\]1356 },1357 {1358 "type": "google_search_result",1359 "status": "done",1360 "content": \[1361 {1362 "type": "text",1363 "text": "Spain won Euro 2024..."1364 }1365 \]1366 },1367 {1368 "type": "model_output",1369 "status": "done",1370 "content": \[1371 {1372 "type": "text",1373 "text": "Spain won Euro 2024, defeating England 2-1.",1374 "annotations": \[1375 {1376 "start_index": 0,1377 "end_index": 42,1378 "uri": "https://vertexaisearch...",1379 "title": "aljazeera.com"1380 }1381 \]1382 }1383 \]1384 }1385 \]1386 }13871388## Function calling13891390The structure of function calls and results has also changed to fit the Steps schema.13911392### Before (`generateContent`)13931394In `generateContent`, the response returns function calls within the candidates.\* {Python}13951396 ```python1397 from google import genai1398 from google.genai import types13991400 client = genai.Client()14011402 response = client.models.generate_content(1403 model="gemini-2.5-flash-lite",1404 contents="What's the weather in Boston?",1405 config=types.GenerateContentConfig(tools=[weather_tool]),1406 )14071408 function_call = response.candidates[0].content.parts[0].function_call1409 print(f"Requested tool: {function_call.name}")14101411 result = "52°F and rain"14121413 response = client.models.generate_content(1414 model="gemini-2.5-flash-lite",1415 contents=[1416 types.Content(1417 role="user",1418 parts=[1419 types.Part.from_text(text="What's the weather in Boston?")1420 ],1421 ),1422 response.candidates[0].content,1423 types.Content(1424 role="user",1425 parts=[1426 types.Part.from_function_response(1427 name=function_call.name,1428 response={"result": result},1429 )1430 ],1431 ),1432 ],1433 config=types.GenerateContentConfig(tools=[weather_tool]),1434 )1435 print(response.text)1436 ```14371438### JavaScript14391440 import { GoogleGenAI } from '@google/genai';14411442 const client = new GoogleGenAI({});14431444 let response = await client.models.generateContent({1445 model: 'gemini-2.5-flash-lite',1446 contents: "What's the weather in Boston?",1447 config: { tools: [weatherTool] }1448 });14491450 const functionCall = response.candidates[0].content.parts[0].functionCall;1451 console.log(`Requested tool: ${functionCall.name}`);14521453 const result = "52°F and rain";14541455 response = await client.models.generateContent({1456 model: 'gemini-2.5-flash-lite',1457 contents: [1458 { role: 'user', parts: [{ text: "What's the weather in Boston?" }] },1459 response.candidates[0].content,1460 {1461 role: 'user',1462 parts: [{1463 functionResponse: {1464 name: functionCall.name,1465 response: { result: result }1466 }1467 }]1468 }1469 ],1470 config: { tools: [weatherTool] }1471 });1472 console.log(response.text);14731474### Java14751476 import com.google.genai.Client;1477 import com.google.genai.types.Content;1478 import com.google.genai.types.FunctionCall;1479 import com.google.genai.types.FunctionDeclaration;1480 import com.google.genai.types.GenerateContentConfig;1481 import com.google.genai.types.GenerateContentResponse;1482 import com.google.genai.types.Part;1483 import com.google.genai.types.Schema;1484 import com.google.genai.types.Tool;1485 import com.google.genai.types.Type;1486 import java.util.Arrays;1487 import java.util.Map;14881489 Client client = new Client();14901491 FunctionDeclaration weatherFunc =1492 FunctionDeclaration.builder()1493 .name("get_weather")1494 .description("Gets weather")1495 .parameters(1496 Schema.builder()1497 .type(Type.Known.OBJECT)1498 .properties(Map.of("location", Schema.builder().type(Type.Known.STRING).build()))1499 .build())1500 .build();15011502 Tool weatherTool = Tool.builder().functionDeclarations(Arrays.asList(weatherFunc)).build();15031504 GenerateContentResponse response =1505 client.models.generateContent(1506 "gemini-2.5-flash-lite",1507 "What's the weather in Boston?",1508 GenerateContentConfig.builder().tools(Arrays.asList(weatherTool)).build());15091510 FunctionCall functionCall = response.functionCalls().get(0);1511 System.out.println("Requested tool: " + functionCall.name().orElse(""));15121513 String result = "52°F and rain";15141515 GenerateContentResponse finalResponse =1516 client.models.generateContent(1517 "gemini-2.5-flash-lite",1518 Arrays.asList(1519 Content.builder()1520 .role("user")1521 .parts(Arrays.asList(Part.fromText("What's the weather in Boston?")))1522 .build(),1523 response.candidates().get().get(0).content().get(),1524 Content.builder()1525 .role("user")1526 .parts(1527 Arrays.asList(1528 Part.fromFunctionResponse(1529 functionCall.name().orElse(""), Map.of("result", result))))1530 .build()),1531 GenerateContentConfig.builder().tools(Arrays.asList(weatherTool)).build());1532 System.out.println(finalResponse.text());15331534### REST15351536 # Request1537 curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent" \1538 -H "Content-Type: application/json" \1539 -H "x-goog-api-key: $GEMINI_API_KEY" \1540 -d '{1541 "contents": \[{1542 "parts": \[{1543 "text": "What is the weather like in Boston, MA?"1544 }\]1545 }\],1546 "tools": \[{1547 "functionDeclarations": \[{1548 "name": "get_weather",1549 "description": "Get the current weather",1550 "parameters": {1551 "type": "OBJECT",1552 "properties": {1553 "location": {"type": "STRING"}1554 },1555 "required": \["location"\]1556 }1557 }\]1558 }\]1559 }'15601561 # Response1562 {1563 "candidates": \[1564 {1565 "content": {1566 "parts": \[1567 {1568 "functionCall": {1569 "name": "get_weather",1570 "args": { "location": "Boston, MA" }1571 }1572 }1573 \],1574 "role": "model"1575 },1576 "finishReason": "STOP",1577 "index": 01578 }1579 \]1580 }15811582### After (Interactions API)15831584Tool calls and results are now distinct steps in the timeline.15851586### Python15871588 from google import genai15891590 client = genai.Client()15911592 weather_tool = {1593 "type": "function",1594 "name": "get_weather",1595 "description": "Gets weather",1596 "parameters": {1597 "type": "object",1598 "properties": {1599 "location": {"type": "string"}1600 },1601 },1602 }16031604 interaction = client.interactions.create(1605 model="gemini-3.8-flash",1606 input="What's the weather in Boston?",1607 tools=[weather_tool],1608 )16091610 for step in interaction.steps:1611 if step.type == "function_call":1612 print(f"Executing {step.name} for {step.arguments}")16131614 result = "52°F and rain"16151616 interaction = client.interactions.create(1617 model="gemini-3.8-flash",1618 previous_interaction_id=interaction.id,1619 input=[1620 {1621 "type": "function_result",1622 "call_id": step.id,1623 "name": step.name,1624 "result": [{"type": "text", "text": result}],1625 }1626 ],1627 )1628 print(interaction.output_text)16291630### JavaScript16311632 import { GoogleGenAI } from '@google/genai';16331634 const client = new GoogleGenAI({});16351636 const weatherTool = {1637 type: "function",1638 name: "get_weather",1639 description: "Get weather for a location",1640 parameters: {1641 type: "object",1642 properties: {1643 location: { type: "string" }1644 },1645 required: ["location"]1646 }1647 };16481649 const interaction = await client.interactions.create({1650 model: 'gemini-3.8-flash',1651 input: "What's the weather in Boston?",1652 tools: [weatherTool]1653 });16541655 for (const step of interaction.steps) {1656 if (step.type === 'function_call') {1657 console.log(`Executing ${step.name} for ${JSON.stringify(step.arguments)}`);16581659 const result = "52°F and rain";16601661 const nextInteraction = await client.interactions.create({1662 model: 'gemini-3.8-flash',1663 previous_interaction_id: interaction.id,1664 input: [1665 {1666 type: 'function_result',1667 call_id: step.id,1668 name: step.name,1669 result: [{ type: 'text', text: result }]1670 }1671 ]1672 });16731674 console.log(nextInteraction.output_text);1675 }1676 }16771678### Java16791680 import com.google.genai.Client;1681 import com.google.genai.gaos.models.interactions.CreateModelInteraction;1682 import com.google.genai.gaos.models.interactions.Function;1683 import com.google.genai.gaos.models.interactions.FunctionCallStep;1684 import com.google.genai.gaos.models.interactions.FunctionResultStep;1685 import com.google.genai.gaos.models.interactions.FunctionResultStepResultUnion;1686 import com.google.genai.gaos.models.interactions.Interaction;1687 import com.google.genai.gaos.models.interactions.InteractionsInput;1688 import com.google.genai.gaos.models.interactions.Model;1689 import com.google.genai.gaos.models.interactions.Step;1690 import com.google.genai.gaos.models.interactions.TextContent;1691 import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;1692 import java.util.Arrays;1693 import java.util.Collections;1694 import java.util.HashMap;1695 import java.util.Map;16961697 Client client = new Client();16981699 Map<String, Object> properties = new HashMap<>();1700 properties.put("location", Map.of("type", "string"));17011702 Map<String, Object> parameters = new HashMap<>();1703 parameters.put("type", "object");1704 parameters.put("properties", properties);1705 parameters.put("required", Arrays.asList("location"));17061707 Function weatherTool =1708 Function.builder()1709 .name("get_weather")1710 .description("Gets weather")1711 .parameters(parameters)1712 .build();17131714 CreateModelInteraction request =1715 CreateModelInteraction.builder()1716 .model(Model.of("gemini-3.8-flash"))1717 .input(InteractionsInput.of("What's the weather in Boston?"))1718 .tools(Arrays.asList(weatherTool))1719 .build();17201721 Interaction interaction =1722 client.interactions.create(CreateInteractionRequestBody.of(request)).interaction().get();17231724 for (Step step : interaction.steps().orElse(Collections.emptyList())) {1725 if (step instanceof FunctionCallStep) {1726 FunctionCallStep fcStep = (FunctionCallStep) step;1727 System.out.println(1728 "Executing "1729 + fcStep.name().orElse("")1730 + " for "1731 + fcStep.arguments().orElse(Collections.emptyMap()));17321733 String result = "52°F and rain";17341735 FunctionResultStep funcResult =1736 FunctionResultStep.builder()1737 .callId(fcStep.id().orElse(""))1738 .name(fcStep.name().orElse(""))1739 .result(1740 FunctionResultStepResultUnion.of(1741 Arrays.asList(TextContent.builder().text(result).build())))1742 .build();17431744 CreateModelInteraction nextRequest =1745 CreateModelInteraction.builder()1746 .model(Model.of("gemini-3.8-flash"))1747 .previousInteractionId(interaction.id().orElse(""))1748 .input(InteractionsInput.ofStep(Arrays.asList(funcResult)))1749 .build();17501751 Interaction nextInteraction =1752 client.interactions.create(CreateInteractionRequestBody.of(nextRequest)).interaction().get();1753 System.out.println(nextInteraction.outputText().orElse(""));1754 }1755 }17561757### REST17581759 # Initial Request1760 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \1761 -H "Content-Type: application/json" \1762 -H "x-goog-api-key: $GEMINI_API_KEY" \1763 -d '{1764 "model": "gemini-3.8-flash",1765 "input": "What's the weather in Boston?",1766 "tools": \[{1767 "type": "function",1768 "name": "get_weather",1769 "description": "Get weather for a location",1770 "parameters": {1771 "type": "object",1772 "properties": {1773 "location": { "type": "string" }1774 },1775 "required": \["location"\]1776 }1777 }\]1778 }'17791780 # Response (requires action)1781 {1782 "id": "int_001",1783 "status": "requires_action",1784 "steps": \[1785 {1786 "type": "user_input",1787 "status": "done",1788 "content": \[1789 { "type": "text", "text": "What's the weather in Boston?" }1790 \]1791 },1792 {1793 "type": "function_call",1794 "status": "waiting",1795 "id": "fc_1",1796 "name": "get_weather",1797 "arguments": { "location": "Boston, MA" }1798 }1799 \]1800 }18011802 # Submit Tool Result Request1803 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \1804 -H "Content-Type: application/json" \1805 -H "x-goog-api-key: $GEMINI_API_KEY" \1806 -d '{1807 "model": "gemini-3.8-flash",1808 "previous_interaction_id": "int_001",1809 "input": {1810 "type": "function_result",1811 "call_id": "fc_1",1812 "name": "get_weather",1813 "result": \[1814 { "type": "text", "text": "52°F with rain" }1815 \]1816 }1817 }'18181819 # Final Response1820 {1821 "id": "int_002",1822 "status": "completed",1823 "steps": \[1824 {1825 "type": "function_result",1826 "call_id": "fc_1",1827 "name": "get_weather",1828 "result": \[1829 { "type": "text", "text": "52°F with rain" }1830 \]1831 },1832 {1833 "type": "model_output",1834 "status": "done",1835 "content": \[1836 { "type": "text", "text": "It's 52°F with rain in Boston." }1837 \]1838 }1839 \]1840 }18411842## Streaming18431844A key difference in streaming is that the Interactions API uses the same endpoint with `"stream": true` in the request body, whereas the `generateContent` API required calling a dedicated endpoint (`:streamGenerateContent`).18451846Additionally, streaming events now use specialized types to monitor the interaction lifecycle and track execution steps along the timeline.18471848### Before (`generateContentStream`)18491850With `generateContent`, you consume a stream of response chunks.18511852### Python18531854 from google import genai18551856 client = genai.Client()18571858 response = client.models.generate_content_stream(1859 model="gemini-2.5-flash-lite", contents="Tell me a story"1860 )1861 for chunk in response:1862 print(chunk.text, end="")18631864### JavaScript18651866 const responseStream = await client.models.generateContentStream({1867 model: 'gemini-2.5-flash-lite',1868 contents: 'Tell me a story',1869 });1870 for await (const chunk of responseStream) {1871 process.stdout.write(chunk.text);1872 }18731874### Java18751876 import com.google.genai.Client;1877 import com.google.genai.ResponseStream;1878 import com.google.genai.types.GenerateContentResponse;18791880 Client client = new Client();18811882 try (ResponseStream<GenerateContentResponse> responseStream =1883 client.models.generateContentStream("gemini-2.5-flash-lite", "Tell me a story", null)) {1884 for (GenerateContentResponse chunk : responseStream) {1885 System.out.print(chunk.text());1886 }1887 }18881889### REST18901891 # Request1892 curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:streamGenerateContent" \1893 -H "Content-Type: application/json" \1894 -H "x-goog-api-key: $GEMINI_API_KEY" \1895 -d '{1896 "contents": \[{1897 "parts": \[{1898 "text": "Tell me a story"1899 }\]1900 }\]1901 }'19021903 # Response stream1904 event: content.start1905 data: {"event_type": "content.start", "index": 0, "content": {"type": "thought"}}1906 event: content.delta1907 data: {"event_type": "content.delta", "index": 0, "delta": {"type": "thought_summary", "text": "User wants an explanation."}}1908 event: content.stop1909 data: {"event_type": "content.stop", "index": 0}1910 event: content.start1911 data: {"event_type": "content.start", "index": 1, "content": {"type": "text"}}1912 event: content.delta1913 data: {"event_type": "content.delta", "index": 1, "delta": {"type": "text", "text": "Hello"}}1914 event: content.stop1915 data: {"event_type": "content.stop", "index": 1}19161917### After (Interactions API)19181919In the Interactions API, streaming uses Server-Sent Events (SSE) and specialized delta types to represent execution steps as they happen.19201921### Python19221923 from google import genai19241925 client = genai.Client()19261927 stream = client.interactions.create(1928 model="gemini-3.8-flash",1929 input="Tell me a story",1930 stream=True,1931 )19321933 for event in stream:1934 if event.event_type == "step.delta" and event.delta:1935 if getattr(event.delta, "type", None) == "text" and getattr(event.delta, "text", None):1936 print(event.delta.text, end="", flush=True)1937 elif event.event_type == "interaction.completed":1938 print(f"\n\n--- Stream Finished ---")19391940### JavaScript19411942 import { GoogleGenAI } from '@google/genai';19431944 const client = new GoogleGenAI({});19451946 const stream = await client.interactions.create({1947 model: 'gemini-3.8-flash',1948 input: 'Tell me a story',1949 stream: true,1950 });19511952 for await (const event of stream) {1953 if (event.event_type === 'step.delta' && event.delta) {1954 if (event.delta.type === 'text' && event.delta.text) {1955 process.stdout.write(event.delta.text);1956 }1957 } else if (event.event_type === 'interaction.completed') {1958 console.log('\n\n--- Stream Finished ---');1959 }1960 }19611962### Java19631964 import com.google.genai.Client;1965 import com.google.genai.gaos.models.interactions.CreateModelInteraction;1966 import com.google.genai.gaos.models.interactions.InteractionCompletedEvent;1967 import com.google.genai.gaos.models.interactions.InteractionSSEEvent;1968 import com.google.genai.gaos.models.interactions.InteractionSSEStreamEvent;1969 import com.google.genai.gaos.models.interactions.InteractionsInput;1970 import com.google.genai.gaos.models.interactions.Model;1971 import com.google.genai.gaos.models.interactions.StepDelta;1972 import com.google.genai.gaos.models.interactions.TextDelta;1973 import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;1974 import com.google.genai.gaos.utils.EventStream;19751976 Client client = new Client();19771978 CreateModelInteraction request =1979 CreateModelInteraction.builder()1980 .model(Model.of("gemini-3.8-flash"))1981 .input(InteractionsInput.of("Tell me a story"))1982 .stream(true)1983 .build();19841985 try (EventStream<InteractionSSEStreamEvent> stream =1986 client.interactions.create(CreateInteractionRequestBody.of(request)).events()) {1987 for (InteractionSSEStreamEvent streamEvent : stream) {1988 if (streamEvent.data().isPresent()) {1989 InteractionSSEEvent event = streamEvent.data().get();1990 if (event instanceof StepDelta) {1991 StepDelta stepDelta = (StepDelta) event;1992 if (stepDelta.delta().isPresent() && stepDelta.delta().get() instanceof TextDelta) {1993 TextDelta textDelta = (TextDelta) stepDelta.delta().get();1994 System.out.print(textDelta.text().orElse(""));1995 }1996 } else if (event instanceof InteractionCompletedEvent) {1997 System.out.println("\n\n--- Stream Finished ---");1998 }1999 }2000 }2001 }20022003### REST20042005# Example SSE stream output2006**event: interaction.created2007data: {"type": "interaction.created", "interaction": {"id": "int_xyz", "status": "created"}}2008event: interaction.in_progress2009data: {"type": "interaction.in_progress", "interaction": {"id": "int_xyz", "status": "in_progress"}}2010event: step.start2011data: {"type": "step.start", "index": 0, "step": {"type": "thought"}}2012event: step.delta2013data: {"type": "step.delta", "index": 0, "delta": {"type": "thought", "text": "User wants an explanation."}}2014event: step.stop2015data: {"type": "step.stop", "index": 0, "status": "done"}2016event: step.start2017data: {"type": "step.start", "index": 1, "step": {"type": "model_output"}}2018event: step.delta2019data: {"type": "step.delta", "index": 1, "delta": {"type": "text", "text": "Hello"}}2020event: step.stop2021data: {"type": "step.stop", "index": 1, "status": "done"}2022event: interaction.completed2023data: {"type": "interaction.completed", "interaction": {"id": "int_xyz", "status": "completed", "usage": {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15}}}**2024\`\`\`20252026### Streaming tools and function calls20272028The way tools behave in the stream has shifted significantly from `generateContent` to provide more granular control and visibility.20292030#### Before (`generateContent`)20312032With `generateContent`, streaming function calls arrived complete in a single chunk. You could not see the arguments being generated in real-time, so the handler simply checked for a complete `functionCall` object.20332034### Python20352036 from google import genai2037 from google.genai import types20382039 client = genai.Client()20402041 stream = client.models.generate_content_stream(2042 model="gemini-2.5-flash-lite",2043 contents="What's the weather in Boston?",2044 config=types.GenerateContentConfig(tools=[weather_tool]),2045 )20462047 for chunk in stream:2048 # Function calls arrived complete --- no partial arguments2049 if chunk.candidates[0].content.parts[0].function_call:2050 fc = chunk.candidates[0].content.parts[0].function_call2051 print(f"Call: {fc.name}({fc.args})")2052 elif chunk.text:2053 print(chunk.text, end="")20542055### JavaScript20562057 import { GoogleGenAI } from '@google/genai';20582059 const client = new GoogleGenAI({});20602061 const stream = await client.models.generateContentStream({2062 model: 'gemini-2.5-flash-lite',2063 contents: "What's the weather in Boston?",2064 config: { tools: [weatherTool] }2065 });20662067 for await (const chunk of stream) {2068 const part = chunk.candidates[0].content.parts[0];2069 if (part.functionCall) {2070 console.log(`Call: ${part.functionCall.name}(${JSON.stringify(part.functionCall.args)})`);2071 } else if (part.text) {2072 process.stdout.write(part.text);2073 }2074 }20752076### Java20772078 import com.google.genai.Client;2079 import com.google.genai.ResponseStream;2080 import com.google.genai.types.FunctionCall;2081 import com.google.genai.types.FunctionDeclaration;2082 import com.google.genai.types.GenerateContentConfig;2083 import com.google.genai.types.GenerateContentResponse;2084 import com.google.genai.types.Schema;2085 import com.google.genai.types.Tool;2086 import com.google.genai.types.Type;2087 import java.util.Arrays;2088 import java.util.Map;20892090 Client client = new Client();20912092 FunctionDeclaration weatherFunc =2093 FunctionDeclaration.builder()2094 .name("get_weather")2095 .description("Gets weather")2096 .parameters(2097 Schema.builder()2098 .type(Type.Known.OBJECT)2099 .properties(Map.of("location", Schema.builder().type(Type.Known.STRING).build()))2100 .build())2101 .build();21022103 Tool weatherTool = Tool.builder().functionDeclarations(Arrays.asList(weatherFunc)).build();21042105 try (ResponseStream<GenerateContentResponse> stream =2106 client.models.generateContentStream(2107 "gemini-2.5-flash-lite",2108 "What's the weather in Boston?",2109 GenerateContentConfig.builder().tools(Arrays.asList(weatherTool)).build())) {2110 for (GenerateContentResponse chunk : stream) {2111 if (chunk.functionCalls() != null && !chunk.functionCalls().isEmpty()) {2112 FunctionCall fc = chunk.functionCalls().get(0);2113 System.out.println("Call: " + fc.name().orElse("") + "(" + fc.args().orElse(Map.of()) + ")");2114 } else if (chunk.text() != null) {2115 System.out.print(chunk.text());2116 }2117 }2118 }21192120### REST21212122 # Request2123 curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:streamGenerateContent" \2124 -H "Content-Type: application/json" \2125 -H "x-goog-api-key: $GEMINI_API_KEY" \2126 -d '{2127 "contents": \[{"parts": \[{"text": "What is the weather in Boston?"}\]}\],2128 "tools": \[{"functionDeclarations": \[{"name": "get_weather", "parameters": {"type": "OBJECT", "properties": {"location": {"type": "STRING"}}}}\]}\]2129 }'21302131 # Response stream --- function call arrives complete in one chunk2132 {"candidates": \[{"content": {"parts": \[{"functionCall": {"name": "get_weather", "args": {"location": "Boston, MA"}}}\]}}\]}21332134#### After (Interactions API)21352136The Interactions API streams function call arguments character-by-character as `arguments` events. The entire tool lifecycle --- thought, call, result, and output --- plays out as a series of distinct steps.21372138### Python21392140 from google import genai21412142 client = genai.Client()21432144 stream = client.interactions.create(2145 model="gemini-3.8-flash",2146 input="What's the weather in Boston?",2147 tools=[get_weather_tool],2148 stream=True,2149 )21502151 for event in stream:2152 if event.event_type == "step.start" and event.step:2153 if getattr(event.step, "type", None) == "function_call":2154 print(f"Calling: {event.step.name}")2155 elif event.event_type == "step.delta" and event.delta:2156 if getattr(event.delta, "type", None) == "arguments":2157 print(f" args: {event.delta.partial_arguments}")2158 elif getattr(event.delta, "type", None) == "text" and getattr(event.delta, "text", None):2159 print(event.delta.text, end="")2160 elif event.event_type == "interaction.completed":2161 print("\n--- Done ---")21622163### JavaScript21642165 import { GoogleGenAI } from '@google/genai';21662167 const client = new GoogleGenAI({});21682169 const stream = await client.interactions.create({2170 model: 'gemini-3.8-flash',2171 input: "What's the weather in Boston?",2172 tools: [getWeatherTool],2173 stream: true,2174 });21752176 for await (const event of stream) {2177 if (event.event_type === 'step.start' && event.step) {2178 if (event.step.type === 'function_call') {2179 console.log(`Calling: ${event.step.name}`);2180 }2181 } else if (event.event_type === 'step.delta' && event.delta) {2182 if (event.delta.type === 'arguments' && event.delta.partial_arguments) {2183 console.log(` args: ${event.delta.partial_arguments}`);2184 } else if (event.delta.type === 'text' && event.delta.text) {2185 process.stdout.write(event.delta.text);2186 }2187 } else if (event.event_type === 'interaction.completed') {2188 console.log('\n--- Done ---');2189 }2190 }21912192### Java21932194 import com.google.genai.Client;2195 import com.google.genai.gaos.models.interactions.ArgumentsDelta;2196 import com.google.genai.gaos.models.interactions.CreateModelInteraction;2197 import com.google.genai.gaos.models.interactions.Function;2198 import com.google.genai.gaos.models.interactions.FunctionCallStep;2199 import com.google.genai.gaos.models.interactions.InteractionCompletedEvent;2200 import com.google.genai.gaos.models.interactions.InteractionSSEEvent;2201 import com.google.genai.gaos.models.interactions.InteractionSSEStreamEvent;2202 import com.google.genai.gaos.models.interactions.InteractionsInput;2203 import com.google.genai.gaos.models.interactions.Model;2204 import com.google.genai.gaos.models.interactions.StepDelta;2205 import com.google.genai.gaos.models.interactions.StepDeltaData;2206 import com.google.genai.gaos.models.interactions.StepStart;2207 import com.google.genai.gaos.models.interactions.TextDelta;2208 import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;2209 import com.google.genai.gaos.utils.EventStream;2210 import java.util.Arrays;2211 import java.util.HashMap;2212 import java.util.Map;22132214 Client client = new Client();22152216 Map<String, Object> properties = new HashMap<>();2217 properties.put("location", Map.of("type", "string"));22182219 Map<String, Object> parameters = new HashMap<>();2220 parameters.put("type", "object");2221 parameters.put("properties", properties);2222 parameters.put("required", Arrays.asList("location"));22232224 Function getWeatherTool =2225 Function.builder()2226 .name("get_weather")2227 .description("Gets weather")2228 .parameters(parameters)2229 .build();22302231 CreateModelInteraction request =2232 CreateModelInteraction.builder()2233 .model(Model.of("gemini-3.8-flash"))2234 .input(InteractionsInput.of("What's the weather in Boston?"))2235 .tools(Arrays.asList(getWeatherTool))2236 .stream(true)2237 .build();22382239 try (EventStream<InteractionSSEStreamEvent> stream =2240 client.interactions.create(CreateInteractionRequestBody.of(request)).events()) {2241 for (InteractionSSEStreamEvent streamEvent : stream) {2242 if (streamEvent.data().isPresent()) {2243 InteractionSSEEvent event = streamEvent.data().get();2244 if (event instanceof StepStart) {2245 StepStart stepStart = (StepStart) event;2246 if (stepStart.step().isPresent() && stepStart.step().get() instanceof FunctionCallStep) {2247 FunctionCallStep fcStep = (FunctionCallStep) stepStart.step().get();2248 System.out.println("Calling: " + fcStep.name().orElse(""));2249 }2250 } else if (event instanceof StepDelta) {2251 StepDelta stepDelta = (StepDelta) event;2252 if (stepDelta.delta().isPresent()) {2253 StepDeltaData delta = stepDelta.delta().get();2254 if (delta instanceof ArgumentsDelta) {2255 System.out.println(" args: " + ((ArgumentsDelta) delta).arguments().orElse(""));2256 } else if (delta instanceof TextDelta) {2257 System.out.print(((TextDelta) delta).text().orElse(""));2258 }2259 }2260 } else if (event instanceof InteractionCompletedEvent) {2261 System.out.println("\n--- Done ---");2262 }2263 }2264 }2265 }22662267### REST22682269 # Request2270 curl -X POST "https://generativelanguage.googleapis.com/v1beta2/interactions" \2271 -H "Content-Type: application/json" \2272 -H "x-goog-api-key: $GEMINI_API_KEY" \2273 -d '{2274 "model": "gemini-3.8-flash",2275 "input": "What is the weather in Boston?",2276 "tools": \[{"type": "function", "name": "get_weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}}}\],2277 "stream": true2278 }'22792280 # Response stream2281 // Interaction created2282 event: interaction.created2283 data: {"type": "interaction.created", "interaction": {"id": "int_xyz", "status": "created"}}22842285 event: interaction.in_progress2286 data: {"type": "interaction.in_progress", "interaction": {"id": "int_xyz", "status": "in_progress"}}22872288 // ── Step 0: Thought ──────────────────────────────────2289 event: step.start2290 data: {"type": "step.start", "index": 0, "step": {"type": "thought"}}22912292 event: step.delta2293 data: {"type": "step.delta", "index": 0, "delta": {"type": "thought", "text": "The user wants weather data for Boston. I'll call the get_weather tool."}}22942295 event: step.stop2296 data: {"type": "step.stop", "index": 0, "status": "done"}22972298 // ── Step 1: Function Call (arguments streamed) ───────2299 event: step.start2300 data: {"type": "step.start", "index": 1, "step": {"type": "function_call", "id": "fc_1", "name": "get_weather"}}23012302 event: step.delta2303 data: {"type": "step.delta", "index": 1, "delta": {"type": "arguments", "partial_arguments": "{\"location\": \"Boston, MA\"}"}}23042305 event: step.stop2306 data: {"type": "step.stop", "index": 1, "status": "waiting"}23072308 // The interaction pauses --- the model needs the tool result before continuing.2309 event: interaction.requires_action2310 data: {"type": "interaction.requires_action", "interaction": {"id": "int_xyz", "status": "requires_action"}}23112312 // ── (Client submits the tool result) ──────────────────2313 // The client calls interactions.create with the function_result as input2314 // and the previous interaction's ID, then resumes consuming the stream.23152316 event: interaction.in_progress2317 data: {"type": "interaction.in_progress", "interaction": {"id": "int_xyz", "status": "in_progress"}}23182319 // ── Step 2: Function Result (echoed back, no deltas) ─2320 event: step.start2321 data: {"type": "step.start", "index": 2, "step": {"type": "function_result", "call_id": "fc_1", "name": "get_weather", "result": [{"type": "text", "text": "52°F, rain"}]}}23222323 event: step.stop2324 data: {"type": "step.stop", "index": 2, "status": "done"}23252326 // ── Step 3: Thought ──────────────────────────────────2327 event: step.start2328 data: {"type": "step.start", "index": 3, "step": {"type": "thought"}}23292330 event: step.delta2331 data: {"type": "step.delta", "index": 3, "delta": {"type": "thought", "text": "Got weather data. Composing the final response."}}23322333 event: step.stop2334 data: {"type": "step.stop", "index": 3, "status": "done"}23352336 // ── Step 4: Model Output (text streamed) ─────────────2337 event: step.start2338 data: {"type": "step.start", "index": 4, "step": {"type": "model_output"}}23392340 event: step.delta2341 data: {"type": "step.delta", "index": 4, "delta": {"type": "text", "text": "It's currently 52°F and rainy in Boston."}}23422343 event: step.stop2344 data: {"type": "step.stop", "index": 4, "status": "done"}23452346 // ── Interaction complete ─────────────────────────────2347 event: interaction.completed2348 data: {"type": "interaction.completed", "interaction": {"id": "int_xyz", "status": "completed", "usage": {"prompt_tokens": 256, "completion_tokens": 128, "total_tokens": 384}}}