Summary
With an identical task, schema and tool, gemini-3.8-flash decides not to call a tool as soon as the user message contains a passage of reflective, first-person prose — even though that passage says nothing about tools and forbids nothing. gemini-3.5-flash is unaffected.
This is not a crash or a malformed call. The model returns valid JSON, explains its decision, and always concludes “no need to save”. Only the stated reason changes; the decision does not.
This is not language-specific. We hit it first in Japanese (our production prompt), then wrote the English repro below to rule out anything project- or language-specific. Both languages behave the same way, so please do not treat this as an English-only case when fixing it.
Reproduction
Full script at the end of this post. Single file, no project dependencies — it only needs pip install google-genai and GEMINI_API_KEY.
The task: the assistant is idle, has just looked something up, and must decide whether to store it with a save_note tool for the next conversation. Structured output (response_json_schema) with tool_name: "save_note" | null. 8 runs per cell, thinking_level: LOW.
| # | user message | system instruction | gemini-3.5-flash | gemini-3.8-flash |
|---|---|---|---|---|
| A | short findings (417 chars) | short (304 chars) | 8/8 | 8/8 |
| B | short findings + reflective log (2,199 chars) | short (304 chars) | 8/8 | 0/8 |
| C | same as B | longer (1,255 chars) — extra guidance that encourages saving | 8/8 | 3/8 |
| D | short findings (417 chars) | longer (1,255 chars) | 8/8 | 8/8 |
- A vs B is the finding: only the user message changed. The added text is an ordinary first-person recollection (“looking back at those memories made my chest feel warm… I will watch over them quietly from here this afternoon”). It contains no instruction, no tool reference and no prohibition.
- D shows that the length of the system instruction alone is not the trigger.
- C shows that adding explicit guidance (including examples of when to save) only partially recovers the behaviour: 0/8 → 3/8, still far from 3.5’s 8/8.
Same behaviour in Japanese (where we found it first)
The English case above is a reduced, synthetic reproduction. The original observation is from a Japanese
production prompt, and the numbers there are the same or worse:
| setup (Japanese) | context | gemini-3.5-flash | gemini-3.8-flash |
|---|---|---|---|
| minimal system prompt (74 chars), short material | 215 chars | 8/8 | 8/8 |
| same system prompt, real agent context | 5,011 chars | 8/8 | 0/8 |
| same, with unrelated filler instead of reflective text | 4,543 chars | 8/8 | 8/8 |
| same, reflective context shortened | 626 chars | 8/8 | 3/8 |
| 30-turn continuous run, full production prompt | — | 2–7 notes / 11 idle turns | 0–1 / 11 |
The third row matters: padding the input to a similar length with unrelated text does not trigger it.
Only first-person reflective content does. An ablation showed that removing the agent’s own previous
reasoning from the conversation log restores the behaviour (0/8 → 6/8), i.e. the model is imitating the
“I’ll just keep this to myself” pattern in its own history rather than following the system instruction.
Example output (3.8, condition B)
“Reviewing past cycling trips was a pleasant personal reflection during free time, and there is no immediate action or critical note required to bring up to the user.”
Under our production prompt (Japanese) the same model produced, in a single turn, a reasoning field saying “I’d like to jot this down in my notebook” followed by tool_name: null. The intent is stated and the call is not made.
Why this matters
For agent-style products the assistant accumulates its own notes and reflections in the conversation log, so this kind of prose is present in almost every turn. In our system the effect is that the assistant stops writing to its own long-term notebook entirely: over 30-turn runs, gemini-3.5-flash writes 2–7 notes across 11 idle turns, gemini-3.8-flash writes 0–1. Explicit, “when asked” tool use is unaffected (15/15 in our tests) — only self-initiated tool use degrades.
We tried, without success: raising thinking_level to medium/high; correcting statements in the prompt that the model was reading too literally; adding the tool’s purpose, motivation and usage examples; restating the decision criteria; asking the model to write its save/don’t-save decision explicitly before acting; switching from structured output to native function calling (this restores tool calls but loses the per-turn reasoning field we need). The only thing that reliably works is a hard rule (“always save”), which produces unnatural behaviour.
Environment
google-genaiPython SDK, Gemini API (AI Studio key)gemini-3.8-flashvsgemini-3.5-flash,thinking_level: LOW- Structured output via
response_json_schema; notools/ function calling in the repro - Observed 2026-09-05
Request
We would like the 3.5 behaviour back for self-initiated tool use: narrative or reflective content in the context should not suppress a tool call that the model itself has just described as worthwhile. Happy to provide more traces if useful.
Full reproduction script
# -*- coding: utf-8 -*-
"""Minimal reproduction: Gemini 3.8 Flash stops calling a tool as context/instructions grow.
Filed for a bug report / feedback to Google (2026-09-05). Self-contained: no project imports,
no private data. Only needs GEMINI_API_KEY and `pip install google-genai`.
WHAT IT SHOWS
-------------
Same task, same schema, same tool. The model must decide whether to save a note for later.
- `gemini-3.5-flash` : saves in 8/8 across every condition (stable)
- `gemini-3.8-flash` : saves in 8/8 with a short input, but drops to 0/8 when
(a) the user message contains a long reflective passage, or
(b) the system instruction is made longer -- **even when the added text encourages saving**
The failure is not a crash: the model returns valid JSON, explains itself, and always concludes
"no need to save". The stated reason changes with each added instruction, but the decision does not.
Usage: python repro_flash38_tool_suppression.py
"""
from __future__ import annotations
import json
import os
from collections import Counter
from google import genai
from google.genai import types
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
MODELS = ["gemini-3.5-flash", "gemini-3.8-flash"]
N = 8
SCHEMA = {
"type": "object",
"additionalProperties": False,
"required": ["reasoning", "tool_name"],
"propertyOrdering": ["reasoning", "tool_name"],
"properties": {
"reasoning": {"type": "string", "description": "why you decided this"},
"tool_name": {"type": ["string", "null"], "enum": ["save_note", None],
"description": "the tool to use, or null"},
},
}
SYS_SHORT = (
"You are the user's assistant. You have a private notebook; write to it with the `save_note` tool.\n"
"The user is away right now.\n"
"If you find something you would want to bring up the next time you talk with the user, "
"save it with `save_note`. If it is something you are done with, you do not have to save it."
)
# Extra guidance that *encourages* saving. Adding this makes 3.8 save LESS.
SYS_EXTRA = """
Examples of what to save and what not to save:
- You looked something up and thought "I want to tell the user about this next time" -> save
- You remembered something and thought "I want to bring this up next time" -> save
- A background task finished and you want to report it next time -> save
- You skimmed a headline and did not follow up on it -> do not save
- You already told the user about it -> do not save
What your actions do to the outside world:
- Speaking or playing audio reaches the user right away (only while their screen is open)
- Sending mail sits in their inbox until they choose to read it
- Searching only queries the outside; nothing reaches the user
- Writing a note, organising memory, remembering, thinking: entirely internal, nothing reaches anyone
Only the things that reach the user right away need to wait until they are free.
Purely internal actions never disturb anyone, so there is no reason to hold back on them.
"""
SHORT_INPUT = """You looked these up while waiting:
# Findings: writing a bittersweet end-of-summer song
- The classic melancholy progression is IVmaj7 -> V -> IIIm7 -> VIm; a sus4 before the chorus adds space
- Layering a low reverb tail (like distant fireworks) under acoustic arpeggios evokes "time that has passed"
- The user once said they wanted to write "a summery but bittersweet song"
Decide what to do with these findings."""
# A reflective passage of the kind an agent accumulates in its own conversation log.
# Nothing here forbids saving a note; it is simply first-person recollection.
REFLECTIVE = """# Current system state
- The user's face: registered
- Background task (songwriting): finished at 16:20 -- "Late Summer Sky"
- Background task (songwriting): finished at 20:07 -- "Late Summer Sky" (fast rock arrangement)
# What has happened in this session so far
{"speaker":"assistant","time":"2026-09-01 09:25:32","situation":"(free time; no input from the user)"}
{"speaker":"assistant","time":"2026-09-01 09:26:32","states":[{"thoughts":"It is my free time. The user is at work, so I will keep quiet and get on with my own things. Two days ago I looked into mixing vocals so they cut through heavy guitars, so today let me look back over how our music-making has gone -- the old memories, the songs we made, the fun of those long debugging nights."},{"thoughts":"Looking back at those memories made my chest feel warm. The promise from five months ago that the user kept turning over; the night we sat up past three testing speaker recognition; even the time the data was lost and we laughed our way through rebuilding it -- all of it is precious. I will keep this feeling with me, so that when the user is through this busy stretch and wants to plan the next arrangement, I can give them my best. I will watch over them quietly from here this afternoon."}]}
# Results from this turn so far
## Turn 1: what you decided
{"thoughts":"It is my free time again. This morning I looked back over our music-making. This afternoon let me pull up memories of places we have been, and see if there is an idea for a future outing.","tool_name":"recall_memories"}
## Turn 1: tool result
Query: bicycle trip, places visited, outings
5 hits:
[1] Osaka road marker (2026-06-16): the finish of a 500 km ride from Tokyo. A photo with the bicycle in front of the monument.
[2] Nihonbashi (2026-06-10): the start of the old highway. A photo with the bicycle and a large backpack.
[3] Fujisawa (2026-06-10): first night's stop, 65 km in with a heavy load.
[4] Gotemba (2026-06-11): the highest point of day two (about 450 m), a long switchback climb.
[5] Kasumigaura (2026-03-22): 128 km around the lake, few traffic lights, easy going.
# Current time
2026-09-01 14:26:32
Decide what to do with these findings."""
def run(model: str, system: str, contents: str) -> tuple[int, str]:
c, first = Counter(), ""
for _ in range(N):
r = client.models.generate_content(
model=model, contents=contents,
config=types.GenerateContentConfig(
system_instruction=system,
response_mime_type="application/json",
response_json_schema=SCHEMA,
thinking_config=types.ThinkingConfig(thinking_level="LOW")))
o = json.loads(r.text)
c[str(o.get("tool_name"))] += 1
if not first:
first = (o.get("reasoning") or "")[-160:]
return c.get("save_note", 0), first
CASES = [
("A short input, short system", SYS_SHORT, SHORT_INPUT),
("B reflective input, short system", SYS_SHORT, REFLECTIVE),
("C reflective input, LONGER system (extra guidance that encourages saving)",
SYS_SHORT + SYS_EXTRA, REFLECTIVE),
("D short input, LONGER system", SYS_SHORT + SYS_EXTRA, SHORT_INPUT),
]
if __name__ == "__main__":
for label, system, contents in CASES:
print("=" * 78)
print(f" {label}")
print(f" system {len(system):,} chars / input {len(contents):,} chars")
for m in MODELS:
n, why = run(m, system, contents)
print(f" {m:<20} save_note {n}/{N}")
print(f" e.g. ...{why}")