fix(gemini): safely stream and round-trip thought parts - #58
Merged
Conversation
…ransport='provider'
Gemini API returns thinking content as parts with `thought: true`. Previously
these were pushed as regular text blocks regardless of reasoningTransport,
so think_chunk SSE events were never emitted for Gemini models.
When reasoningTransport is 'provider', parts with thought===true are now
pushed as { type: 'reasoning', reasoning } blocks. The agent emits these
as think_chunk_start / think_chunk / think_chunk_end progress events,
allowing clients to render thinking separately from the response text.
Default behavior (reasoningTransport: 'text') is unchanged — thought parts
continue to arrive as text blocks and get normalized by normalizeThinkBlocks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without includeThoughts, the model thinks internally but does not return thought parts in the response. This adds it automatically whenever thinkingBudget or thinkingLevel is set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
parseGeminiChunk now separates parts with thought===true into thoughtChunks when reasoningTransport is 'provider'. The streaming loop yields them as content_block_start(reasoning) + content_block_delta(reasoning_delta) before text chunks, so the agent emits think_chunk_start/think_chunk/think_chunk_end SSE events that clients can render separately from the response text. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR incorporates and extends #56. It merges all four original commits from @kirillreutski unchanged, preserving their exact SHAs and author attribution, then adds the protocol and regression hardening needed for a safe merge.
The original PR correctly enabled Gemini thought summaries and began exposing them as reasoning blocks. Pre-merge review found additional lifecycle, ordering, transport, signature, and compatibility edges that needed to be fixed together so the feature would be safe for direct provider consumers and
Agentusers.What changed
includeThoughts: truefor Gemini thinking budgets/levels, including validbudgetTokens: 0and-1part.thought === trueas canonical reasoning for every history transport, preventing thought leakage into final answer text oromithistoryContent.partsorder across SSE events, tools, and JSON-array fallbackscontent_block_start -> delta* -> stoplifecycles, including error pathsdata:, arbitrary network chunk boundaries, bare JSON fallbacks, and batched arrays inside SSE framesthoughtSignatureon thought, normal text, signature-only empty text, and function-call partsfunctionCall.id/ matchingfunctionResponse.id; synthetic SDK IDs are never sent back to older Gemini models that did not provide an IDAgent, forwardmodelConfig.thinking, emitthink_chunk_end, and remove retained reasoning from both content and metadata whenretainThinking: falsethought_signatureand legacythoughtSignatureon resumepackage-lock.jsongenerator noise from fix(gemini): emit reasoning chunks and fix thought parts extraction #56reasoningTransport: 'provider'remains the mode for lossless native thought/signature continuity.textintentionally rewrites reasoning into<think>parts for cross-provider compatibility, so it does not attach a native signature to a modified Part;omitremoves reasoning from outbound history.Verification
npm run buildnpx tsc --noEmitpostgres:16-alpine)npm pack --dry-rungit diff --checkGitHub Actions remains the merge gate for PostgreSQL, real provider E2E, agent integration, and comprehensive agent workflows.
Attribution and collaboration
The branch contains #56 through merge commit
8be6c1d; original headff5cf2aand all preceding author commits remain ancestors of this PR head. Thank you @kirillreutski for the original diagnosis and implementation direction.Supersedes #56 after CI validation, without squashing away the original contributor history.