@langchain/google 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @langchain/google
2
2
 
3
+ ## 0.1.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#10260](https://github.com/langchain-ai/langchainjs/pull/10260) [`09babb4`](https://github.com/langchain-ai/langchainjs/commit/09babb49853467b00da460c2af3cc811bbffc685) Thanks [@colifran](https://github.com/colifran)! - feat(google): implement standard schema support for structured output
8
+
9
+ ## 0.1.4
10
+
11
+ ### Patch Changes
12
+
13
+ - [#10195](https://github.com/langchain-ai/langchainjs/pull/10195) [`05f46ff`](https://github.com/langchain-ai/langchainjs/commit/05f46ff36c12ce5259c2c8e0da89349396f25b8c) Thanks [@hntrl](https://github.com/hntrl)! - fix(google): don't send empty toolConfig when no tool_choice is specified
14
+
15
+ When `bindTools()` was called without specifying `tool_choice`, an empty
16
+ `toolConfig: { functionCallingConfig: {} }` was included in the API request.
17
+ This caused the Gemini API to return tool invocations as text (Python code
18
+ blocks) instead of structured `functionCall` parts. Now returns `undefined`
19
+ when no `tool_choice` is set, omitting `toolConfig` from the request entirely
20
+ and letting the API default to AUTO mode.
21
+
3
22
  ## 0.1.3
4
23
 
5
24
  ### Patch Changes
@@ -13,8 +13,8 @@ let eventsource_parser_stream = require("eventsource-parser/stream");
13
13
  let _langchain_core_runnables = require("@langchain/core/runnables");
14
14
  let _langchain_core_utils_json_schema = require("@langchain/core/utils/json_schema");
15
15
  let _langchain_core_utils_types = require("@langchain/core/utils/types");
16
- let _langchain_core_output_parsers = require("@langchain/core/output_parsers");
17
- let _langchain_core_output_parsers_openai_tools = require("@langchain/core/output_parsers/openai_tools");
16
+ let _langchain_core_utils_standard_schema = require("@langchain/core/utils/standard_schema");
17
+ let _langchain_core_language_models_structured_output = require("@langchain/core/language_models/structured_output");
18
18
 
19
19
  //#region src/chat_models/base.ts
20
20
  function getPlatformType(platform, hasApiKey) {
@@ -35,7 +35,7 @@ var BaseChatGoogle = class extends _langchain_core_language_models_chat_models.B
35
35
  constructor(params) {
36
36
  super(params);
37
37
  this.params = params;
38
- this._addVersion("@langchain/google", "0.1.3");
38
+ this._addVersion("@langchain/google", "0.1.5");
39
39
  if (!params.apiClient) throw new require_errors.ConfigurationError("BaseChatGoogle requires an apiClient. This should be provided automatically by ChatGoogle constructors. If you're extending BaseChatGoogle directly, please provide an apiClient instance.");
40
40
  this.apiClient = params.apiClient;
41
41
  this.model = params.model;
@@ -126,7 +126,7 @@ var BaseChatGoogle = class extends _langchain_core_language_models_chat_models.B
126
126
  let responseJsonSchema;
127
127
  let responseMimeType;
128
128
  if (fields.responseSchema) {
129
- if ((0, _langchain_core_utils_types.isInteropZodSchema)(fields.responseSchema)) responseJsonSchema = (0, _langchain_core_utils_json_schema.toJsonSchema)(fields.responseSchema);
129
+ if ((0, _langchain_core_utils_types.isInteropZodSchema)(fields.responseSchema) || (0, _langchain_core_utils_standard_schema.isSerializableSchema)(fields.responseSchema)) responseJsonSchema = (0, _langchain_core_utils_json_schema.toJsonSchema)(fields.responseSchema);
130
130
  else responseJsonSchema = fields.responseSchema;
131
131
  responseMimeType = "application/json";
132
132
  }
@@ -354,51 +354,35 @@ var BaseChatGoogle = class extends _langchain_core_language_models_chat_models.B
354
354
  outputParser = _langchain_core_runnables.RunnableLambda.from(async (input) => {
355
355
  if (!_langchain_core_messages.AIMessage.isInstance(input) && !_langchain_core_messages.AIMessageChunk.isInstance(input)) throw new require_errors.MalformedOutputError({ message: "Input is not an AIMessage or AIMessageChunk." });
356
356
  if (!input.text) throw new require_errors.MalformedOutputError({ message: "No content found in response. Cannot parse structured output." });
357
- if ((0, _langchain_core_utils_types.isInteropZodSchema)(schema)) return await _langchain_core_output_parsers.StructuredOutputParser.fromZodSchema(schema).parse(input.text);
358
- else return await new _langchain_core_output_parsers.JsonOutputParser().parse(input.text);
357
+ return await (0, _langchain_core_language_models_structured_output.createContentParser)(schema).parse(input.text);
359
358
  });
360
359
  } else if (method === "functionCalling") {
361
360
  let functionName = name ?? "extract";
362
- let tools;
363
- if ((0, _langchain_core_utils_types.isInteropZodSchema)(schema)) {
361
+ let geminiFunctionDeclaration;
362
+ if ((0, _langchain_core_utils_types.isInteropZodSchema)(schema) || (0, _langchain_core_utils_standard_schema.isSerializableSchema)(schema)) {
364
363
  const jsonSchema = require_tools.schemaToGeminiParameters(schema);
365
364
  const description = typeof jsonSchema.description === "string" ? jsonSchema.description : "A function available to call.";
366
- tools = [{ functionDeclarations: [{
365
+ geminiFunctionDeclaration = {
367
366
  name: functionName,
368
367
  description,
369
368
  parameters: jsonSchema
370
- }] }];
371
- outputParser = new _langchain_core_output_parsers_openai_tools.JsonOutputKeyToolsParser({
372
- returnSingle: true,
373
- keyName: functionName,
374
- zodSchema: schema
375
- });
369
+ };
370
+ } else if (typeof schema.name === "string" && typeof schema.parameters === "object" && schema.parameters != null) {
371
+ geminiFunctionDeclaration = schema;
372
+ functionName = schema.name;
376
373
  } else {
377
- let geminiFunctionDefinition;
378
- if (typeof schema.name === "string" && typeof schema.parameters === "object" && schema.parameters != null) {
379
- geminiFunctionDefinition = schema;
380
- functionName = schema.name;
381
- } else {
382
- const parameters = require_tools.schemaToGeminiParameters(schema);
383
- geminiFunctionDefinition = {
384
- name: functionName,
385
- description: schema.description ?? "",
386
- parameters
387
- };
388
- }
389
- tools = [{ functionDeclarations: [geminiFunctionDefinition] }];
390
- outputParser = new _langchain_core_output_parsers_openai_tools.JsonOutputKeyToolsParser({
391
- returnSingle: true,
392
- keyName: functionName
393
- });
374
+ const parameters = require_tools.schemaToGeminiParameters(schema);
375
+ geminiFunctionDeclaration = {
376
+ name: functionName,
377
+ description: schema.description ?? "",
378
+ parameters
379
+ };
394
380
  }
381
+ const tools = [{ functionDeclarations: [geminiFunctionDeclaration] }];
395
382
  llm = this.bindTools(tools).withConfig({ tool_choice: functionName });
383
+ outputParser = (0, _langchain_core_language_models_structured_output.createFunctionCallingParser)(schema, functionName);
396
384
  } else throw new require_errors.ConfigurationError(`Unrecognized structured output method '${method}'. Expected 'functionCalling' or 'jsonSchema'`);
397
- if (!includeRaw) return llm.pipe(outputParser).withConfig({ runName: "ChatGoogleStructuredOutput" });
398
- const parserAssign = _langchain_core_runnables.RunnablePassthrough.assign({ parsed: (input, config) => outputParser.invoke(input.raw, config) });
399
- const parserNone = _langchain_core_runnables.RunnablePassthrough.assign({ parsed: () => null });
400
- const parsedWithFallback = parserAssign.withFallbacks({ fallbacks: [parserNone] });
401
- return _langchain_core_runnables.RunnableSequence.from([{ raw: llm }, parsedWithFallback]).withConfig({ runName: "ChatGoogleStructuredOutputRunnable" });
385
+ return (0, _langchain_core_language_models_structured_output.assembleStructuredOutputPipeline)(llm, outputParser, includeRaw, includeRaw ? "ChatGoogleStructuredOutputRunnable" : "ChatGoogleStructuredOutput");
402
386
  }
403
387
  };
404
388
  function combineGoogleChatModelFields(a, b, ...rest) {
@@ -1 +1 @@
1
- {"version":3,"file":"base.cjs","names":["BaseChatModel","ConfigurationError","convertParamsToPlatformType","PROFILES","convertToolsToGeminiTools","convertToolChoiceToGeminiConfig","convertFieldsToThinkingConfig","convertFieldsToSpeechConfig","convertMessagesToGeminiSystemInstruction","convertMessagesToGeminiContents","RequestError","PromptBlockedError","NoCandidatesError","convertGeminiCandidateToAIMessage","convertAIMessageToText","convertGeminiGenerateContentResponseToUsageMetadata","EventSourceParserStream","SafeJsonEventParserStream","ChatGenerationChunk","AIMessageChunk","convertGeminiPartsToToolCalls","subtractUsageMetadata","RunnableLambda","AIMessage","MalformedOutputError","StructuredOutputParser","JsonOutputParser","schemaToGeminiParameters","JsonOutputKeyToolsParser","RunnablePassthrough","RunnableSequence"],"sources":["../../src/chat_models/base.ts"],"sourcesContent":["import {\n BaseChatModel,\n type BaseChatModelCallOptions,\n type BaseChatModelParams,\n} from \"@langchain/core/language_models/chat_models\";\nimport {\n AIMessage,\n AIMessageChunk,\n AIMessageChunkFields,\n BaseMessage,\n type UsageMetadata,\n} from \"@langchain/core/messages\";\nimport { CallbackManagerForLLMRun } from \"@langchain/core/callbacks/manager\";\nimport { concat } from \"@langchain/core/utils/stream\";\nimport { ChatGenerationChunk, ChatResult } from \"@langchain/core/outputs\";\nimport { EventSourceParserStream } from \"eventsource-parser/stream\";\nimport type { BindToolsInput } from \"@langchain/core/language_models/chat_models\";\nimport type { ModelProfile } from \"@langchain/core/language_models/profile\";\nimport PROFILES from \"./profiles.js\";\nimport type {\n BaseLanguageModelInput,\n StructuredOutputMethodOptions,\n} from \"@langchain/core/language_models/base\";\nimport {\n Runnable,\n RunnableLambda,\n RunnablePassthrough,\n RunnableSequence,\n} from \"@langchain/core/runnables\";\nimport {\n toJsonSchema,\n type JsonSchema7Type,\n} from \"@langchain/core/utils/json_schema\";\nimport {\n InteropZodType,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n JsonOutputParser,\n StructuredOutputParser,\n} from \"@langchain/core/output_parsers\";\nimport { JsonOutputKeyToolsParser } from \"@langchain/core/output_parsers/openai_tools\";\n\nimport { ApiClient } from \"../clients/index.js\";\nimport type { ChatGoogleFields } from \"./types.js\";\nimport { SafeJsonEventParserStream } from \"../utils/stream.js\";\nimport {\n convertAIMessageToText,\n convertGeminiCandidateToAIMessage,\n convertGeminiGenerateContentResponseToUsageMetadata,\n convertGeminiPartsToToolCalls,\n convertMessagesToGeminiContents,\n convertMessagesToGeminiSystemInstruction,\n} from \"../converters/messages.js\";\nimport {\n ConfigurationError,\n MalformedOutputError,\n NoCandidatesError,\n PromptBlockedError,\n RequestError,\n} from \"../utils/errors.js\";\nimport {\n convertToolsToGeminiTools,\n convertToolChoiceToGeminiConfig,\n schemaToGeminiParameters,\n} from \"../converters/tools.js\";\nimport {\n convertParamsToPlatformType,\n convertFieldsToSpeechConfig,\n convertFieldsToThinkingConfig,\n} from \"../converters/params.js\";\nimport { Gemini } from \"./api-types.js\";\nimport { subtractUsageMetadata } from \"../utils/metadata.js\";\n\nexport type GooglePlatformType = \"gai\" | \"gcp\";\n\nexport function getPlatformType(\n platform: GooglePlatformType | undefined,\n hasApiKey: boolean\n): GooglePlatformType {\n if (typeof platform !== \"undefined\") {\n return platform;\n } else if (hasApiKey) {\n return \"gai\";\n } else {\n return \"gcp\";\n }\n}\n\nexport interface BaseChatGoogleParams\n extends BaseChatModelParams,\n ChatGoogleFields {\n /**\n * The name of the Gemini model to use.\n *\n * Example: \"gemini-3-pro-preview\"\n */\n model: string;\n\n /**\n * Optional. The API client implementation for making HTTP requests to the Gemini API.\n * If not set, a default client will be used based on the runtime environment.\n */\n apiClient?: ApiClient;\n\n /**\n * Hostname for the API call (if this is running on GCP)\n * Usually this is computed based on location and platformType.\n **/\n endpoint?: string;\n\n /**\n * Region where the LLM is stored (if this is running on GCP)\n * Defaults to \"global\"\n **/\n location?: string;\n\n /**\n * The version of the API functions. Part of the path.\n * Usually this is computed based on platformType.\n **/\n apiVersion?: string;\n\n /**\n * What platform to run the service on.\n * If not specified, the class should determine this from other\n * means. Either way, the platform actually used will be in\n * the \"platform\" getter.\n */\n platformType?: GooglePlatformType;\n\n /**\n * For compatibility with Google's libraries, should this use Vertex?\n * The \"platformType\" parmeter takes precedence.\n */\n vertexai?: boolean;\n\n /**\n * Backwards compatibility.\n * @deprecated in favor of using `disableStreaming` or `.stream()`\n */\n streaming?: boolean;\n\n streamUsage?: boolean;\n}\n\nexport interface BaseChatGoogleCallOptions\n extends BaseChatModelCallOptions,\n ChatGoogleFields {}\n\nexport abstract class BaseChatGoogle<\n CallOptions extends BaseChatGoogleCallOptions = BaseChatGoogleCallOptions\n> extends BaseChatModel<CallOptions, AIMessageChunk> {\n model: string;\n\n streaming: boolean;\n\n disableStreaming: boolean;\n\n streamUsage: boolean = true;\n\n protected _platform?: GooglePlatformType;\n\n protected _endpoint?: string;\n\n protected _location?: string;\n\n protected _apiVersion?: string;\n\n protected apiClient: ApiClient;\n\n constructor(protected params: BaseChatGoogleParams) {\n super(params);\n this._addVersion(\"@langchain/google\", __PKG_VERSION__);\n\n if (!params.apiClient) {\n throw new ConfigurationError(\n \"BaseChatGoogle requires an apiClient. This should be provided automatically by ChatGoogle constructors. If you're extending BaseChatGoogle directly, please provide an apiClient instance.\"\n );\n }\n this.apiClient = params.apiClient;\n\n this.model = params.model;\n this._platform = convertParamsToPlatformType(params);\n this._endpoint = params.endpoint;\n this._location = params.location;\n this._apiVersion = params.apiVersion;\n\n this.disableStreaming = params?.disableStreaming === true;\n this.streaming = params?.streaming === true;\n if (this.disableStreaming) this.streaming = false;\n // disable streaming in BaseChatModel if explicitly disabled\n if (params?.streaming === false) this.disableStreaming = true;\n\n this.streamUsage = params?.streamUsage ?? this.streamUsage;\n if (this.disableStreaming) this.streamUsage = false;\n }\n\n _llmType(): string {\n return \"google\";\n }\n\n protected get platformType(): GooglePlatformType | undefined {\n return this._platform;\n }\n\n protected get platform(): GooglePlatformType {\n return getPlatformType(this._platform, this.apiClient.hasApiKey());\n }\n\n protected get isVertexExpress(): boolean {\n return this.platform === \"gcp\" && this.apiClient.hasApiKey();\n }\n\n protected get apiVersion(): string {\n if (typeof this._apiVersion !== \"undefined\") {\n return this._apiVersion;\n } else if (this.platform === \"gai\") {\n return \"v1beta\";\n } else {\n return \"v1\";\n }\n }\n\n protected get location(): string {\n return this._location || \"global\";\n }\n\n protected get endpoint(): string {\n if (typeof this._endpoint !== \"undefined\") {\n return this._endpoint;\n } else if (this.platform === \"gai\") {\n return \"generativelanguage.googleapis.com\";\n } else if (this.isVertexExpress) {\n return \"aiplatform.googleapis.com\";\n } else if (this.location === \"global\") {\n // See https://docs.cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#use_the_global_endpoint\n return \"aiplatform.googleapis.com\";\n } else {\n return `${this.location}-aiplatform.googleapis.com`;\n }\n }\n\n protected get publisher(): string {\n return \"google\";\n }\n\n protected get urlMethod(): string {\n return this.streaming ? \"streamGenerateContent?alt=sse\" : \"generateContent\";\n }\n\n /**\n * Returns the model profile for this instance's model, describing its\n * capabilities and constraints (e.g. max tokens, input/output modalities,\n * tool calling support).\n *\n * @example\n * ```typescript\n * const model = new ChatGoogle({ model: \"gemini-2.5-pro\" });\n * const profile = model.profile;\n * console.log(profile.maxInputTokens); // 1048576\n * console.log(profile.imageInputs); // true\n * ```\n */\n get profile(): ModelProfile {\n return PROFILES[this.model] ?? {};\n }\n\n protected async buildUrlGemini(urlMethod?: string): Promise<string> {\n return `https://${this.endpoint}/${this.apiVersion}/models/${this.model}:${\n urlMethod ?? this.urlMethod\n }`;\n }\n\n protected async buildUrlVertexExpress(urlMethod?: string): Promise<string> {\n return `https://${this.endpoint}/${this.apiVersion}/publishers/${\n this.publisher\n }/models/${this.model}:${urlMethod ?? this.urlMethod}`;\n }\n\n protected async buildUrlVertexLocation(urlMethod?: string): Promise<string> {\n const projectId = await this.apiClient.getProjectId();\n return `https://${this.endpoint}/${\n this.apiVersion\n }/projects/${projectId}/locations/${this.location}/publishers/${\n this.publisher\n }/models/${this.model}:${urlMethod ?? this.urlMethod}`;\n }\n\n protected async buildUrlVertex(urlMethod?: string): Promise<string> {\n if (this.isVertexExpress) {\n return this.buildUrlVertexExpress(urlMethod);\n } else {\n return this.buildUrlVertexLocation(urlMethod);\n }\n }\n\n protected async buildUrl(urlMethod?: string): Promise<string> {\n switch (this.platform) {\n case \"gai\":\n return this.buildUrlGemini(urlMethod);\n default:\n return this.buildUrlVertex(urlMethod);\n }\n }\n\n override invocationParams(options: this[\"ParsedCallOptions\"]) {\n const fields = combineGoogleChatModelFields(this.params, options);\n\n // Convert tools to Gemini format\n const tools = fields.tools\n ? convertToolsToGeminiTools(fields.tools)\n : undefined;\n\n // Convert tool choice to Gemini function calling config\n const toolConfig = convertToolChoiceToGeminiConfig(\n options.tool_choice,\n !!(tools && tools.length > 0)\n );\n\n let responseJsonSchema:\n | JsonSchema7Type\n | Record<string, unknown>\n | undefined;\n let responseMimeType: string | undefined;\n\n if (fields.responseSchema) {\n // Convert Zod schema to JSON Schema if needed\n if (isInteropZodSchema(fields.responseSchema)) {\n responseJsonSchema = toJsonSchema(fields.responseSchema);\n } else {\n responseJsonSchema = fields.responseSchema as Record<string, unknown>;\n }\n // Automatically set responseMimeType to \"application/json\" when schema is provided\n responseMimeType = \"application/json\";\n }\n\n return {\n ...(tools && tools.length > 0 ? { tools } : {}),\n ...(toolConfig ? { toolConfig } : {}),\n safetySettings: fields.safetySettings,\n generationConfig: {\n temperature: fields.temperature,\n topP: fields.topP,\n topK: fields.topK,\n maxOutputTokens: fields.maxOutputTokens,\n presencePenalty: fields.presencePenalty,\n frequencyPenalty: fields.frequencyPenalty,\n stopSequences: fields.stopSequences,\n ...(responseMimeType ? { responseMimeType } : {}),\n ...(responseJsonSchema ? { responseJsonSchema } : {}),\n ...(fields.responseModalities && fields.responseModalities.length > 0\n ? { responseModalities: fields.responseModalities }\n : {}),\n candidateCount: 1,\n seed: fields.seed,\n responseLogprobs: fields.responseLogprobs,\n logprobs: fields.logprobs,\n ...(fields.enableEnhancedCivicAnswers !== undefined\n ? { enableEnhancedCivicAnswers: fields.enableEnhancedCivicAnswers }\n : {}),\n thinkingConfig: convertFieldsToThinkingConfig(this.model, fields),\n speechConfig: convertFieldsToSpeechConfig(fields),\n ...(fields.imageConfig ? { imageConfig: fields.imageConfig } : {}),\n ...(fields.mediaResolution\n ? { mediaResolution: fields.mediaResolution }\n : {}),\n },\n };\n }\n\n async _generate(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n if (this.streaming) {\n const stream = await this._streamResponseChunks(\n messages,\n options,\n runManager\n );\n let finalChunk: ChatGenerationChunk | null = null;\n for await (const chunk of stream) {\n finalChunk = !finalChunk ? chunk : concat(finalChunk, chunk);\n }\n if (\n typeof finalChunk?.message?.content === \"string\" &&\n typeof (\n finalChunk?.message?.additional_kwargs\n ?.originalTextContentBlock as Record<string, unknown>\n )?.text === \"string\"\n ) {\n (\n finalChunk.message.additional_kwargs\n .originalTextContentBlock as Record<string, unknown>\n ).text = finalChunk.message.content;\n }\n return {\n generations: finalChunk ? [finalChunk] : [],\n };\n }\n\n const url = await this.buildUrl();\n const body = {\n ...this.invocationParams(options),\n systemInstruction: convertMessagesToGeminiSystemInstruction(messages),\n contents: convertMessagesToGeminiContents(messages),\n };\n\n const moduleName = this.constructor.name;\n await runManager?.handleCustomEvent(`google-request-${moduleName}`, {\n url,\n body,\n });\n\n const response = await this.apiClient.fetch(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n })\n );\n\n if (!response.ok) {\n const error = await RequestError.fromResponse(response);\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n error,\n });\n throw error;\n }\n\n const data: Gemini.GenerateContentResponse = await response.json();\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n data,\n url: response.url,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n\n // Check for prompt feedback errors\n if (data.promptFeedback?.blockReason) {\n throw PromptBlockedError.fromPromptFeedback(data.promptFeedback);\n }\n\n // Check if we have candidates\n if (!data.candidates || data.candidates.length === 0) {\n throw new NoCandidatesError();\n }\n\n // Use the first candidate\n const candidate = data.candidates[0];\n const message = convertGeminiCandidateToAIMessage(candidate);\n\n // Extract text content from the message\n const text = convertAIMessageToText(message);\n\n const usageMetadata =\n convertGeminiGenerateContentResponseToUsageMetadata(data);\n message.usage_metadata = usageMetadata;\n\n return {\n generations: [\n {\n text,\n message,\n generationInfo: {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n safetyRatings: candidate.safetyRatings,\n citationMetadata: candidate.citationMetadata,\n tokenCount: candidate.tokenCount,\n },\n },\n ],\n llmOutput: {\n tokenUsage: usageMetadata,\n model: data.modelVersion,\n responseId: data.responseId,\n usageMetadata,\n },\n };\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const streamUsage: boolean = this.streamUsage ?? true;\n\n const body = {\n ...this.invocationParams(options),\n systemInstruction: convertMessagesToGeminiSystemInstruction(messages),\n contents: convertMessagesToGeminiContents(messages),\n };\n\n const url = await this.buildUrl(\"streamGenerateContent?alt=sse\");\n const moduleName = this.constructor.name;\n await runManager?.handleCustomEvent(`google-request-${moduleName}`, {\n url,\n body,\n });\n\n const response = await this.apiClient.fetch(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: options.signal,\n })\n );\n\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n url: response.url,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n\n if (!response.ok) {\n const error = await RequestError.fromResponse(response);\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n error,\n });\n throw error;\n }\n\n if (response.body) {\n let previousUsage: UsageMetadata | undefined;\n const stream = response.body\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new EventSourceParserStream())\n .pipeThrough(\n new SafeJsonEventParserStream<Gemini.GenerateContentResponse>()\n )\n .pipeThrough(\n new TransformStream<\n Gemini.GenerateContentResponse,\n ChatGenerationChunk\n >({\n transform(chunk, controller) {\n // eslint-disable-next-line no-void\n void runManager?.handleCustomEvent(`google-chunk-${moduleName}`, {\n chunk,\n });\n if (chunk === null) {\n controller.enqueue(\n new ChatGenerationChunk({\n text: \"\",\n message: new AIMessageChunk({ content: \"\" }),\n generationInfo: { finishReason: \"stop\" },\n })\n );\n return;\n }\n\n // Extract text delta from the chunk\n const candidate = chunk.candidates?.[0];\n if (!candidate) {\n return;\n }\n\n const message = convertGeminiCandidateToAIMessage(candidate);\n const text = convertAIMessageToText(message);\n\n const parts = candidate.content?.parts ?? [];\n const toolCalls = convertGeminiPartsToToolCalls(parts);\n\n // Only emit if we have content\n if (parts.length > 0 || candidate.finishReason) {\n const messageChunkParams: AIMessageChunkFields = {\n content: message.content,\n tool_calls: toolCalls,\n response_metadata: {\n model_provider: \"google\",\n },\n additional_kwargs: {\n ...(message.additional_kwargs.originalTextContentBlock\n ? {\n originalTextContentBlock:\n message.additional_kwargs.originalTextContentBlock,\n }\n : {}),\n ...(candidate.finishReason\n ? {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n }\n : {}),\n },\n };\n\n if (chunk?.usageMetadata && streamUsage) {\n const cumulative =\n convertGeminiGenerateContentResponseToUsageMetadata(chunk);\n messageChunkParams.usage_metadata = subtractUsageMetadata(\n cumulative,\n previousUsage\n );\n previousUsage = cumulative;\n }\n const messageChunk = new AIMessageChunk(messageChunkParams);\n\n controller.enqueue(\n new ChatGenerationChunk({\n text: text,\n message: messageChunk,\n generationInfo: {\n ...(candidate.finishReason && {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n }),\n ...(candidate.safetyRatings && {\n safetyRatings: candidate.safetyRatings,\n }),\n },\n })\n );\n }\n },\n })\n );\n\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n yield value;\n await runManager?.handleLLMNewToken(\n value.text ?? \"\",\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: value }\n );\n }\n } finally {\n reader.releaseLock();\n }\n }\n }\n\n /**\n * Bind tool-like objects to this chat model.\n *\n * @param tools A list of tool definitions to bind to this chat model.\n * Can be a structured tool, an OpenAI formatted tool, or a Gemini function declaration.\n * @param kwargs Any additional parameters to bind.\n */\n bindTools(\n tools: BindToolsInput[],\n kwargs?: Partial<CallOptions>\n ): Runnable<BaseMessage[], AIMessageChunk, CallOptions> {\n return this.withConfig({\n ...kwargs,\n tools,\n } as Partial<CallOptions>);\n }\n\n /**\n * Get structured output from the model based on a schema.\n *\n * This method supports two modes:\n * - `jsonMode`: Uses `responseSchema` to get JSON responses directly (preferred for structured outputs)\n * - `functionCalling`: Uses function calling with tools (default, for compatibility)\n *\n * @param outputSchema - The schema to use for structured output (Zod schema or JSON Schema)\n * @param config - Configuration options including method and whether to include raw response\n * @returns A Runnable that returns the parsed structured output\n */\n withStructuredOutput<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RunOutput extends Record<string, any> = Record<string, any>\n >(\n outputSchema:\n | InteropZodType<RunOutput>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | Record<string, any>,\n config?: StructuredOutputMethodOptions<boolean>\n ):\n | Runnable<BaseLanguageModelInput, RunOutput>\n | Runnable<\n BaseLanguageModelInput,\n { raw: BaseMessage; parsed: RunOutput }\n > {\n let llm: Runnable<BaseMessage[], AIMessageChunk, CallOptions>;\n let outputParser: Runnable<BaseMessage, RunOutput>;\n\n const { schema, name, includeRaw } = {\n ...config,\n schema: outputSchema,\n };\n let method = config?.method ?? \"functionCalling\";\n\n if (method === \"jsonMode\") {\n console.warn(\n `\"jsonMode\" is not supported for Google models. Falling back to \"jsonSchema\".`\n );\n method = \"jsonSchema\";\n }\n\n if (method === \"jsonSchema\") {\n // Use JSON mode with responseSchema\n llm = this.withConfig({\n responseSchema: schema,\n } as Partial<CallOptions>);\n\n outputParser = RunnableLambda.from<BaseMessage, RunOutput>(\n async (input: BaseMessage): Promise<RunOutput> => {\n if (\n !AIMessage.isInstance(input) &&\n !AIMessageChunk.isInstance(input)\n ) {\n throw new MalformedOutputError({\n message: \"Input is not an AIMessage or AIMessageChunk.\",\n });\n }\n\n if (!input.text) {\n throw new MalformedOutputError({\n message:\n \"No content found in response. Cannot parse structured output.\",\n });\n }\n\n // Parse JSON and validate with schema\n if (isInteropZodSchema(schema)) {\n const zodParser = StructuredOutputParser.fromZodSchema(\n schema as InteropZodType<RunOutput>\n );\n return (await zodParser.parse(input.text)) as RunOutput;\n } else {\n const jsonParser = new JsonOutputParser<RunOutput>();\n return await jsonParser.parse(input.text);\n }\n }\n );\n } else if (method === \"functionCalling\") {\n // Use function calling mode\n let functionName = name ?? \"extract\";\n let tools: Gemini.Tool[];\n\n if (isInteropZodSchema(schema)) {\n const jsonSchema = schemaToGeminiParameters(schema);\n const description =\n typeof jsonSchema.description === \"string\"\n ? jsonSchema.description\n : \"A function available to call.\";\n tools = [\n {\n functionDeclarations: [\n {\n name: functionName,\n description,\n parameters: jsonSchema as Gemini.Tools.Schema,\n },\n ],\n },\n ];\n outputParser = new JsonOutputKeyToolsParser({\n returnSingle: true,\n keyName: functionName,\n zodSchema: schema,\n });\n } else {\n let geminiFunctionDefinition: Gemini.Tools.FunctionDeclaration;\n if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n geminiFunctionDefinition = schema as Gemini.Tools.FunctionDeclaration;\n functionName = schema.name;\n } else {\n // We are providing the schema for *just* the parameters\n const parameters = schemaToGeminiParameters(schema);\n geminiFunctionDefinition = {\n name: functionName,\n description: (schema as { description?: string }).description ?? \"\",\n parameters,\n };\n }\n tools = [\n {\n functionDeclarations: [geminiFunctionDefinition],\n },\n ];\n outputParser = new JsonOutputKeyToolsParser<RunOutput>({\n returnSingle: true,\n keyName: functionName,\n });\n }\n\n llm = this.bindTools(tools).withConfig({\n tool_choice: functionName,\n } as Partial<CallOptions>);\n } else {\n throw new ConfigurationError(\n `Unrecognized structured output method '${method}'. Expected 'functionCalling' or 'jsonSchema'`\n );\n }\n\n // Shared logic for handling includeRaw\n if (!includeRaw) {\n return llm.pipe(outputParser).withConfig({\n runName: \"ChatGoogleStructuredOutput\",\n }) as Runnable<BaseLanguageModelInput, RunOutput>;\n }\n\n const parserAssign = RunnablePassthrough.assign({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n parsed: (input: any, config) => outputParser.invoke(input.raw, config),\n });\n const parserNone = RunnablePassthrough.assign({\n parsed: () => null,\n });\n const parsedWithFallback = parserAssign.withFallbacks({\n fallbacks: [parserNone],\n });\n return RunnableSequence.from<\n BaseLanguageModelInput,\n { raw: BaseMessage; parsed: RunOutput }\n >([\n {\n raw: llm,\n },\n parsedWithFallback,\n ]).withConfig({\n runName: \"ChatGoogleStructuredOutputRunnable\",\n });\n }\n}\n\ntype CombinableFields = Omit<BaseChatGoogleParams, \"model\">;\n\nexport function combineGoogleChatModelFields(\n a: CombinableFields,\n b: CombinableFields,\n ...rest: CombinableFields[]\n): CombinableFields {\n const combined: CombinableFields = {\n temperature: b.temperature ?? a.temperature,\n topP: b.topP ?? a.topP,\n topK: b.topK ?? a.topK,\n maxOutputTokens: b.maxOutputTokens ?? a.maxOutputTokens,\n presencePenalty: b.presencePenalty ?? a.presencePenalty,\n frequencyPenalty: b.frequencyPenalty ?? a.frequencyPenalty,\n stopSequences: b.stopSequences ?? a.stopSequences,\n seed: b.seed ?? a.seed,\n responseLogprobs: b.responseLogprobs ?? a.responseLogprobs,\n logprobs: b.logprobs ?? a.logprobs,\n safetySettings: b.safetySettings ?? a.safetySettings,\n responseSchema: b.responseSchema ?? a.responseSchema,\n tools: b.tools ?? a.tools,\n responseModalities: b.responseModalities ?? a.responseModalities,\n enableEnhancedCivicAnswers:\n b.enableEnhancedCivicAnswers ?? a.enableEnhancedCivicAnswers,\n speechConfig: b.speechConfig ?? a.speechConfig,\n imageConfig: b.imageConfig ?? a.imageConfig,\n mediaResolution: b.mediaResolution ?? a.mediaResolution,\n maxReasoningTokens: b.maxReasoningTokens ?? a.maxReasoningTokens,\n thinkingBudget: b.thinkingBudget ?? a.thinkingBudget,\n reasoningEffort: b.reasoningEffort ?? a.reasoningEffort,\n thinkingLevel: b.thinkingLevel ?? a.thinkingLevel,\n };\n if (rest.length > 0) {\n return combineGoogleChatModelFields(combined, rest[0], ...rest.slice(1));\n }\n return combined;\n}\n\nexport function getGoogleChatModelParams<TParams extends BaseChatGoogleParams>(\n modelOrParams: string | TParams,\n paramsArg?: Omit<TParams, \"model\">\n): TParams {\n const model =\n typeof modelOrParams === \"string\" ? modelOrParams : modelOrParams.model;\n const params = typeof modelOrParams === \"string\" ? paramsArg : modelOrParams;\n return { model, ...params } as TParams;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.cjs","names":["BaseChatModel","ConfigurationError","convertParamsToPlatformType","PROFILES","convertToolsToGeminiTools","convertToolChoiceToGeminiConfig","convertFieldsToThinkingConfig","convertFieldsToSpeechConfig","convertMessagesToGeminiSystemInstruction","convertMessagesToGeminiContents","RequestError","PromptBlockedError","NoCandidatesError","convertGeminiCandidateToAIMessage","convertAIMessageToText","convertGeminiGenerateContentResponseToUsageMetadata","EventSourceParserStream","SafeJsonEventParserStream","ChatGenerationChunk","AIMessageChunk","convertGeminiPartsToToolCalls","subtractUsageMetadata","RunnableLambda","AIMessage","MalformedOutputError","schemaToGeminiParameters"],"sources":["../../src/chat_models/base.ts"],"sourcesContent":["import {\n BaseChatModel,\n type BaseChatModelCallOptions,\n type BaseChatModelParams,\n} from \"@langchain/core/language_models/chat_models\";\nimport {\n AIMessage,\n AIMessageChunk,\n AIMessageChunkFields,\n BaseMessage,\n type UsageMetadata,\n} from \"@langchain/core/messages\";\nimport { CallbackManagerForLLMRun } from \"@langchain/core/callbacks/manager\";\nimport { concat } from \"@langchain/core/utils/stream\";\nimport { ChatGenerationChunk, ChatResult } from \"@langchain/core/outputs\";\nimport { EventSourceParserStream } from \"eventsource-parser/stream\";\nimport type { BindToolsInput } from \"@langchain/core/language_models/chat_models\";\nimport type { ModelProfile } from \"@langchain/core/language_models/profile\";\nimport PROFILES from \"./profiles.js\";\nimport type {\n BaseLanguageModelInput,\n StructuredOutputMethodOptions,\n} from \"@langchain/core/language_models/base\";\nimport { Runnable, RunnableLambda } from \"@langchain/core/runnables\";\nimport {\n toJsonSchema,\n type JsonSchema7Type,\n} from \"@langchain/core/utils/json_schema\";\nimport {\n InteropZodType,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\n\nimport { ApiClient } from \"../clients/index.js\";\nimport type { ChatGoogleFields } from \"./types.js\";\nimport { SafeJsonEventParserStream } from \"../utils/stream.js\";\nimport {\n convertAIMessageToText,\n convertGeminiCandidateToAIMessage,\n convertGeminiGenerateContentResponseToUsageMetadata,\n convertGeminiPartsToToolCalls,\n convertMessagesToGeminiContents,\n convertMessagesToGeminiSystemInstruction,\n} from \"../converters/messages.js\";\nimport {\n ConfigurationError,\n MalformedOutputError,\n NoCandidatesError,\n PromptBlockedError,\n RequestError,\n} from \"../utils/errors.js\";\nimport {\n convertToolsToGeminiTools,\n convertToolChoiceToGeminiConfig,\n schemaToGeminiParameters,\n} from \"../converters/tools.js\";\nimport {\n convertParamsToPlatformType,\n convertFieldsToSpeechConfig,\n convertFieldsToThinkingConfig,\n} from \"../converters/params.js\";\nimport { Gemini } from \"./api-types.js\";\nimport { subtractUsageMetadata } from \"../utils/metadata.js\";\nimport {\n isSerializableSchema,\n SerializableSchema,\n} from \"@langchain/core/utils/standard_schema\";\nimport {\n assembleStructuredOutputPipeline,\n createContentParser,\n createFunctionCallingParser,\n} from \"@langchain/core/language_models/structured_output\";\n\nexport type GooglePlatformType = \"gai\" | \"gcp\";\n\nexport function getPlatformType(\n platform: GooglePlatformType | undefined,\n hasApiKey: boolean\n): GooglePlatformType {\n if (typeof platform !== \"undefined\") {\n return platform;\n } else if (hasApiKey) {\n return \"gai\";\n } else {\n return \"gcp\";\n }\n}\n\nexport interface BaseChatGoogleParams\n extends BaseChatModelParams,\n ChatGoogleFields {\n /**\n * The name of the Gemini model to use.\n *\n * Example: \"gemini-3-pro-preview\"\n */\n model: string;\n\n /**\n * Optional. The API client implementation for making HTTP requests to the Gemini API.\n * If not set, a default client will be used based on the runtime environment.\n */\n apiClient?: ApiClient;\n\n /**\n * Hostname for the API call (if this is running on GCP)\n * Usually this is computed based on location and platformType.\n **/\n endpoint?: string;\n\n /**\n * Region where the LLM is stored (if this is running on GCP)\n * Defaults to \"global\"\n **/\n location?: string;\n\n /**\n * The version of the API functions. Part of the path.\n * Usually this is computed based on platformType.\n **/\n apiVersion?: string;\n\n /**\n * What platform to run the service on.\n * If not specified, the class should determine this from other\n * means. Either way, the platform actually used will be in\n * the \"platform\" getter.\n */\n platformType?: GooglePlatformType;\n\n /**\n * For compatibility with Google's libraries, should this use Vertex?\n * The \"platformType\" parmeter takes precedence.\n */\n vertexai?: boolean;\n\n /**\n * Backwards compatibility.\n * @deprecated in favor of using `disableStreaming` or `.stream()`\n */\n streaming?: boolean;\n\n streamUsage?: boolean;\n}\n\nexport interface BaseChatGoogleCallOptions\n extends BaseChatModelCallOptions,\n ChatGoogleFields {}\n\nexport abstract class BaseChatGoogle<\n CallOptions extends BaseChatGoogleCallOptions = BaseChatGoogleCallOptions\n> extends BaseChatModel<CallOptions, AIMessageChunk> {\n model: string;\n\n streaming: boolean;\n\n disableStreaming: boolean;\n\n streamUsage: boolean = true;\n\n protected _platform?: GooglePlatformType;\n\n protected _endpoint?: string;\n\n protected _location?: string;\n\n protected _apiVersion?: string;\n\n protected apiClient: ApiClient;\n\n constructor(protected params: BaseChatGoogleParams) {\n super(params);\n this._addVersion(\"@langchain/google\", __PKG_VERSION__);\n\n if (!params.apiClient) {\n throw new ConfigurationError(\n \"BaseChatGoogle requires an apiClient. This should be provided automatically by ChatGoogle constructors. If you're extending BaseChatGoogle directly, please provide an apiClient instance.\"\n );\n }\n this.apiClient = params.apiClient;\n\n this.model = params.model;\n this._platform = convertParamsToPlatformType(params);\n this._endpoint = params.endpoint;\n this._location = params.location;\n this._apiVersion = params.apiVersion;\n\n this.disableStreaming = params?.disableStreaming === true;\n this.streaming = params?.streaming === true;\n if (this.disableStreaming) this.streaming = false;\n // disable streaming in BaseChatModel if explicitly disabled\n if (params?.streaming === false) this.disableStreaming = true;\n\n this.streamUsage = params?.streamUsage ?? this.streamUsage;\n if (this.disableStreaming) this.streamUsage = false;\n }\n\n _llmType(): string {\n return \"google\";\n }\n\n protected get platformType(): GooglePlatformType | undefined {\n return this._platform;\n }\n\n protected get platform(): GooglePlatformType {\n return getPlatformType(this._platform, this.apiClient.hasApiKey());\n }\n\n protected get isVertexExpress(): boolean {\n return this.platform === \"gcp\" && this.apiClient.hasApiKey();\n }\n\n protected get apiVersion(): string {\n if (typeof this._apiVersion !== \"undefined\") {\n return this._apiVersion;\n } else if (this.platform === \"gai\") {\n return \"v1beta\";\n } else {\n return \"v1\";\n }\n }\n\n protected get location(): string {\n return this._location || \"global\";\n }\n\n protected get endpoint(): string {\n if (typeof this._endpoint !== \"undefined\") {\n return this._endpoint;\n } else if (this.platform === \"gai\") {\n return \"generativelanguage.googleapis.com\";\n } else if (this.isVertexExpress) {\n return \"aiplatform.googleapis.com\";\n } else if (this.location === \"global\") {\n // See https://docs.cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#use_the_global_endpoint\n return \"aiplatform.googleapis.com\";\n } else {\n return `${this.location}-aiplatform.googleapis.com`;\n }\n }\n\n protected get publisher(): string {\n return \"google\";\n }\n\n protected get urlMethod(): string {\n return this.streaming ? \"streamGenerateContent?alt=sse\" : \"generateContent\";\n }\n\n /**\n * Returns the model profile for this instance's model, describing its\n * capabilities and constraints (e.g. max tokens, input/output modalities,\n * tool calling support).\n *\n * @example\n * ```typescript\n * const model = new ChatGoogle({ model: \"gemini-2.5-pro\" });\n * const profile = model.profile;\n * console.log(profile.maxInputTokens); // 1048576\n * console.log(profile.imageInputs); // true\n * ```\n */\n get profile(): ModelProfile {\n return PROFILES[this.model] ?? {};\n }\n\n protected async buildUrlGemini(urlMethod?: string): Promise<string> {\n return `https://${this.endpoint}/${this.apiVersion}/models/${this.model}:${\n urlMethod ?? this.urlMethod\n }`;\n }\n\n protected async buildUrlVertexExpress(urlMethod?: string): Promise<string> {\n return `https://${this.endpoint}/${this.apiVersion}/publishers/${\n this.publisher\n }/models/${this.model}:${urlMethod ?? this.urlMethod}`;\n }\n\n protected async buildUrlVertexLocation(urlMethod?: string): Promise<string> {\n const projectId = await this.apiClient.getProjectId();\n return `https://${this.endpoint}/${\n this.apiVersion\n }/projects/${projectId}/locations/${this.location}/publishers/${\n this.publisher\n }/models/${this.model}:${urlMethod ?? this.urlMethod}`;\n }\n\n protected async buildUrlVertex(urlMethod?: string): Promise<string> {\n if (this.isVertexExpress) {\n return this.buildUrlVertexExpress(urlMethod);\n } else {\n return this.buildUrlVertexLocation(urlMethod);\n }\n }\n\n protected async buildUrl(urlMethod?: string): Promise<string> {\n switch (this.platform) {\n case \"gai\":\n return this.buildUrlGemini(urlMethod);\n default:\n return this.buildUrlVertex(urlMethod);\n }\n }\n\n override invocationParams(options: this[\"ParsedCallOptions\"]) {\n const fields = combineGoogleChatModelFields(this.params, options);\n\n // Convert tools to Gemini format\n const tools = fields.tools\n ? convertToolsToGeminiTools(fields.tools)\n : undefined;\n\n // Convert tool choice to Gemini function calling config\n const toolConfig = convertToolChoiceToGeminiConfig(\n options.tool_choice,\n !!(tools && tools.length > 0)\n );\n\n let responseJsonSchema:\n | JsonSchema7Type\n | Record<string, unknown>\n | undefined;\n let responseMimeType: string | undefined;\n\n if (fields.responseSchema) {\n // Convert Zod schema to JSON Schema if needed\n if (\n isInteropZodSchema(fields.responseSchema) ||\n isSerializableSchema(fields.responseSchema)\n ) {\n responseJsonSchema = toJsonSchema(fields.responseSchema);\n } else {\n responseJsonSchema = fields.responseSchema as Record<string, unknown>;\n }\n // Automatically set responseMimeType to \"application/json\" when schema is provided\n responseMimeType = \"application/json\";\n }\n\n return {\n ...(tools && tools.length > 0 ? { tools } : {}),\n ...(toolConfig ? { toolConfig } : {}),\n safetySettings: fields.safetySettings,\n generationConfig: {\n temperature: fields.temperature,\n topP: fields.topP,\n topK: fields.topK,\n maxOutputTokens: fields.maxOutputTokens,\n presencePenalty: fields.presencePenalty,\n frequencyPenalty: fields.frequencyPenalty,\n stopSequences: fields.stopSequences,\n ...(responseMimeType ? { responseMimeType } : {}),\n ...(responseJsonSchema ? { responseJsonSchema } : {}),\n ...(fields.responseModalities && fields.responseModalities.length > 0\n ? { responseModalities: fields.responseModalities }\n : {}),\n candidateCount: 1,\n seed: fields.seed,\n responseLogprobs: fields.responseLogprobs,\n logprobs: fields.logprobs,\n ...(fields.enableEnhancedCivicAnswers !== undefined\n ? { enableEnhancedCivicAnswers: fields.enableEnhancedCivicAnswers }\n : {}),\n thinkingConfig: convertFieldsToThinkingConfig(this.model, fields),\n speechConfig: convertFieldsToSpeechConfig(fields),\n ...(fields.imageConfig ? { imageConfig: fields.imageConfig } : {}),\n ...(fields.mediaResolution\n ? { mediaResolution: fields.mediaResolution }\n : {}),\n },\n };\n }\n\n async _generate(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n if (this.streaming) {\n const stream = await this._streamResponseChunks(\n messages,\n options,\n runManager\n );\n let finalChunk: ChatGenerationChunk | null = null;\n for await (const chunk of stream) {\n finalChunk = !finalChunk ? chunk : concat(finalChunk, chunk);\n }\n if (\n typeof finalChunk?.message?.content === \"string\" &&\n typeof (\n finalChunk?.message?.additional_kwargs\n ?.originalTextContentBlock as Record<string, unknown>\n )?.text === \"string\"\n ) {\n (\n finalChunk.message.additional_kwargs\n .originalTextContentBlock as Record<string, unknown>\n ).text = finalChunk.message.content;\n }\n return {\n generations: finalChunk ? [finalChunk] : [],\n };\n }\n\n const url = await this.buildUrl();\n const body = {\n ...this.invocationParams(options),\n systemInstruction: convertMessagesToGeminiSystemInstruction(messages),\n contents: convertMessagesToGeminiContents(messages),\n };\n\n const moduleName = this.constructor.name;\n await runManager?.handleCustomEvent(`google-request-${moduleName}`, {\n url,\n body,\n });\n\n const response = await this.apiClient.fetch(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n })\n );\n\n if (!response.ok) {\n const error = await RequestError.fromResponse(response);\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n error,\n });\n throw error;\n }\n\n const data: Gemini.GenerateContentResponse = await response.json();\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n data,\n url: response.url,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n\n // Check for prompt feedback errors\n if (data.promptFeedback?.blockReason) {\n throw PromptBlockedError.fromPromptFeedback(data.promptFeedback);\n }\n\n // Check if we have candidates\n if (!data.candidates || data.candidates.length === 0) {\n throw new NoCandidatesError();\n }\n\n // Use the first candidate\n const candidate = data.candidates[0];\n const message = convertGeminiCandidateToAIMessage(candidate);\n\n // Extract text content from the message\n const text = convertAIMessageToText(message);\n\n const usageMetadata =\n convertGeminiGenerateContentResponseToUsageMetadata(data);\n message.usage_metadata = usageMetadata;\n\n return {\n generations: [\n {\n text,\n message,\n generationInfo: {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n safetyRatings: candidate.safetyRatings,\n citationMetadata: candidate.citationMetadata,\n tokenCount: candidate.tokenCount,\n },\n },\n ],\n llmOutput: {\n tokenUsage: usageMetadata,\n model: data.modelVersion,\n responseId: data.responseId,\n usageMetadata,\n },\n };\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const streamUsage: boolean = this.streamUsage ?? true;\n\n const body = {\n ...this.invocationParams(options),\n systemInstruction: convertMessagesToGeminiSystemInstruction(messages),\n contents: convertMessagesToGeminiContents(messages),\n };\n\n const url = await this.buildUrl(\"streamGenerateContent?alt=sse\");\n const moduleName = this.constructor.name;\n await runManager?.handleCustomEvent(`google-request-${moduleName}`, {\n url,\n body,\n });\n\n const response = await this.apiClient.fetch(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: options.signal,\n })\n );\n\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n url: response.url,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n\n if (!response.ok) {\n const error = await RequestError.fromResponse(response);\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n error,\n });\n throw error;\n }\n\n if (response.body) {\n let previousUsage: UsageMetadata | undefined;\n const stream = response.body\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new EventSourceParserStream())\n .pipeThrough(\n new SafeJsonEventParserStream<Gemini.GenerateContentResponse>()\n )\n .pipeThrough(\n new TransformStream<\n Gemini.GenerateContentResponse,\n ChatGenerationChunk\n >({\n transform(chunk, controller) {\n // eslint-disable-next-line no-void\n void runManager?.handleCustomEvent(`google-chunk-${moduleName}`, {\n chunk,\n });\n if (chunk === null) {\n controller.enqueue(\n new ChatGenerationChunk({\n text: \"\",\n message: new AIMessageChunk({ content: \"\" }),\n generationInfo: { finishReason: \"stop\" },\n })\n );\n return;\n }\n\n // Extract text delta from the chunk\n const candidate = chunk.candidates?.[0];\n if (!candidate) {\n return;\n }\n\n const message = convertGeminiCandidateToAIMessage(candidate);\n const text = convertAIMessageToText(message);\n\n const parts = candidate.content?.parts ?? [];\n const toolCalls = convertGeminiPartsToToolCalls(parts);\n\n // Only emit if we have content\n if (parts.length > 0 || candidate.finishReason) {\n const messageChunkParams: AIMessageChunkFields = {\n content: message.content,\n tool_calls: toolCalls,\n response_metadata: {\n model_provider: \"google\",\n },\n additional_kwargs: {\n ...(message.additional_kwargs.originalTextContentBlock\n ? {\n originalTextContentBlock:\n message.additional_kwargs.originalTextContentBlock,\n }\n : {}),\n ...(candidate.finishReason\n ? {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n }\n : {}),\n },\n };\n\n if (chunk?.usageMetadata && streamUsage) {\n const cumulative =\n convertGeminiGenerateContentResponseToUsageMetadata(chunk);\n messageChunkParams.usage_metadata = subtractUsageMetadata(\n cumulative,\n previousUsage\n );\n previousUsage = cumulative;\n }\n const messageChunk = new AIMessageChunk(messageChunkParams);\n\n controller.enqueue(\n new ChatGenerationChunk({\n text: text,\n message: messageChunk,\n generationInfo: {\n ...(candidate.finishReason && {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n }),\n ...(candidate.safetyRatings && {\n safetyRatings: candidate.safetyRatings,\n }),\n },\n })\n );\n }\n },\n })\n );\n\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n yield value;\n await runManager?.handleLLMNewToken(\n value.text ?? \"\",\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: value }\n );\n }\n } finally {\n reader.releaseLock();\n }\n }\n }\n\n /**\n * Bind tool-like objects to this chat model.\n *\n * @param tools A list of tool definitions to bind to this chat model.\n * Can be a structured tool, an OpenAI formatted tool, or a Gemini function declaration.\n * @param kwargs Any additional parameters to bind.\n */\n bindTools(\n tools: BindToolsInput[],\n kwargs?: Partial<CallOptions>\n ): Runnable<BaseMessage[], AIMessageChunk, CallOptions> {\n return this.withConfig({\n ...kwargs,\n tools,\n } as Partial<CallOptions>);\n }\n\n /**\n * Get structured output from the model based on a schema.\n *\n * This method supports two modes:\n * - `jsonMode`: Uses `responseSchema` to get JSON responses directly (preferred for structured outputs)\n * - `functionCalling`: Uses function calling with tools (default, for compatibility)\n *\n * @param outputSchema - The schema to use for structured output (Zod schema or JSON Schema)\n * @param config - Configuration options including method and whether to include raw response\n * @returns A Runnable that returns the parsed structured output\n */\n withStructuredOutput<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RunOutput extends Record<string, any> = Record<string, any>\n >(\n outputSchema:\n | InteropZodType<RunOutput>\n | SerializableSchema<RunOutput>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | Record<string, any>,\n config?: StructuredOutputMethodOptions<boolean>\n ):\n | Runnable<BaseLanguageModelInput, RunOutput>\n | Runnable<\n BaseLanguageModelInput,\n { raw: BaseMessage; parsed: RunOutput }\n > {\n let llm: Runnable<BaseMessage[], AIMessageChunk, CallOptions>;\n let outputParser: Runnable<BaseMessage, RunOutput>;\n\n const { schema, name, includeRaw } = {\n ...config,\n schema: outputSchema,\n };\n let method = config?.method ?? \"functionCalling\";\n\n if (method === \"jsonMode\") {\n console.warn(\n `\"jsonMode\" is not supported for Google models. Falling back to \"jsonSchema\".`\n );\n method = \"jsonSchema\";\n }\n\n if (method === \"jsonSchema\") {\n // Use JSON mode with responseSchema\n llm = this.withConfig({\n responseSchema: schema,\n } as Partial<CallOptions>);\n\n outputParser = RunnableLambda.from<BaseMessage, RunOutput>(\n async (input: BaseMessage): Promise<RunOutput> => {\n if (\n !AIMessage.isInstance(input) &&\n !AIMessageChunk.isInstance(input)\n ) {\n throw new MalformedOutputError({\n message: \"Input is not an AIMessage or AIMessageChunk.\",\n });\n }\n\n if (!input.text) {\n throw new MalformedOutputError({\n message:\n \"No content found in response. Cannot parse structured output.\",\n });\n }\n\n // Parse JSON and validate with schema\n const parser = createContentParser(schema);\n return await parser.parse(input.text);\n }\n );\n } else if (method === \"functionCalling\") {\n // Use function calling mode\n let functionName = name ?? \"extract\";\n let geminiFunctionDeclaration: Gemini.Tools.FunctionDeclaration;\n\n if (isInteropZodSchema(schema) || isSerializableSchema(schema)) {\n const jsonSchema = schemaToGeminiParameters(schema);\n const description =\n typeof jsonSchema.description === \"string\"\n ? jsonSchema.description\n : \"A function available to call.\";\n geminiFunctionDeclaration = {\n name: functionName,\n description,\n parameters: jsonSchema as Gemini.Tools.Schema,\n };\n } else if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n geminiFunctionDeclaration = schema as Gemini.Tools.FunctionDeclaration;\n functionName = schema.name;\n } else {\n // We are providing the schema for *just* the parameters\n const parameters = schemaToGeminiParameters(schema);\n geminiFunctionDeclaration = {\n name: functionName,\n description: (schema as { description?: string }).description ?? \"\",\n parameters,\n };\n }\n\n const tools: Gemini.Tool[] = [\n {\n functionDeclarations: [geminiFunctionDeclaration],\n },\n ];\n llm = this.bindTools(tools).withConfig({\n tool_choice: functionName,\n } as Partial<CallOptions>);\n\n outputParser = createFunctionCallingParser(schema, functionName);\n } else {\n throw new ConfigurationError(\n `Unrecognized structured output method '${method}'. Expected 'functionCalling' or 'jsonSchema'`\n );\n }\n\n return assembleStructuredOutputPipeline(\n llm,\n outputParser,\n includeRaw,\n includeRaw\n ? \"ChatGoogleStructuredOutputRunnable\"\n : \"ChatGoogleStructuredOutput\"\n );\n }\n}\n\ntype CombinableFields = Omit<BaseChatGoogleParams, \"model\">;\n\nexport function combineGoogleChatModelFields(\n a: CombinableFields,\n b: CombinableFields,\n ...rest: CombinableFields[]\n): CombinableFields {\n const combined: CombinableFields = {\n temperature: b.temperature ?? a.temperature,\n topP: b.topP ?? a.topP,\n topK: b.topK ?? a.topK,\n maxOutputTokens: b.maxOutputTokens ?? a.maxOutputTokens,\n presencePenalty: b.presencePenalty ?? a.presencePenalty,\n frequencyPenalty: b.frequencyPenalty ?? a.frequencyPenalty,\n stopSequences: b.stopSequences ?? a.stopSequences,\n seed: b.seed ?? a.seed,\n responseLogprobs: b.responseLogprobs ?? a.responseLogprobs,\n logprobs: b.logprobs ?? a.logprobs,\n safetySettings: b.safetySettings ?? a.safetySettings,\n responseSchema: b.responseSchema ?? a.responseSchema,\n tools: b.tools ?? a.tools,\n responseModalities: b.responseModalities ?? a.responseModalities,\n enableEnhancedCivicAnswers:\n b.enableEnhancedCivicAnswers ?? a.enableEnhancedCivicAnswers,\n speechConfig: b.speechConfig ?? a.speechConfig,\n imageConfig: b.imageConfig ?? a.imageConfig,\n mediaResolution: b.mediaResolution ?? a.mediaResolution,\n maxReasoningTokens: b.maxReasoningTokens ?? a.maxReasoningTokens,\n thinkingBudget: b.thinkingBudget ?? a.thinkingBudget,\n reasoningEffort: b.reasoningEffort ?? a.reasoningEffort,\n thinkingLevel: b.thinkingLevel ?? a.thinkingLevel,\n };\n if (rest.length > 0) {\n return combineGoogleChatModelFields(combined, rest[0], ...rest.slice(1));\n }\n return combined;\n}\n\nexport function getGoogleChatModelParams<TParams extends BaseChatGoogleParams>(\n modelOrParams: string | TParams,\n paramsArg?: Omit<TParams, \"model\">\n): TParams {\n const model =\n typeof modelOrParams === \"string\" ? modelOrParams : modelOrParams.model;\n const params = typeof modelOrParams === \"string\" ? paramsArg : modelOrParams;\n return { model, ...params } as TParams;\n}\n"],"mappings":"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"}
@@ -11,6 +11,7 @@ import { BaseLanguageModelInput, StructuredOutputMethodOptions } from "@langchai
11
11
  import { Runnable } from "@langchain/core/runnables";
12
12
  import { JsonSchema7Type } from "@langchain/core/utils/json_schema";
13
13
  import { InteropZodType } from "@langchain/core/utils/types";
14
+ import { SerializableSchema } from "@langchain/core/utils/standard_schema";
14
15
 
15
16
  //#region src/chat_models/base.d.ts
16
17
  type GooglePlatformType = "gai" | "gcp";
@@ -309,7 +310,7 @@ declare abstract class BaseChatGoogle<CallOptions extends BaseChatGoogleCallOpti
309
310
  * @param config - Configuration options including method and whether to include raw response
310
311
  * @returns A Runnable that returns the parsed structured output
311
312
  */
312
- withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: InteropZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<boolean>): Runnable<BaseLanguageModelInput, RunOutput> | Runnable<BaseLanguageModelInput, {
313
+ withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: InteropZodType<RunOutput> | SerializableSchema<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<boolean>): Runnable<BaseLanguageModelInput, RunOutput> | Runnable<BaseLanguageModelInput, {
313
314
  raw: BaseMessage;
314
315
  parsed: RunOutput;
315
316
  }>;
@@ -9,6 +9,7 @@ import { Runnable } from "@langchain/core/runnables";
9
9
  import { JsonSchema7Type } from "@langchain/core/utils/json_schema";
10
10
  import { InteropZodType } from "@langchain/core/utils/types";
11
11
  import { BaseLanguageModelInput, StructuredOutputMethodOptions } from "@langchain/core/language_models/base";
12
+ import { SerializableSchema } from "@langchain/core/utils/standard_schema";
12
13
  import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
13
14
  import { ModelProfile } from "@langchain/core/language_models/profile";
14
15
 
@@ -309,7 +310,7 @@ declare abstract class BaseChatGoogle<CallOptions extends BaseChatGoogleCallOpti
309
310
  * @param config - Configuration options including method and whether to include raw response
310
311
  * @returns A Runnable that returns the parsed structured output
311
312
  */
312
- withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: InteropZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<boolean>): Runnable<BaseLanguageModelInput, RunOutput> | Runnable<BaseLanguageModelInput, {
313
+ withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: InteropZodType<RunOutput> | SerializableSchema<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<boolean>): Runnable<BaseLanguageModelInput, RunOutput> | Runnable<BaseLanguageModelInput, {
313
314
  raw: BaseMessage;
314
315
  parsed: RunOutput;
315
316
  }>;
@@ -10,11 +10,11 @@ import { AIMessage, AIMessageChunk } from "@langchain/core/messages";
10
10
  import { concat } from "@langchain/core/utils/stream";
11
11
  import { ChatGenerationChunk } from "@langchain/core/outputs";
12
12
  import { EventSourceParserStream } from "eventsource-parser/stream";
13
- import { RunnableLambda, RunnablePassthrough, RunnableSequence } from "@langchain/core/runnables";
13
+ import { RunnableLambda } from "@langchain/core/runnables";
14
14
  import { toJsonSchema } from "@langchain/core/utils/json_schema";
15
15
  import { isInteropZodSchema } from "@langchain/core/utils/types";
16
- import { JsonOutputParser, StructuredOutputParser } from "@langchain/core/output_parsers";
17
- import { JsonOutputKeyToolsParser } from "@langchain/core/output_parsers/openai_tools";
16
+ import { isSerializableSchema } from "@langchain/core/utils/standard_schema";
17
+ import { assembleStructuredOutputPipeline, createContentParser, createFunctionCallingParser } from "@langchain/core/language_models/structured_output";
18
18
 
19
19
  //#region src/chat_models/base.ts
20
20
  function getPlatformType(platform, hasApiKey) {
@@ -35,7 +35,7 @@ var BaseChatGoogle = class extends BaseChatModel {
35
35
  constructor(params) {
36
36
  super(params);
37
37
  this.params = params;
38
- this._addVersion("@langchain/google", "0.1.3");
38
+ this._addVersion("@langchain/google", "0.1.5");
39
39
  if (!params.apiClient) throw new ConfigurationError("BaseChatGoogle requires an apiClient. This should be provided automatically by ChatGoogle constructors. If you're extending BaseChatGoogle directly, please provide an apiClient instance.");
40
40
  this.apiClient = params.apiClient;
41
41
  this.model = params.model;
@@ -126,7 +126,7 @@ var BaseChatGoogle = class extends BaseChatModel {
126
126
  let responseJsonSchema;
127
127
  let responseMimeType;
128
128
  if (fields.responseSchema) {
129
- if (isInteropZodSchema(fields.responseSchema)) responseJsonSchema = toJsonSchema(fields.responseSchema);
129
+ if (isInteropZodSchema(fields.responseSchema) || isSerializableSchema(fields.responseSchema)) responseJsonSchema = toJsonSchema(fields.responseSchema);
130
130
  else responseJsonSchema = fields.responseSchema;
131
131
  responseMimeType = "application/json";
132
132
  }
@@ -354,51 +354,35 @@ var BaseChatGoogle = class extends BaseChatModel {
354
354
  outputParser = RunnableLambda.from(async (input) => {
355
355
  if (!AIMessage.isInstance(input) && !AIMessageChunk.isInstance(input)) throw new MalformedOutputError({ message: "Input is not an AIMessage or AIMessageChunk." });
356
356
  if (!input.text) throw new MalformedOutputError({ message: "No content found in response. Cannot parse structured output." });
357
- if (isInteropZodSchema(schema)) return await StructuredOutputParser.fromZodSchema(schema).parse(input.text);
358
- else return await new JsonOutputParser().parse(input.text);
357
+ return await createContentParser(schema).parse(input.text);
359
358
  });
360
359
  } else if (method === "functionCalling") {
361
360
  let functionName = name ?? "extract";
362
- let tools;
363
- if (isInteropZodSchema(schema)) {
361
+ let geminiFunctionDeclaration;
362
+ if (isInteropZodSchema(schema) || isSerializableSchema(schema)) {
364
363
  const jsonSchema = schemaToGeminiParameters(schema);
365
364
  const description = typeof jsonSchema.description === "string" ? jsonSchema.description : "A function available to call.";
366
- tools = [{ functionDeclarations: [{
365
+ geminiFunctionDeclaration = {
367
366
  name: functionName,
368
367
  description,
369
368
  parameters: jsonSchema
370
- }] }];
371
- outputParser = new JsonOutputKeyToolsParser({
372
- returnSingle: true,
373
- keyName: functionName,
374
- zodSchema: schema
375
- });
369
+ };
370
+ } else if (typeof schema.name === "string" && typeof schema.parameters === "object" && schema.parameters != null) {
371
+ geminiFunctionDeclaration = schema;
372
+ functionName = schema.name;
376
373
  } else {
377
- let geminiFunctionDefinition;
378
- if (typeof schema.name === "string" && typeof schema.parameters === "object" && schema.parameters != null) {
379
- geminiFunctionDefinition = schema;
380
- functionName = schema.name;
381
- } else {
382
- const parameters = schemaToGeminiParameters(schema);
383
- geminiFunctionDefinition = {
384
- name: functionName,
385
- description: schema.description ?? "",
386
- parameters
387
- };
388
- }
389
- tools = [{ functionDeclarations: [geminiFunctionDefinition] }];
390
- outputParser = new JsonOutputKeyToolsParser({
391
- returnSingle: true,
392
- keyName: functionName
393
- });
374
+ const parameters = schemaToGeminiParameters(schema);
375
+ geminiFunctionDeclaration = {
376
+ name: functionName,
377
+ description: schema.description ?? "",
378
+ parameters
379
+ };
394
380
  }
381
+ const tools = [{ functionDeclarations: [geminiFunctionDeclaration] }];
395
382
  llm = this.bindTools(tools).withConfig({ tool_choice: functionName });
383
+ outputParser = createFunctionCallingParser(schema, functionName);
396
384
  } else throw new ConfigurationError(`Unrecognized structured output method '${method}'. Expected 'functionCalling' or 'jsonSchema'`);
397
- if (!includeRaw) return llm.pipe(outputParser).withConfig({ runName: "ChatGoogleStructuredOutput" });
398
- const parserAssign = RunnablePassthrough.assign({ parsed: (input, config) => outputParser.invoke(input.raw, config) });
399
- const parserNone = RunnablePassthrough.assign({ parsed: () => null });
400
- const parsedWithFallback = parserAssign.withFallbacks({ fallbacks: [parserNone] });
401
- return RunnableSequence.from([{ raw: llm }, parsedWithFallback]).withConfig({ runName: "ChatGoogleStructuredOutputRunnable" });
385
+ return assembleStructuredOutputPipeline(llm, outputParser, includeRaw, includeRaw ? "ChatGoogleStructuredOutputRunnable" : "ChatGoogleStructuredOutput");
402
386
  }
403
387
  };
404
388
  function combineGoogleChatModelFields(a, b, ...rest) {
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../src/chat_models/base.ts"],"sourcesContent":["import {\n BaseChatModel,\n type BaseChatModelCallOptions,\n type BaseChatModelParams,\n} from \"@langchain/core/language_models/chat_models\";\nimport {\n AIMessage,\n AIMessageChunk,\n AIMessageChunkFields,\n BaseMessage,\n type UsageMetadata,\n} from \"@langchain/core/messages\";\nimport { CallbackManagerForLLMRun } from \"@langchain/core/callbacks/manager\";\nimport { concat } from \"@langchain/core/utils/stream\";\nimport { ChatGenerationChunk, ChatResult } from \"@langchain/core/outputs\";\nimport { EventSourceParserStream } from \"eventsource-parser/stream\";\nimport type { BindToolsInput } from \"@langchain/core/language_models/chat_models\";\nimport type { ModelProfile } from \"@langchain/core/language_models/profile\";\nimport PROFILES from \"./profiles.js\";\nimport type {\n BaseLanguageModelInput,\n StructuredOutputMethodOptions,\n} from \"@langchain/core/language_models/base\";\nimport {\n Runnable,\n RunnableLambda,\n RunnablePassthrough,\n RunnableSequence,\n} from \"@langchain/core/runnables\";\nimport {\n toJsonSchema,\n type JsonSchema7Type,\n} from \"@langchain/core/utils/json_schema\";\nimport {\n InteropZodType,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n JsonOutputParser,\n StructuredOutputParser,\n} from \"@langchain/core/output_parsers\";\nimport { JsonOutputKeyToolsParser } from \"@langchain/core/output_parsers/openai_tools\";\n\nimport { ApiClient } from \"../clients/index.js\";\nimport type { ChatGoogleFields } from \"./types.js\";\nimport { SafeJsonEventParserStream } from \"../utils/stream.js\";\nimport {\n convertAIMessageToText,\n convertGeminiCandidateToAIMessage,\n convertGeminiGenerateContentResponseToUsageMetadata,\n convertGeminiPartsToToolCalls,\n convertMessagesToGeminiContents,\n convertMessagesToGeminiSystemInstruction,\n} from \"../converters/messages.js\";\nimport {\n ConfigurationError,\n MalformedOutputError,\n NoCandidatesError,\n PromptBlockedError,\n RequestError,\n} from \"../utils/errors.js\";\nimport {\n convertToolsToGeminiTools,\n convertToolChoiceToGeminiConfig,\n schemaToGeminiParameters,\n} from \"../converters/tools.js\";\nimport {\n convertParamsToPlatformType,\n convertFieldsToSpeechConfig,\n convertFieldsToThinkingConfig,\n} from \"../converters/params.js\";\nimport { Gemini } from \"./api-types.js\";\nimport { subtractUsageMetadata } from \"../utils/metadata.js\";\n\nexport type GooglePlatformType = \"gai\" | \"gcp\";\n\nexport function getPlatformType(\n platform: GooglePlatformType | undefined,\n hasApiKey: boolean\n): GooglePlatformType {\n if (typeof platform !== \"undefined\") {\n return platform;\n } else if (hasApiKey) {\n return \"gai\";\n } else {\n return \"gcp\";\n }\n}\n\nexport interface BaseChatGoogleParams\n extends BaseChatModelParams,\n ChatGoogleFields {\n /**\n * The name of the Gemini model to use.\n *\n * Example: \"gemini-3-pro-preview\"\n */\n model: string;\n\n /**\n * Optional. The API client implementation for making HTTP requests to the Gemini API.\n * If not set, a default client will be used based on the runtime environment.\n */\n apiClient?: ApiClient;\n\n /**\n * Hostname for the API call (if this is running on GCP)\n * Usually this is computed based on location and platformType.\n **/\n endpoint?: string;\n\n /**\n * Region where the LLM is stored (if this is running on GCP)\n * Defaults to \"global\"\n **/\n location?: string;\n\n /**\n * The version of the API functions. Part of the path.\n * Usually this is computed based on platformType.\n **/\n apiVersion?: string;\n\n /**\n * What platform to run the service on.\n * If not specified, the class should determine this from other\n * means. Either way, the platform actually used will be in\n * the \"platform\" getter.\n */\n platformType?: GooglePlatformType;\n\n /**\n * For compatibility with Google's libraries, should this use Vertex?\n * The \"platformType\" parmeter takes precedence.\n */\n vertexai?: boolean;\n\n /**\n * Backwards compatibility.\n * @deprecated in favor of using `disableStreaming` or `.stream()`\n */\n streaming?: boolean;\n\n streamUsage?: boolean;\n}\n\nexport interface BaseChatGoogleCallOptions\n extends BaseChatModelCallOptions,\n ChatGoogleFields {}\n\nexport abstract class BaseChatGoogle<\n CallOptions extends BaseChatGoogleCallOptions = BaseChatGoogleCallOptions\n> extends BaseChatModel<CallOptions, AIMessageChunk> {\n model: string;\n\n streaming: boolean;\n\n disableStreaming: boolean;\n\n streamUsage: boolean = true;\n\n protected _platform?: GooglePlatformType;\n\n protected _endpoint?: string;\n\n protected _location?: string;\n\n protected _apiVersion?: string;\n\n protected apiClient: ApiClient;\n\n constructor(protected params: BaseChatGoogleParams) {\n super(params);\n this._addVersion(\"@langchain/google\", __PKG_VERSION__);\n\n if (!params.apiClient) {\n throw new ConfigurationError(\n \"BaseChatGoogle requires an apiClient. This should be provided automatically by ChatGoogle constructors. If you're extending BaseChatGoogle directly, please provide an apiClient instance.\"\n );\n }\n this.apiClient = params.apiClient;\n\n this.model = params.model;\n this._platform = convertParamsToPlatformType(params);\n this._endpoint = params.endpoint;\n this._location = params.location;\n this._apiVersion = params.apiVersion;\n\n this.disableStreaming = params?.disableStreaming === true;\n this.streaming = params?.streaming === true;\n if (this.disableStreaming) this.streaming = false;\n // disable streaming in BaseChatModel if explicitly disabled\n if (params?.streaming === false) this.disableStreaming = true;\n\n this.streamUsage = params?.streamUsage ?? this.streamUsage;\n if (this.disableStreaming) this.streamUsage = false;\n }\n\n _llmType(): string {\n return \"google\";\n }\n\n protected get platformType(): GooglePlatformType | undefined {\n return this._platform;\n }\n\n protected get platform(): GooglePlatformType {\n return getPlatformType(this._platform, this.apiClient.hasApiKey());\n }\n\n protected get isVertexExpress(): boolean {\n return this.platform === \"gcp\" && this.apiClient.hasApiKey();\n }\n\n protected get apiVersion(): string {\n if (typeof this._apiVersion !== \"undefined\") {\n return this._apiVersion;\n } else if (this.platform === \"gai\") {\n return \"v1beta\";\n } else {\n return \"v1\";\n }\n }\n\n protected get location(): string {\n return this._location || \"global\";\n }\n\n protected get endpoint(): string {\n if (typeof this._endpoint !== \"undefined\") {\n return this._endpoint;\n } else if (this.platform === \"gai\") {\n return \"generativelanguage.googleapis.com\";\n } else if (this.isVertexExpress) {\n return \"aiplatform.googleapis.com\";\n } else if (this.location === \"global\") {\n // See https://docs.cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#use_the_global_endpoint\n return \"aiplatform.googleapis.com\";\n } else {\n return `${this.location}-aiplatform.googleapis.com`;\n }\n }\n\n protected get publisher(): string {\n return \"google\";\n }\n\n protected get urlMethod(): string {\n return this.streaming ? \"streamGenerateContent?alt=sse\" : \"generateContent\";\n }\n\n /**\n * Returns the model profile for this instance's model, describing its\n * capabilities and constraints (e.g. max tokens, input/output modalities,\n * tool calling support).\n *\n * @example\n * ```typescript\n * const model = new ChatGoogle({ model: \"gemini-2.5-pro\" });\n * const profile = model.profile;\n * console.log(profile.maxInputTokens); // 1048576\n * console.log(profile.imageInputs); // true\n * ```\n */\n get profile(): ModelProfile {\n return PROFILES[this.model] ?? {};\n }\n\n protected async buildUrlGemini(urlMethod?: string): Promise<string> {\n return `https://${this.endpoint}/${this.apiVersion}/models/${this.model}:${\n urlMethod ?? this.urlMethod\n }`;\n }\n\n protected async buildUrlVertexExpress(urlMethod?: string): Promise<string> {\n return `https://${this.endpoint}/${this.apiVersion}/publishers/${\n this.publisher\n }/models/${this.model}:${urlMethod ?? this.urlMethod}`;\n }\n\n protected async buildUrlVertexLocation(urlMethod?: string): Promise<string> {\n const projectId = await this.apiClient.getProjectId();\n return `https://${this.endpoint}/${\n this.apiVersion\n }/projects/${projectId}/locations/${this.location}/publishers/${\n this.publisher\n }/models/${this.model}:${urlMethod ?? this.urlMethod}`;\n }\n\n protected async buildUrlVertex(urlMethod?: string): Promise<string> {\n if (this.isVertexExpress) {\n return this.buildUrlVertexExpress(urlMethod);\n } else {\n return this.buildUrlVertexLocation(urlMethod);\n }\n }\n\n protected async buildUrl(urlMethod?: string): Promise<string> {\n switch (this.platform) {\n case \"gai\":\n return this.buildUrlGemini(urlMethod);\n default:\n return this.buildUrlVertex(urlMethod);\n }\n }\n\n override invocationParams(options: this[\"ParsedCallOptions\"]) {\n const fields = combineGoogleChatModelFields(this.params, options);\n\n // Convert tools to Gemini format\n const tools = fields.tools\n ? convertToolsToGeminiTools(fields.tools)\n : undefined;\n\n // Convert tool choice to Gemini function calling config\n const toolConfig = convertToolChoiceToGeminiConfig(\n options.tool_choice,\n !!(tools && tools.length > 0)\n );\n\n let responseJsonSchema:\n | JsonSchema7Type\n | Record<string, unknown>\n | undefined;\n let responseMimeType: string | undefined;\n\n if (fields.responseSchema) {\n // Convert Zod schema to JSON Schema if needed\n if (isInteropZodSchema(fields.responseSchema)) {\n responseJsonSchema = toJsonSchema(fields.responseSchema);\n } else {\n responseJsonSchema = fields.responseSchema as Record<string, unknown>;\n }\n // Automatically set responseMimeType to \"application/json\" when schema is provided\n responseMimeType = \"application/json\";\n }\n\n return {\n ...(tools && tools.length > 0 ? { tools } : {}),\n ...(toolConfig ? { toolConfig } : {}),\n safetySettings: fields.safetySettings,\n generationConfig: {\n temperature: fields.temperature,\n topP: fields.topP,\n topK: fields.topK,\n maxOutputTokens: fields.maxOutputTokens,\n presencePenalty: fields.presencePenalty,\n frequencyPenalty: fields.frequencyPenalty,\n stopSequences: fields.stopSequences,\n ...(responseMimeType ? { responseMimeType } : {}),\n ...(responseJsonSchema ? { responseJsonSchema } : {}),\n ...(fields.responseModalities && fields.responseModalities.length > 0\n ? { responseModalities: fields.responseModalities }\n : {}),\n candidateCount: 1,\n seed: fields.seed,\n responseLogprobs: fields.responseLogprobs,\n logprobs: fields.logprobs,\n ...(fields.enableEnhancedCivicAnswers !== undefined\n ? { enableEnhancedCivicAnswers: fields.enableEnhancedCivicAnswers }\n : {}),\n thinkingConfig: convertFieldsToThinkingConfig(this.model, fields),\n speechConfig: convertFieldsToSpeechConfig(fields),\n ...(fields.imageConfig ? { imageConfig: fields.imageConfig } : {}),\n ...(fields.mediaResolution\n ? { mediaResolution: fields.mediaResolution }\n : {}),\n },\n };\n }\n\n async _generate(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n if (this.streaming) {\n const stream = await this._streamResponseChunks(\n messages,\n options,\n runManager\n );\n let finalChunk: ChatGenerationChunk | null = null;\n for await (const chunk of stream) {\n finalChunk = !finalChunk ? chunk : concat(finalChunk, chunk);\n }\n if (\n typeof finalChunk?.message?.content === \"string\" &&\n typeof (\n finalChunk?.message?.additional_kwargs\n ?.originalTextContentBlock as Record<string, unknown>\n )?.text === \"string\"\n ) {\n (\n finalChunk.message.additional_kwargs\n .originalTextContentBlock as Record<string, unknown>\n ).text = finalChunk.message.content;\n }\n return {\n generations: finalChunk ? [finalChunk] : [],\n };\n }\n\n const url = await this.buildUrl();\n const body = {\n ...this.invocationParams(options),\n systemInstruction: convertMessagesToGeminiSystemInstruction(messages),\n contents: convertMessagesToGeminiContents(messages),\n };\n\n const moduleName = this.constructor.name;\n await runManager?.handleCustomEvent(`google-request-${moduleName}`, {\n url,\n body,\n });\n\n const response = await this.apiClient.fetch(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n })\n );\n\n if (!response.ok) {\n const error = await RequestError.fromResponse(response);\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n error,\n });\n throw error;\n }\n\n const data: Gemini.GenerateContentResponse = await response.json();\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n data,\n url: response.url,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n\n // Check for prompt feedback errors\n if (data.promptFeedback?.blockReason) {\n throw PromptBlockedError.fromPromptFeedback(data.promptFeedback);\n }\n\n // Check if we have candidates\n if (!data.candidates || data.candidates.length === 0) {\n throw new NoCandidatesError();\n }\n\n // Use the first candidate\n const candidate = data.candidates[0];\n const message = convertGeminiCandidateToAIMessage(candidate);\n\n // Extract text content from the message\n const text = convertAIMessageToText(message);\n\n const usageMetadata =\n convertGeminiGenerateContentResponseToUsageMetadata(data);\n message.usage_metadata = usageMetadata;\n\n return {\n generations: [\n {\n text,\n message,\n generationInfo: {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n safetyRatings: candidate.safetyRatings,\n citationMetadata: candidate.citationMetadata,\n tokenCount: candidate.tokenCount,\n },\n },\n ],\n llmOutput: {\n tokenUsage: usageMetadata,\n model: data.modelVersion,\n responseId: data.responseId,\n usageMetadata,\n },\n };\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const streamUsage: boolean = this.streamUsage ?? true;\n\n const body = {\n ...this.invocationParams(options),\n systemInstruction: convertMessagesToGeminiSystemInstruction(messages),\n contents: convertMessagesToGeminiContents(messages),\n };\n\n const url = await this.buildUrl(\"streamGenerateContent?alt=sse\");\n const moduleName = this.constructor.name;\n await runManager?.handleCustomEvent(`google-request-${moduleName}`, {\n url,\n body,\n });\n\n const response = await this.apiClient.fetch(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: options.signal,\n })\n );\n\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n url: response.url,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n\n if (!response.ok) {\n const error = await RequestError.fromResponse(response);\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n error,\n });\n throw error;\n }\n\n if (response.body) {\n let previousUsage: UsageMetadata | undefined;\n const stream = response.body\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new EventSourceParserStream())\n .pipeThrough(\n new SafeJsonEventParserStream<Gemini.GenerateContentResponse>()\n )\n .pipeThrough(\n new TransformStream<\n Gemini.GenerateContentResponse,\n ChatGenerationChunk\n >({\n transform(chunk, controller) {\n // eslint-disable-next-line no-void\n void runManager?.handleCustomEvent(`google-chunk-${moduleName}`, {\n chunk,\n });\n if (chunk === null) {\n controller.enqueue(\n new ChatGenerationChunk({\n text: \"\",\n message: new AIMessageChunk({ content: \"\" }),\n generationInfo: { finishReason: \"stop\" },\n })\n );\n return;\n }\n\n // Extract text delta from the chunk\n const candidate = chunk.candidates?.[0];\n if (!candidate) {\n return;\n }\n\n const message = convertGeminiCandidateToAIMessage(candidate);\n const text = convertAIMessageToText(message);\n\n const parts = candidate.content?.parts ?? [];\n const toolCalls = convertGeminiPartsToToolCalls(parts);\n\n // Only emit if we have content\n if (parts.length > 0 || candidate.finishReason) {\n const messageChunkParams: AIMessageChunkFields = {\n content: message.content,\n tool_calls: toolCalls,\n response_metadata: {\n model_provider: \"google\",\n },\n additional_kwargs: {\n ...(message.additional_kwargs.originalTextContentBlock\n ? {\n originalTextContentBlock:\n message.additional_kwargs.originalTextContentBlock,\n }\n : {}),\n ...(candidate.finishReason\n ? {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n }\n : {}),\n },\n };\n\n if (chunk?.usageMetadata && streamUsage) {\n const cumulative =\n convertGeminiGenerateContentResponseToUsageMetadata(chunk);\n messageChunkParams.usage_metadata = subtractUsageMetadata(\n cumulative,\n previousUsage\n );\n previousUsage = cumulative;\n }\n const messageChunk = new AIMessageChunk(messageChunkParams);\n\n controller.enqueue(\n new ChatGenerationChunk({\n text: text,\n message: messageChunk,\n generationInfo: {\n ...(candidate.finishReason && {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n }),\n ...(candidate.safetyRatings && {\n safetyRatings: candidate.safetyRatings,\n }),\n },\n })\n );\n }\n },\n })\n );\n\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n yield value;\n await runManager?.handleLLMNewToken(\n value.text ?? \"\",\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: value }\n );\n }\n } finally {\n reader.releaseLock();\n }\n }\n }\n\n /**\n * Bind tool-like objects to this chat model.\n *\n * @param tools A list of tool definitions to bind to this chat model.\n * Can be a structured tool, an OpenAI formatted tool, or a Gemini function declaration.\n * @param kwargs Any additional parameters to bind.\n */\n bindTools(\n tools: BindToolsInput[],\n kwargs?: Partial<CallOptions>\n ): Runnable<BaseMessage[], AIMessageChunk, CallOptions> {\n return this.withConfig({\n ...kwargs,\n tools,\n } as Partial<CallOptions>);\n }\n\n /**\n * Get structured output from the model based on a schema.\n *\n * This method supports two modes:\n * - `jsonMode`: Uses `responseSchema` to get JSON responses directly (preferred for structured outputs)\n * - `functionCalling`: Uses function calling with tools (default, for compatibility)\n *\n * @param outputSchema - The schema to use for structured output (Zod schema or JSON Schema)\n * @param config - Configuration options including method and whether to include raw response\n * @returns A Runnable that returns the parsed structured output\n */\n withStructuredOutput<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RunOutput extends Record<string, any> = Record<string, any>\n >(\n outputSchema:\n | InteropZodType<RunOutput>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | Record<string, any>,\n config?: StructuredOutputMethodOptions<boolean>\n ):\n | Runnable<BaseLanguageModelInput, RunOutput>\n | Runnable<\n BaseLanguageModelInput,\n { raw: BaseMessage; parsed: RunOutput }\n > {\n let llm: Runnable<BaseMessage[], AIMessageChunk, CallOptions>;\n let outputParser: Runnable<BaseMessage, RunOutput>;\n\n const { schema, name, includeRaw } = {\n ...config,\n schema: outputSchema,\n };\n let method = config?.method ?? \"functionCalling\";\n\n if (method === \"jsonMode\") {\n console.warn(\n `\"jsonMode\" is not supported for Google models. Falling back to \"jsonSchema\".`\n );\n method = \"jsonSchema\";\n }\n\n if (method === \"jsonSchema\") {\n // Use JSON mode with responseSchema\n llm = this.withConfig({\n responseSchema: schema,\n } as Partial<CallOptions>);\n\n outputParser = RunnableLambda.from<BaseMessage, RunOutput>(\n async (input: BaseMessage): Promise<RunOutput> => {\n if (\n !AIMessage.isInstance(input) &&\n !AIMessageChunk.isInstance(input)\n ) {\n throw new MalformedOutputError({\n message: \"Input is not an AIMessage or AIMessageChunk.\",\n });\n }\n\n if (!input.text) {\n throw new MalformedOutputError({\n message:\n \"No content found in response. Cannot parse structured output.\",\n });\n }\n\n // Parse JSON and validate with schema\n if (isInteropZodSchema(schema)) {\n const zodParser = StructuredOutputParser.fromZodSchema(\n schema as InteropZodType<RunOutput>\n );\n return (await zodParser.parse(input.text)) as RunOutput;\n } else {\n const jsonParser = new JsonOutputParser<RunOutput>();\n return await jsonParser.parse(input.text);\n }\n }\n );\n } else if (method === \"functionCalling\") {\n // Use function calling mode\n let functionName = name ?? \"extract\";\n let tools: Gemini.Tool[];\n\n if (isInteropZodSchema(schema)) {\n const jsonSchema = schemaToGeminiParameters(schema);\n const description =\n typeof jsonSchema.description === \"string\"\n ? jsonSchema.description\n : \"A function available to call.\";\n tools = [\n {\n functionDeclarations: [\n {\n name: functionName,\n description,\n parameters: jsonSchema as Gemini.Tools.Schema,\n },\n ],\n },\n ];\n outputParser = new JsonOutputKeyToolsParser({\n returnSingle: true,\n keyName: functionName,\n zodSchema: schema,\n });\n } else {\n let geminiFunctionDefinition: Gemini.Tools.FunctionDeclaration;\n if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n geminiFunctionDefinition = schema as Gemini.Tools.FunctionDeclaration;\n functionName = schema.name;\n } else {\n // We are providing the schema for *just* the parameters\n const parameters = schemaToGeminiParameters(schema);\n geminiFunctionDefinition = {\n name: functionName,\n description: (schema as { description?: string }).description ?? \"\",\n parameters,\n };\n }\n tools = [\n {\n functionDeclarations: [geminiFunctionDefinition],\n },\n ];\n outputParser = new JsonOutputKeyToolsParser<RunOutput>({\n returnSingle: true,\n keyName: functionName,\n });\n }\n\n llm = this.bindTools(tools).withConfig({\n tool_choice: functionName,\n } as Partial<CallOptions>);\n } else {\n throw new ConfigurationError(\n `Unrecognized structured output method '${method}'. Expected 'functionCalling' or 'jsonSchema'`\n );\n }\n\n // Shared logic for handling includeRaw\n if (!includeRaw) {\n return llm.pipe(outputParser).withConfig({\n runName: \"ChatGoogleStructuredOutput\",\n }) as Runnable<BaseLanguageModelInput, RunOutput>;\n }\n\n const parserAssign = RunnablePassthrough.assign({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n parsed: (input: any, config) => outputParser.invoke(input.raw, config),\n });\n const parserNone = RunnablePassthrough.assign({\n parsed: () => null,\n });\n const parsedWithFallback = parserAssign.withFallbacks({\n fallbacks: [parserNone],\n });\n return RunnableSequence.from<\n BaseLanguageModelInput,\n { raw: BaseMessage; parsed: RunOutput }\n >([\n {\n raw: llm,\n },\n parsedWithFallback,\n ]).withConfig({\n runName: \"ChatGoogleStructuredOutputRunnable\",\n });\n }\n}\n\ntype CombinableFields = Omit<BaseChatGoogleParams, \"model\">;\n\nexport function combineGoogleChatModelFields(\n a: CombinableFields,\n b: CombinableFields,\n ...rest: CombinableFields[]\n): CombinableFields {\n const combined: CombinableFields = {\n temperature: b.temperature ?? a.temperature,\n topP: b.topP ?? a.topP,\n topK: b.topK ?? a.topK,\n maxOutputTokens: b.maxOutputTokens ?? a.maxOutputTokens,\n presencePenalty: b.presencePenalty ?? a.presencePenalty,\n frequencyPenalty: b.frequencyPenalty ?? a.frequencyPenalty,\n stopSequences: b.stopSequences ?? a.stopSequences,\n seed: b.seed ?? a.seed,\n responseLogprobs: b.responseLogprobs ?? a.responseLogprobs,\n logprobs: b.logprobs ?? a.logprobs,\n safetySettings: b.safetySettings ?? a.safetySettings,\n responseSchema: b.responseSchema ?? a.responseSchema,\n tools: b.tools ?? a.tools,\n responseModalities: b.responseModalities ?? a.responseModalities,\n enableEnhancedCivicAnswers:\n b.enableEnhancedCivicAnswers ?? a.enableEnhancedCivicAnswers,\n speechConfig: b.speechConfig ?? a.speechConfig,\n imageConfig: b.imageConfig ?? a.imageConfig,\n mediaResolution: b.mediaResolution ?? a.mediaResolution,\n maxReasoningTokens: b.maxReasoningTokens ?? a.maxReasoningTokens,\n thinkingBudget: b.thinkingBudget ?? a.thinkingBudget,\n reasoningEffort: b.reasoningEffort ?? a.reasoningEffort,\n thinkingLevel: b.thinkingLevel ?? a.thinkingLevel,\n };\n if (rest.length > 0) {\n return combineGoogleChatModelFields(combined, rest[0], ...rest.slice(1));\n }\n return combined;\n}\n\nexport function getGoogleChatModelParams<TParams extends BaseChatGoogleParams>(\n modelOrParams: string | TParams,\n paramsArg?: Omit<TParams, \"model\">\n): TParams {\n const model =\n typeof modelOrParams === \"string\" ? modelOrParams : modelOrParams.model;\n const params = typeof modelOrParams === \"string\" ? paramsArg : modelOrParams;\n return { model, ...params } as TParams;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/chat_models/base.ts"],"sourcesContent":["import {\n BaseChatModel,\n type BaseChatModelCallOptions,\n type BaseChatModelParams,\n} from \"@langchain/core/language_models/chat_models\";\nimport {\n AIMessage,\n AIMessageChunk,\n AIMessageChunkFields,\n BaseMessage,\n type UsageMetadata,\n} from \"@langchain/core/messages\";\nimport { CallbackManagerForLLMRun } from \"@langchain/core/callbacks/manager\";\nimport { concat } from \"@langchain/core/utils/stream\";\nimport { ChatGenerationChunk, ChatResult } from \"@langchain/core/outputs\";\nimport { EventSourceParserStream } from \"eventsource-parser/stream\";\nimport type { BindToolsInput } from \"@langchain/core/language_models/chat_models\";\nimport type { ModelProfile } from \"@langchain/core/language_models/profile\";\nimport PROFILES from \"./profiles.js\";\nimport type {\n BaseLanguageModelInput,\n StructuredOutputMethodOptions,\n} from \"@langchain/core/language_models/base\";\nimport { Runnable, RunnableLambda } from \"@langchain/core/runnables\";\nimport {\n toJsonSchema,\n type JsonSchema7Type,\n} from \"@langchain/core/utils/json_schema\";\nimport {\n InteropZodType,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\n\nimport { ApiClient } from \"../clients/index.js\";\nimport type { ChatGoogleFields } from \"./types.js\";\nimport { SafeJsonEventParserStream } from \"../utils/stream.js\";\nimport {\n convertAIMessageToText,\n convertGeminiCandidateToAIMessage,\n convertGeminiGenerateContentResponseToUsageMetadata,\n convertGeminiPartsToToolCalls,\n convertMessagesToGeminiContents,\n convertMessagesToGeminiSystemInstruction,\n} from \"../converters/messages.js\";\nimport {\n ConfigurationError,\n MalformedOutputError,\n NoCandidatesError,\n PromptBlockedError,\n RequestError,\n} from \"../utils/errors.js\";\nimport {\n convertToolsToGeminiTools,\n convertToolChoiceToGeminiConfig,\n schemaToGeminiParameters,\n} from \"../converters/tools.js\";\nimport {\n convertParamsToPlatformType,\n convertFieldsToSpeechConfig,\n convertFieldsToThinkingConfig,\n} from \"../converters/params.js\";\nimport { Gemini } from \"./api-types.js\";\nimport { subtractUsageMetadata } from \"../utils/metadata.js\";\nimport {\n isSerializableSchema,\n SerializableSchema,\n} from \"@langchain/core/utils/standard_schema\";\nimport {\n assembleStructuredOutputPipeline,\n createContentParser,\n createFunctionCallingParser,\n} from \"@langchain/core/language_models/structured_output\";\n\nexport type GooglePlatformType = \"gai\" | \"gcp\";\n\nexport function getPlatformType(\n platform: GooglePlatformType | undefined,\n hasApiKey: boolean\n): GooglePlatformType {\n if (typeof platform !== \"undefined\") {\n return platform;\n } else if (hasApiKey) {\n return \"gai\";\n } else {\n return \"gcp\";\n }\n}\n\nexport interface BaseChatGoogleParams\n extends BaseChatModelParams,\n ChatGoogleFields {\n /**\n * The name of the Gemini model to use.\n *\n * Example: \"gemini-3-pro-preview\"\n */\n model: string;\n\n /**\n * Optional. The API client implementation for making HTTP requests to the Gemini API.\n * If not set, a default client will be used based on the runtime environment.\n */\n apiClient?: ApiClient;\n\n /**\n * Hostname for the API call (if this is running on GCP)\n * Usually this is computed based on location and platformType.\n **/\n endpoint?: string;\n\n /**\n * Region where the LLM is stored (if this is running on GCP)\n * Defaults to \"global\"\n **/\n location?: string;\n\n /**\n * The version of the API functions. Part of the path.\n * Usually this is computed based on platformType.\n **/\n apiVersion?: string;\n\n /**\n * What platform to run the service on.\n * If not specified, the class should determine this from other\n * means. Either way, the platform actually used will be in\n * the \"platform\" getter.\n */\n platformType?: GooglePlatformType;\n\n /**\n * For compatibility with Google's libraries, should this use Vertex?\n * The \"platformType\" parmeter takes precedence.\n */\n vertexai?: boolean;\n\n /**\n * Backwards compatibility.\n * @deprecated in favor of using `disableStreaming` or `.stream()`\n */\n streaming?: boolean;\n\n streamUsage?: boolean;\n}\n\nexport interface BaseChatGoogleCallOptions\n extends BaseChatModelCallOptions,\n ChatGoogleFields {}\n\nexport abstract class BaseChatGoogle<\n CallOptions extends BaseChatGoogleCallOptions = BaseChatGoogleCallOptions\n> extends BaseChatModel<CallOptions, AIMessageChunk> {\n model: string;\n\n streaming: boolean;\n\n disableStreaming: boolean;\n\n streamUsage: boolean = true;\n\n protected _platform?: GooglePlatformType;\n\n protected _endpoint?: string;\n\n protected _location?: string;\n\n protected _apiVersion?: string;\n\n protected apiClient: ApiClient;\n\n constructor(protected params: BaseChatGoogleParams) {\n super(params);\n this._addVersion(\"@langchain/google\", __PKG_VERSION__);\n\n if (!params.apiClient) {\n throw new ConfigurationError(\n \"BaseChatGoogle requires an apiClient. This should be provided automatically by ChatGoogle constructors. If you're extending BaseChatGoogle directly, please provide an apiClient instance.\"\n );\n }\n this.apiClient = params.apiClient;\n\n this.model = params.model;\n this._platform = convertParamsToPlatformType(params);\n this._endpoint = params.endpoint;\n this._location = params.location;\n this._apiVersion = params.apiVersion;\n\n this.disableStreaming = params?.disableStreaming === true;\n this.streaming = params?.streaming === true;\n if (this.disableStreaming) this.streaming = false;\n // disable streaming in BaseChatModel if explicitly disabled\n if (params?.streaming === false) this.disableStreaming = true;\n\n this.streamUsage = params?.streamUsage ?? this.streamUsage;\n if (this.disableStreaming) this.streamUsage = false;\n }\n\n _llmType(): string {\n return \"google\";\n }\n\n protected get platformType(): GooglePlatformType | undefined {\n return this._platform;\n }\n\n protected get platform(): GooglePlatformType {\n return getPlatformType(this._platform, this.apiClient.hasApiKey());\n }\n\n protected get isVertexExpress(): boolean {\n return this.platform === \"gcp\" && this.apiClient.hasApiKey();\n }\n\n protected get apiVersion(): string {\n if (typeof this._apiVersion !== \"undefined\") {\n return this._apiVersion;\n } else if (this.platform === \"gai\") {\n return \"v1beta\";\n } else {\n return \"v1\";\n }\n }\n\n protected get location(): string {\n return this._location || \"global\";\n }\n\n protected get endpoint(): string {\n if (typeof this._endpoint !== \"undefined\") {\n return this._endpoint;\n } else if (this.platform === \"gai\") {\n return \"generativelanguage.googleapis.com\";\n } else if (this.isVertexExpress) {\n return \"aiplatform.googleapis.com\";\n } else if (this.location === \"global\") {\n // See https://docs.cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#use_the_global_endpoint\n return \"aiplatform.googleapis.com\";\n } else {\n return `${this.location}-aiplatform.googleapis.com`;\n }\n }\n\n protected get publisher(): string {\n return \"google\";\n }\n\n protected get urlMethod(): string {\n return this.streaming ? \"streamGenerateContent?alt=sse\" : \"generateContent\";\n }\n\n /**\n * Returns the model profile for this instance's model, describing its\n * capabilities and constraints (e.g. max tokens, input/output modalities,\n * tool calling support).\n *\n * @example\n * ```typescript\n * const model = new ChatGoogle({ model: \"gemini-2.5-pro\" });\n * const profile = model.profile;\n * console.log(profile.maxInputTokens); // 1048576\n * console.log(profile.imageInputs); // true\n * ```\n */\n get profile(): ModelProfile {\n return PROFILES[this.model] ?? {};\n }\n\n protected async buildUrlGemini(urlMethod?: string): Promise<string> {\n return `https://${this.endpoint}/${this.apiVersion}/models/${this.model}:${\n urlMethod ?? this.urlMethod\n }`;\n }\n\n protected async buildUrlVertexExpress(urlMethod?: string): Promise<string> {\n return `https://${this.endpoint}/${this.apiVersion}/publishers/${\n this.publisher\n }/models/${this.model}:${urlMethod ?? this.urlMethod}`;\n }\n\n protected async buildUrlVertexLocation(urlMethod?: string): Promise<string> {\n const projectId = await this.apiClient.getProjectId();\n return `https://${this.endpoint}/${\n this.apiVersion\n }/projects/${projectId}/locations/${this.location}/publishers/${\n this.publisher\n }/models/${this.model}:${urlMethod ?? this.urlMethod}`;\n }\n\n protected async buildUrlVertex(urlMethod?: string): Promise<string> {\n if (this.isVertexExpress) {\n return this.buildUrlVertexExpress(urlMethod);\n } else {\n return this.buildUrlVertexLocation(urlMethod);\n }\n }\n\n protected async buildUrl(urlMethod?: string): Promise<string> {\n switch (this.platform) {\n case \"gai\":\n return this.buildUrlGemini(urlMethod);\n default:\n return this.buildUrlVertex(urlMethod);\n }\n }\n\n override invocationParams(options: this[\"ParsedCallOptions\"]) {\n const fields = combineGoogleChatModelFields(this.params, options);\n\n // Convert tools to Gemini format\n const tools = fields.tools\n ? convertToolsToGeminiTools(fields.tools)\n : undefined;\n\n // Convert tool choice to Gemini function calling config\n const toolConfig = convertToolChoiceToGeminiConfig(\n options.tool_choice,\n !!(tools && tools.length > 0)\n );\n\n let responseJsonSchema:\n | JsonSchema7Type\n | Record<string, unknown>\n | undefined;\n let responseMimeType: string | undefined;\n\n if (fields.responseSchema) {\n // Convert Zod schema to JSON Schema if needed\n if (\n isInteropZodSchema(fields.responseSchema) ||\n isSerializableSchema(fields.responseSchema)\n ) {\n responseJsonSchema = toJsonSchema(fields.responseSchema);\n } else {\n responseJsonSchema = fields.responseSchema as Record<string, unknown>;\n }\n // Automatically set responseMimeType to \"application/json\" when schema is provided\n responseMimeType = \"application/json\";\n }\n\n return {\n ...(tools && tools.length > 0 ? { tools } : {}),\n ...(toolConfig ? { toolConfig } : {}),\n safetySettings: fields.safetySettings,\n generationConfig: {\n temperature: fields.temperature,\n topP: fields.topP,\n topK: fields.topK,\n maxOutputTokens: fields.maxOutputTokens,\n presencePenalty: fields.presencePenalty,\n frequencyPenalty: fields.frequencyPenalty,\n stopSequences: fields.stopSequences,\n ...(responseMimeType ? { responseMimeType } : {}),\n ...(responseJsonSchema ? { responseJsonSchema } : {}),\n ...(fields.responseModalities && fields.responseModalities.length > 0\n ? { responseModalities: fields.responseModalities }\n : {}),\n candidateCount: 1,\n seed: fields.seed,\n responseLogprobs: fields.responseLogprobs,\n logprobs: fields.logprobs,\n ...(fields.enableEnhancedCivicAnswers !== undefined\n ? { enableEnhancedCivicAnswers: fields.enableEnhancedCivicAnswers }\n : {}),\n thinkingConfig: convertFieldsToThinkingConfig(this.model, fields),\n speechConfig: convertFieldsToSpeechConfig(fields),\n ...(fields.imageConfig ? { imageConfig: fields.imageConfig } : {}),\n ...(fields.mediaResolution\n ? { mediaResolution: fields.mediaResolution }\n : {}),\n },\n };\n }\n\n async _generate(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n if (this.streaming) {\n const stream = await this._streamResponseChunks(\n messages,\n options,\n runManager\n );\n let finalChunk: ChatGenerationChunk | null = null;\n for await (const chunk of stream) {\n finalChunk = !finalChunk ? chunk : concat(finalChunk, chunk);\n }\n if (\n typeof finalChunk?.message?.content === \"string\" &&\n typeof (\n finalChunk?.message?.additional_kwargs\n ?.originalTextContentBlock as Record<string, unknown>\n )?.text === \"string\"\n ) {\n (\n finalChunk.message.additional_kwargs\n .originalTextContentBlock as Record<string, unknown>\n ).text = finalChunk.message.content;\n }\n return {\n generations: finalChunk ? [finalChunk] : [],\n };\n }\n\n const url = await this.buildUrl();\n const body = {\n ...this.invocationParams(options),\n systemInstruction: convertMessagesToGeminiSystemInstruction(messages),\n contents: convertMessagesToGeminiContents(messages),\n };\n\n const moduleName = this.constructor.name;\n await runManager?.handleCustomEvent(`google-request-${moduleName}`, {\n url,\n body,\n });\n\n const response = await this.apiClient.fetch(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n })\n );\n\n if (!response.ok) {\n const error = await RequestError.fromResponse(response);\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n error,\n });\n throw error;\n }\n\n const data: Gemini.GenerateContentResponse = await response.json();\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n data,\n url: response.url,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n\n // Check for prompt feedback errors\n if (data.promptFeedback?.blockReason) {\n throw PromptBlockedError.fromPromptFeedback(data.promptFeedback);\n }\n\n // Check if we have candidates\n if (!data.candidates || data.candidates.length === 0) {\n throw new NoCandidatesError();\n }\n\n // Use the first candidate\n const candidate = data.candidates[0];\n const message = convertGeminiCandidateToAIMessage(candidate);\n\n // Extract text content from the message\n const text = convertAIMessageToText(message);\n\n const usageMetadata =\n convertGeminiGenerateContentResponseToUsageMetadata(data);\n message.usage_metadata = usageMetadata;\n\n return {\n generations: [\n {\n text,\n message,\n generationInfo: {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n safetyRatings: candidate.safetyRatings,\n citationMetadata: candidate.citationMetadata,\n tokenCount: candidate.tokenCount,\n },\n },\n ],\n llmOutput: {\n tokenUsage: usageMetadata,\n model: data.modelVersion,\n responseId: data.responseId,\n usageMetadata,\n },\n };\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const streamUsage: boolean = this.streamUsage ?? true;\n\n const body = {\n ...this.invocationParams(options),\n systemInstruction: convertMessagesToGeminiSystemInstruction(messages),\n contents: convertMessagesToGeminiContents(messages),\n };\n\n const url = await this.buildUrl(\"streamGenerateContent?alt=sse\");\n const moduleName = this.constructor.name;\n await runManager?.handleCustomEvent(`google-request-${moduleName}`, {\n url,\n body,\n });\n\n const response = await this.apiClient.fetch(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: options.signal,\n })\n );\n\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n url: response.url,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n\n if (!response.ok) {\n const error = await RequestError.fromResponse(response);\n await runManager?.handleCustomEvent(`google-response-${moduleName}`, {\n error,\n });\n throw error;\n }\n\n if (response.body) {\n let previousUsage: UsageMetadata | undefined;\n const stream = response.body\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new EventSourceParserStream())\n .pipeThrough(\n new SafeJsonEventParserStream<Gemini.GenerateContentResponse>()\n )\n .pipeThrough(\n new TransformStream<\n Gemini.GenerateContentResponse,\n ChatGenerationChunk\n >({\n transform(chunk, controller) {\n // eslint-disable-next-line no-void\n void runManager?.handleCustomEvent(`google-chunk-${moduleName}`, {\n chunk,\n });\n if (chunk === null) {\n controller.enqueue(\n new ChatGenerationChunk({\n text: \"\",\n message: new AIMessageChunk({ content: \"\" }),\n generationInfo: { finishReason: \"stop\" },\n })\n );\n return;\n }\n\n // Extract text delta from the chunk\n const candidate = chunk.candidates?.[0];\n if (!candidate) {\n return;\n }\n\n const message = convertGeminiCandidateToAIMessage(candidate);\n const text = convertAIMessageToText(message);\n\n const parts = candidate.content?.parts ?? [];\n const toolCalls = convertGeminiPartsToToolCalls(parts);\n\n // Only emit if we have content\n if (parts.length > 0 || candidate.finishReason) {\n const messageChunkParams: AIMessageChunkFields = {\n content: message.content,\n tool_calls: toolCalls,\n response_metadata: {\n model_provider: \"google\",\n },\n additional_kwargs: {\n ...(message.additional_kwargs.originalTextContentBlock\n ? {\n originalTextContentBlock:\n message.additional_kwargs.originalTextContentBlock,\n }\n : {}),\n ...(candidate.finishReason\n ? {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n }\n : {}),\n },\n };\n\n if (chunk?.usageMetadata && streamUsage) {\n const cumulative =\n convertGeminiGenerateContentResponseToUsageMetadata(chunk);\n messageChunkParams.usage_metadata = subtractUsageMetadata(\n cumulative,\n previousUsage\n );\n previousUsage = cumulative;\n }\n const messageChunk = new AIMessageChunk(messageChunkParams);\n\n controller.enqueue(\n new ChatGenerationChunk({\n text: text,\n message: messageChunk,\n generationInfo: {\n ...(candidate.finishReason && {\n finishReason: candidate.finishReason,\n finishMessage: candidate.finishMessage,\n }),\n ...(candidate.safetyRatings && {\n safetyRatings: candidate.safetyRatings,\n }),\n },\n })\n );\n }\n },\n })\n );\n\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n yield value;\n await runManager?.handleLLMNewToken(\n value.text ?? \"\",\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: value }\n );\n }\n } finally {\n reader.releaseLock();\n }\n }\n }\n\n /**\n * Bind tool-like objects to this chat model.\n *\n * @param tools A list of tool definitions to bind to this chat model.\n * Can be a structured tool, an OpenAI formatted tool, or a Gemini function declaration.\n * @param kwargs Any additional parameters to bind.\n */\n bindTools(\n tools: BindToolsInput[],\n kwargs?: Partial<CallOptions>\n ): Runnable<BaseMessage[], AIMessageChunk, CallOptions> {\n return this.withConfig({\n ...kwargs,\n tools,\n } as Partial<CallOptions>);\n }\n\n /**\n * Get structured output from the model based on a schema.\n *\n * This method supports two modes:\n * - `jsonMode`: Uses `responseSchema` to get JSON responses directly (preferred for structured outputs)\n * - `functionCalling`: Uses function calling with tools (default, for compatibility)\n *\n * @param outputSchema - The schema to use for structured output (Zod schema or JSON Schema)\n * @param config - Configuration options including method and whether to include raw response\n * @returns A Runnable that returns the parsed structured output\n */\n withStructuredOutput<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RunOutput extends Record<string, any> = Record<string, any>\n >(\n outputSchema:\n | InteropZodType<RunOutput>\n | SerializableSchema<RunOutput>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | Record<string, any>,\n config?: StructuredOutputMethodOptions<boolean>\n ):\n | Runnable<BaseLanguageModelInput, RunOutput>\n | Runnable<\n BaseLanguageModelInput,\n { raw: BaseMessage; parsed: RunOutput }\n > {\n let llm: Runnable<BaseMessage[], AIMessageChunk, CallOptions>;\n let outputParser: Runnable<BaseMessage, RunOutput>;\n\n const { schema, name, includeRaw } = {\n ...config,\n schema: outputSchema,\n };\n let method = config?.method ?? \"functionCalling\";\n\n if (method === \"jsonMode\") {\n console.warn(\n `\"jsonMode\" is not supported for Google models. Falling back to \"jsonSchema\".`\n );\n method = \"jsonSchema\";\n }\n\n if (method === \"jsonSchema\") {\n // Use JSON mode with responseSchema\n llm = this.withConfig({\n responseSchema: schema,\n } as Partial<CallOptions>);\n\n outputParser = RunnableLambda.from<BaseMessage, RunOutput>(\n async (input: BaseMessage): Promise<RunOutput> => {\n if (\n !AIMessage.isInstance(input) &&\n !AIMessageChunk.isInstance(input)\n ) {\n throw new MalformedOutputError({\n message: \"Input is not an AIMessage or AIMessageChunk.\",\n });\n }\n\n if (!input.text) {\n throw new MalformedOutputError({\n message:\n \"No content found in response. Cannot parse structured output.\",\n });\n }\n\n // Parse JSON and validate with schema\n const parser = createContentParser(schema);\n return await parser.parse(input.text);\n }\n );\n } else if (method === \"functionCalling\") {\n // Use function calling mode\n let functionName = name ?? \"extract\";\n let geminiFunctionDeclaration: Gemini.Tools.FunctionDeclaration;\n\n if (isInteropZodSchema(schema) || isSerializableSchema(schema)) {\n const jsonSchema = schemaToGeminiParameters(schema);\n const description =\n typeof jsonSchema.description === \"string\"\n ? jsonSchema.description\n : \"A function available to call.\";\n geminiFunctionDeclaration = {\n name: functionName,\n description,\n parameters: jsonSchema as Gemini.Tools.Schema,\n };\n } else if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n geminiFunctionDeclaration = schema as Gemini.Tools.FunctionDeclaration;\n functionName = schema.name;\n } else {\n // We are providing the schema for *just* the parameters\n const parameters = schemaToGeminiParameters(schema);\n geminiFunctionDeclaration = {\n name: functionName,\n description: (schema as { description?: string }).description ?? \"\",\n parameters,\n };\n }\n\n const tools: Gemini.Tool[] = [\n {\n functionDeclarations: [geminiFunctionDeclaration],\n },\n ];\n llm = this.bindTools(tools).withConfig({\n tool_choice: functionName,\n } as Partial<CallOptions>);\n\n outputParser = createFunctionCallingParser(schema, functionName);\n } else {\n throw new ConfigurationError(\n `Unrecognized structured output method '${method}'. Expected 'functionCalling' or 'jsonSchema'`\n );\n }\n\n return assembleStructuredOutputPipeline(\n llm,\n outputParser,\n includeRaw,\n includeRaw\n ? \"ChatGoogleStructuredOutputRunnable\"\n : \"ChatGoogleStructuredOutput\"\n );\n }\n}\n\ntype CombinableFields = Omit<BaseChatGoogleParams, \"model\">;\n\nexport function combineGoogleChatModelFields(\n a: CombinableFields,\n b: CombinableFields,\n ...rest: CombinableFields[]\n): CombinableFields {\n const combined: CombinableFields = {\n temperature: b.temperature ?? a.temperature,\n topP: b.topP ?? a.topP,\n topK: b.topK ?? a.topK,\n maxOutputTokens: b.maxOutputTokens ?? a.maxOutputTokens,\n presencePenalty: b.presencePenalty ?? a.presencePenalty,\n frequencyPenalty: b.frequencyPenalty ?? a.frequencyPenalty,\n stopSequences: b.stopSequences ?? a.stopSequences,\n seed: b.seed ?? a.seed,\n responseLogprobs: b.responseLogprobs ?? a.responseLogprobs,\n logprobs: b.logprobs ?? a.logprobs,\n safetySettings: b.safetySettings ?? a.safetySettings,\n responseSchema: b.responseSchema ?? a.responseSchema,\n tools: b.tools ?? a.tools,\n responseModalities: b.responseModalities ?? a.responseModalities,\n enableEnhancedCivicAnswers:\n b.enableEnhancedCivicAnswers ?? a.enableEnhancedCivicAnswers,\n speechConfig: b.speechConfig ?? a.speechConfig,\n imageConfig: b.imageConfig ?? a.imageConfig,\n mediaResolution: b.mediaResolution ?? a.mediaResolution,\n maxReasoningTokens: b.maxReasoningTokens ?? a.maxReasoningTokens,\n thinkingBudget: b.thinkingBudget ?? a.thinkingBudget,\n reasoningEffort: b.reasoningEffort ?? a.reasoningEffort,\n thinkingLevel: b.thinkingLevel ?? a.thinkingLevel,\n };\n if (rest.length > 0) {\n return combineGoogleChatModelFields(combined, rest[0], ...rest.slice(1));\n }\n return combined;\n}\n\nexport function getGoogleChatModelParams<TParams extends BaseChatGoogleParams>(\n modelOrParams: string | TParams,\n paramsArg?: Omit<TParams, \"model\">\n): TParams {\n const model =\n typeof modelOrParams === \"string\" ? modelOrParams : modelOrParams.model;\n const params = typeof modelOrParams === \"string\" ? paramsArg : modelOrParams;\n return { model, ...params } as TParams;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA2EA,SAAgB,gBACd,UACA,WACoB;AACpB,KAAI,OAAO,aAAa,YACtB,QAAO;UACE,UACT,QAAO;KAEP,QAAO;;AAiEX,IAAsB,iBAAtB,cAEU,cAA2C;CACnD;CAEA;CAEA;CAEA,cAAuB;CAEvB,AAAU;CAEV,AAAU;CAEV,AAAU;CAEV,AAAU;CAEV,AAAU;CAEV,YAAY,AAAU,QAA8B;AAClD,QAAM,OAAO;EADO;AAEpB,OAAK,YAAY,6BAAqC;AAEtD,MAAI,CAAC,OAAO,UACV,OAAM,IAAI,mBACR,6LACD;AAEH,OAAK,YAAY,OAAO;AAExB,OAAK,QAAQ,OAAO;AACpB,OAAK,YAAY,4BAA4B,OAAO;AACpD,OAAK,YAAY,OAAO;AACxB,OAAK,YAAY,OAAO;AACxB,OAAK,cAAc,OAAO;AAE1B,OAAK,mBAAmB,QAAQ,qBAAqB;AACrD,OAAK,YAAY,QAAQ,cAAc;AACvC,MAAI,KAAK,iBAAkB,MAAK,YAAY;AAE5C,MAAI,QAAQ,cAAc,MAAO,MAAK,mBAAmB;AAEzD,OAAK,cAAc,QAAQ,eAAe,KAAK;AAC/C,MAAI,KAAK,iBAAkB,MAAK,cAAc;;CAGhD,WAAmB;AACjB,SAAO;;CAGT,IAAc,eAA+C;AAC3D,SAAO,KAAK;;CAGd,IAAc,WAA+B;AAC3C,SAAO,gBAAgB,KAAK,WAAW,KAAK,UAAU,WAAW,CAAC;;CAGpE,IAAc,kBAA2B;AACvC,SAAO,KAAK,aAAa,SAAS,KAAK,UAAU,WAAW;;CAG9D,IAAc,aAAqB;AACjC,MAAI,OAAO,KAAK,gBAAgB,YAC9B,QAAO,KAAK;WACH,KAAK,aAAa,MAC3B,QAAO;MAEP,QAAO;;CAIX,IAAc,WAAmB;AAC/B,SAAO,KAAK,aAAa;;CAG3B,IAAc,WAAmB;AAC/B,MAAI,OAAO,KAAK,cAAc,YAC5B,QAAO,KAAK;WACH,KAAK,aAAa,MAC3B,QAAO;WACE,KAAK,gBACd,QAAO;WACE,KAAK,aAAa,SAE3B,QAAO;MAEP,QAAO,GAAG,KAAK,SAAS;;CAI5B,IAAc,YAAoB;AAChC,SAAO;;CAGT,IAAc,YAAoB;AAChC,SAAO,KAAK,YAAY,kCAAkC;;;;;;;;;;;;;;;CAgB5D,IAAI,UAAwB;AAC1B,SAAO,SAAS,KAAK,UAAU,EAAE;;CAGnC,MAAgB,eAAe,WAAqC;AAClE,SAAO,WAAW,KAAK,SAAS,GAAG,KAAK,WAAW,UAAU,KAAK,MAAM,GACtE,aAAa,KAAK;;CAItB,MAAgB,sBAAsB,WAAqC;AACzE,SAAO,WAAW,KAAK,SAAS,GAAG,KAAK,WAAW,cACjD,KAAK,UACN,UAAU,KAAK,MAAM,GAAG,aAAa,KAAK;;CAG7C,MAAgB,uBAAuB,WAAqC;EAC1E,MAAM,YAAY,MAAM,KAAK,UAAU,cAAc;AACrD,SAAO,WAAW,KAAK,SAAS,GAC9B,KAAK,WACN,YAAY,UAAU,aAAa,KAAK,SAAS,cAChD,KAAK,UACN,UAAU,KAAK,MAAM,GAAG,aAAa,KAAK;;CAG7C,MAAgB,eAAe,WAAqC;AAClE,MAAI,KAAK,gBACP,QAAO,KAAK,sBAAsB,UAAU;MAE5C,QAAO,KAAK,uBAAuB,UAAU;;CAIjD,MAAgB,SAAS,WAAqC;AAC5D,UAAQ,KAAK,UAAb;GACE,KAAK,MACH,QAAO,KAAK,eAAe,UAAU;GACvC,QACE,QAAO,KAAK,eAAe,UAAU;;;CAI3C,AAAS,iBAAiB,SAAoC;EAC5D,MAAM,SAAS,6BAA6B,KAAK,QAAQ,QAAQ;EAGjE,MAAM,QAAQ,OAAO,QACjB,0BAA0B,OAAO,MAAM,GACvC;EAGJ,MAAM,aAAa,gCACjB,QAAQ,aACR,CAAC,EAAE,SAAS,MAAM,SAAS,GAC5B;EAED,IAAI;EAIJ,IAAI;AAEJ,MAAI,OAAO,gBAAgB;AAEzB,OACE,mBAAmB,OAAO,eAAe,IACzC,qBAAqB,OAAO,eAAe,CAE3C,sBAAqB,aAAa,OAAO,eAAe;OAExD,sBAAqB,OAAO;AAG9B,sBAAmB;;AAGrB,SAAO;GACL,GAAI,SAAS,MAAM,SAAS,IAAI,EAAE,OAAO,GAAG,EAAE;GAC9C,GAAI,aAAa,EAAE,YAAY,GAAG,EAAE;GACpC,gBAAgB,OAAO;GACvB,kBAAkB;IAChB,aAAa,OAAO;IACpB,MAAM,OAAO;IACb,MAAM,OAAO;IACb,iBAAiB,OAAO;IACxB,iBAAiB,OAAO;IACxB,kBAAkB,OAAO;IACzB,eAAe,OAAO;IACtB,GAAI,mBAAmB,EAAE,kBAAkB,GAAG,EAAE;IAChD,GAAI,qBAAqB,EAAE,oBAAoB,GAAG,EAAE;IACpD,GAAI,OAAO,sBAAsB,OAAO,mBAAmB,SAAS,IAChE,EAAE,oBAAoB,OAAO,oBAAoB,GACjD,EAAE;IACN,gBAAgB;IAChB,MAAM,OAAO;IACb,kBAAkB,OAAO;IACzB,UAAU,OAAO;IACjB,GAAI,OAAO,+BAA+B,SACtC,EAAE,4BAA4B,OAAO,4BAA4B,GACjE,EAAE;IACN,gBAAgB,8BAA8B,KAAK,OAAO,OAAO;IACjE,cAAc,4BAA4B,OAAO;IACjD,GAAI,OAAO,cAAc,EAAE,aAAa,OAAO,aAAa,GAAG,EAAE;IACjE,GAAI,OAAO,kBACP,EAAE,iBAAiB,OAAO,iBAAiB,GAC3C,EAAE;IACP;GACF;;CAGH,MAAM,UACJ,UACA,SACA,YACqB;AACrB,MAAI,KAAK,WAAW;GAClB,MAAM,SAAS,MAAM,KAAK,sBACxB,UACA,SACA,WACD;GACD,IAAI,aAAyC;AAC7C,cAAW,MAAM,SAAS,OACxB,cAAa,CAAC,aAAa,QAAQ,OAAO,YAAY,MAAM;AAE9D,OACE,OAAO,YAAY,SAAS,YAAY,YACxC,QACE,YAAY,SAAS,mBACjB,2BACH,SAAS,SAEZ,CACE,WAAW,QAAQ,kBAChB,yBACH,OAAO,WAAW,QAAQ;AAE9B,UAAO,EACL,aAAa,aAAa,CAAC,WAAW,GAAG,EAAE,EAC5C;;EAGH,MAAM,MAAM,MAAM,KAAK,UAAU;EACjC,MAAM,OAAO;GACX,GAAG,KAAK,iBAAiB,QAAQ;GACjC,mBAAmB,yCAAyC,SAAS;GACrE,UAAU,gCAAgC,SAAS;GACpD;EAED,MAAM,aAAa,KAAK,YAAY;AACpC,QAAM,YAAY,kBAAkB,kBAAkB,cAAc;GAClE;GACA;GACD,CAAC;EAEF,MAAM,WAAW,MAAM,KAAK,UAAU,MACpC,IAAI,QAAQ,KAAK;GACf,QAAQ;GACR,SAAS,EACP,gBAAgB,oBACjB;GACD,MAAM,KAAK,UAAU,KAAK;GAC3B,CAAC,CACH;AAED,MAAI,CAAC,SAAS,IAAI;GAChB,MAAM,QAAQ,MAAM,aAAa,aAAa,SAAS;AACvD,SAAM,YAAY,kBAAkB,mBAAmB,cAAc,EACnE,OACD,CAAC;AACF,SAAM;;EAGR,MAAM,OAAuC,MAAM,SAAS,MAAM;AAClE,QAAM,YAAY,kBAAkB,mBAAmB,cAAc;GACnE;GACA,KAAK,SAAS;GACd,SAAS,SAAS;GAClB,QAAQ,SAAS;GACjB,YAAY,SAAS;GACtB,CAAC;AAGF,MAAI,KAAK,gBAAgB,YACvB,OAAM,mBAAmB,mBAAmB,KAAK,eAAe;AAIlE,MAAI,CAAC,KAAK,cAAc,KAAK,WAAW,WAAW,EACjD,OAAM,IAAI,mBAAmB;EAI/B,MAAM,YAAY,KAAK,WAAW;EAClC,MAAM,UAAU,kCAAkC,UAAU;EAG5D,MAAM,OAAO,uBAAuB,QAAQ;EAE5C,MAAM,gBACJ,oDAAoD,KAAK;AAC3D,UAAQ,iBAAiB;AAEzB,SAAO;GACL,aAAa,CACX;IACE;IACA;IACA,gBAAgB;KACd,cAAc,UAAU;KACxB,eAAe,UAAU;KACzB,eAAe,UAAU;KACzB,kBAAkB,UAAU;KAC5B,YAAY,UAAU;KACvB;IACF,CACF;GACD,WAAW;IACT,YAAY;IACZ,OAAO,KAAK;IACZ,YAAY,KAAK;IACjB;IACD;GACF;;CAGH,OAAO,sBACL,UACA,SACA,YACqC;EACrC,MAAM,cAAuB,KAAK,eAAe;EAEjD,MAAM,OAAO;GACX,GAAG,KAAK,iBAAiB,QAAQ;GACjC,mBAAmB,yCAAyC,SAAS;GACrE,UAAU,gCAAgC,SAAS;GACpD;EAED,MAAM,MAAM,MAAM,KAAK,SAAS,gCAAgC;EAChE,MAAM,aAAa,KAAK,YAAY;AACpC,QAAM,YAAY,kBAAkB,kBAAkB,cAAc;GAClE;GACA;GACD,CAAC;EAEF,MAAM,WAAW,MAAM,KAAK,UAAU,MACpC,IAAI,QAAQ,KAAK;GACf,QAAQ;GACR,SAAS,EACP,gBAAgB,oBACjB;GACD,MAAM,KAAK,UAAU,KAAK;GAC1B,QAAQ,QAAQ;GACjB,CAAC,CACH;AAED,QAAM,YAAY,kBAAkB,mBAAmB,cAAc;GACnE,KAAK,SAAS;GACd,SAAS,SAAS;GAClB,QAAQ,SAAS;GACjB,YAAY,SAAS;GACtB,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GAChB,MAAM,QAAQ,MAAM,aAAa,aAAa,SAAS;AACvD,SAAM,YAAY,kBAAkB,mBAAmB,cAAc,EACnE,OACD,CAAC;AACF,SAAM;;AAGR,MAAI,SAAS,MAAM;GACjB,IAAI;GA+FJ,MAAM,SA9FS,SAAS,KACrB,YAAY,IAAI,mBAAmB,CAAC,CACpC,YAAY,IAAI,yBAAyB,CAAC,CAC1C,YACC,IAAI,2BAA2D,CAChE,CACA,YACC,IAAI,gBAGF,EACA,UAAU,OAAO,YAAY;AAE3B,IAAK,YAAY,kBAAkB,gBAAgB,cAAc,EAC/D,OACD,CAAC;AACF,QAAI,UAAU,MAAM;AAClB,gBAAW,QACT,IAAI,oBAAoB;MACtB,MAAM;MACN,SAAS,IAAI,eAAe,EAAE,SAAS,IAAI,CAAC;MAC5C,gBAAgB,EAAE,cAAc,QAAQ;MACzC,CAAC,CACH;AACD;;IAIF,MAAM,YAAY,MAAM,aAAa;AACrC,QAAI,CAAC,UACH;IAGF,MAAM,UAAU,kCAAkC,UAAU;IAC5D,MAAM,OAAO,uBAAuB,QAAQ;IAE5C,MAAM,QAAQ,UAAU,SAAS,SAAS,EAAE;IAC5C,MAAM,YAAY,8BAA8B,MAAM;AAGtD,QAAI,MAAM,SAAS,KAAK,UAAU,cAAc;KAC9C,MAAM,qBAA2C;MAC/C,SAAS,QAAQ;MACjB,YAAY;MACZ,mBAAmB,EACjB,gBAAgB,UACjB;MACD,mBAAmB;OACjB,GAAI,QAAQ,kBAAkB,2BAC1B,EACE,0BACE,QAAQ,kBAAkB,0BAC7B,GACD,EAAE;OACN,GAAI,UAAU,eACV;QACE,cAAc,UAAU;QACxB,eAAe,UAAU;QAC1B,GACD,EAAE;OACP;MACF;AAED,SAAI,OAAO,iBAAiB,aAAa;MACvC,MAAM,aACJ,oDAAoD,MAAM;AAC5D,yBAAmB,iBAAiB,sBAClC,YACA,cACD;AACD,sBAAgB;;KAElB,MAAM,eAAe,IAAI,eAAe,mBAAmB;AAE3D,gBAAW,QACT,IAAI,oBAAoB;MAChB;MACN,SAAS;MACT,gBAAgB;OACd,GAAI,UAAU,gBAAgB;QAC5B,cAAc,UAAU;QACxB,eAAe,UAAU;QAC1B;OACD,GAAI,UAAU,iBAAiB,EAC7B,eAAe,UAAU,eAC1B;OACF;MACF,CAAC,CACH;;MAGN,CAAC,CACH,CAEmB,WAAW;AACjC,OAAI;AACF,WAAO,MAAM;KACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,SAAI,KAAM;AACV,WAAM;AACN,WAAM,YAAY,kBAChB,MAAM,QAAQ,IACd,QACA,QACA,QACA,QACA,EAAE,OAAO,OAAO,CACjB;;aAEK;AACR,WAAO,aAAa;;;;;;;;;;;CAY1B,UACE,OACA,QACsD;AACtD,SAAO,KAAK,WAAW;GACrB,GAAG;GACH;GACD,CAAyB;;;;;;;;;;;;;CAc5B,qBAIE,cAKA,QAMI;EACJ,IAAI;EACJ,IAAI;EAEJ,MAAM,EAAE,QAAQ,MAAM,eAAe;GACnC,GAAG;GACH,QAAQ;GACT;EACD,IAAI,SAAS,QAAQ,UAAU;AAE/B,MAAI,WAAW,YAAY;AACzB,WAAQ,KACN,+EACD;AACD,YAAS;;AAGX,MAAI,WAAW,cAAc;AAE3B,SAAM,KAAK,WAAW,EACpB,gBAAgB,QACjB,CAAyB;AAE1B,kBAAe,eAAe,KAC5B,OAAO,UAA2C;AAChD,QACE,CAAC,UAAU,WAAW,MAAM,IAC5B,CAAC,eAAe,WAAW,MAAM,CAEjC,OAAM,IAAI,qBAAqB,EAC7B,SAAS,gDACV,CAAC;AAGJ,QAAI,CAAC,MAAM,KACT,OAAM,IAAI,qBAAqB,EAC7B,SACE,iEACH,CAAC;AAKJ,WAAO,MADQ,oBAAoB,OAAO,CACtB,MAAM,MAAM,KAAK;KAExC;aACQ,WAAW,mBAAmB;GAEvC,IAAI,eAAe,QAAQ;GAC3B,IAAI;AAEJ,OAAI,mBAAmB,OAAO,IAAI,qBAAqB,OAAO,EAAE;IAC9D,MAAM,aAAa,yBAAyB,OAAO;IACnD,MAAM,cACJ,OAAO,WAAW,gBAAgB,WAC9B,WAAW,cACX;AACN,gCAA4B;KAC1B,MAAM;KACN;KACA,YAAY;KACb;cAED,OAAO,OAAO,SAAS,YACvB,OAAO,OAAO,eAAe,YAC7B,OAAO,cAAc,MACrB;AACA,gCAA4B;AAC5B,mBAAe,OAAO;UACjB;IAEL,MAAM,aAAa,yBAAyB,OAAO;AACnD,gCAA4B;KAC1B,MAAM;KACN,aAAc,OAAoC,eAAe;KACjE;KACD;;GAGH,MAAM,QAAuB,CAC3B,EACE,sBAAsB,CAAC,0BAA0B,EAClD,CACF;AACD,SAAM,KAAK,UAAU,MAAM,CAAC,WAAW,EACrC,aAAa,cACd,CAAyB;AAE1B,kBAAe,4BAA4B,QAAQ,aAAa;QAEhE,OAAM,IAAI,mBACR,0CAA0C,OAAO,+CAClD;AAGH,SAAO,iCACL,KACA,cACA,YACA,aACI,uCACA,6BACL;;;AAML,SAAgB,6BACd,GACA,GACA,GAAG,MACe;CAClB,MAAM,WAA6B;EACjC,aAAa,EAAE,eAAe,EAAE;EAChC,MAAM,EAAE,QAAQ,EAAE;EAClB,MAAM,EAAE,QAAQ,EAAE;EAClB,iBAAiB,EAAE,mBAAmB,EAAE;EACxC,iBAAiB,EAAE,mBAAmB,EAAE;EACxC,kBAAkB,EAAE,oBAAoB,EAAE;EAC1C,eAAe,EAAE,iBAAiB,EAAE;EACpC,MAAM,EAAE,QAAQ,EAAE;EAClB,kBAAkB,EAAE,oBAAoB,EAAE;EAC1C,UAAU,EAAE,YAAY,EAAE;EAC1B,gBAAgB,EAAE,kBAAkB,EAAE;EACtC,gBAAgB,EAAE,kBAAkB,EAAE;EACtC,OAAO,EAAE,SAAS,EAAE;EACpB,oBAAoB,EAAE,sBAAsB,EAAE;EAC9C,4BACE,EAAE,8BAA8B,EAAE;EACpC,cAAc,EAAE,gBAAgB,EAAE;EAClC,aAAa,EAAE,eAAe,EAAE;EAChC,iBAAiB,EAAE,mBAAmB,EAAE;EACxC,oBAAoB,EAAE,sBAAsB,EAAE;EAC9C,gBAAgB,EAAE,kBAAkB,EAAE;EACtC,iBAAiB,EAAE,mBAAmB,EAAE;EACxC,eAAe,EAAE,iBAAiB,EAAE;EACrC;AACD,KAAI,KAAK,SAAS,EAChB,QAAO,6BAA6B,UAAU,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;AAE1E,QAAO;;AAGT,SAAgB,yBACd,eACA,WACS;AAIT,QAAO;EAAE,OAFP,OAAO,kBAAkB,WAAW,gBAAgB,cAAc;EAEpD,GADD,OAAO,kBAAkB,WAAW,YAAY;EACpC"}
@@ -3,6 +3,7 @@ let _langchain_core_utils_json_schema = require("@langchain/core/utils/json_sche
3
3
  let _langchain_core_utils_types = require("@langchain/core/utils/types");
4
4
  let _langchain_core_utils_function_calling = require("@langchain/core/utils/function_calling");
5
5
  let _langchain_core_language_models_base = require("@langchain/core/language_models/base");
6
+ let _langchain_core_utils_standard_schema = require("@langchain/core/utils/standard_schema");
6
7
 
7
8
  //#region src/converters/tools.ts
8
9
  /**
@@ -73,7 +74,7 @@ function removeAdditionalProperties(obj) {
73
74
  * @internal
74
75
  */
75
76
  function schemaToGeminiParameters(schema) {
76
- const { $schema, ...rest } = removeAdditionalProperties((0, _langchain_core_utils_types.isInteropZodSchema)(schema) ? (0, _langchain_core_utils_json_schema.toJsonSchema)(schema) : schema);
77
+ const { $schema, ...rest } = removeAdditionalProperties((0, _langchain_core_utils_types.isInteropZodSchema)(schema) || (0, _langchain_core_utils_standard_schema.isSerializableSchema)(schema) ? (0, _langchain_core_utils_json_schema.toJsonSchema)(schema) : schema);
77
78
  return rest;
78
79
  }
79
80
  /**
@@ -319,7 +320,7 @@ const convertToolsToGeminiTools = (tools) => {
319
320
  * @returns The Gemini tool configuration object, or undefined if no tools are present
320
321
  */
321
322
  function convertToolChoiceToGeminiConfig(toolChoice, hasTools) {
322
- if (!hasTools) return;
323
+ if (!hasTools || toolChoice === void 0) return;
323
324
  let mode;
324
325
  let allowedFunctionNames;
325
326
  let toolChoiceMode;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.cjs","names":["InvalidInputError","InvalidToolError"],"sources":["../../src/converters/tools.ts"],"sourcesContent":["import { isLangChainTool } from \"@langchain/core/utils/function_calling\";\nimport { isOpenAITool } from \"@langchain/core/language_models/base\";\nimport {\n InteropZodType,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n type JsonSchema7Type,\n toJsonSchema,\n} from \"@langchain/core/utils/json_schema\";\nimport { Converter } from \"@langchain/core/utils/format\";\nimport type {\n BindToolsInput,\n ToolChoice,\n} from \"@langchain/core/language_models/chat_models\";\nimport type { Gemini } from \"../chat_models/types.js\";\nimport { InvalidInputError, InvalidToolError } from \"../utils/errors.js\";\n\n/**\n * Adjusts a JSON Schema object type to be compatible with Gemini's function schema format.\n *\n * Gemini's function schema format has specific requirements:\n * - Type must be a string, not an array\n * - Nullable types should use the `nullable` property instead of including \"null\" in a type array\n * - Union types are not supported\n *\n * @param obj - The JSON Schema object to adjust\n * @returns The adjusted object with type converted to Gemini-compatible format\n * @throws {Error} If the type is a union type or null-only type, which Gemini cannot handle\n *\n * @internal\n */\nfunction adjustObjectType(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj: Record<string, any>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, any> {\n if (!Array.isArray(obj.type)) {\n return obj;\n }\n\n const len = obj.type.length;\n const nullIndex = obj.type.indexOf(\"null\");\n if (len === 2 && nullIndex >= 0) {\n // There are only two values set for the type, and one of them is \"null\".\n // Set the type to the other one and set nullable to true.\n const typeIndex = nullIndex === 0 ? 1 : 0;\n obj.type = obj.type[typeIndex];\n obj.nullable = true;\n } else if (len === 1 && nullIndex === 0) {\n // This is nullable only without a type, which doesn't make sense for Gemini\n throw new InvalidInputError(\n \"Gemini does not support null-only types in function schemas. Provide a non-null type alongside nullable.\"\n );\n } else if (len === 1) {\n // Although an array, it has only one value.\n // So set it to the string to match what Gemini expects.\n obj.type = obj?.type[0];\n } else if (len === 0) {\n // Empty type array is invalid\n throw new InvalidInputError(\n \"Gemini does not support empty type arrays in function schemas. Provide at least one type.\"\n );\n } else {\n // Anything else could be a union type, so reject it.\n throw new InvalidInputError(\n \"Gemini does not support union types in function schemas. Use a single type instead.\"\n );\n }\n return obj;\n}\n\n/**\n * Recursively removes unsupported properties from a JSON Schema object to make it\n * compatible with Gemini's function schema format.\n *\n * Gemini's function schema format does not support:\n * - `additionalProperties` property\n * - Array types (must be converted to string types with nullable flag)\n * - Union types\n *\n * @param obj - The JSON Schema object to clean\n * @returns A cleaned GeminiFunctionSchema object\n *\n * @internal\n */\nfunction removeAdditionalProperties(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj: Record<string, any>\n): Gemini.Tools.Schema & { $schema?: string } {\n if (typeof obj === \"object\" && obj !== null) {\n const newObj = { ...obj };\n\n if (\"additionalProperties\" in newObj) {\n delete newObj.additionalProperties;\n }\n\n adjustObjectType(newObj);\n\n for (const key in newObj) {\n if (key in newObj) {\n if (Array.isArray(newObj[key])) {\n newObj[key] = newObj[key].map(removeAdditionalProperties);\n } else if (typeof newObj[key] === \"object\" && newObj[key] !== null) {\n newObj[key] = removeAdditionalProperties(newObj[key]);\n }\n }\n }\n\n return newObj as Gemini.Tools.Schema;\n }\n\n return obj as Gemini.Tools.Schema;\n}\n\n/**\n * Converts a Zod schema or JSON Schema to Gemini function parameters format.\n *\n * This function handles the conversion of schema definitions from various formats\n * (Zod schemas, JSON Schema 7) to Gemini's function schema format. It removes\n * unsupported properties and adjusts type definitions to be compatible with Gemini.\n *\n * @param schema - The schema to convert (Zod schema or JSON Schema 7)\n * @returns A schema object compatible with Gemini's API\n *\n * @internal\n */\nexport function schemaToGeminiParameters<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RunOutput extends Record<string, any> = Record<string, any>\n>(schema: InteropZodType<RunOutput> | JsonSchema7Type): Gemini.Tools.Schema {\n // Gemini doesn't accept either the $schema or additionalProperties\n // attributes, so we need to explicitly remove them.\n // Zod sometimes also makes an array of type (because of .nullish()),\n // which needs cleaning up.\n const jsonSchema = removeAdditionalProperties(\n isInteropZodSchema(schema) ? toJsonSchema(schema) : schema\n );\n const { $schema, ...rest } = jsonSchema;\n\n return rest;\n}\n\n/**\n * Converts a JSON Schema object to Gemini function parameters format.\n *\n * @param schema - The JSON Schema object to convert\n * @returns A schema object compatible with Gemini's API\n *\n * @internal\n */\nfunction jsonSchemaToGeminiParameters(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>\n): Gemini.Tools.Schema {\n const jsonSchema = removeAdditionalProperties(schema);\n const { $schema, ...rest } = jsonSchema;\n\n return rest;\n}\n\n/**\n * Type guard to check if a tool is already in Gemini's native format.\n *\n * Gemini tools can be:\n * - Function declarations (`functionDeclarations`)\n * - Code execution tools (`codeExecution`)\n * - Google Search retrieval tools (`googleSearchRetrieval` or `googleSearch`)\n *\n * The full list of tool types are those defined by the `Gemini.Tool` type.\n * Updating that list requires a change to the `geminiToolAttributes` below.\n *\n * @param tool - The tool to check\n * @returns `true` if the tool is already in Gemini format, `false` otherwise\n *\n * @internal\n */\nfunction isGeminiTool(tool: BindToolsInput): tool is Gemini.Tool {\n if (typeof tool !== \"object\" || tool === null) {\n return false;\n }\n\n const geminiToolAttributes = [\n \"functionDeclarations\",\n \"codeExecution\",\n \"googleSearch\",\n \"urlContext\",\n \"googleMaps\",\n \"fileSearch\",\n \"computerUse\",\n \"mcpServers\",\n ];\n\n return geminiToolAttributes.some((attr) => attr in tool);\n}\n\n/**\n * Converts an array of LangChain tools to Gemini function declarations.\n *\n * This converter transforms various tool formats into Gemini's function declaration\n * format. It supports:\n * - LangChain structured tools (with Zod schemas)\n * - OpenAI format tools (with JSON Schema)\n * - Gemini-native function declarations (passed through)\n * - Raw function declaration objects\n *\n * @remarks\n * The converter handles each tool type differently:\n * - **LangChain tools**: Extracts name, description, and schema, converting the schema\n * to Gemini-compatible format\n * - **OpenAI tools**: Extracts function name, description, and parameters from the\n * OpenAI tool format\n * - **Gemini tools**: If the tool contains `functionDeclarations`, extracts and returns\n * them directly. Non-function Gemini tools (like `codeExecution`) are skipped.\n * - **Raw objects**: Assumes the object is a function declaration and validates it has\n * a `name` property\n *\n * @example\n * ```typescript\n * import { StructuredTool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const weatherTool = new StructuredTool({\n * name: \"get_weather\",\n * description: \"Get the weather for a location\",\n * schema: z.object({\n * location: z.string().describe(\"The city name\"),\n * unit: z.enum([\"celsius\", \"fahrenheit\"]).optional()\n * }),\n * func: async (args) => { /* ... *\\/ }\n * });\n *\n * const declarations = convertToolsToGeminiFunctionDeclarations([weatherTool]);\n * // Returns: [{\n * // name: \"get_weather\",\n * // description: \"Get the weather for a location\",\n * // parameters: {\n * // type: \"object\",\n * // properties: {\n * // location: { type: \"string\", description: \"The city name\" },\n * // unit: { type: \"string\", enum: [\"celsius\", \"fahrenheit\"], nullable: true }\n * // },\n * // required: [\"location\"]\n * // }\n * // }]\n * ```\n *\n * @param tools - Array of tools in various formats (LangChain, OpenAI, or Gemini)\n * @returns Array of Gemini function declarations ready for API submission\n * @throws {Error} If a tool cannot be converted (invalid format)\n */\nexport const convertToolsToGeminiFunctionDeclarations: Converter<\n BindToolsInput[],\n Gemini.Tools.FunctionDeclaration[]\n> = (tools) => {\n const functionDeclarations: Gemini.Tools.FunctionDeclaration[] = [];\n\n for (const tool of tools) {\n // Skip if already in Gemini format (non-function tools)\n if (isGeminiTool(tool) && !(\"functionDeclarations\" in tool)) {\n continue;\n }\n\n // Handle Gemini format with functionDeclarations\n if (\n isGeminiTool(tool) &&\n \"functionDeclarations\" in tool &&\n Array.isArray(tool.functionDeclarations)\n ) {\n functionDeclarations.push(...tool.functionDeclarations);\n continue;\n }\n\n // Handle LangChain structured tools\n if (isLangChainTool(tool)) {\n const jsonSchema = schemaToGeminiParameters(tool.schema);\n functionDeclarations.push({\n name: tool.name,\n description: tool.description ?? `A function available to call.`,\n parameters: jsonSchema,\n });\n continue;\n }\n\n // Handle OpenAI format tools\n if (isOpenAITool(tool)) {\n functionDeclarations.push({\n name: tool.function.name,\n description:\n tool.function.description ?? `A function available to call.`,\n parameters: jsonSchemaToGeminiParameters(tool.function.parameters),\n });\n continue;\n }\n\n // Handle raw function declaration objects\n if (\n typeof tool === \"object\" &&\n tool !== null &&\n \"name\" in tool &&\n typeof tool.name === \"string\"\n ) {\n const funcDecl = tool as Partial<Gemini.Tools.FunctionDeclaration>;\n functionDeclarations.push({\n name: funcDecl.name!,\n description: funcDecl.description ?? `A function available to call.`,\n parameters: funcDecl.parameters,\n });\n continue;\n }\n\n throw new InvalidToolError(tool);\n }\n\n return functionDeclarations;\n};\n\n/**\n * Converts an array of tools to Gemini's Tools array format.\n *\n * This converter groups function declarations into a single tool object while\n * preserving Gemini-native tools (like code execution and Google Search retrieval)\n * as separate tool objects. This matches Gemini's API structure where:\n * - Function declarations are grouped together in a single tool\n * - Non-function tools (codeExecution, googleSearchRetrieval) are separate tools\n *\n * @remarks\n * The conversion process:\n * 1. Separates Gemini-native tools from function declarations\n * 2. Converts LangChain/OpenAI tools to function declarations\n * 3. Groups all function declarations into a single Tool object\n * 4. Returns an array with the grouped function declarations tool plus any\n * non-function Gemini tools\n *\n * @example\n * ```typescript\n * import { StructuredTool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const weatherTool = new StructuredTool({\n * name: \"get_weather\",\n * description: \"Get the weather\",\n * schema: z.object({ location: z.string() }),\n * func: async () => {}\n * });\n *\n * const geminiCodeTool: Gemini.Tool = {\n * codeExecution: { enabled: true }\n * };\n *\n * const tools = convertToolsToGeminiTools([weatherTool, geminiCodeTool]);\n * // Returns: [\n * // { functionDeclarations: [{ name: \"get_weather\", ... }] },\n * // { codeExecution: { enabled: true } }\n * // ]\n * ```\n *\n * @param tools - Array of tools in various formats (LangChain, OpenAI, or Gemini)\n * @returns Array of Tool objects ready for API submission\n */\nexport const convertToolsToGeminiTools: Converter<\n BindToolsInput[],\n Gemini.Tool[]\n> = (tools) => {\n if (tools.length === 0) {\n return [];\n }\n\n const geminiTools: Gemini.Tool[] = [];\n const functionDeclarations: Gemini.Tools.FunctionDeclaration[] = [];\n\n // Separate Gemini-native tools from function declarations\n for (const tool of tools) {\n if (isGeminiTool(tool)) {\n if (\"functionDeclarations\" in tool) {\n // Already a Gemini tool with function declarations\n geminiTools.push(tool);\n } else {\n // Non-function Gemini tool (codeExecution, googleSearch, etc.)\n geminiTools.push(tool);\n }\n } else if (\"googleSearchRetrieval\" in tool) {\n // Convert the obsolete search into the modern one\n const searchTool: Gemini.Tool = {\n googleSearch: {},\n };\n geminiTools.push(searchTool);\n } else {\n // Convert to function declaration\n const funcDecls = convertToolsToGeminiFunctionDeclarations([tool]);\n functionDeclarations.push(...funcDecls);\n }\n }\n\n // Add function declarations as a single tool if we have any\n if (functionDeclarations.length > 0) {\n geminiTools.push({\n functionDeclarations,\n });\n }\n\n return geminiTools;\n};\n\n/**\n * Converts tool choice to Gemini's function calling configuration.\n *\n * This converter transforms LangChain's tool choice format into Gemini's\n * `toolConfig.functionCallingConfig` format. The configuration is only\n * created when tools are present (`hasTools` is true).\n *\n * @remarks\n * The conversion logic:\n * - If `hasTools` is `false`, returns `undefined` (no config needed)\n * - If `toolChoice` is provided, converts it to a Gemini mode:\n * - `\"auto\"` → `\"AUTO\"` - Model decides whether to call functions\n * - `\"any\"` or `\"required\"` → `\"ANY\"` - Model must call at least one function\n * - `\"none\"` → `\"NONE\"` - Model cannot call functions\n * - Function name string → `\"ANY\"` - Forces function use\n * - Object with `mode` → Maps the mode string to Gemini format\n * - Object with `function` → `\"ANY\"` - Forces function use\n * - If `toolChoice` is not provided but tools exist, defaults to `\"AUTO\"`\n *\n * Gemini's function calling modes:\n * - **AUTO**: The model can choose whether to call functions based on the conversation\n * - **ANY**: The model must call at least one function before responding\n * - **NONE**: The model cannot call any functions\n *\n * When a specific function is requested (via function name string or `{ function: { name } }`),\n * the converter uses `\"ANY\"` mode to force function usage, as Gemini doesn't support\n * specifying individual functions in the mode.\n *\n * @example\n * ```typescript\n * // With explicit tool choice\n * convertToolChoiceToGeminiConfig(\"auto\", true);\n * // Returns: { functionCallingConfig: { mode: \"AUTO\" } }\n *\n * // Required mode - must call a function\n * convertToolChoiceToGeminiConfig(\"any\", true);\n * // Returns: { functionCallingConfig: { mode: \"ANY\" } }\n *\n * // Without tool choice (defaults to AUTO when tools exist)\n * convertToolChoiceToGeminiConfig(undefined, true);\n * // Returns: { functionCallingConfig: { mode: \"AUTO\" } }\n *\n * // No tools - returns undefined\n * convertToolChoiceToGeminiConfig(\"auto\", false);\n * // Returns: undefined\n * ```\n *\n * @param toolChoice - The tool choice option from LangChain (string, object, or undefined)\n * @param hasTools - Whether tools are present. If false, returns undefined\n * @returns The Gemini tool configuration object, or undefined if no tools are present\n */\nexport function convertToolChoiceToGeminiConfig(\n toolChoice: ToolChoice | undefined,\n hasTools: boolean\n): Gemini.Tools.ToolConfig | undefined {\n // Only create config if tools are present\n if (!hasTools) {\n return undefined;\n }\n\n // Convert tool_choice to Gemini function calling config mode\n let mode: Gemini.Tools.FunctionCallingConfigMode | undefined;\n let allowedFunctionNames: string[] | undefined;\n\n let toolChoiceMode: string | undefined;\n let toolChoiceFunction: string | string[] | undefined;\n if (typeof toolChoice === \"object\") {\n toolChoiceMode = toolChoice.mode;\n toolChoiceFunction = toolChoice.function?.name;\n } else {\n toolChoiceMode = toolChoice;\n }\n\n if (toolChoiceMode === \"auto\") {\n mode = \"AUTO\";\n } else if (toolChoiceMode === \"any\" || toolChoiceMode === \"required\") {\n mode = \"ANY\";\n } else if (toolChoiceMode === \"none\") {\n mode = \"NONE\";\n } else if (typeof toolChoiceMode === \"string\") {\n // A function name, which is deprecated, but supported\n mode = \"ANY\";\n toolChoiceFunction = toolChoiceMode;\n }\n\n if (toolChoiceFunction) {\n if (Array.isArray(toolChoiceFunction)) {\n allowedFunctionNames = toolChoiceFunction;\n } else {\n allowedFunctionNames = [toolChoiceFunction];\n }\n }\n\n // Build toolConfig: use explicit mode if provided, otherwise default to AUTO\n const functionCallingConfig: Gemini.Tools.FunctionCallingConfig = {};\n if (allowedFunctionNames?.length) {\n functionCallingConfig.allowedFunctionNames = allowedFunctionNames;\n }\n if (mode) {\n functionCallingConfig.mode = mode;\n }\n return {\n functionCallingConfig,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tools.cjs","names":["InvalidInputError","InvalidToolError"],"sources":["../../src/converters/tools.ts"],"sourcesContent":["import { isLangChainTool } from \"@langchain/core/utils/function_calling\";\nimport { isOpenAITool } from \"@langchain/core/language_models/base\";\nimport {\n InteropZodType,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n type JsonSchema7Type,\n toJsonSchema,\n} from \"@langchain/core/utils/json_schema\";\nimport { Converter } from \"@langchain/core/utils/format\";\nimport type {\n BindToolsInput,\n ToolChoice,\n} from \"@langchain/core/language_models/chat_models\";\nimport type { Gemini } from \"../chat_models/types.js\";\nimport { InvalidInputError, InvalidToolError } from \"../utils/errors.js\";\nimport {\n isSerializableSchema,\n SerializableSchema,\n} from \"@langchain/core/utils/standard_schema\";\n\n/**\n * Adjusts a JSON Schema object type to be compatible with Gemini's function schema format.\n *\n * Gemini's function schema format has specific requirements:\n * - Type must be a string, not an array\n * - Nullable types should use the `nullable` property instead of including \"null\" in a type array\n * - Union types are not supported\n *\n * @param obj - The JSON Schema object to adjust\n * @returns The adjusted object with type converted to Gemini-compatible format\n * @throws {Error} If the type is a union type or null-only type, which Gemini cannot handle\n *\n * @internal\n */\nfunction adjustObjectType(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj: Record<string, any>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, any> {\n if (!Array.isArray(obj.type)) {\n return obj;\n }\n\n const len = obj.type.length;\n const nullIndex = obj.type.indexOf(\"null\");\n if (len === 2 && nullIndex >= 0) {\n // There are only two values set for the type, and one of them is \"null\".\n // Set the type to the other one and set nullable to true.\n const typeIndex = nullIndex === 0 ? 1 : 0;\n obj.type = obj.type[typeIndex];\n obj.nullable = true;\n } else if (len === 1 && nullIndex === 0) {\n // This is nullable only without a type, which doesn't make sense for Gemini\n throw new InvalidInputError(\n \"Gemini does not support null-only types in function schemas. Provide a non-null type alongside nullable.\"\n );\n } else if (len === 1) {\n // Although an array, it has only one value.\n // So set it to the string to match what Gemini expects.\n obj.type = obj?.type[0];\n } else if (len === 0) {\n // Empty type array is invalid\n throw new InvalidInputError(\n \"Gemini does not support empty type arrays in function schemas. Provide at least one type.\"\n );\n } else {\n // Anything else could be a union type, so reject it.\n throw new InvalidInputError(\n \"Gemini does not support union types in function schemas. Use a single type instead.\"\n );\n }\n return obj;\n}\n\n/**\n * Recursively removes unsupported properties from a JSON Schema object to make it\n * compatible with Gemini's function schema format.\n *\n * Gemini's function schema format does not support:\n * - `additionalProperties` property\n * - Array types (must be converted to string types with nullable flag)\n * - Union types\n *\n * @param obj - The JSON Schema object to clean\n * @returns A cleaned GeminiFunctionSchema object\n *\n * @internal\n */\nfunction removeAdditionalProperties(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj: Record<string, any>\n): Gemini.Tools.Schema & { $schema?: string } {\n if (typeof obj === \"object\" && obj !== null) {\n const newObj = { ...obj };\n\n if (\"additionalProperties\" in newObj) {\n delete newObj.additionalProperties;\n }\n\n adjustObjectType(newObj);\n\n for (const key in newObj) {\n if (key in newObj) {\n if (Array.isArray(newObj[key])) {\n newObj[key] = newObj[key].map(removeAdditionalProperties);\n } else if (typeof newObj[key] === \"object\" && newObj[key] !== null) {\n newObj[key] = removeAdditionalProperties(newObj[key]);\n }\n }\n }\n\n return newObj as Gemini.Tools.Schema;\n }\n\n return obj as Gemini.Tools.Schema;\n}\n\n/**\n * Converts a Zod schema or JSON Schema to Gemini function parameters format.\n *\n * This function handles the conversion of schema definitions from various formats\n * (Zod schemas, JSON Schema 7) to Gemini's function schema format. It removes\n * unsupported properties and adjusts type definitions to be compatible with Gemini.\n *\n * @param schema - The schema to convert (Zod schema or JSON Schema 7)\n * @returns A schema object compatible with Gemini's API\n *\n * @internal\n */\nexport function schemaToGeminiParameters<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RunOutput extends Record<string, any> = Record<string, any>\n>(\n schema:\n | SerializableSchema<RunOutput>\n | InteropZodType<RunOutput>\n | JsonSchema7Type\n): Gemini.Tools.Schema {\n // Gemini doesn't accept either the $schema or additionalProperties\n // attributes, so we need to explicitly remove them.\n // Zod sometimes also makes an array of type (because of .nullish()),\n // which needs cleaning up.\n const jsonSchema = removeAdditionalProperties(\n isInteropZodSchema(schema) || isSerializableSchema(schema)\n ? toJsonSchema(schema)\n : schema\n );\n const { $schema, ...rest } = jsonSchema;\n return rest;\n}\n\n/**\n * Converts a JSON Schema object to Gemini function parameters format.\n *\n * @param schema - The JSON Schema object to convert\n * @returns A schema object compatible with Gemini's API\n *\n * @internal\n */\nfunction jsonSchemaToGeminiParameters(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>\n): Gemini.Tools.Schema {\n const jsonSchema = removeAdditionalProperties(schema);\n const { $schema, ...rest } = jsonSchema;\n\n return rest;\n}\n\n/**\n * Type guard to check if a tool is already in Gemini's native format.\n *\n * Gemini tools can be:\n * - Function declarations (`functionDeclarations`)\n * - Code execution tools (`codeExecution`)\n * - Google Search retrieval tools (`googleSearchRetrieval` or `googleSearch`)\n *\n * The full list of tool types are those defined by the `Gemini.Tool` type.\n * Updating that list requires a change to the `geminiToolAttributes` below.\n *\n * @param tool - The tool to check\n * @returns `true` if the tool is already in Gemini format, `false` otherwise\n *\n * @internal\n */\nfunction isGeminiTool(tool: BindToolsInput): tool is Gemini.Tool {\n if (typeof tool !== \"object\" || tool === null) {\n return false;\n }\n\n const geminiToolAttributes = [\n \"functionDeclarations\",\n \"codeExecution\",\n \"googleSearch\",\n \"urlContext\",\n \"googleMaps\",\n \"fileSearch\",\n \"computerUse\",\n \"mcpServers\",\n ];\n\n return geminiToolAttributes.some((attr) => attr in tool);\n}\n\n/**\n * Converts an array of LangChain tools to Gemini function declarations.\n *\n * This converter transforms various tool formats into Gemini's function declaration\n * format. It supports:\n * - LangChain structured tools (with Zod schemas)\n * - OpenAI format tools (with JSON Schema)\n * - Gemini-native function declarations (passed through)\n * - Raw function declaration objects\n *\n * @remarks\n * The converter handles each tool type differently:\n * - **LangChain tools**: Extracts name, description, and schema, converting the schema\n * to Gemini-compatible format\n * - **OpenAI tools**: Extracts function name, description, and parameters from the\n * OpenAI tool format\n * - **Gemini tools**: If the tool contains `functionDeclarations`, extracts and returns\n * them directly. Non-function Gemini tools (like `codeExecution`) are skipped.\n * - **Raw objects**: Assumes the object is a function declaration and validates it has\n * a `name` property\n *\n * @example\n * ```typescript\n * import { StructuredTool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const weatherTool = new StructuredTool({\n * name: \"get_weather\",\n * description: \"Get the weather for a location\",\n * schema: z.object({\n * location: z.string().describe(\"The city name\"),\n * unit: z.enum([\"celsius\", \"fahrenheit\"]).optional()\n * }),\n * func: async (args) => { /* ... *\\/ }\n * });\n *\n * const declarations = convertToolsToGeminiFunctionDeclarations([weatherTool]);\n * // Returns: [{\n * // name: \"get_weather\",\n * // description: \"Get the weather for a location\",\n * // parameters: {\n * // type: \"object\",\n * // properties: {\n * // location: { type: \"string\", description: \"The city name\" },\n * // unit: { type: \"string\", enum: [\"celsius\", \"fahrenheit\"], nullable: true }\n * // },\n * // required: [\"location\"]\n * // }\n * // }]\n * ```\n *\n * @param tools - Array of tools in various formats (LangChain, OpenAI, or Gemini)\n * @returns Array of Gemini function declarations ready for API submission\n * @throws {Error} If a tool cannot be converted (invalid format)\n */\nexport const convertToolsToGeminiFunctionDeclarations: Converter<\n BindToolsInput[],\n Gemini.Tools.FunctionDeclaration[]\n> = (tools) => {\n const functionDeclarations: Gemini.Tools.FunctionDeclaration[] = [];\n\n for (const tool of tools) {\n // Skip if already in Gemini format (non-function tools)\n if (isGeminiTool(tool) && !(\"functionDeclarations\" in tool)) {\n continue;\n }\n\n // Handle Gemini format with functionDeclarations\n if (\n isGeminiTool(tool) &&\n \"functionDeclarations\" in tool &&\n Array.isArray(tool.functionDeclarations)\n ) {\n functionDeclarations.push(...tool.functionDeclarations);\n continue;\n }\n\n // Handle LangChain structured tools\n if (isLangChainTool(tool)) {\n const jsonSchema = schemaToGeminiParameters(tool.schema);\n functionDeclarations.push({\n name: tool.name,\n description: tool.description ?? `A function available to call.`,\n parameters: jsonSchema,\n });\n continue;\n }\n\n // Handle OpenAI format tools\n if (isOpenAITool(tool)) {\n functionDeclarations.push({\n name: tool.function.name,\n description:\n tool.function.description ?? `A function available to call.`,\n parameters: jsonSchemaToGeminiParameters(tool.function.parameters),\n });\n continue;\n }\n\n // Handle raw function declaration objects\n if (\n typeof tool === \"object\" &&\n tool !== null &&\n \"name\" in tool &&\n typeof tool.name === \"string\"\n ) {\n const funcDecl = tool as Partial<Gemini.Tools.FunctionDeclaration>;\n functionDeclarations.push({\n name: funcDecl.name!,\n description: funcDecl.description ?? `A function available to call.`,\n parameters: funcDecl.parameters,\n });\n continue;\n }\n\n throw new InvalidToolError(tool);\n }\n\n return functionDeclarations;\n};\n\n/**\n * Converts an array of tools to Gemini's Tools array format.\n *\n * This converter groups function declarations into a single tool object while\n * preserving Gemini-native tools (like code execution and Google Search retrieval)\n * as separate tool objects. This matches Gemini's API structure where:\n * - Function declarations are grouped together in a single tool\n * - Non-function tools (codeExecution, googleSearchRetrieval) are separate tools\n *\n * @remarks\n * The conversion process:\n * 1. Separates Gemini-native tools from function declarations\n * 2. Converts LangChain/OpenAI tools to function declarations\n * 3. Groups all function declarations into a single Tool object\n * 4. Returns an array with the grouped function declarations tool plus any\n * non-function Gemini tools\n *\n * @example\n * ```typescript\n * import { StructuredTool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const weatherTool = new StructuredTool({\n * name: \"get_weather\",\n * description: \"Get the weather\",\n * schema: z.object({ location: z.string() }),\n * func: async () => {}\n * });\n *\n * const geminiCodeTool: Gemini.Tool = {\n * codeExecution: { enabled: true }\n * };\n *\n * const tools = convertToolsToGeminiTools([weatherTool, geminiCodeTool]);\n * // Returns: [\n * // { functionDeclarations: [{ name: \"get_weather\", ... }] },\n * // { codeExecution: { enabled: true } }\n * // ]\n * ```\n *\n * @param tools - Array of tools in various formats (LangChain, OpenAI, or Gemini)\n * @returns Array of Tool objects ready for API submission\n */\nexport const convertToolsToGeminiTools: Converter<\n BindToolsInput[],\n Gemini.Tool[]\n> = (tools) => {\n if (tools.length === 0) {\n return [];\n }\n\n const geminiTools: Gemini.Tool[] = [];\n const functionDeclarations: Gemini.Tools.FunctionDeclaration[] = [];\n\n // Separate Gemini-native tools from function declarations\n for (const tool of tools) {\n if (isGeminiTool(tool)) {\n if (\"functionDeclarations\" in tool) {\n // Already a Gemini tool with function declarations\n geminiTools.push(tool);\n } else {\n // Non-function Gemini tool (codeExecution, googleSearch, etc.)\n geminiTools.push(tool);\n }\n } else if (\"googleSearchRetrieval\" in tool) {\n // Convert the obsolete search into the modern one\n const searchTool: Gemini.Tool = {\n googleSearch: {},\n };\n geminiTools.push(searchTool);\n } else {\n // Convert to function declaration\n const funcDecls = convertToolsToGeminiFunctionDeclarations([tool]);\n functionDeclarations.push(...funcDecls);\n }\n }\n\n // Add function declarations as a single tool if we have any\n if (functionDeclarations.length > 0) {\n geminiTools.push({\n functionDeclarations,\n });\n }\n\n return geminiTools;\n};\n\n/**\n * Converts tool choice to Gemini's function calling configuration.\n *\n * This converter transforms LangChain's tool choice format into Gemini's\n * `toolConfig.functionCallingConfig` format. The configuration is only\n * created when tools are present (`hasTools` is true).\n *\n * @remarks\n * The conversion logic:\n * - If `hasTools` is `false`, returns `undefined` (no config needed)\n * - If `toolChoice` is provided, converts it to a Gemini mode:\n * - `\"auto\"` → `\"AUTO\"` - Model decides whether to call functions\n * - `\"any\"` or `\"required\"` → `\"ANY\"` - Model must call at least one function\n * - `\"none\"` → `\"NONE\"` - Model cannot call functions\n * - Function name string → `\"ANY\"` - Forces function use\n * - Object with `mode` → Maps the mode string to Gemini format\n * - Object with `function` → `\"ANY\"` - Forces function use\n * - If `toolChoice` is not provided but tools exist, defaults to `\"AUTO\"`\n *\n * Gemini's function calling modes:\n * - **AUTO**: The model can choose whether to call functions based on the conversation\n * - **ANY**: The model must call at least one function before responding\n * - **NONE**: The model cannot call any functions\n *\n * When a specific function is requested (via function name string or `{ function: { name } }`),\n * the converter uses `\"ANY\"` mode to force function usage, as Gemini doesn't support\n * specifying individual functions in the mode.\n *\n * @example\n * ```typescript\n * // With explicit tool choice\n * convertToolChoiceToGeminiConfig(\"auto\", true);\n * // Returns: { functionCallingConfig: { mode: \"AUTO\" } }\n *\n * // Required mode - must call a function\n * convertToolChoiceToGeminiConfig(\"any\", true);\n * // Returns: { functionCallingConfig: { mode: \"ANY\" } }\n *\n * // Without tool choice (defaults to AUTO when tools exist)\n * convertToolChoiceToGeminiConfig(undefined, true);\n * // Returns: { functionCallingConfig: { mode: \"AUTO\" } }\n *\n * // No tools - returns undefined\n * convertToolChoiceToGeminiConfig(\"auto\", false);\n * // Returns: undefined\n * ```\n *\n * @param toolChoice - The tool choice option from LangChain (string, object, or undefined)\n * @param hasTools - Whether tools are present. If false, returns undefined\n * @returns The Gemini tool configuration object, or undefined if no tools are present\n */\nexport function convertToolChoiceToGeminiConfig(\n toolChoice: ToolChoice | undefined,\n hasTools: boolean\n): Gemini.Tools.ToolConfig | undefined {\n if (!hasTools || toolChoice === undefined) {\n return undefined;\n }\n\n let mode: Gemini.Tools.FunctionCallingConfigMode | undefined;\n let allowedFunctionNames: string[] | undefined;\n\n let toolChoiceMode: string | undefined;\n let toolChoiceFunction: string | string[] | undefined;\n if (typeof toolChoice === \"object\") {\n toolChoiceMode = toolChoice.mode;\n toolChoiceFunction = toolChoice.function?.name;\n } else {\n toolChoiceMode = toolChoice;\n }\n\n if (toolChoiceMode === \"auto\") {\n mode = \"AUTO\";\n } else if (toolChoiceMode === \"any\" || toolChoiceMode === \"required\") {\n mode = \"ANY\";\n } else if (toolChoiceMode === \"none\") {\n mode = \"NONE\";\n } else if (typeof toolChoiceMode === \"string\") {\n mode = \"ANY\";\n toolChoiceFunction = toolChoiceMode;\n }\n\n if (toolChoiceFunction) {\n if (Array.isArray(toolChoiceFunction)) {\n allowedFunctionNames = toolChoiceFunction;\n } else {\n allowedFunctionNames = [toolChoiceFunction];\n }\n }\n\n const functionCallingConfig: Gemini.Tools.FunctionCallingConfig = {};\n if (allowedFunctionNames?.length) {\n functionCallingConfig.allowedFunctionNames = allowedFunctionNames;\n }\n if (mode) {\n functionCallingConfig.mode = mode;\n }\n return {\n functionCallingConfig,\n };\n}\n"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { toJsonSchema } from "@langchain/core/utils/json_schema";
3
3
  import { isInteropZodSchema } from "@langchain/core/utils/types";
4
4
  import { isLangChainTool } from "@langchain/core/utils/function_calling";
5
5
  import { isOpenAITool } from "@langchain/core/language_models/base";
6
+ import { isSerializableSchema } from "@langchain/core/utils/standard_schema";
6
7
 
7
8
  //#region src/converters/tools.ts
8
9
  /**
@@ -73,7 +74,7 @@ function removeAdditionalProperties(obj) {
73
74
  * @internal
74
75
  */
75
76
  function schemaToGeminiParameters(schema) {
76
- const { $schema, ...rest } = removeAdditionalProperties(isInteropZodSchema(schema) ? toJsonSchema(schema) : schema);
77
+ const { $schema, ...rest } = removeAdditionalProperties(isInteropZodSchema(schema) || isSerializableSchema(schema) ? toJsonSchema(schema) : schema);
77
78
  return rest;
78
79
  }
79
80
  /**
@@ -319,7 +320,7 @@ const convertToolsToGeminiTools = (tools) => {
319
320
  * @returns The Gemini tool configuration object, or undefined if no tools are present
320
321
  */
321
322
  function convertToolChoiceToGeminiConfig(toolChoice, hasTools) {
322
- if (!hasTools) return;
323
+ if (!hasTools || toolChoice === void 0) return;
323
324
  let mode;
324
325
  let allowedFunctionNames;
325
326
  let toolChoiceMode;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","names":[],"sources":["../../src/converters/tools.ts"],"sourcesContent":["import { isLangChainTool } from \"@langchain/core/utils/function_calling\";\nimport { isOpenAITool } from \"@langchain/core/language_models/base\";\nimport {\n InteropZodType,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n type JsonSchema7Type,\n toJsonSchema,\n} from \"@langchain/core/utils/json_schema\";\nimport { Converter } from \"@langchain/core/utils/format\";\nimport type {\n BindToolsInput,\n ToolChoice,\n} from \"@langchain/core/language_models/chat_models\";\nimport type { Gemini } from \"../chat_models/types.js\";\nimport { InvalidInputError, InvalidToolError } from \"../utils/errors.js\";\n\n/**\n * Adjusts a JSON Schema object type to be compatible with Gemini's function schema format.\n *\n * Gemini's function schema format has specific requirements:\n * - Type must be a string, not an array\n * - Nullable types should use the `nullable` property instead of including \"null\" in a type array\n * - Union types are not supported\n *\n * @param obj - The JSON Schema object to adjust\n * @returns The adjusted object with type converted to Gemini-compatible format\n * @throws {Error} If the type is a union type or null-only type, which Gemini cannot handle\n *\n * @internal\n */\nfunction adjustObjectType(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj: Record<string, any>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, any> {\n if (!Array.isArray(obj.type)) {\n return obj;\n }\n\n const len = obj.type.length;\n const nullIndex = obj.type.indexOf(\"null\");\n if (len === 2 && nullIndex >= 0) {\n // There are only two values set for the type, and one of them is \"null\".\n // Set the type to the other one and set nullable to true.\n const typeIndex = nullIndex === 0 ? 1 : 0;\n obj.type = obj.type[typeIndex];\n obj.nullable = true;\n } else if (len === 1 && nullIndex === 0) {\n // This is nullable only without a type, which doesn't make sense for Gemini\n throw new InvalidInputError(\n \"Gemini does not support null-only types in function schemas. Provide a non-null type alongside nullable.\"\n );\n } else if (len === 1) {\n // Although an array, it has only one value.\n // So set it to the string to match what Gemini expects.\n obj.type = obj?.type[0];\n } else if (len === 0) {\n // Empty type array is invalid\n throw new InvalidInputError(\n \"Gemini does not support empty type arrays in function schemas. Provide at least one type.\"\n );\n } else {\n // Anything else could be a union type, so reject it.\n throw new InvalidInputError(\n \"Gemini does not support union types in function schemas. Use a single type instead.\"\n );\n }\n return obj;\n}\n\n/**\n * Recursively removes unsupported properties from a JSON Schema object to make it\n * compatible with Gemini's function schema format.\n *\n * Gemini's function schema format does not support:\n * - `additionalProperties` property\n * - Array types (must be converted to string types with nullable flag)\n * - Union types\n *\n * @param obj - The JSON Schema object to clean\n * @returns A cleaned GeminiFunctionSchema object\n *\n * @internal\n */\nfunction removeAdditionalProperties(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj: Record<string, any>\n): Gemini.Tools.Schema & { $schema?: string } {\n if (typeof obj === \"object\" && obj !== null) {\n const newObj = { ...obj };\n\n if (\"additionalProperties\" in newObj) {\n delete newObj.additionalProperties;\n }\n\n adjustObjectType(newObj);\n\n for (const key in newObj) {\n if (key in newObj) {\n if (Array.isArray(newObj[key])) {\n newObj[key] = newObj[key].map(removeAdditionalProperties);\n } else if (typeof newObj[key] === \"object\" && newObj[key] !== null) {\n newObj[key] = removeAdditionalProperties(newObj[key]);\n }\n }\n }\n\n return newObj as Gemini.Tools.Schema;\n }\n\n return obj as Gemini.Tools.Schema;\n}\n\n/**\n * Converts a Zod schema or JSON Schema to Gemini function parameters format.\n *\n * This function handles the conversion of schema definitions from various formats\n * (Zod schemas, JSON Schema 7) to Gemini's function schema format. It removes\n * unsupported properties and adjusts type definitions to be compatible with Gemini.\n *\n * @param schema - The schema to convert (Zod schema or JSON Schema 7)\n * @returns A schema object compatible with Gemini's API\n *\n * @internal\n */\nexport function schemaToGeminiParameters<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RunOutput extends Record<string, any> = Record<string, any>\n>(schema: InteropZodType<RunOutput> | JsonSchema7Type): Gemini.Tools.Schema {\n // Gemini doesn't accept either the $schema or additionalProperties\n // attributes, so we need to explicitly remove them.\n // Zod sometimes also makes an array of type (because of .nullish()),\n // which needs cleaning up.\n const jsonSchema = removeAdditionalProperties(\n isInteropZodSchema(schema) ? toJsonSchema(schema) : schema\n );\n const { $schema, ...rest } = jsonSchema;\n\n return rest;\n}\n\n/**\n * Converts a JSON Schema object to Gemini function parameters format.\n *\n * @param schema - The JSON Schema object to convert\n * @returns A schema object compatible with Gemini's API\n *\n * @internal\n */\nfunction jsonSchemaToGeminiParameters(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>\n): Gemini.Tools.Schema {\n const jsonSchema = removeAdditionalProperties(schema);\n const { $schema, ...rest } = jsonSchema;\n\n return rest;\n}\n\n/**\n * Type guard to check if a tool is already in Gemini's native format.\n *\n * Gemini tools can be:\n * - Function declarations (`functionDeclarations`)\n * - Code execution tools (`codeExecution`)\n * - Google Search retrieval tools (`googleSearchRetrieval` or `googleSearch`)\n *\n * The full list of tool types are those defined by the `Gemini.Tool` type.\n * Updating that list requires a change to the `geminiToolAttributes` below.\n *\n * @param tool - The tool to check\n * @returns `true` if the tool is already in Gemini format, `false` otherwise\n *\n * @internal\n */\nfunction isGeminiTool(tool: BindToolsInput): tool is Gemini.Tool {\n if (typeof tool !== \"object\" || tool === null) {\n return false;\n }\n\n const geminiToolAttributes = [\n \"functionDeclarations\",\n \"codeExecution\",\n \"googleSearch\",\n \"urlContext\",\n \"googleMaps\",\n \"fileSearch\",\n \"computerUse\",\n \"mcpServers\",\n ];\n\n return geminiToolAttributes.some((attr) => attr in tool);\n}\n\n/**\n * Converts an array of LangChain tools to Gemini function declarations.\n *\n * This converter transforms various tool formats into Gemini's function declaration\n * format. It supports:\n * - LangChain structured tools (with Zod schemas)\n * - OpenAI format tools (with JSON Schema)\n * - Gemini-native function declarations (passed through)\n * - Raw function declaration objects\n *\n * @remarks\n * The converter handles each tool type differently:\n * - **LangChain tools**: Extracts name, description, and schema, converting the schema\n * to Gemini-compatible format\n * - **OpenAI tools**: Extracts function name, description, and parameters from the\n * OpenAI tool format\n * - **Gemini tools**: If the tool contains `functionDeclarations`, extracts and returns\n * them directly. Non-function Gemini tools (like `codeExecution`) are skipped.\n * - **Raw objects**: Assumes the object is a function declaration and validates it has\n * a `name` property\n *\n * @example\n * ```typescript\n * import { StructuredTool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const weatherTool = new StructuredTool({\n * name: \"get_weather\",\n * description: \"Get the weather for a location\",\n * schema: z.object({\n * location: z.string().describe(\"The city name\"),\n * unit: z.enum([\"celsius\", \"fahrenheit\"]).optional()\n * }),\n * func: async (args) => { /* ... *\\/ }\n * });\n *\n * const declarations = convertToolsToGeminiFunctionDeclarations([weatherTool]);\n * // Returns: [{\n * // name: \"get_weather\",\n * // description: \"Get the weather for a location\",\n * // parameters: {\n * // type: \"object\",\n * // properties: {\n * // location: { type: \"string\", description: \"The city name\" },\n * // unit: { type: \"string\", enum: [\"celsius\", \"fahrenheit\"], nullable: true }\n * // },\n * // required: [\"location\"]\n * // }\n * // }]\n * ```\n *\n * @param tools - Array of tools in various formats (LangChain, OpenAI, or Gemini)\n * @returns Array of Gemini function declarations ready for API submission\n * @throws {Error} If a tool cannot be converted (invalid format)\n */\nexport const convertToolsToGeminiFunctionDeclarations: Converter<\n BindToolsInput[],\n Gemini.Tools.FunctionDeclaration[]\n> = (tools) => {\n const functionDeclarations: Gemini.Tools.FunctionDeclaration[] = [];\n\n for (const tool of tools) {\n // Skip if already in Gemini format (non-function tools)\n if (isGeminiTool(tool) && !(\"functionDeclarations\" in tool)) {\n continue;\n }\n\n // Handle Gemini format with functionDeclarations\n if (\n isGeminiTool(tool) &&\n \"functionDeclarations\" in tool &&\n Array.isArray(tool.functionDeclarations)\n ) {\n functionDeclarations.push(...tool.functionDeclarations);\n continue;\n }\n\n // Handle LangChain structured tools\n if (isLangChainTool(tool)) {\n const jsonSchema = schemaToGeminiParameters(tool.schema);\n functionDeclarations.push({\n name: tool.name,\n description: tool.description ?? `A function available to call.`,\n parameters: jsonSchema,\n });\n continue;\n }\n\n // Handle OpenAI format tools\n if (isOpenAITool(tool)) {\n functionDeclarations.push({\n name: tool.function.name,\n description:\n tool.function.description ?? `A function available to call.`,\n parameters: jsonSchemaToGeminiParameters(tool.function.parameters),\n });\n continue;\n }\n\n // Handle raw function declaration objects\n if (\n typeof tool === \"object\" &&\n tool !== null &&\n \"name\" in tool &&\n typeof tool.name === \"string\"\n ) {\n const funcDecl = tool as Partial<Gemini.Tools.FunctionDeclaration>;\n functionDeclarations.push({\n name: funcDecl.name!,\n description: funcDecl.description ?? `A function available to call.`,\n parameters: funcDecl.parameters,\n });\n continue;\n }\n\n throw new InvalidToolError(tool);\n }\n\n return functionDeclarations;\n};\n\n/**\n * Converts an array of tools to Gemini's Tools array format.\n *\n * This converter groups function declarations into a single tool object while\n * preserving Gemini-native tools (like code execution and Google Search retrieval)\n * as separate tool objects. This matches Gemini's API structure where:\n * - Function declarations are grouped together in a single tool\n * - Non-function tools (codeExecution, googleSearchRetrieval) are separate tools\n *\n * @remarks\n * The conversion process:\n * 1. Separates Gemini-native tools from function declarations\n * 2. Converts LangChain/OpenAI tools to function declarations\n * 3. Groups all function declarations into a single Tool object\n * 4. Returns an array with the grouped function declarations tool plus any\n * non-function Gemini tools\n *\n * @example\n * ```typescript\n * import { StructuredTool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const weatherTool = new StructuredTool({\n * name: \"get_weather\",\n * description: \"Get the weather\",\n * schema: z.object({ location: z.string() }),\n * func: async () => {}\n * });\n *\n * const geminiCodeTool: Gemini.Tool = {\n * codeExecution: { enabled: true }\n * };\n *\n * const tools = convertToolsToGeminiTools([weatherTool, geminiCodeTool]);\n * // Returns: [\n * // { functionDeclarations: [{ name: \"get_weather\", ... }] },\n * // { codeExecution: { enabled: true } }\n * // ]\n * ```\n *\n * @param tools - Array of tools in various formats (LangChain, OpenAI, or Gemini)\n * @returns Array of Tool objects ready for API submission\n */\nexport const convertToolsToGeminiTools: Converter<\n BindToolsInput[],\n Gemini.Tool[]\n> = (tools) => {\n if (tools.length === 0) {\n return [];\n }\n\n const geminiTools: Gemini.Tool[] = [];\n const functionDeclarations: Gemini.Tools.FunctionDeclaration[] = [];\n\n // Separate Gemini-native tools from function declarations\n for (const tool of tools) {\n if (isGeminiTool(tool)) {\n if (\"functionDeclarations\" in tool) {\n // Already a Gemini tool with function declarations\n geminiTools.push(tool);\n } else {\n // Non-function Gemini tool (codeExecution, googleSearch, etc.)\n geminiTools.push(tool);\n }\n } else if (\"googleSearchRetrieval\" in tool) {\n // Convert the obsolete search into the modern one\n const searchTool: Gemini.Tool = {\n googleSearch: {},\n };\n geminiTools.push(searchTool);\n } else {\n // Convert to function declaration\n const funcDecls = convertToolsToGeminiFunctionDeclarations([tool]);\n functionDeclarations.push(...funcDecls);\n }\n }\n\n // Add function declarations as a single tool if we have any\n if (functionDeclarations.length > 0) {\n geminiTools.push({\n functionDeclarations,\n });\n }\n\n return geminiTools;\n};\n\n/**\n * Converts tool choice to Gemini's function calling configuration.\n *\n * This converter transforms LangChain's tool choice format into Gemini's\n * `toolConfig.functionCallingConfig` format. The configuration is only\n * created when tools are present (`hasTools` is true).\n *\n * @remarks\n * The conversion logic:\n * - If `hasTools` is `false`, returns `undefined` (no config needed)\n * - If `toolChoice` is provided, converts it to a Gemini mode:\n * - `\"auto\"` → `\"AUTO\"` - Model decides whether to call functions\n * - `\"any\"` or `\"required\"` → `\"ANY\"` - Model must call at least one function\n * - `\"none\"` → `\"NONE\"` - Model cannot call functions\n * - Function name string → `\"ANY\"` - Forces function use\n * - Object with `mode` → Maps the mode string to Gemini format\n * - Object with `function` → `\"ANY\"` - Forces function use\n * - If `toolChoice` is not provided but tools exist, defaults to `\"AUTO\"`\n *\n * Gemini's function calling modes:\n * - **AUTO**: The model can choose whether to call functions based on the conversation\n * - **ANY**: The model must call at least one function before responding\n * - **NONE**: The model cannot call any functions\n *\n * When a specific function is requested (via function name string or `{ function: { name } }`),\n * the converter uses `\"ANY\"` mode to force function usage, as Gemini doesn't support\n * specifying individual functions in the mode.\n *\n * @example\n * ```typescript\n * // With explicit tool choice\n * convertToolChoiceToGeminiConfig(\"auto\", true);\n * // Returns: { functionCallingConfig: { mode: \"AUTO\" } }\n *\n * // Required mode - must call a function\n * convertToolChoiceToGeminiConfig(\"any\", true);\n * // Returns: { functionCallingConfig: { mode: \"ANY\" } }\n *\n * // Without tool choice (defaults to AUTO when tools exist)\n * convertToolChoiceToGeminiConfig(undefined, true);\n * // Returns: { functionCallingConfig: { mode: \"AUTO\" } }\n *\n * // No tools - returns undefined\n * convertToolChoiceToGeminiConfig(\"auto\", false);\n * // Returns: undefined\n * ```\n *\n * @param toolChoice - The tool choice option from LangChain (string, object, or undefined)\n * @param hasTools - Whether tools are present. If false, returns undefined\n * @returns The Gemini tool configuration object, or undefined if no tools are present\n */\nexport function convertToolChoiceToGeminiConfig(\n toolChoice: ToolChoice | undefined,\n hasTools: boolean\n): Gemini.Tools.ToolConfig | undefined {\n // Only create config if tools are present\n if (!hasTools) {\n return undefined;\n }\n\n // Convert tool_choice to Gemini function calling config mode\n let mode: Gemini.Tools.FunctionCallingConfigMode | undefined;\n let allowedFunctionNames: string[] | undefined;\n\n let toolChoiceMode: string | undefined;\n let toolChoiceFunction: string | string[] | undefined;\n if (typeof toolChoice === \"object\") {\n toolChoiceMode = toolChoice.mode;\n toolChoiceFunction = toolChoice.function?.name;\n } else {\n toolChoiceMode = toolChoice;\n }\n\n if (toolChoiceMode === \"auto\") {\n mode = \"AUTO\";\n } else if (toolChoiceMode === \"any\" || toolChoiceMode === \"required\") {\n mode = \"ANY\";\n } else if (toolChoiceMode === \"none\") {\n mode = \"NONE\";\n } else if (typeof toolChoiceMode === \"string\") {\n // A function name, which is deprecated, but supported\n mode = \"ANY\";\n toolChoiceFunction = toolChoiceMode;\n }\n\n if (toolChoiceFunction) {\n if (Array.isArray(toolChoiceFunction)) {\n allowedFunctionNames = toolChoiceFunction;\n } else {\n allowedFunctionNames = [toolChoiceFunction];\n }\n }\n\n // Build toolConfig: use explicit mode if provided, otherwise default to AUTO\n const functionCallingConfig: Gemini.Tools.FunctionCallingConfig = {};\n if (allowedFunctionNames?.length) {\n functionCallingConfig.allowedFunctionNames = allowedFunctionNames;\n }\n if (mode) {\n functionCallingConfig.mode = mode;\n }\n return {\n functionCallingConfig,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","names":[],"sources":["../../src/converters/tools.ts"],"sourcesContent":["import { isLangChainTool } from \"@langchain/core/utils/function_calling\";\nimport { isOpenAITool } from \"@langchain/core/language_models/base\";\nimport {\n InteropZodType,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n type JsonSchema7Type,\n toJsonSchema,\n} from \"@langchain/core/utils/json_schema\";\nimport { Converter } from \"@langchain/core/utils/format\";\nimport type {\n BindToolsInput,\n ToolChoice,\n} from \"@langchain/core/language_models/chat_models\";\nimport type { Gemini } from \"../chat_models/types.js\";\nimport { InvalidInputError, InvalidToolError } from \"../utils/errors.js\";\nimport {\n isSerializableSchema,\n SerializableSchema,\n} from \"@langchain/core/utils/standard_schema\";\n\n/**\n * Adjusts a JSON Schema object type to be compatible with Gemini's function schema format.\n *\n * Gemini's function schema format has specific requirements:\n * - Type must be a string, not an array\n * - Nullable types should use the `nullable` property instead of including \"null\" in a type array\n * - Union types are not supported\n *\n * @param obj - The JSON Schema object to adjust\n * @returns The adjusted object with type converted to Gemini-compatible format\n * @throws {Error} If the type is a union type or null-only type, which Gemini cannot handle\n *\n * @internal\n */\nfunction adjustObjectType(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj: Record<string, any>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, any> {\n if (!Array.isArray(obj.type)) {\n return obj;\n }\n\n const len = obj.type.length;\n const nullIndex = obj.type.indexOf(\"null\");\n if (len === 2 && nullIndex >= 0) {\n // There are only two values set for the type, and one of them is \"null\".\n // Set the type to the other one and set nullable to true.\n const typeIndex = nullIndex === 0 ? 1 : 0;\n obj.type = obj.type[typeIndex];\n obj.nullable = true;\n } else if (len === 1 && nullIndex === 0) {\n // This is nullable only without a type, which doesn't make sense for Gemini\n throw new InvalidInputError(\n \"Gemini does not support null-only types in function schemas. Provide a non-null type alongside nullable.\"\n );\n } else if (len === 1) {\n // Although an array, it has only one value.\n // So set it to the string to match what Gemini expects.\n obj.type = obj?.type[0];\n } else if (len === 0) {\n // Empty type array is invalid\n throw new InvalidInputError(\n \"Gemini does not support empty type arrays in function schemas. Provide at least one type.\"\n );\n } else {\n // Anything else could be a union type, so reject it.\n throw new InvalidInputError(\n \"Gemini does not support union types in function schemas. Use a single type instead.\"\n );\n }\n return obj;\n}\n\n/**\n * Recursively removes unsupported properties from a JSON Schema object to make it\n * compatible with Gemini's function schema format.\n *\n * Gemini's function schema format does not support:\n * - `additionalProperties` property\n * - Array types (must be converted to string types with nullable flag)\n * - Union types\n *\n * @param obj - The JSON Schema object to clean\n * @returns A cleaned GeminiFunctionSchema object\n *\n * @internal\n */\nfunction removeAdditionalProperties(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj: Record<string, any>\n): Gemini.Tools.Schema & { $schema?: string } {\n if (typeof obj === \"object\" && obj !== null) {\n const newObj = { ...obj };\n\n if (\"additionalProperties\" in newObj) {\n delete newObj.additionalProperties;\n }\n\n adjustObjectType(newObj);\n\n for (const key in newObj) {\n if (key in newObj) {\n if (Array.isArray(newObj[key])) {\n newObj[key] = newObj[key].map(removeAdditionalProperties);\n } else if (typeof newObj[key] === \"object\" && newObj[key] !== null) {\n newObj[key] = removeAdditionalProperties(newObj[key]);\n }\n }\n }\n\n return newObj as Gemini.Tools.Schema;\n }\n\n return obj as Gemini.Tools.Schema;\n}\n\n/**\n * Converts a Zod schema or JSON Schema to Gemini function parameters format.\n *\n * This function handles the conversion of schema definitions from various formats\n * (Zod schemas, JSON Schema 7) to Gemini's function schema format. It removes\n * unsupported properties and adjusts type definitions to be compatible with Gemini.\n *\n * @param schema - The schema to convert (Zod schema or JSON Schema 7)\n * @returns A schema object compatible with Gemini's API\n *\n * @internal\n */\nexport function schemaToGeminiParameters<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RunOutput extends Record<string, any> = Record<string, any>\n>(\n schema:\n | SerializableSchema<RunOutput>\n | InteropZodType<RunOutput>\n | JsonSchema7Type\n): Gemini.Tools.Schema {\n // Gemini doesn't accept either the $schema or additionalProperties\n // attributes, so we need to explicitly remove them.\n // Zod sometimes also makes an array of type (because of .nullish()),\n // which needs cleaning up.\n const jsonSchema = removeAdditionalProperties(\n isInteropZodSchema(schema) || isSerializableSchema(schema)\n ? toJsonSchema(schema)\n : schema\n );\n const { $schema, ...rest } = jsonSchema;\n return rest;\n}\n\n/**\n * Converts a JSON Schema object to Gemini function parameters format.\n *\n * @param schema - The JSON Schema object to convert\n * @returns A schema object compatible with Gemini's API\n *\n * @internal\n */\nfunction jsonSchemaToGeminiParameters(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>\n): Gemini.Tools.Schema {\n const jsonSchema = removeAdditionalProperties(schema);\n const { $schema, ...rest } = jsonSchema;\n\n return rest;\n}\n\n/**\n * Type guard to check if a tool is already in Gemini's native format.\n *\n * Gemini tools can be:\n * - Function declarations (`functionDeclarations`)\n * - Code execution tools (`codeExecution`)\n * - Google Search retrieval tools (`googleSearchRetrieval` or `googleSearch`)\n *\n * The full list of tool types are those defined by the `Gemini.Tool` type.\n * Updating that list requires a change to the `geminiToolAttributes` below.\n *\n * @param tool - The tool to check\n * @returns `true` if the tool is already in Gemini format, `false` otherwise\n *\n * @internal\n */\nfunction isGeminiTool(tool: BindToolsInput): tool is Gemini.Tool {\n if (typeof tool !== \"object\" || tool === null) {\n return false;\n }\n\n const geminiToolAttributes = [\n \"functionDeclarations\",\n \"codeExecution\",\n \"googleSearch\",\n \"urlContext\",\n \"googleMaps\",\n \"fileSearch\",\n \"computerUse\",\n \"mcpServers\",\n ];\n\n return geminiToolAttributes.some((attr) => attr in tool);\n}\n\n/**\n * Converts an array of LangChain tools to Gemini function declarations.\n *\n * This converter transforms various tool formats into Gemini's function declaration\n * format. It supports:\n * - LangChain structured tools (with Zod schemas)\n * - OpenAI format tools (with JSON Schema)\n * - Gemini-native function declarations (passed through)\n * - Raw function declaration objects\n *\n * @remarks\n * The converter handles each tool type differently:\n * - **LangChain tools**: Extracts name, description, and schema, converting the schema\n * to Gemini-compatible format\n * - **OpenAI tools**: Extracts function name, description, and parameters from the\n * OpenAI tool format\n * - **Gemini tools**: If the tool contains `functionDeclarations`, extracts and returns\n * them directly. Non-function Gemini tools (like `codeExecution`) are skipped.\n * - **Raw objects**: Assumes the object is a function declaration and validates it has\n * a `name` property\n *\n * @example\n * ```typescript\n * import { StructuredTool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const weatherTool = new StructuredTool({\n * name: \"get_weather\",\n * description: \"Get the weather for a location\",\n * schema: z.object({\n * location: z.string().describe(\"The city name\"),\n * unit: z.enum([\"celsius\", \"fahrenheit\"]).optional()\n * }),\n * func: async (args) => { /* ... *\\/ }\n * });\n *\n * const declarations = convertToolsToGeminiFunctionDeclarations([weatherTool]);\n * // Returns: [{\n * // name: \"get_weather\",\n * // description: \"Get the weather for a location\",\n * // parameters: {\n * // type: \"object\",\n * // properties: {\n * // location: { type: \"string\", description: \"The city name\" },\n * // unit: { type: \"string\", enum: [\"celsius\", \"fahrenheit\"], nullable: true }\n * // },\n * // required: [\"location\"]\n * // }\n * // }]\n * ```\n *\n * @param tools - Array of tools in various formats (LangChain, OpenAI, or Gemini)\n * @returns Array of Gemini function declarations ready for API submission\n * @throws {Error} If a tool cannot be converted (invalid format)\n */\nexport const convertToolsToGeminiFunctionDeclarations: Converter<\n BindToolsInput[],\n Gemini.Tools.FunctionDeclaration[]\n> = (tools) => {\n const functionDeclarations: Gemini.Tools.FunctionDeclaration[] = [];\n\n for (const tool of tools) {\n // Skip if already in Gemini format (non-function tools)\n if (isGeminiTool(tool) && !(\"functionDeclarations\" in tool)) {\n continue;\n }\n\n // Handle Gemini format with functionDeclarations\n if (\n isGeminiTool(tool) &&\n \"functionDeclarations\" in tool &&\n Array.isArray(tool.functionDeclarations)\n ) {\n functionDeclarations.push(...tool.functionDeclarations);\n continue;\n }\n\n // Handle LangChain structured tools\n if (isLangChainTool(tool)) {\n const jsonSchema = schemaToGeminiParameters(tool.schema);\n functionDeclarations.push({\n name: tool.name,\n description: tool.description ?? `A function available to call.`,\n parameters: jsonSchema,\n });\n continue;\n }\n\n // Handle OpenAI format tools\n if (isOpenAITool(tool)) {\n functionDeclarations.push({\n name: tool.function.name,\n description:\n tool.function.description ?? `A function available to call.`,\n parameters: jsonSchemaToGeminiParameters(tool.function.parameters),\n });\n continue;\n }\n\n // Handle raw function declaration objects\n if (\n typeof tool === \"object\" &&\n tool !== null &&\n \"name\" in tool &&\n typeof tool.name === \"string\"\n ) {\n const funcDecl = tool as Partial<Gemini.Tools.FunctionDeclaration>;\n functionDeclarations.push({\n name: funcDecl.name!,\n description: funcDecl.description ?? `A function available to call.`,\n parameters: funcDecl.parameters,\n });\n continue;\n }\n\n throw new InvalidToolError(tool);\n }\n\n return functionDeclarations;\n};\n\n/**\n * Converts an array of tools to Gemini's Tools array format.\n *\n * This converter groups function declarations into a single tool object while\n * preserving Gemini-native tools (like code execution and Google Search retrieval)\n * as separate tool objects. This matches Gemini's API structure where:\n * - Function declarations are grouped together in a single tool\n * - Non-function tools (codeExecution, googleSearchRetrieval) are separate tools\n *\n * @remarks\n * The conversion process:\n * 1. Separates Gemini-native tools from function declarations\n * 2. Converts LangChain/OpenAI tools to function declarations\n * 3. Groups all function declarations into a single Tool object\n * 4. Returns an array with the grouped function declarations tool plus any\n * non-function Gemini tools\n *\n * @example\n * ```typescript\n * import { StructuredTool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const weatherTool = new StructuredTool({\n * name: \"get_weather\",\n * description: \"Get the weather\",\n * schema: z.object({ location: z.string() }),\n * func: async () => {}\n * });\n *\n * const geminiCodeTool: Gemini.Tool = {\n * codeExecution: { enabled: true }\n * };\n *\n * const tools = convertToolsToGeminiTools([weatherTool, geminiCodeTool]);\n * // Returns: [\n * // { functionDeclarations: [{ name: \"get_weather\", ... }] },\n * // { codeExecution: { enabled: true } }\n * // ]\n * ```\n *\n * @param tools - Array of tools in various formats (LangChain, OpenAI, or Gemini)\n * @returns Array of Tool objects ready for API submission\n */\nexport const convertToolsToGeminiTools: Converter<\n BindToolsInput[],\n Gemini.Tool[]\n> = (tools) => {\n if (tools.length === 0) {\n return [];\n }\n\n const geminiTools: Gemini.Tool[] = [];\n const functionDeclarations: Gemini.Tools.FunctionDeclaration[] = [];\n\n // Separate Gemini-native tools from function declarations\n for (const tool of tools) {\n if (isGeminiTool(tool)) {\n if (\"functionDeclarations\" in tool) {\n // Already a Gemini tool with function declarations\n geminiTools.push(tool);\n } else {\n // Non-function Gemini tool (codeExecution, googleSearch, etc.)\n geminiTools.push(tool);\n }\n } else if (\"googleSearchRetrieval\" in tool) {\n // Convert the obsolete search into the modern one\n const searchTool: Gemini.Tool = {\n googleSearch: {},\n };\n geminiTools.push(searchTool);\n } else {\n // Convert to function declaration\n const funcDecls = convertToolsToGeminiFunctionDeclarations([tool]);\n functionDeclarations.push(...funcDecls);\n }\n }\n\n // Add function declarations as a single tool if we have any\n if (functionDeclarations.length > 0) {\n geminiTools.push({\n functionDeclarations,\n });\n }\n\n return geminiTools;\n};\n\n/**\n * Converts tool choice to Gemini's function calling configuration.\n *\n * This converter transforms LangChain's tool choice format into Gemini's\n * `toolConfig.functionCallingConfig` format. The configuration is only\n * created when tools are present (`hasTools` is true).\n *\n * @remarks\n * The conversion logic:\n * - If `hasTools` is `false`, returns `undefined` (no config needed)\n * - If `toolChoice` is provided, converts it to a Gemini mode:\n * - `\"auto\"` → `\"AUTO\"` - Model decides whether to call functions\n * - `\"any\"` or `\"required\"` → `\"ANY\"` - Model must call at least one function\n * - `\"none\"` → `\"NONE\"` - Model cannot call functions\n * - Function name string → `\"ANY\"` - Forces function use\n * - Object with `mode` → Maps the mode string to Gemini format\n * - Object with `function` → `\"ANY\"` - Forces function use\n * - If `toolChoice` is not provided but tools exist, defaults to `\"AUTO\"`\n *\n * Gemini's function calling modes:\n * - **AUTO**: The model can choose whether to call functions based on the conversation\n * - **ANY**: The model must call at least one function before responding\n * - **NONE**: The model cannot call any functions\n *\n * When a specific function is requested (via function name string or `{ function: { name } }`),\n * the converter uses `\"ANY\"` mode to force function usage, as Gemini doesn't support\n * specifying individual functions in the mode.\n *\n * @example\n * ```typescript\n * // With explicit tool choice\n * convertToolChoiceToGeminiConfig(\"auto\", true);\n * // Returns: { functionCallingConfig: { mode: \"AUTO\" } }\n *\n * // Required mode - must call a function\n * convertToolChoiceToGeminiConfig(\"any\", true);\n * // Returns: { functionCallingConfig: { mode: \"ANY\" } }\n *\n * // Without tool choice (defaults to AUTO when tools exist)\n * convertToolChoiceToGeminiConfig(undefined, true);\n * // Returns: { functionCallingConfig: { mode: \"AUTO\" } }\n *\n * // No tools - returns undefined\n * convertToolChoiceToGeminiConfig(\"auto\", false);\n * // Returns: undefined\n * ```\n *\n * @param toolChoice - The tool choice option from LangChain (string, object, or undefined)\n * @param hasTools - Whether tools are present. If false, returns undefined\n * @returns The Gemini tool configuration object, or undefined if no tools are present\n */\nexport function convertToolChoiceToGeminiConfig(\n toolChoice: ToolChoice | undefined,\n hasTools: boolean\n): Gemini.Tools.ToolConfig | undefined {\n if (!hasTools || toolChoice === undefined) {\n return undefined;\n }\n\n let mode: Gemini.Tools.FunctionCallingConfigMode | undefined;\n let allowedFunctionNames: string[] | undefined;\n\n let toolChoiceMode: string | undefined;\n let toolChoiceFunction: string | string[] | undefined;\n if (typeof toolChoice === \"object\") {\n toolChoiceMode = toolChoice.mode;\n toolChoiceFunction = toolChoice.function?.name;\n } else {\n toolChoiceMode = toolChoice;\n }\n\n if (toolChoiceMode === \"auto\") {\n mode = \"AUTO\";\n } else if (toolChoiceMode === \"any\" || toolChoiceMode === \"required\") {\n mode = \"ANY\";\n } else if (toolChoiceMode === \"none\") {\n mode = \"NONE\";\n } else if (typeof toolChoiceMode === \"string\") {\n mode = \"ANY\";\n toolChoiceFunction = toolChoiceMode;\n }\n\n if (toolChoiceFunction) {\n if (Array.isArray(toolChoiceFunction)) {\n allowedFunctionNames = toolChoiceFunction;\n } else {\n allowedFunctionNames = [toolChoiceFunction];\n }\n }\n\n const functionCallingConfig: Gemini.Tools.FunctionCallingConfig = {};\n if (allowedFunctionNames?.length) {\n functionCallingConfig.allowedFunctionNames = allowedFunctionNames;\n }\n if (mode) {\n functionCallingConfig.mode = mode;\n }\n return {\n functionCallingConfig,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAS,iBAEP,KAEqB;AACrB,KAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,CAC1B,QAAO;CAGT,MAAM,MAAM,IAAI,KAAK;CACrB,MAAM,YAAY,IAAI,KAAK,QAAQ,OAAO;AAC1C,KAAI,QAAQ,KAAK,aAAa,GAAG;EAG/B,MAAM,YAAY,cAAc,IAAI,IAAI;AACxC,MAAI,OAAO,IAAI,KAAK;AACpB,MAAI,WAAW;YACN,QAAQ,KAAK,cAAc,EAEpC,OAAM,IAAI,kBACR,2GACD;UACQ,QAAQ,EAGjB,KAAI,OAAO,KAAK,KAAK;UACZ,QAAQ,EAEjB,OAAM,IAAI,kBACR,4FACD;KAGD,OAAM,IAAI,kBACR,sFACD;AAEH,QAAO;;;;;;;;;;;;;;;;AAiBT,SAAS,2BAEP,KAC4C;AAC5C,KAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;EAC3C,MAAM,SAAS,EAAE,GAAG,KAAK;AAEzB,MAAI,0BAA0B,OAC5B,QAAO,OAAO;AAGhB,mBAAiB,OAAO;AAExB,OAAK,MAAM,OAAO,OAChB,KAAI,OAAO,QACT;OAAI,MAAM,QAAQ,OAAO,KAAK,CAC5B,QAAO,OAAO,OAAO,KAAK,IAAI,2BAA2B;YAChD,OAAO,OAAO,SAAS,YAAY,OAAO,SAAS,KAC5D,QAAO,OAAO,2BAA2B,OAAO,KAAK;;AAK3D,SAAO;;AAGT,QAAO;;;;;;;;;;;;;;AAeT,SAAgB,yBAId,QAIqB;CAUrB,MAAM,EAAE,SAAS,GAAG,SALD,2BACjB,mBAAmB,OAAO,IAAI,qBAAqB,OAAO,GACtD,aAAa,OAAO,GACpB,OACL;AAED,QAAO;;;;;;;;;;AAWT,SAAS,6BAEP,QACqB;CAErB,MAAM,EAAE,SAAS,GAAG,SADD,2BAA2B,OAAO;AAGrD,QAAO;;;;;;;;;;;;;;;;;;AAmBT,SAAS,aAAa,MAA2C;AAC/D,KAAI,OAAO,SAAS,YAAY,SAAS,KACvC,QAAO;AAcT,QAX6B;EAC3B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAE2B,MAAM,SAAS,QAAQ,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0D1D,MAAa,4CAGR,UAAU;CACb,MAAM,uBAA2D,EAAE;AAEnE,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,aAAa,KAAK,IAAI,EAAE,0BAA0B,MACpD;AAIF,MACE,aAAa,KAAK,IAClB,0BAA0B,QAC1B,MAAM,QAAQ,KAAK,qBAAqB,EACxC;AACA,wBAAqB,KAAK,GAAG,KAAK,qBAAqB;AACvD;;AAIF,MAAI,gBAAgB,KAAK,EAAE;GACzB,MAAM,aAAa,yBAAyB,KAAK,OAAO;AACxD,wBAAqB,KAAK;IACxB,MAAM,KAAK;IACX,aAAa,KAAK,eAAe;IACjC,YAAY;IACb,CAAC;AACF;;AAIF,MAAI,aAAa,KAAK,EAAE;AACtB,wBAAqB,KAAK;IACxB,MAAM,KAAK,SAAS;IACpB,aACE,KAAK,SAAS,eAAe;IAC/B,YAAY,6BAA6B,KAAK,SAAS,WAAW;IACnE,CAAC;AACF;;AAIF,MACE,OAAO,SAAS,YAChB,SAAS,QACT,UAAU,QACV,OAAO,KAAK,SAAS,UACrB;GACA,MAAM,WAAW;AACjB,wBAAqB,KAAK;IACxB,MAAM,SAAS;IACf,aAAa,SAAS,eAAe;IACrC,YAAY,SAAS;IACtB,CAAC;AACF;;AAGF,QAAM,IAAI,iBAAiB,KAAK;;AAGlC,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CT,MAAa,6BAGR,UAAU;AACb,KAAI,MAAM,WAAW,EACnB,QAAO,EAAE;CAGX,MAAM,cAA6B,EAAE;CACrC,MAAM,uBAA2D,EAAE;AAGnE,MAAK,MAAM,QAAQ,MACjB,KAAI,aAAa,KAAK,CACpB,KAAI,0BAA0B,KAE5B,aAAY,KAAK,KAAK;KAGtB,aAAY,KAAK,KAAK;UAEf,2BAA2B,KAKpC,aAAY,KAHoB,EAC9B,cAAc,EAAE,EACjB,CAC2B;MACvB;EAEL,MAAM,YAAY,yCAAyC,CAAC,KAAK,CAAC;AAClE,uBAAqB,KAAK,GAAG,UAAU;;AAK3C,KAAI,qBAAqB,SAAS,EAChC,aAAY,KAAK,EACf,sBACD,CAAC;AAGJ,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDT,SAAgB,gCACd,YACA,UACqC;AACrC,KAAI,CAAC,YAAY,eAAe,OAC9B;CAGF,IAAI;CACJ,IAAI;CAEJ,IAAI;CACJ,IAAI;AACJ,KAAI,OAAO,eAAe,UAAU;AAClC,mBAAiB,WAAW;AAC5B,uBAAqB,WAAW,UAAU;OAE1C,kBAAiB;AAGnB,KAAI,mBAAmB,OACrB,QAAO;UACE,mBAAmB,SAAS,mBAAmB,WACxD,QAAO;UACE,mBAAmB,OAC5B,QAAO;UACE,OAAO,mBAAmB,UAAU;AAC7C,SAAO;AACP,uBAAqB;;AAGvB,KAAI,mBACF,KAAI,MAAM,QAAQ,mBAAmB,CACnC,wBAAuB;KAEvB,wBAAuB,CAAC,mBAAmB;CAI/C,MAAM,wBAA4D,EAAE;AACpE,KAAI,sBAAsB,OACxB,uBAAsB,uBAAuB;AAE/C,KAAI,KACF,uBAAsB,OAAO;AAE/B,QAAO,EACL,uBACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/google",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Google integrations for LangChain.js",
5
5
  "author": "LangChain",
6
6
  "license": "MIT",
@@ -32,7 +32,7 @@
32
32
  "vitest": "^3.2.4",
33
33
  "zod": "^3.25.76 || ^4",
34
34
  "zod-to-json-schema": "^3.24.6",
35
- "@langchain/core": "^1.1.29",
35
+ "@langchain/core": "^1.1.30",
36
36
  "@langchain/eslint": "0.1.1",
37
37
  "@langchain/standard-tests": "0.0.23"
38
38
  },