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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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