Skip to content

fix(FlowiseChatGoogleGenerativeAI): handle 'thinking' content type round-trip#6449

Open
azamiftikhar1000 wants to merge 2 commits into
FlowiseAI:mainfrom
azamiftikhar1000:fix/gemini-thinking-content-roundtrip
Open

fix(FlowiseChatGoogleGenerativeAI): handle 'thinking' content type round-trip#6449
azamiftikhar1000 wants to merge 2 commits into
FlowiseAI:mainfrom
azamiftikhar1000:fix/gemini-thinking-content-roundtrip

Conversation

@azamiftikhar1000
Copy link
Copy Markdown

Gemini models with thinking enabled emit thought summary parts in their responses. This file's response parsers convert them into LangChain content blocks of shape:

{ type: 'thinking', thinking: '...', signature: '...' }

(see the two existing producer sites in this same file).

But when those blocks are echoed back to Gemini as conversation history on the next iteration of an agent loop, they hit
_convertLangChainContentToPart, which has cases for text, executableCode, codeExecutionResult, image_url, media, tool_use, tool_call, mimetype patterns and functionCall — but NOT for thinking. The function falls through to the throwing else and raises:

Error: Unknown content type thinking

surfacing in the Agent_AgentFlow node as
"Error in Agent node: Unknown content type thinking" on the SECOND iteration of any agent loop running on a thinking model.

The asymmetry is the bug: the file produces type: 'thinking' blocks but doesn't consume them.

Fix: add a branch that translates the LangChain thinking block back into Google's native shape — a text Part with thought: true plus an optional thoughtSignature (preserving the Gemini-3 thought-signature that PR #5715 added for functionCall continuity). This is the exact shape Google's API expects per
https://ai.google.dev/gemini-api/docs/thinking and https://ai.google.dev/gemini-api/docs/thought-signatures.

Tests (5/5 pass with the fix, 4/5 fail without — at the same line 307 throw users see in production):

✓ round-trips a thinking content block back into a Gemini text Part
with thought=true
✓ preserves the thoughtSignature for Gemini-3 multi-turn tool-call
continuity
✓ also accepts thoughtSignature on the LangChain block (alternate
key name)
✓ coerces non-string thinking payload to a string instead of throwing
✓ still throws "Unknown content type" for truly unrecognized types

…und-trip

Gemini models with thinking enabled (gemini-2.5-* with thinkingConfig,
gemini-3-flash-preview with thinkingLevel, …) emit thought summary
parts in their responses. This file's response parsers convert them
into LangChain content blocks of shape:

  { type: 'thinking', thinking: '...', signature: '...' }

(see the two existing producer sites in this same file).

But when those blocks are echoed back to Gemini as conversation history
on the next iteration of an agent loop, they hit
`_convertLangChainContentToPart`, which has cases for text,
executableCode, codeExecutionResult, image_url, media, tool_use,
tool_call, mimetype patterns and functionCall — but NOT for thinking.
The function falls through to the throwing else and raises:

  Error: Unknown content type thinking

surfacing in the Agent_AgentFlow node as
"Error in Agent node: Unknown content type thinking" on the SECOND
iteration of any agent loop running on a thinking model.

The asymmetry is the bug: the file produces `type: 'thinking'`
blocks but doesn't consume them.

Fix: add a branch that translates the LangChain `thinking` block back
into Google's native shape — a text Part with `thought: true` plus an
optional `thoughtSignature` (preserving the Gemini-3 thought-signature
that PR FlowiseAI#5715 added for functionCall continuity). This is the exact
shape Google's API expects per
https://ai.google.dev/gemini-api/docs/thinking and
https://ai.google.dev/gemini-api/docs/thought-signatures.

Tests (5/5 pass with the fix, 4/5 fail without — at the same line 307
throw users see in production):

  ✓ round-trips a thinking content block back into a Gemini text Part
    with thought=true
  ✓ preserves the thoughtSignature for Gemini-3 multi-turn tool-call
    continuity
  ✓ also accepts thoughtSignature on the LangChain block (alternate
    key name)
  ✓ coerces non-string thinking payload to a string instead of throwing
  ✓ still throws "Unknown content type" for truly unrecognized types
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for Gemini thinking content blocks when echoing assistant messages back to the API as conversation history. It maps the thinking content type to Google's native shape with thought: true and preserves the thoughtSignature for Gemini-3 tool-call continuity, accompanied by comprehensive unit tests. The reviewer suggests validating the types of the text and signature fields and throwing an error for invalid types to promote fail-fast behavior instead of silently coercing them.

Comment on lines +321 to +327
const text = (content as any).thinking ?? (content as any).text ?? ''
const signature = (content as any).signature ?? (content as any).thoughtSignature
return {
text: typeof text === 'string' ? text : String(text ?? ''),
thought: true,
...(signature ? { thoughtSignature: signature } : {})
} as Part
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When handling potentially invalid data from external API responses, we should prefer throwing an error for invalid input types rather than silently returning a default/empty value or silently coercing them. This promotes fail-fast behavior. Please validate that the text and signature fields are of the expected types and throw an error if they are invalid.

        const text = (content as any).thinking ?? (content as any).text
        if (text !== undefined && typeof text !== 'string') {
            throw new Error('Invalid text type received from Google Generative AI API')
        }
        const signature = (content as any).signature ?? (content as any).thoughtSignature
        if (signature !== undefined && typeof signature !== 'string') {
            throw new Error('Invalid signature type received from Google Generative AI API')
        }
        return {
            text: text ?? '',
            thought: true,
            ...(signature ? { thoughtSignature: signature } : {})
        } as Part
References
  1. When handling potentially invalid data from external sources (like an API response), prefer throwing an error for invalid input types rather than silently returning a default or empty value. This promotes fail-fast behavior.

azamiftikhar1000 added a commit to azamiftikhar1000/Flowise that referenced this pull request May 29, 2026
Per @gemini-code-assist review feedback on PR FlowiseAI#6449. Replaces the
silent coercion of non-string `thinking` / `signature` fields with
explicit validation that throws an informative error. Matches the
existing fail-fast pattern used by the rest of
`_convertLangChainContentToPart`.

undefined/null thinking still degrades gracefully to empty text
(producer sites always emit a string, but the converter shouldn't
crash on a missing field). Tests updated to cover both directions:

  ✓ treats undefined/null thinking as empty text rather than throwing
  ✓ fails fast on non-string thinking payload (per code-review feedback)
  ✓ fails fast on non-string thinking signature

7/7 tests pass.
Per @gemini-code-assist review feedback on PR FlowiseAI#6449. Replaces the
silent coercion of non-string `thinking` / `signature` fields with
explicit validation that throws an informative error. Matches the
existing fail-fast pattern used by the rest of
`_convertLangChainContentToPart`.

undefined/null thinking still degrades gracefully to empty text
(producer sites always emit a string, but the converter shouldn't
crash on a missing field). Tests updated to cover both directions:

  ✓ treats undefined/null thinking as empty text rather than throwing
  ✓ fails fast on non-string thinking payload (per code-review feedback)
  ✓ fails fast on non-string thinking signature

7/7 tests pass.
@azamiftikhar1000 azamiftikhar1000 force-pushed the fix/gemini-thinking-content-roundtrip branch from 6a38754 to 21e7725 Compare May 29, 2026 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant