Skip to content

IChatClient.GetStreamingResponseAsync yields nothing: streamGenerateContent is requested without ?alt=sse but parsed as SSE #994

Description

@HavenDV

Symptom

IChatClient.GetStreamingResponseAsync on GeminiClient (Google_Gemini 0.11.2) completes without yielding a single TextContent against the live API, while GetResponseAsync answers the same prompt normally. Observed 2026-09-15 from a production backend: every streamed call ended with an empty aggregate (gemini returned an empty response), model gemini-3.5-flash-lite, plain-text prompt, ThinkingLevel = Minimal via RawRepresentationFactory.

Root cause (from the generated code)

Google.Gemini.GeminiClient.ModelsStreamGenerateContentAsStream.g.cs builds the request as

var __pathBuilder = new PathBuilder(path: $"/models/{modelsId}:streamGenerateContent", baseUri: HttpClient.BaseAddress);
// … only the ApiKey query authorization is appended …

and then reads the body with

await foreach (var __sseEvent in System.Net.ServerSentEvents.SseParser.Create(__stream).EnumerateAsync(...))

The Gemini REST API only answers streamGenerateContent as server-sent events when ?alt=sse is on the query string. Without it the response is a chunked JSON array of GenerateContentResponse objects ([{…},\r\n{…}]), which contains no data: lines, so SseParser enumerates zero events and the method returns having yielded nothing — no exception, no text.

Nothing in the repo adds the parameter: GeminiClient.ChatClient.cs calls ModelsStreamGenerateContentAsStreamAsync(modelsId, request, cancellationToken) with no requestOptions, and src/libs/Google.Gemini/openapi.json / convert_discovery.py do not declare alt on the stream operations. (Dynamic… and TunedModels…StreamGenerateContentAsStreamAsync have the same shape.)

Reference: https://ai.google.dev/api/generate-content#method:-models.streamgeneratecontent — "alt=sse … streams the response as server-sent events".

Fix options

  1. Cheapest, in the SDK: have the three …StreamGenerateContentAsStreamAsync requests always carry alt=sse — e.g. PrepareModelsStreamGenerateContentAsStreamArguments partial, or the ChatClient extension passing requestOptions: new AutoSDKRequestOptions { QueryParameters = { ["alt"] = "sse" } }.
  2. In the spec: declare alt as a query parameter with default sse on the :streamGenerateContent operations in openapi.json (via convert_discovery.py), so the generator emits it.
  3. Alternatively, fall back to parsing the JSON-array form when the response Content-Type is application/json.

Either way, src/tests/IntegrationTests/Examples/ChatClient.FiveRandomWords.Streaming.cs would have caught this if it ran against the live API — worth asserting updates.Any(u => u.Text.Length > 0) there.

Consumer-side workaround

A separate GeminiClient with Options.QueryParameters["alt"] = "sse" used only for streaming calls. Tracking on our side: HavenDV/Advantage (linked below).

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions