fix(FlowiseChatGoogleGenerativeAI): handle 'thinking' content type round-trip
Summary
Closes the round-trip serialization bug in FlowiseChatGoogleGenerativeAI.ts that breaks every agent loop running on a Gemini model with thinking enabled. Users see this in production as:
Error in Agent node: Unknown content type thinking
What was wrong
FlowiseChatGoogleGenerativeAI.ts has two sites that produce LangChain content blocks of shape { type: 'thinking', thinking: '...', signature: '...' } when parsing Gemini's response parts (the parts where Google sets thought: true). But _convertLangChainContentToPart has no case for content.type === 'thinking' — it handles text, executableCode, codeExecutionResult, image_url, media, tool_use, tool_call, mimetype patterns and functionCall, then falls through to the throwing else.
So the conversion is asymmetric: response ➜ LangChain works, LangChain ➜ request throws. On the FIRST agent turn this is invisible. On the SECOND iteration (or any tool-call loop / structured-output step) the assistant message's previous thinking block hits _convertLangChainContentToPart and crashes with Unknown content type thinking at line 307.
How the patch fixes it
Adds a branch that translates the LangChain thinking block back into Google's native shape per the Gemini thinking docs: a text Part with thought: true and an optional thoughtSignature (preserving the Gemini-3 signature continuity that #5715 added for functionCall parts).
} else if (content.type === 'thinking') {
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
}
Why two LangChain keys are accepted
The existing response-parser sites in this file emit signature (the LangChain v0 convention). thoughtSignature is also accepted because newer @langchain/google-genai versions put the signature there. Defensive on both for forward compatibility.
Verification
Added FlowiseChatGoogleGenerativeAI.test.ts with 5 cases. Red-green proven:
|
Without patch |
With patch |
round-trips a thinking content block back into a Gemini text Part with thought=true |
❌ throws at line 307 |
✅ pass |
preserves the thoughtSignature for Gemini-3 multi-turn tool-call continuity |
❌ throws |
✅ pass |
also accepts thoughtSignature on the LangChain block (alternate key name) |
❌ throws |
✅ pass |
| coerces non-string thinking payload to a string instead of throwing |
❌ throws |
✅ pass |
| still throws "Unknown content type" for truly unrecognized types |
✅ pass |
✅ pass |
PASS nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.test.ts
Tests: 5 passed, 5 total
The throwing path is preserved — only the thinking type is intercepted; truly unknown types still surface as before.
Reproduction
- Build any AgentFlow V2 chatflow with at least one
agentAgentflow node
- Set its model to
gemini-3-flash-preview (or gemini-2.5-flash with a thinkingConfig)
- Set
thinkingLevel: LOW (or higher)
- Send any user message that requires at least one internal iteration of the agent loop (e.g. with tools attached, or structured output enabled)
- Without this patch: the flow errors at ~9s with
Error in Agent node: Unknown content type thinking
- With this patch: the flow completes normally; thought summaries are sent back to Gemini per the official API contract
Related
Test plan
fix(FlowiseChatGoogleGenerativeAI): handle 'thinking' content type round-trip
Summary
Closes the round-trip serialization bug in
FlowiseChatGoogleGenerativeAI.tsthat breaks every agent loop running on a Gemini model with thinking enabled. Users see this in production as:What was wrong
FlowiseChatGoogleGenerativeAI.tshas two sites that produce LangChain content blocks of shape{ type: 'thinking', thinking: '...', signature: '...' }when parsing Gemini's response parts (the parts where Google setsthought: true). But_convertLangChainContentToParthas no case forcontent.type === 'thinking'— it handlestext,executableCode,codeExecutionResult,image_url,media,tool_use,tool_call, mimetype patterns andfunctionCall, then falls through to the throwing else.So the conversion is asymmetric: response ➜ LangChain works, LangChain ➜ request throws. On the FIRST agent turn this is invisible. On the SECOND iteration (or any tool-call loop / structured-output step) the assistant message's previous
thinkingblock hits_convertLangChainContentToPartand crashes withUnknown content type thinkingat line 307.How the patch fixes it
Adds a branch that translates the LangChain
thinkingblock back into Google's native shape per the Gemini thinking docs: a textPartwiththought: trueand an optionalthoughtSignature(preserving the Gemini-3 signature continuity that #5715 added forfunctionCallparts).Why two LangChain keys are accepted
The existing response-parser sites in this file emit
signature(the LangChain v0 convention).thoughtSignatureis also accepted because newer@langchain/google-genaiversions put the signature there. Defensive on both for forward compatibility.Verification
Added
FlowiseChatGoogleGenerativeAI.test.tswith 5 cases. Red-green proven:thought=truethoughtSignaturefor Gemini-3 multi-turn tool-call continuitythoughtSignatureon the LangChain block (alternate key name)The throwing path is preserved — only the
thinkingtype is intercepted; truly unknown types still surface as before.Reproduction
agentAgentflownodegemini-3-flash-preview(orgemini-2.5-flashwith athinkingConfig)thinkingLevel: LOW(or higher)Error in Agent node: Unknown content type thinkingRelated
thoughtSignatureonfunctionCallparts (related but doesn't address thethinkingcontent type round-trip)thinkingBudget/thinkingLevelto the Gemini UI (made it possible to opt in to thinking but the parser wasn't updated for the response shape)Test plan
src/storage/*andsrc/utils.ts, none in touched file)