googleapis / googleapis/python-genai

Gemini 2.5 Pro intermittently emits reasoning-like content as normal text with include_thoughts=False

Open
#2,925 2 comments 0 reactions 1 assignee Claimed by @Venkaiahbabuneelam View on GitHub
priority: p2 type: bug
Dominant language
Python
Stars
4k
Forks
1k
Avg merge
2d 11h
Merged PRs (30d)
40

Description

## Summary

When using `gemini-2.5-pro` through the Gemini Developer API with the Python GenAI SDK, reasoning-like content is intermittently emitted through the ordinary text path even though `ThinkingConfig(include_thoughts=False)` is set.

The response may begin with a preamble shaped like this synthetic, sanitized example:

```text
thought. Here's a thinking process for how to respond...
[intended final response]
```

The application separates every response part for which `bool(part.thought)` is true before exposing normal text. The preamble nevertheless reaches the ordinary text path, so it is not structurally identifiable as a thought part at the point where the SDK response is consumed.

This appears related to #2121, but the observed environment uses Gemini 2.5 Pro, the Gemini Developer API, a newer SDK version, and explicitly sets `include_thoughts=False`.

## Environment details

- Programming language: Python
- OS: Linux
- Language runtime version: 3.14.3
- Package version: `google-genai==2.18.0`
- Model: `gemini-2.5-pro`
- Backend: Gemini Developer API
- Mode: async `generate_content_stream()`

## Sanitized request shape

```python
from google import genai
from google.genai import types

client = genai.Client(api_key=API_KEY)

stream = await client.aio.models.generate_content_stream(
model="gemini-2.5-pro",
contents="Respond with only the final answer.",
config=types.GenerateContentConfig(
thinking_config=types.ThinkingConfig(
thinking_budget=128,
include_thoughts=False,
),
),
)

async for chunk in stream:
for part in chunk.candidates[0].content.parts:
if getattr(part, "thought", False):
continue
if part.text:
print(part.text)
```

The behavior is intermittent, so this simplified prompt does not reproduce it deterministically. It shows the request and response-consumption shape without including any private prompt or application data.

## Expected behavior

With `include_thoughts=False`, reasoning summaries should not appear in the ordinary visible text stream. If reasoning content is returned, applications should have a reliable structured field such as `part.thought=True` with which to separate it from the final response.

## Actual behavior

Reasoning-like prose can appear before the intended final response through the same ordinary text path as the answer. Filtering all parts marked with `part.thought=True` therefore does not prevent the preamble from being exposed.

For affected responses, application-level usage metadata does not report thought tokens. Raw pre-SDK SSE payload capture is not currently available, so it is not yet clear whether the marker is absent in the API response or lost during SDK transformation.

## Questions

1. Is reasoning content ever expected to appear in ordinary `part.text` with `part.thought` unset when `include_thoughts=False`?
2. Is this a known issue for `gemini-2.5-pro` on the Gemini Developer API?
3. Is there a reliable structured signal clients can use to distinguish this content from the final answer?
4. Is additional raw-response instrumentation recommended to determine whether this originates in the backend or the SDK transformation layer?

## Related issues

- #2121
- #2239

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.