Client or integration
Direct HTTP/API client
Area
Provider adapter
Summary
The Google adapter classifies every non-empty Gemini Part.text as visible assistant output, even when the same part is marked thought: true.
Both the streaming and non-streaming parsers currently emit { type: "text_delta", text: part.text } without checking the thought flag:
The downstream Responses bridge treats text_delta as ordinary assistant output. As a result, model-internal thought text can cross the hidden-reasoning boundary and appear as visible answer text.
Expected: when part.thought === true, its text should produce a hidden reasoning event such as reasoning_raw_delta or thinking_delta. It must not produce text_delta, and reasoning.summary: "none" should continue to suppress its visible rendering. Thought-signature replay should remain unchanged.
Actual: both parsers produce visible text_delta for the thought text.
This affects Google-family routes handled by this adapter when the upstream returns a text-bearing thought part. It is not specific to one client transport or to streaming mode. Normal parts without thought: true should remain visible text.
Reproduction
A synthetic provider response is sufficient; no credential or live model request is needed.
Use this minimal candidate in the Google adapter response parser:
{
"candidates": [
{
"content": {
"parts": [
{ "thought": true, "text": "internal reasoning" }
]
},
"finishReason": "STOP"
}
]
}
Non-streaming fixture:
const response = new Response(JSON.stringify(payload), {
headers: { "content-type": "application/json" },
});
const events = await adapter.parseResponse!(response, budget);
expect(events).not.toContainEqual({
type: "text_delta",
text: "internal reasoning",
});
expect(events).toContainEqual({
type: "reasoning_raw_delta",
text: "internal reasoning",
});
For the streaming fixture, put the same candidate object in one data: SSE event and collect adapter.parseStream(...).
Current result in both modes:
{ type: "text_delta", text: "internal reasoning" }
Expected result in both modes:
{ type: "reasoning_raw_delta", text: "internal reasoning" }
A focused regression test should also cover:
- standalone
{ thought: true, text };
- a thought part followed by a
functionCall, preserving signature replay;
- an ordinary
{ text } part, which must remain visible;
- both
parseStream and parseResponse.
A small shared part classifier used by both parser paths would prevent the two implementations from drifting.
Version
2.12.0 and current main/dev as of 2026-08-12. Verified at main commit 6d881db206c6a74da6b64fa22b6980faf05d0122; the same classification is present on dev commit e8db4e0365b12a314d1c08ec2cf81599efe5b2d3.
Operating system
Not operating-system-specific; this is deterministic TypeScript response classification in the Google adapter.
Provider and model
Google adapter (google, including applicable Google AI Studio, Vertex, and Cloud Code Assist routes) with a Gemini-family response containing a text-bearing thought: true part.
Logs or error output
No upstream error is required. The incorrect adapter event is:
{ type: "text_delta", text: "internal reasoning" }
Screenshots and supporting files
None. The synthetic fixture above is self-contained.
Redacted configuration
No provider credential or local configuration is required for the synthetic parser fixture.
Checks
Client or integration
Direct HTTP/API client
Area
Provider adapter
Summary
The Google adapter classifies every non-empty Gemini
Part.textas visible assistant output, even when the same part is markedthought: true.Both the streaming and non-streaming parsers currently emit
{ type: "text_delta", text: part.text }without checking thethoughtflag:src/adapters/google.tslines 605-619src/adapters/google.tslines 825-836The downstream Responses bridge treats
text_deltaas ordinary assistant output. As a result, model-internal thought text can cross the hidden-reasoning boundary and appear as visible answer text.Expected: when
part.thought === true, its text should produce a hidden reasoning event such asreasoning_raw_deltaorthinking_delta. It must not producetext_delta, andreasoning.summary: "none"should continue to suppress its visible rendering. Thought-signature replay should remain unchanged.Actual: both parsers produce visible
text_deltafor the thought text.This affects Google-family routes handled by this adapter when the upstream returns a text-bearing thought part. It is not specific to one client transport or to streaming mode. Normal parts without
thought: trueshould remain visible text.Reproduction
A synthetic provider response is sufficient; no credential or live model request is needed.
Use this minimal candidate in the Google adapter response parser:
{ "candidates": [ { "content": { "parts": [ { "thought": true, "text": "internal reasoning" } ] }, "finishReason": "STOP" } ] }Non-streaming fixture:
For the streaming fixture, put the same candidate object in one
data:SSE event and collectadapter.parseStream(...).Current result in both modes:
Expected result in both modes:
A focused regression test should also cover:
{ thought: true, text };functionCall, preserving signature replay;{ text }part, which must remain visible;parseStreamandparseResponse.A small shared part classifier used by both parser paths would prevent the two implementations from drifting.
Version
2.12.0 and current
main/devas of 2026-08-12. Verified atmaincommit6d881db206c6a74da6b64fa22b6980faf05d0122; the same classification is present ondevcommite8db4e0365b12a314d1c08ec2cf81599efe5b2d3.Operating system
Not operating-system-specific; this is deterministic TypeScript response classification in the Google adapter.
Provider and model
Google adapter (
google, including applicable Google AI Studio, Vertex, and Cloud Code Assist routes) with a Gemini-family response containing a text-bearingthought: truepart.Logs or error output
No upstream error is required. The incorrect adapter event is: { type: "text_delta", text: "internal reasoning" }Screenshots and supporting files
None. The synthetic fixture above is self-contained.
Redacted configuration
{}No provider credential or local configuration is required for the synthetic parser fixture.
Checks