Skip to content

Python: [Feature]: Gemini thought summaries are dropped — surface them as reasoning content #7225

Description

@antsok

Description

Summary

GeminiChatClient never surfaces a Gemini model's reasoning. Gemini can return thought summaries (condensed traces of its internal reasoning) as response parts with part.thought = True when thinking_config.include_thoughts is set, but _parse_parts skips every thought part, so reasoning never reaches ChatResponse.contents and downstream consumers (AG-UI/CopilotKit, the harness "thinking" UI) show nothing. The behaviour is deliberate and codified — the method docstring says "skipping thought/reasoning parts" and the test test_thinking_parts_are_silently_skipped asserts it — so it reads as a placeholder, not a final decision.

By contrast the sibling OpenAIResponsesClient surfaces reasoning as Content.from_text_reasoning(...), so behaviour is inconsistent across providers.

Environment

  • agent-framework-core 1.10.0, agent-framework-gemini 1.0.0a260630
  • Google Gemini Developer API, models gemini-2.5-flash / gemini-3.* (thinking-capable).

Package Versions

agent-framework-core: 1.11.0, agent-framework-gemini: 1.0.0a260709 (newer than agent-framework-gemini 1.0.0a260630 the bug was originally verified against)

Current behaviour

python/packages/gemini/agent_framework_gemini/_chat_client.py, _parse_parts:

for part in parts:
    if part.thought:
        continue                      # <- reasoning discarded
    if part.text is not None:
        contents.append(Content.from_text(text=part.text, raw_representation=part))
    ...

ThinkingConfig.include_thoughts is accepted on the request side, but its output is thrown away here, so setting it has no visible effect.

Proposed

Emit thought parts as reasoning instead of dropping them:

for part in parts:
    if part.thought:
        if part.text:
            contents.append(Content.from_text_reasoning(text=part.text, raw_representation=part))
        continue
    ...

Round-trip is already safe: _convert_message_contents has no text_reasoning case, so reasoning is dropped on replay and never sent back to Gemini. Replace the test_thinking_parts_are_silently_skipped assertion with one that expects a text_reasoning Content when include_thoughts is on. Optionally gate on include_thoughts so behaviour is unchanged unless the caller opted in.

Workaround

ats._gemini.SchemaSafeGeminiChatClient overrides _parse_parts to re-add thought parts as text_reasoning, and _prepare_config to set include_thoughts = True. Verified live: Gemini 3.5 Flash renders its thought summaries as a "Thought" block, no round-trip breakage. Remove once fixed upstream.

Code Sample

Language/SDK

Both

Metadata

Metadata

Assignees

Labels

pythonUsage: [Issues, PRs], Target: Python

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions