feat: @langchain/google#10000
Conversation
🦋 Changeset detectedLatest commit: 77f1689 The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Christian Bromann (christian-bromann)
left a comment
There was a problem hiding this comment.
Thanks for the contribution! This is an excellent and comprehensive implementation of a unified Google/Gemini integration. The code is well-structured with proper abstractions, thorough error handling, and extensive documentation. The approach of consolidating the fragmented package ecosystem is very valuable. A few edge case suggestions and improvements below.
| } | ||
| return fetch(request); | ||
| } | ||
| } |
There was a problem hiding this comment.
The authentication priority logic here could cause issues. When both apiKey and credentials are provided, the function only checks this.params.apiKey but should also check the resolved this.apiKey field:
| } | |
| fetch(request: Request): Promise<Response> { | |
| if (this.apiKey) { | |
| request.headers.set(GOOGLE_API_KEY_HEADER, this.apiKey); | |
| } else if (this.credentials) { | |
| request.headers.set( | |
| GCP_API_KEY_HEADER, | |
| `Bearer ${getGCPCredentialsAccessToken(this.credentials)}` | |
| ); | |
| } | |
| return fetch(request); | |
| } |
This ensures consistent behavior with the hasApiKey() method.
| isInstance(obj: unknown): obj is this { | ||
| return ( | ||
| typeof obj === "object" && | ||
| obj !== null && | ||
| symbol in obj && | ||
| obj[symbol as keyof typeof obj] === true | ||
| ); | ||
| } |
There was a problem hiding this comment.
The type guard implementation could be more robust. Consider strengthening the check:
| isInstance(obj: unknown): obj is this { | |
| return ( | |
| typeof obj === "object" && | |
| obj !== null && | |
| symbol in obj && | |
| obj[symbol as keyof typeof obj] === true | |
| ); | |
| } | |
| isInstance(obj: unknown): obj is this { | |
| return ( | |
| typeof obj === "object" && | |
| obj !== null && | |
| symbol in obj && | |
| obj[symbol as keyof typeof obj] === true && | |
| obj instanceof Error | |
| ); | |
| } |
This ensures the object is actually an Error instance, not just any object with the symbol property.
| statusText: response.statusText, | ||
| }); | ||
|
|
||
| if (!response.ok) { |
There was a problem hiding this comment.
The streaming response handling could benefit from better error recovery. When parsing chunks fails, the current implementation might not provide enough context:
| if (!response.ok) { | |
| } catch (parseError) { | |
| // If parsing fails, still yield a chunk with error context | |
| const errorMessage = parseError instanceof Error ? parseError.message : 'Unknown parsing error'; | |
| yield new ChatGenerationChunk({ | |
| message: new AIMessageChunk({ | |
| content: `[Parse Error: ${errorMessage}]`, | |
| additional_kwargs: { parseError: true } | |
| }), | |
| text: `[Parse Error: ${errorMessage}]`, | |
| }); | |
| } |
There was a problem hiding this comment.
mmm if we do this stream consumers cant catch errors
| Object.hasOwn(config, "multiSpeakerVoiceConfig")) | ||
| ); | ||
| } | ||
|
|
There was a problem hiding this comment.
The speech configuration conversion logic should validate the voice names against known prebuilt voices to catch configuration errors early:
| // If this is already a SpeechConfig, validate it before returning | |
| if (isSpeechConfig(config)) { | |
| // Add validation for voice names if needed | |
| return config; | |
| } |
Consider adding a list of valid prebuilt voice names for validation.
There was a problem hiding this comment.
we can treat this like a model string from google -- we can't know these without an extra network request locally
|
|
||
| cache.set(cacheKey, { created: now, promise }); | ||
| return await promise.then((data) => data.token); | ||
| } |
There was a problem hiding this comment.
The token caching mechanism could lead to race conditions when multiple requests are made simultaneously. Consider using a more robust caching strategy or adding proper locking mechanisms to prevent duplicate token requests.
There was a problem hiding this comment.
thats fine
| return { | ||
| type: "tool_call", | ||
| id: message.id, | ||
| name: block.functionCall.name, | ||
| args: block.functionCall.args, | ||
| }; |
There was a problem hiding this comment.
The tool_call conversion assumes message.id is available, but this might not always be the case. Add a fallback:
| return { | |
| type: "tool_call", | |
| id: message.id, | |
| name: block.functionCall.name, | |
| args: block.functionCall.args, | |
| }; | |
| return { | |
| type: "tool_call", | |
| id: message.id || `tool_call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, | |
| name: block.functionCall.name, | |
| args: block.functionCall.args, | |
| }; |
There was a problem hiding this comment.
we shouldn't do this
Co-authored-by: afirstenberg <github@addventure.com>
1c4ba50 to
8643cd9
Compare
Co-authored-by: afirstenberg <github@addventure.com>
Co-authored-by: afirstenberg <github@addventure.com>
Summary
Add new
@langchain/googlepackage -- a unified Google/Gemini integration that will replace@langchain/google-genai,@langchain/google-common, and the Vertex AI family of packages.Huge huge huge shoutout to Allen Firstenberg (@afirstenberg) for driving a lot of this feature work
Why a new package?
The existing Google integration stack has accumulated significant technical debt:
@langchain/google-genaidepends on a long-deprecated SDK from Google (@google/generative-ai). That SDK has been superseded by@google/genai, but migrating to it would be a breaking change with limited upside -- we'd still be coupling to Google's SDK release cycle and its opinionated abstractions.@langchain/google-common/ Vertex AI packages had to adopt an awkward multi-package split (google-common,google-gauth,google-webauth,google-vertexai,google-vertexai-web) to accommodate web and edge environments. This fragmentation makes it confusing for users to know which package to install, duplicates logic across packages, and creates a maintenance burden.google-commondrifted from the actual Gemini API surface over time, leading to broken fields, missing properties, and constant churn to keep them in sync with Google's rapid iteration.Usage
The package exposes two entrypoints. The constructor takes the model name as the first positional argument, with an optional params object:
@langchain/google-- for web, edge, and serverless environments (Cloudflare Workers, Vercel Edge, Deno, browsers). Uses the Web Fetch API and authenticates via API key only.@langchain/google/node-- for Node.js environments. Extends the base entrypoint withgoogle-auth-librarysupport, enabling Vertex AI via Application Default Credentials (ADC), service account JSON, and other Node-native auth flows.Both entrypoints export the same
ChatGoogleclass name, so switching between them is just an import path change.Versioning and stability
This package is being published at 0.1.0 to signal that it is an early release. While we have confidence in the core functionality (chat, streaming, tool calling, reasoning, multimodal), the API surface may evolve as we gather feedback and close the remaining feature gaps relative to the existing packages. We intend to promote to 1.0 once we've validated the API through user feedback and reached feature parity with the existing packages.
Support policy for existing packages
The existing
@langchain/google-genai,@langchain/google-vertexai, and related packages will continue to receive maintenance updates (bug fixes, security patches) for the foreseeable future. We are not deprecating them with this release. Once@langchain/googlereaches feature parity, we will publish a migration guide and announce a deprecation timeline with adequate notice.Changes
New package:
libs/providers/langchain-google/base.ts,node.ts,index.ts,types.tsChatGoogleextendingBaseChatModelwith tool calling, streaming, structured output, and multimodal supportapi-types.ts,typegen.jsoncGemininamespace from the OpenAPI spec, plus module augmentations for utility types and spec gapsconverters/messages.ts,converters/params.ts,converters/tools.tsclients/index.ts,clients/node.tsutils/errors.ts,utils/gcp-auth.ts,utils/handler.ts,utils/misc.ts,utils/stream.tstests/index.test.ts,tests/index.int.test.ts@langchain/corechangesChatGoogleTranslatorblock translator (block_translators/google.ts) and registered it under the"google"provider key.