Skip to content

Preserve the full HttpResponse in generateContentStream responses #1869

Description

@dani29

Description

Hi! I ran into this while adding response-level observability around generateContentStream().

Each streamed GenerateContentResponse has an sdkHttpResponse property typed as HttpResponse. I expected it to include the original Response through responseInternal, which would make the HTTP status and other response metadata available.

In practice, sdkHttpResponse only contains the headers:

{
  headers: {
    "content-type": "text/event-stream"
  }
}

The SDK appears to have the full HttpResponse internally, but replaces it with { headers: chunk.headers } when it creates the public response chunk:

https://github.com/googleapis/js-genai/blob/v2.17.1/src/models.ts#L801-L891

Would it be possible to preserve and return the complete HttpResponse instead? For example, returning the existing chunk would retain both the headers and responseInternal.status.

This would also make the runtime value match the exported HttpResponse type:

https://github.com/googleapis/js-genai/blob/v2.17.1/src/types.ts#L3197-L3216

Reproduction

import { GoogleGenAI } from "@google/genai";

const originalFetch = globalThis.fetch;

globalThis.fetch = async () =>
  new Response(
    `data: ${JSON.stringify({
      candidates: [
        {
          content: {
            role: "model",
            parts: [{ text: "ok" }],
          },
          finishReason: "STOP",
        },
      ],
    })}\n\n`,
    {
      status: 200,
      headers: {
        "content-type": "text/event-stream",
        "x-repro-header": "visible",
      },
    },
  );

try {
  const client = new GoogleGenAI({
    apiKey: "test-key",
    httpOptions: {
      baseUrl: "https://upstream.test",
      apiVersion: "",
    },
  });

  const stream = await client.models.generateContentStream({
    model: "test-model",
    contents: "hello",
  });

  const { value: chunk } = await stream.next();

  console.log({
    headers: chunk.sdkHttpResponse?.headers,
    responseInternal: chunk.sdkHttpResponse?.responseInternal,
    status: chunk.sdkHttpResponse?.responseInternal?.status,
  });
} finally {
  globalThis.fetch = originalFetch;
}

The headers are present, but responseInternal and status are both undefined.

Expected behavior

I would expect sdkHttpResponse to contain the full HttpResponse, so this works:

chunk.sdkHttpResponse.responseInternal.status; // 200

Environment

  • @google/genai: 2.17.1
  • Node.js: 24.5.0
  • OS: macOS

Metadata

Metadata

Assignees

Labels

api:gemini-apipriority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions