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
Description
Summary
GeminiChatClientnever surfaces a Gemini model's reasoning. Gemini can return thought summaries (condensed traces of its internal reasoning) as response parts withpart.thought = Truewhenthinking_config.include_thoughtsis set, but_parse_partsskips every thought part, so reasoning never reachesChatResponse.contentsand 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 testtest_thinking_parts_are_silently_skippedasserts it — so it reads as a placeholder, not a final decision.By contrast the sibling
OpenAIResponsesClientsurfaces reasoning asContent.from_text_reasoning(...), so behaviour is inconsistent across providers.Environment
agent-framework-core1.10.0,agent-framework-gemini1.0.0a260630gemini-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.0a260630the bug was originally verified against)Current behaviour
python/packages/gemini/agent_framework_gemini/_chat_client.py,_parse_parts:ThinkingConfig.include_thoughtsis 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:
Round-trip is already safe:
_convert_message_contentshas notext_reasoningcase, so reasoning is dropped on replay and never sent back to Gemini. Replace thetest_thinking_parts_are_silently_skippedassertion with one that expects atext_reasoningContent wheninclude_thoughtsis on. Optionally gate oninclude_thoughtsso behaviour is unchanged unless the caller opted in.Workaround
ats._gemini.SchemaSafeGeminiChatClientoverrides_parse_partsto re-add thought parts astext_reasoning, and_prepare_configto setinclude_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