fix(AI Agent Node): Fix gemini 3 thought signature handling on Vertex AI (#24473)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Benjamin Schroth <benjamin@n8n.io>
This commit is contained in:
Mutasem Aldmour
2026-01-22 17:21:46 +01:00
committed by GitHub
parent 4dedbdde4e
commit d513f1ca3f
8 changed files with 488 additions and 58 deletions
+3 -3
View File
@@ -185,7 +185,7 @@
"@getzep/zep-cloud": "1.0.6",
"@getzep/zep-js": "0.9.0",
"@google-cloud/resource-manager": "5.3.0",
"@google/generative-ai": "0.21.0",
"@google/generative-ai": "0.24.0",
"@google/genai": "1.19.0",
"@huggingface/inference": "4.0.5",
"@langchain/anthropic": "catalog:",
@@ -193,8 +193,8 @@
"@langchain/cohere": "1.0.1",
"@langchain/community": "catalog:",
"@langchain/core": "catalog:",
"@langchain/google-genai": "2.0.0",
"@langchain/google-vertexai": "2.0.0",
"@langchain/google-genai": "2.1.10",
"@langchain/google-vertexai": "2.1.10",
"@langchain/groq": "1.0.2",
"@langchain/mistralai": "1.0.1",
"@langchain/mongodb": "1.0.1",
@@ -201,17 +201,12 @@ export function buildSteps(
const toolId = typeof toolInput?.id === 'string' ? toolInput.id : 'reconstructed_call';
const toolName = nodeNameToToolName(tool.action.nodeName);
// Build the tool call object with thought_signature if present (for Gemini)
// Build the tool call object
const toolCall = {
id: toolId,
name: toolName,
args: toolInput,
type: 'tool_call' as const,
additional_kwargs: {
...(providerMetadata.thoughtSignature && {
thought_signature: providerMetadata.thoughtSignature,
}),
},
};
// Build message content using provider-specific logic
@@ -223,12 +218,33 @@ export function buildSteps(
tool.action.nodeName,
);
const syntheticAIMessage = new AIMessage({
// Build AIMessage options, handling provider-specific requirements
// Note: tool_calls is only used when content is a string
// When content is an array (thinking mode), tool_use blocks are in the content array
const aiMessageOptions: {
content: typeof messageContent;
tool_calls?: Array<typeof toolCall>;
additional_kwargs?: Record<string, unknown>;
} = {
content: messageContent,
// Note: tool_calls is only used when content is a string
// When content is an array (thinking mode), tool_use blocks are in the content array
...(typeof messageContent === 'string' && { tool_calls: [toolCall] }),
});
};
if (typeof messageContent === 'string') {
aiMessageOptions.tool_calls = [toolCall];
}
// Include additional_kwargs with Gemini thought signatures for LangChain to pass back
if (providerMetadata.thoughtSignature) {
aiMessageOptions.additional_kwargs = {
__gemini_function_call_thought_signatures__: {
[toolId]: providerMetadata.thoughtSignature,
},
tool_calls: [{ id: toolId, name: toolName, args: toolInput }],
signatures: ['', providerMetadata.thoughtSignature],
};
}
const syntheticAIMessage = new AIMessage(aiMessageOptions);
// Extract tool input arguments for the result
// Exclude metadata fields: id, log, type - always keep as object for type consistency
@@ -23,6 +23,14 @@ export async function createEngineRequests(
itemIndex: number,
tools: Array<DynamicStructuredTool | Tool>,
): Promise<EngineRequest<RequestResponseMetadata>['actions']> {
// For parallel tool calls, LangChain may only populate messageLog on the first action.
// Find a shared messageLog to use for all tool calls in this batch.
const sharedMessageLog = toolCalls.find(
(tc) => tc.messageLog && tc.messageLog.length > 0,
)?.messageLog;
// Similarly for additionalKwargs (contains Gemini thought signatures)
const sharedAdditionalKwargs = toolCalls.find((tc) => tc.additionalKwargs)?.additionalKwargs;
return toolCalls
.map((toolCall) => {
// First try to get from metadata (for toolkit tools)
@@ -47,8 +55,39 @@ export async function createEngineRequests(
let thinkingType: 'thinking' | 'redacted_thinking' | undefined;
let thinkingSignature: string | undefined;
if (toolCall.messageLog && Array.isArray(toolCall.messageLog)) {
for (const message of toolCall.messageLog) {
// Use toolCall's additionalKwargs or fall back to shared one from batch
const effectiveAdditionalKwargs = toolCall.additionalKwargs || sharedAdditionalKwargs;
// Use toolCall's messageLog or fall back to shared one from batch
const effectiveMessageLog =
toolCall.messageLog && toolCall.messageLog.length > 0
? toolCall.messageLog
: sharedMessageLog;
// First check additionalKwargs on the toolCall itself (Gemini thought signatures via LangChain)
if (effectiveAdditionalKwargs) {
// Check for signature mapped by tool call ID
const geminiSignatures = effectiveAdditionalKwargs[
'__gemini_function_call_thought_signatures__'
] as Record<string, string> | undefined;
if (geminiSignatures && typeof geminiSignatures === 'object') {
// Get signature for this specific tool call, or ANY signature if ID not found
// (for parallel calls, signature may be keyed to first call's ID)
thoughtSignature =
geminiSignatures[toolCall.toolCallId] || Object.values(geminiSignatures)[0];
}
// Also check signatures array format (LangChain Google uses this)
if (!thoughtSignature) {
const signatures = effectiveAdditionalKwargs.signatures as string[] | undefined;
if (signatures && Array.isArray(signatures) && signatures.length > 0) {
// First non-empty signature (parallel calls have signature only on first)
thoughtSignature = signatures.find((s) => s && s.length > 0);
}
}
}
if (effectiveMessageLog && Array.isArray(effectiveMessageLog)) {
for (const message of effectiveMessageLog) {
// Check if message has content that could contain thought_signature or thinking blocks
if (message && typeof message === 'object' && 'content' in message) {
const content = message.content;
@@ -57,8 +96,8 @@ export async function createEngineRequests(
// Look for thought_signature in content blocks (Gemini)
// and thinking/redacted_thinking blocks (Anthropic)
for (const block of content) {
// Gemini thought_signature
if (isGeminiThoughtSignatureBlock(block)) {
// Gemini thought_signature as content block (only if not already found)
if (!thoughtSignature && isGeminiThoughtSignatureBlock(block)) {
thoughtSignature = block.thoughtSignature;
}
@@ -73,6 +112,52 @@ export async function createEngineRequests(
}
}
}
// Also check additional_kwargs on the message for Gemini thought signatures
if (!thoughtSignature && 'additional_kwargs' in message) {
const msgAdditionalKwargs = message.additional_kwargs as
| Record<string, unknown>
| undefined;
if (msgAdditionalKwargs) {
// First check the map format: __gemini_function_call_thought_signatures__
const geminiSignatures = msgAdditionalKwargs[
'__gemini_function_call_thought_signatures__'
] as Record<string, string> | undefined;
if (geminiSignatures && typeof geminiSignatures === 'object') {
// Get signature for this tool call, or ANY signature for parallel calls
thoughtSignature =
geminiSignatures[toolCall.toolCallId] || Object.values(geminiSignatures)[0];
}
// If not found, check the signatures array format
// LangChain Google returns signatures as an array that corresponds to tool_calls array
if (!thoughtSignature) {
const signatures = msgAdditionalKwargs.signatures as string[] | undefined;
// Get tool_calls from message (not from additional_kwargs)
const msgToolCalls =
'tool_calls' in message
? (message.tool_calls as Array<{ id?: string }> | undefined)
: undefined;
if (signatures && Array.isArray(signatures)) {
if (msgToolCalls && Array.isArray(msgToolCalls)) {
// Find the index of this tool call by ID
const toolCallIndex = msgToolCalls.findIndex(
(tc) => tc.id === toolCall.toolCallId,
);
if (toolCallIndex !== -1 && toolCallIndex < signatures.length) {
thoughtSignature = signatures[toolCallIndex];
}
}
// Fallback: get first non-empty signature
if (!thoughtSignature) {
thoughtSignature = signatures.find((s) => s && s.length > 0);
}
}
}
}
}
if (thoughtSignature || thinkingContent) break;
}
}
@@ -60,6 +60,8 @@ export async function processEventStream(
// Check if this LLM response contains tool calls
if (output?.tool_calls && output.tool_calls.length > 0) {
// Collect tool calls for request building
// Note: For Gemini, we pass additional_kwargs to ALL tool calls
// so the signature can be applied to each when rebuilding
for (const toolCall of output.tool_calls) {
toolCalls.push({
tool: toolCall.name,
@@ -70,6 +72,8 @@ export async function processEventStream(
output.content ||
`Calling ${toolCall.name} with input: ${JSON.stringify(toolCall.args)}`,
messageLog: [output],
// Pass additional_kwargs to ALL tool calls so signature is available
additionalKwargs: output.additional_kwargs as Record<string, unknown> | undefined,
});
}
}
@@ -1158,4 +1158,92 @@ describe('buildSteps', () => {
expect(result[0].action.toolInput).not.toHaveProperty('id');
});
});
describe('Gemini thought_signature in additional_kwargs', () => {
it('should include thought_signature in AIMessage additional_kwargs', () => {
const response: EngineResponse<RequestResponseMetadata> = {
actionResponses: [
{
action: {
actionType: 'ExecutionNodeAction',
nodeName: 'Calculator',
input: {
id: 'call_123',
input: { expression: '2+2' },
},
type: NodeConnectionTypes.AiTool,
id: 'call_123',
metadata: {
itemIndex: 0,
google: {
thoughtSignature: 'gemini_thought_sig_abc123',
},
},
},
data: {
data: {
ai_tool: [[{ json: { result: '4' } }]],
},
executionTime: 0,
startTime: 0,
executionIndex: 0,
source: [],
},
},
],
metadata: {},
};
const result = buildSteps(response, itemIndex);
expect(result).toHaveLength(1);
const message = result[0].action.messageLog![0];
// Verify additional_kwargs contains the thought signature
expect(message.additional_kwargs).toBeDefined();
expect(message.additional_kwargs.__gemini_function_call_thought_signatures__).toEqual({
call_123: 'gemini_thought_sig_abc123',
});
});
it('should not include additional_kwargs when no thought_signature present', () => {
const response: EngineResponse<RequestResponseMetadata> = {
actionResponses: [
{
action: {
actionType: 'ExecutionNodeAction',
nodeName: 'Calculator',
input: {
id: 'call_123',
input: { expression: '2+2' },
},
type: NodeConnectionTypes.AiTool,
id: 'call_123',
metadata: {
itemIndex: 0,
},
},
data: {
data: {
ai_tool: [[{ json: { result: '4' } }]],
},
executionTime: 0,
startTime: 0,
executionIndex: 0,
source: [],
},
},
],
metadata: {},
};
const result = buildSteps(response, itemIndex);
expect(result).toHaveLength(1);
const message = result[0].action.messageLog![0];
// Should not have __gemini_function_call_thought_signatures__ when no signature
expect(
message.additional_kwargs?.__gemini_function_call_thought_signatures__,
).toBeUndefined();
});
});
});
@@ -505,4 +505,248 @@ describe('createEngineRequests', () => {
expect(result[0].metadata.anthropic?.thinkingSignature).toBe('anthropic_sig_456');
});
});
describe('Gemini thought_signature from additionalKwargs', () => {
it('should extract thought_signature from additionalKwargs on toolCall', async () => {
const tools = [createMockTool('calculator', { sourceNodeName: 'Calculator' })];
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_123',
additionalKwargs: {
__gemini_function_call_thought_signatures__: {
call_123: 'gemini_signature_from_kwargs',
},
},
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(1);
expect(result[0].metadata.google?.thoughtSignature).toBe('gemini_signature_from_kwargs');
});
it('should extract thought_signature from message additional_kwargs', async () => {
const tools = [createMockTool('calculator', { sourceNodeName: 'Calculator' })];
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_456',
messageLog: [
{
content: 'Some content',
additional_kwargs: {
__gemini_function_call_thought_signatures__: {
call_456: 'gemini_signature_from_message_kwargs',
},
},
},
],
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(1);
expect(result[0].metadata.google?.thoughtSignature).toBe(
'gemini_signature_from_message_kwargs',
);
});
it('should prefer additionalKwargs over content block thoughtSignature', async () => {
const tools = [createMockTool('calculator', { sourceNodeName: 'Calculator' })];
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_123',
additionalKwargs: {
__gemini_function_call_thought_signatures__: {
call_123: 'signature_from_kwargs',
},
},
messageLog: [
{
content: [
{
thoughtSignature: 'signature_from_content_block',
},
],
},
],
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(1);
// Should prefer additionalKwargs over content block
expect(result[0].metadata.google?.thoughtSignature).toBe('signature_from_kwargs');
});
it('should fallback to any available signature for parallel tool calls', async () => {
// For parallel tool calls, Gemini only provides thought_signature on the first call.
// When a different call_id is in the map, we should still use that signature
// because all parallel calls need the same signature.
const tools = [createMockTool('calculator', { sourceNodeName: 'Calculator' })];
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_123',
additionalKwargs: {
__gemini_function_call_thought_signatures__: {
different_call_id: 'some_signature',
},
},
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(1);
// Should use the available signature even though call ID doesn't match
// This supports parallel tool calls where only first call has the signature
expect(result[0].metadata.google?.thoughtSignature).toBe('some_signature');
});
it('should handle truly missing thought_signature gracefully', async () => {
const tools = [createMockTool('calculator', { sourceNodeName: 'Calculator' })];
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_123',
additionalKwargs: {
__gemini_function_call_thought_signatures__: {},
},
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(1);
expect(result[0].metadata.google).toBeUndefined();
});
});
describe('Parallel tool calls signature sharing', () => {
it('should share messageLog from first tool call to subsequent calls', async () => {
const tools = [
createMockTool('calculator', { sourceNodeName: 'Calculator' }),
createMockTool('weather', { sourceNodeName: 'Weather' }),
];
// Simulates LangChain behavior where only first tool call has messageLog
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_1',
messageLog: [
{
content: [{ type: 'text', text: 'thinking...' }],
additional_kwargs: {
signatures: ['', 'shared_signature'],
},
},
],
},
{
tool: 'weather',
toolInput: { location: 'NYC' },
toolCallId: 'call_2',
messageLog: [], // Empty messageLog on second call
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(2);
// Both should get the signature from the shared messageLog
expect(result[0].metadata.google?.thoughtSignature).toBe('shared_signature');
expect(result[1].metadata.google?.thoughtSignature).toBe('shared_signature');
});
it('should share additionalKwargs from first tool call to subsequent calls', async () => {
const tools = [
createMockTool('calculator', { sourceNodeName: 'Calculator' }),
createMockTool('weather', { sourceNodeName: 'Weather' }),
];
// Simulates case where additionalKwargs is only on first call
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_1',
additionalKwargs: {
signatures: ['', 'shared_sig_from_kwargs'],
},
},
{
tool: 'weather',
toolInput: { location: 'NYC' },
toolCallId: 'call_2',
// No additionalKwargs on second call
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(2);
// Both should get the signature from the shared additionalKwargs
expect(result[0].metadata.google?.thoughtSignature).toBe('shared_sig_from_kwargs');
expect(result[1].metadata.google?.thoughtSignature).toBe('shared_sig_from_kwargs');
});
it('should extract signature from signatures array format', async () => {
const tools = [createMockTool('calculator', { sourceNodeName: 'Calculator' })];
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_1',
additionalKwargs: {
signatures: ['first_signature', 'second_signature'],
},
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(1);
// Should get the first non-empty signature
expect(result[0].metadata.google?.thoughtSignature).toBe('first_signature');
});
it('should skip empty strings when finding signature in array', async () => {
const tools = [createMockTool('calculator', { sourceNodeName: 'Calculator' })];
const toolCalls: ToolCallRequest[] = [
{
tool: 'calculator',
toolInput: { expression: '2+2' },
toolCallId: 'call_1',
additionalKwargs: {
signatures: ['', '', 'actual_signature'],
},
},
];
const result = await createEngineRequests(toolCalls, 0, tools);
expect(result).toHaveLength(1);
expect(result[0].metadata.google?.thoughtSignature).toBe('actual_signature');
});
});
});
@@ -18,6 +18,8 @@ export type ToolCallRequest = {
log?: string;
/** Full message log including LLM response */
messageLog?: unknown[];
/** Additional kwargs from the LLM response (for Gemini thought signatures) */
additionalKwargs?: Record<string, unknown>;
};
/**
+31 -40
View File
@@ -1246,8 +1246,8 @@ importers:
specifier: 1.19.0
version: 1.19.0(@modelcontextprotocol/sdk@1.25.2(hono@4.11.3)(zod@3.25.67))(bufferutil@4.0.9)(utf-8-validate@5.0.10)
'@google/generative-ai':
specifier: 0.21.0
version: 0.21.0
specifier: 0.24.0
version: 0.24.0
'@huggingface/inference':
specifier: 4.0.5
version: 4.0.5
@@ -1270,11 +1270,11 @@ importers:
specifier: 'catalog:'
version: 1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))
'@langchain/google-genai':
specifier: 2.0.0
version: 2.0.0(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))
specifier: 2.1.10
version: 2.1.10(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))
'@langchain/google-vertexai':
specifier: 2.0.0
version: 2.0.0(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))
specifier: 2.1.10
version: 2.1.10(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))
'@langchain/groq':
specifier: 1.0.2
version: 1.0.2(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)
@@ -5345,12 +5345,8 @@ packages:
'@modelcontextprotocol/sdk':
optional: true
'@google/generative-ai@0.21.0':
resolution: {integrity: sha512-7XhUbtnlkSEZK15kN3t+tzIMxsbKm/dSkKBFalj+20NvPKe1kBY7mR2P7vuijEn+f06z5+A8bVGKO0v39cr6Wg==}
engines: {node: '>=18.0.0'}
'@google/generative-ai@0.24.1':
resolution: {integrity: sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==}
'@google/generative-ai@0.24.0':
resolution: {integrity: sha512-fnEITCGEB7NdX0BhoYZ/cq/7WPZ1QS5IzJJfC3Tg/OwkvBetMiVJciyaan297OvE4B9Jg1xvo0zIazX/9sGu1Q==}
engines: {node: '>=18.0.0'}
'@graphql-typed-document-node/core@3.2.0':
@@ -6171,28 +6167,25 @@ packages:
resolution: {integrity: sha512-kIUidOgc0ZdyXo4Ahn9Zas+OayqOfk4ZoKPi7XaDipNSWSApc2+QK5BVcjvwtzxstsNOrmXJiJWEN6WPF/MvAw==}
engines: {node: '>=20'}
'@langchain/google-common@2.0.0':
resolution: {integrity: sha512-n+UWeZVARGm7d3TaQlLYKTH3VNpWrePsmLGWt1OBr6IzC6TTrhyf39UD0Okw02h/+tWJ7LSQrrOgfx5BOhdnAw==}
engines: {node: '>=20'}
deprecated: Use version 1.x instead
peerDependencies:
'@langchain/core': 1.1.0
'@langchain/google-gauth@2.0.0':
resolution: {integrity: sha512-9/N0qQeK9R1RDWCaXbWQRbZt9OkJh9MsBt+HgKH/Vjeiop3QNjto3EmyywOIU5Ak4OhaSBKRVX6SkEyFzZq7VQ==}
engines: {node: '>=20'}
deprecated: Use version 1.x instead
'@langchain/google-genai@2.0.0':
resolution: {integrity: sha512-PaAWkogQdF+Y2bhhXWXUrC2nO7sTgWLtobBbZl/0V8Aa1F/KG2wrMECie3S17bAdFu/6VmQOuFFrlgSMwQC5KA==}
'@langchain/google-common@2.1.10':
resolution: {integrity: sha512-te9UZf7ajL6p7VkGSG6iKnRDMXcJB+SSOeEWBV0Jih72eXEP55v9RLTRlCLWf+RZbtv1fofAv9J8YCvg2WoYdw==}
engines: {node: '>=20'}
peerDependencies:
'@langchain/core': 1.1.0
'@langchain/core': 1.1.15
'@langchain/google-vertexai@2.0.0':
resolution: {integrity: sha512-OGm1P3i/E/xfz/2HoV50sEcEwsgV/hmsgrngWAUZTum4LjJAn/RkRACEhewq0hognEwaQNPmuP5tDiHj/0MgFA==}
'@langchain/google-gauth@2.1.10':
resolution: {integrity: sha512-xJX9WNpItvOPDhgVPgLlTIr+Gu/G/E6eGcb+vlagY9crdAg3R10KcI3fb8lZFIR9eqvXKFbntiddOxZqFpxuQg==}
engines: {node: '>=20'}
'@langchain/google-genai@2.1.10':
resolution: {integrity: sha512-OpiBr2OUzB9Pg20mjLId+vfxJvYurc8TzbElaM/d6KE7aE8DiKCEOuQn5ZSgHTVzZV2g++lcJXw6iZlso4SORA==}
engines: {node: '>=20'}
peerDependencies:
'@langchain/core': 1.1.15
'@langchain/google-vertexai@2.1.10':
resolution: {integrity: sha512-LoUgGi+i8q3fo8UXeWxvHm4JAPhf06aTOSCx/l41Tys+Dce1ArX/eTlIjOkuJ0t9YHWDExP3F8kbvF5RGuWqYA==}
engines: {node: '>=20'}
deprecated: Use version 1.x instead
'@langchain/groq@1.0.2':
resolution: {integrity: sha512-buD2oSPFv8QpJpkoTS+xkBLNUeOrplmPFdiipt/qmYvaL/YOz0/tnMzTARCyeq2+jJvxV609cbuyW5aGvRQ3Rg==}
@@ -21874,9 +21867,7 @@ snapshots:
- supports-color
- utf-8-validate
'@google/generative-ai@0.21.0': {}
'@google/generative-ai@0.24.1': {}
'@google/generative-ai@0.24.0': {}
'@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)':
dependencies:
@@ -22602,28 +22593,28 @@ snapshots:
- '@opentelemetry/sdk-trace-base'
- openai
'@langchain/google-common@2.0.0(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))':
'@langchain/google-common@2.1.10(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))':
dependencies:
'@langchain/core': 1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))
uuid: 10.0.0
'@langchain/google-gauth@2.0.0(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))':
'@langchain/google-gauth@2.1.10(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))':
dependencies:
'@langchain/google-common': 2.0.0(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))
'@langchain/google-common': 2.1.10(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))
google-auth-library: 10.1.0
transitivePeerDependencies:
- '@langchain/core'
- supports-color
'@langchain/google-genai@2.0.0(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))':
'@langchain/google-genai@2.1.10(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))':
dependencies:
'@google/generative-ai': 0.24.1
'@google/generative-ai': 0.24.0
'@langchain/core': 1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))
uuid: 11.1.0
'@langchain/google-vertexai@2.0.0(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))':
'@langchain/google-vertexai@2.1.10(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))':
dependencies:
'@langchain/google-gauth': 2.0.0(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))
'@langchain/google-gauth': 2.1.10(@langchain/core@1.1.8(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@6.9.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))
transitivePeerDependencies:
- '@langchain/core'
- supports-color