GEMINI LABJP
FLASH36 — Gemini 3.6 Flash, shipped July 21, uses about 17% fewer output tokens than 3.5 Flash at a lower price, with fewer stray code edits and execution loopsCYBER — Gemini 3.5 Flash Cyber is a lightweight model focused on finding, validating, and patching vulnerabilitiesCOMPUTER — Computer use is now available as a built-in client-side tool through the Gemini API and Gemini EnterpriseSPARK — Gemini Spark began rolling out in Japanese on July 16, starting with Google AI Ultra subscribersPARALLEL — Spark now processes multiple reference sources in parallel, and handles a wider range of image edits across Docs, Sheets, and SlidesSTUDENT — Students 18 and older in four countries, Japan included, get a free upgrade to Google AI Pro with NotebookLM and 2TB of storageFLASH36 — Gemini 3.6 Flash, shipped July 21, uses about 17% fewer output tokens than 3.5 Flash at a lower price, with fewer stray code edits and execution loopsCYBER — Gemini 3.5 Flash Cyber is a lightweight model focused on finding, validating, and patching vulnerabilitiesCOMPUTER — Computer use is now available as a built-in client-side tool through the Gemini API and Gemini EnterpriseSPARK — Gemini Spark began rolling out in Japanese on July 16, starting with Google AI Ultra subscribersPARALLEL — Spark now processes multiple reference sources in parallel, and handles a wider range of image edits across Docs, Sheets, and SlidesSTUDENT — Students 18 and older in four countries, Japan included, get a free upgrade to Google AI Pro with NotebookLM and 2TB of storage
Articles/API / SDK
API / SDK/2026-07-23Advanced

When to Hand Conversation State to the Server: previous_interaction_id vs. Pruning History Yourself

With the Interactions API, passing previous_interaction_id lets the server hold conversation state so you stop resending history. But a large tool output that lands mid-conversation can't be pruned afterward, and every later turn drags its weight. Here is a branching design that mixes server-side state with client-side pruning, plus a thin, working Python wrapper.

gemini-api278interactions-api4architecture16cost-optimization31conversation-stateautomation52

Premium Article

As an indie developer, a few weeks after I wired a chat-style support helper into my automation, I was looking over the monthly cost breakdown and stopped. The total was within range, but a single conversation ID stuck out, far heavier than the rest. Tracing it, I found one turn had injected a roughly 40KB excerpt from a product catalog, and the dozen or so exchanges that followed had each dutifully dragged those 40KB along.

I had switched to previous_interaction_id because "I no longer resend the whole history, so it should be cheaper." And the outbound payload did shrink. Yet the bill did not. If anything, a heavy blob that I could have dropped in a single line back when I assembled history myself had, by being handed to the server, become impossible to drop.

This article is a record of that fork in the design. Should conversation state live on the server, or stay in your hands where you can prune it? I want to separate what the Interactions API's previous_interaction_id spares you from what it quietly takes custody of, and leave behind a thin wrapper — with working code — for choosing between them by situation.

What previous_interaction_id spares you, and what it takes custody of

In the Interactions API, you pass the ID that the previous response returns as previous_interaction_id on the next request, and the server carries the accumulated conversation context forward for you. It frees you from the loop of stacking up a messages array by hand and resending the whole thing every turn.

What it spares you is clear: sending a history array that swells with every exchange, the logic to build and trim it, and the bookkeeping of "how much have I sent so far." From single-turn understanding to stateful conversation, it all sits under one front door.

But there is something it quietly takes custody of: the right to edit context. When history lives in your hands, the moment a tool output from three turns ago stops being useful, you can pull just that element out of the array, or swap it for a short summary, and send the next turn. When conversation state is held as a chain on the server, there is no surgical way to extract a heavy blob after it has entered the chain. As long as you continue the chain, that blob lives on as context.

You save the effort of sending; you surrender the freedom to prune. That asymmetry was the real cause of the cost spike above.

The counterintuitive way the cost grows

Hand state to the server, and traffic drops. So it should be cheaper. Let me follow, in tokens, exactly where that reasoning slipped.

What you are billed for is not bytes on the wire but the total tokens the model reads on each turn. Even when the server holds conversation state, the model re-reads that held context as input tokens every time it generates a response. In other words, "not sending" and "not being read" are different things. That is what I had conflated.

Numbers make it concrete. Say one turn injects a catalog excerpt of about 40KB, roughly 18,000 tokens with mixed Japanese and English. If twelve exchanges follow, the server-side chain keeps those 18,000 tokens riding on the input essentially every turn. Even a rough estimate — 18,000 × 12 — piles up over 210,000 tokens for a blob whose job was done on the first call.

DesignHandling of a heavy tool outputDrag over the next 12 exchanges
Server-side chain (previous_interaction_id)Cannot be removed from the chain~18,000 tokens × 12 remain on input
Client-held history + pruningSwap just that turn for a summaryCompressed to ~400 tokens × 12 after summarizing

If history is in your hands, you can replace the catalog excerpt with a one-line summary like "product in question: model X, in stock," and from then on each turn costs around 400 tokens. Reaching the same conclusion in the same conversation, the order of magnitude of input tokens changes. It is the kind of gap you cannot see in the light conversations of a preview, surfacing only once real, long conversations start mixing in.

What ran counter to intuition was this: the choice I made to go lighter had simultaneously given away the means to go lighter.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Why previous_interaction_id, expected to be cheaper, can cost more: the drag of a bloated turn shown in concrete token math
A thin hybrid wrapper (working Python) that stays on server-side state by default but breaks the chain and folds history to a summary when a turn goes heavy
How to recover per-user token attribution, which server-side state quietly hides, using a two-ledger approach of developer logs plus your own counter
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

API / SDK2026-06-30
Folding Scattered Call Sites Into One Front Door: Migrating to the Interactions API for Automation
With the Interactions API now generally available, Gemini's calls can settle behind a single entry point. Here is a migration design for folding scattered call sites — generateContent, Batch, and homegrown agent loops — into one front door without breaking anything, complete with a working adapter layer.
API / SDK2026-07-02
Routing Between Local Gemma 4 and the Gemini API Cut My Bill from ¥32,000 to ¥9,000 — A Production Hybrid Router Design
How I cut a ¥32,000/month Gemini API bill to the ¥9,000 range with hybrid inference: routing design, a full Python router, production pitfalls, and how Gemma 4 arriving on the Gemini API in July 2026 changes the decision.
API / SDK2026-06-21
Should You Move Your Agent Loop to Gemini's Managed Agents? Three Questions That Decide What Migrates
With Gemini API's Managed Agents in public preview, deciding between a self-hosted agent loop and a Google-hosted sandbox is now a real question. Three questions — execution environment, state ownership, and failure recovery — decide what migrates and what stays.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →