Skip to content
Blog

How to Run Long-Running AI Tasks With Gemini Background Execution

Learn how to use Gemini Interactions API background execution to run deep research, complex reasoning, and multi-step agent tasks asynchronously, with polling, streaming reconnection, multi-turn chaining, and cancellation patterns.

Published on August 5, 2026

AI Assistant

Introduction

For long-running tasks like deep research, complex reasoning, or multi-step agents, connection timeouts can suddenly interrupt standard HTTP requests, which typically close after about 60 seconds. If your application needs to drive a model that’s thinking through a hard problem for several minutes, a plain synchronous request simply won’t work.

The Gemini Interactions API solves this with background execution. By setting "background": true when you create an interaction, the task runs asynchronously on Google’s servers. The API immediately returns an interaction ID, which your client can use to poll for status, stream progress, or reconnect to a stream that was interrupted.

In this post we’ll cover how background execution works, how to create background interactions, how to retrieve results with polling or streaming, how to chain multi-turn conversations, and how to cancel or delete running interactions.

Why background execution matters

Standard HTTP requests have real, practical limits. If a model needs to browse the web, run code, orchestrate sub-agents, or perform deep research, the request can easily outlive a client’s connection timeout. Background execution decouples the task lifecycle from your client connection:

  • The server keeps working even if your client disconnects.
  • You get an interaction ID immediately, which is the handle for everything that happens next.
  • You can poll, stream, or reconnect to the same interaction from anywhere.
  • It’s supported for standard Gemini models (gemini-3.6-flash, gemini-3.1-pro-preview) and Managed Agents like antigravity-preview-05-2026.

Creating a background interaction

Starting a background interaction is a one-line change: set background to true.

Python

from google import genai

client = genai.Client()

interaction = client.interactions.create(
    model="gemini-3.6-flash",
    input="Write a guide on space exploration.",
    background=True,
)
print(f"Created background interaction ID: {interaction.id}")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

const interaction = await client.interactions.create({
    model: "gemini-3.6-flash",
    input: "Write a guide on space exploration.",
    background: true,
});
console.log(`Created background interaction ID: ${interaction.id}`);

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Api-Revision: 2026-05-20" \
  -d '{
    "model": "gemini-3.6-flash",
    "input": "Write a guide on space exploration.",
    "background": true
  }'

How background execution works

When you create a background interaction, the task runs asynchronously on the server. The interaction transitions through various execution states:

  • in_progress: The server is actively executing the interaction (running code, researching, etc.).
  • requires_action: The interaction paused and is waiting for client input (confirming a tool execution or answering a question).
  • completed: The interaction finished successfully and output is available.
  • failed: An error occurred during execution (tool failure, rate limits, etc.).
  • cancelled: A client request stopped the execution.

Best use cases

Reach for background execution when:

  • Agent executions need code execution, web browsing, or sub-agent orchestration (for example antigravity-preview-05-2026).
  • Deep research runs via deep-research-preview-04-2026 or deep-research-max-preview-04-2026, which can take several minutes.
  • Long reasoning tasks need thinking steps that exceed standard HTTP connection limits.

Retrieving results

You can obtain background interaction results using either polling or streaming.

Polling pattern (non-blocking)

Polling checks the interaction status periodically with non-blocking GET requests until it reaches a terminal state.

Python

import time
from google import genai

client = genai.Client()

interaction = client.interactions.get(id="YOUR_INTERACTION_ID")

while interaction.status == "in_progress":
    time.sleep(5)
    interaction = client.interactions.get(id=interaction.id)

if interaction.status == "completed":
    print(interaction.output_text)
else:
    print(f"Finished with status: {interaction.status}")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

let interaction = await client.interactions.get("YOUR_INTERACTION_ID");

while (interaction.status === "in_progress") {
    await new Promise(resolve => setTimeout(resolve, 5000));
    interaction = await client.interactions.get(interaction.id);
}

if (interaction.status === "completed") {
    console.log(interaction.output_text);
} else {
    console.log(`Finished with status: ${interaction.status}`);
}

REST

curl -X GET "https://generativelanguage.googleapis.com/v1beta/interactions/YOUR_INTERACTION_ID" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Api-Revision: 2026-05-20"

Streaming pattern with reconnection

If a network interruption disconnects a stream, the stream can resume from the last received event. Each delta contains a unique event_id in its payload. Passing this ID as last_event_id resumes the stream from that event.

Python

import time
from google import genai

client = genai.Client()
interaction_id = "YOUR_INTERACTION_ID"

def stream_with_reconnect(interaction_id: str):
    last_event_id = None
    while True:
        try:
            # Retrieve the stream. If resuming, pass last_event_id
            stream = client.interactions.get(
                id=interaction_id,
                stream=True,
                last_event_id=last_event_id
            )

            for event in stream:
                # Log event updates and capture event_id if present
                if event.event_id:
                    last_event_id = event.event_id

                if event.event_type == "step.delta" and event.delta.type == "text":
                    print(event.delta.text, end="", flush=True)

                if event.event_type == "interaction.completed":
                    return

        except Exception as e:
            print(f"\n[Connection lost: {e}. Reconnecting in 3s...]")
            time.sleep(3)

stream_with_reconnect(interaction_id)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});
const interactionId = "YOUR_INTERACTION_ID";

async function streamWithReconnect(id) {
    let lastEventId = undefined;
    while (true) {
        try {
            const stream = await client.interactions.get(id, {
                stream: true,
                last_event_id: lastEventId
            });

            for await (const event of stream) {
                const idVal = event.event_id || event.id;
                if (idVal) {
                    lastEventId = idVal;
                }

                if (event.event_type === "step.delta" && event.delta?.type === "text") {
                    process.stdout.write(event.delta.text);
                }

                if (event.event_type === "interaction.completed") {
                    return;
                }
            }
        } catch (error) {
            console.log(`\n[Connection lost: ${error.message}. Reconnecting in 3s...]`);
            await new Promise(resolve => setTimeout(resolve, 3000));
        }
    }
}

await streamWithReconnect(interactionId);

REST

curl -N -X GET "https://generativelanguage.googleapis.com/v1beta/interactions/YOUR_INTERACTION_ID?stream=true&last_event_id=YOUR_LAST_EVENT_ID" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Api-Revision: 2026-05-20"

Multi-turn conversations

Subsequent interactions can chain to a background conversation using previous_interaction_id, subject to two constraints:

  1. Active executions are blocked: Chaining to an interaction with in_progress status returns a 400 Bad Request. Wait for the previous interaction to reach completed before starting the next one.
  2. Environment parameter for Managed Agents: When chaining interactions for Managed Agents, requests must include both previous_interaction_id and environment.

Python

import time
from google import genai

client = genai.Client()
agent_model = "antigravity-preview-05-2026"

# First interaction: provision sandbox environment and execute first instruction
interaction1 = client.interactions.create(
    model=agent_model,
    input="Create a folder named project/ and write hello.py inside.",
    environment="remote",
    background=True
)

# Wait for completion
while True:
    check = client.interactions.get(id=interaction1.id)
    if check.status != "in_progress":
        break
    time.sleep(2)

# Second interaction: chain using previous_interaction_id and environment
interaction2 = client.interactions.create(
    model=agent_model,
    input="List all files in the project/ directory.",
    previous_interaction_id=interaction1.id,
    environment="remote",
    background=True
)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});
const agentModel = "antigravity-preview-05-2026";

// First interaction: provision sandbox environment and execute first instruction
const interaction1 = await client.interactions.create({
    model: agentModel,
    input: "Create a folder named project/ and write hello.py inside.",
    environment: "remote",
    background: true
});

// Wait for completion
while (true) {
    const check = await client.interactions.get(interaction1.id);
    if (check.status !== "in_progress") {
        break;
    }
    await new Promise(resolve => setTimeout(resolve, 2000));
}

// Second interaction: chain using previous_interaction_id and environment
const interaction2 = await client.interactions.create({
    model: agentModel,
    input: "List all files in the project/ directory.",
    previous_interaction_id: interaction1.id,
    environment: "remote",
    background: true
});

REST

# Chain second interaction (make sure FIRST_INTERACTION_ID has status 'completed')
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Api-Revision: 2026-05-20" \
  -d '{
    "model": "antigravity-preview-05-2026",
    "input": "List all files in the project/ directory.",
    "previous_interaction_id": "FIRST_INTERACTION_ID",
    "environment": "remote",
    "background": true
  }'

Cancellation and deletion

You can control running executions and manage storage with cancel and delete requests:

  • Cancel (POST /interactions/{id}/cancel): Stops the running task. The status transitions to cancelled. Clean-up actions on the server can cause a slight delay before the status updates in GET requests.
  • Delete (DELETE /interactions/{id}): Removes the interaction records from the server. Subsequent GET requests return a 404 Not Found error.

Python

from google import genai

client = genai.Client()

# Cancel a running interaction
client.interactions.cancel(id="YOUR_INTERACTION_ID")

# Delete the interaction record entirely
client.interactions.delete(id="YOUR_INTERACTION_ID")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

// Cancel a running interaction
await client.interactions.cancel("YOUR_INTERACTION_ID");

// Delete the interaction record entirely
await client.interactions.delete("YOUR_INTERACTION_ID");

REST

# Cancel the interaction
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions/YOUR_INTERACTION_ID/cancel" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Api-Revision: 2026-05-20"

# Delete the interaction
curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/interactions/YOUR_INTERACTION_ID" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Api-Revision: 2026-05-20"

Best practices

  • Choose the right retrieval pattern: Poll for simple status checks; stream when you want live progress and to receive output incrementally.
  • Make streaming resilient: Persist last_event_id on each event so you can reconnect seamlessly after network drops.
  • Always wait before chaining: Never chain to an interaction that’s still in_progress — you’ll get a 400, so build your loop around reaching a terminal state.
  • Clean up after yourself: Cancel tasks you no longer need and delete interaction records to keep storage and costs in check.

Summary

Background execution turns the Gemini Interactions API into a true server-side task engine. You create an interaction asynchronously, get an ID back immediately, and then poll, stream, or reconnect to it as it completes. Combined with multi-turn chaining, cancellation, and deletion, it gives you everything you need to build robust, long-running agentic applications without fighting HTTP connection timeouts.

Further reading