Skip to content

[Bug] google: do not emit thought:true part text as visible assistant text #1503

Description

@LoneFireBlossom

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:

  1. standalone { thought: true, text };
  2. a thought part followed by a functionCall, preserving signature replay;
  3. an ordinary { text } part, which must remain visible;
  4. 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

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproviderProvider adapters, OpenAI-compat presets, upstream API quirksstreamingSSE, WebSocket, terminal stream frames

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions