@langchain/google-common 0.2.3 → 0.2.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.
@@ -144,6 +144,12 @@ class ChatGoogleBase extends chat_models_1.BaseChatModel {
144
144
  writable: true,
145
145
  value: void 0
146
146
  });
147
+ Object.defineProperty(this, "maxReasoningTokens", {
148
+ enumerable: true,
149
+ configurable: true,
150
+ writable: true,
151
+ value: void 0
152
+ });
147
153
  Object.defineProperty(this, "topP", {
148
154
  enumerable: true,
149
155
  configurable: true,
@@ -369,7 +375,7 @@ class ChatGoogleBase extends chat_models_1.BaseChatModel {
369
375
  let outputParser;
370
376
  let tools;
371
377
  if (isZodSchema(schema)) {
372
- const jsonSchema = (0, zod_to_gemini_parameters_js_1.zodToGeminiParameters)(schema);
378
+ const jsonSchema = (0, zod_to_gemini_parameters_js_1.schemaToGeminiParameters)(schema);
373
379
  tools = [
374
380
  {
375
381
  functionDeclarations: [
@@ -39,6 +39,7 @@ export declare abstract class ChatGoogleBase<AuthOptions> extends BaseChatModel<
39
39
  modelName: string;
40
40
  temperature: number;
41
41
  maxOutputTokens: number;
42
+ maxReasoningTokens: number;
42
43
  topP: number;
43
44
  topK: number;
44
45
  presencePenalty: number;
@@ -10,7 +10,7 @@ import { AbstractGoogleLLMConnection } from "./connection.js";
10
10
  import { DefaultGeminiSafetyHandler, getGeminiAPI } from "./utils/gemini.js";
11
11
  import { ApiKeyGoogleAuth } from "./auth.js";
12
12
  import { ensureParams } from "./utils/failed_handler.js";
13
- import { zodToGeminiParameters } from "./utils/zod_to_gemini_parameters.js";
13
+ import { schemaToGeminiParameters } from "./utils/zod_to_gemini_parameters.js";
14
14
  export class ChatConnection extends AbstractGoogleLLMConnection {
15
15
  constructor(fields, caller, client, streaming) {
16
16
  super(fields, caller, client, streaming);
@@ -140,6 +140,12 @@ export class ChatGoogleBase extends BaseChatModel {
140
140
  writable: true,
141
141
  value: void 0
142
142
  });
143
+ Object.defineProperty(this, "maxReasoningTokens", {
144
+ enumerable: true,
145
+ configurable: true,
146
+ writable: true,
147
+ value: void 0
148
+ });
143
149
  Object.defineProperty(this, "topP", {
144
150
  enumerable: true,
145
151
  configurable: true,
@@ -365,7 +371,7 @@ export class ChatGoogleBase extends BaseChatModel {
365
371
  let outputParser;
366
372
  let tools;
367
373
  if (isZodSchema(schema)) {
368
- const jsonSchema = zodToGeminiParameters(schema);
374
+ const jsonSchema = schemaToGeminiParameters(schema);
369
375
  tools = [
370
376
  {
371
377
  functionDeclarations: [
@@ -13,8 +13,11 @@ export interface AnthropicMessageContentImage extends AnthropicMessageContentBas
13
13
  type: "image";
14
14
  source: {
15
15
  type: "base64" | string;
16
- media_type: string;
16
+ media_type?: string;
17
17
  data: string;
18
+ } | {
19
+ type: "url" | string;
20
+ url: string;
18
21
  };
19
22
  }
20
23
  export interface AnthropicMessageContentThinking extends AnthropicMessageContentBase {
@@ -22,6 +25,38 @@ export interface AnthropicMessageContentThinking extends AnthropicMessageContent
22
25
  thinking: string;
23
26
  signature: string;
24
27
  }
28
+ export interface AnthropicMessageContentDocument extends AnthropicMessageContentBase {
29
+ type: "document";
30
+ source: {
31
+ type: "base64" | "text" | string;
32
+ media_type?: "application/pdf" | "text/plain" | string;
33
+ data: string;
34
+ } | {
35
+ type: "url" | string;
36
+ url: string;
37
+ } | {
38
+ type: "content" | string;
39
+ content: {
40
+ type: "image" | string;
41
+ source: {
42
+ type: "base64" | string;
43
+ data: string;
44
+ media_type?: "image/jpeg" | "image/png" | "image/gif" | "image/webp" | string;
45
+ } | {
46
+ type: "url" | string;
47
+ url: string;
48
+ } | {
49
+ type: "text" | string;
50
+ text: string;
51
+ };
52
+ }[];
53
+ };
54
+ citations?: {
55
+ enabled?: boolean;
56
+ };
57
+ context?: string;
58
+ title?: string;
59
+ }
25
60
  export interface AnthropicMessageContentRedactedThinking extends AnthropicMessageContentBase {
26
61
  type: "redacted_thinking";
27
62
  data: string;
package/dist/types.d.ts CHANGED
@@ -85,6 +85,10 @@ export interface GoogleAISafetySetting {
85
85
  }
86
86
  export type GoogleAIResponseMimeType = "text/plain" | "application/json";
87
87
  export type GoogleAIModelModality = "TEXT" | "IMAGE" | "AUDIO" | string;
88
+ export interface GoogleThinkingConfig {
89
+ thinkingBudget?: number;
90
+ includeThoughts?: boolean;
91
+ }
88
92
  export interface GoogleAIModelParams {
89
93
  /** Model to use */
90
94
  model?: string;
@@ -97,8 +101,22 @@ export interface GoogleAIModelParams {
97
101
  temperature?: number;
98
102
  /**
99
103
  * Maximum number of tokens to generate in the completion.
104
+ * This may include reasoning tokens (for backwards compatibility).
100
105
  */
101
106
  maxOutputTokens?: number;
107
+ /**
108
+ * The maximum number of the output tokens that will be used
109
+ * for the "thinking" or "reasoning" stages.
110
+ */
111
+ maxReasoningTokens?: number;
112
+ /**
113
+ * An alias for "maxReasoningTokens"
114
+ */
115
+ thinkingBudget?: number;
116
+ /**
117
+ * An OpenAI compatible parameter that will map to "maxReasoningTokens"
118
+ */
119
+ reasoningEffort?: "low" | "medium" | "high";
102
120
  /**
103
121
  * Top-p changes how the model selects tokens for output.
104
122
  *
@@ -398,6 +416,7 @@ export interface GeminiGenerationConfig {
398
416
  responseLogprobs?: boolean;
399
417
  logprobs?: number;
400
418
  responseModalities?: GoogleAIModelModality[];
419
+ thinkingConfig?: GoogleThinkingConfig;
401
420
  }
402
421
  export interface GeminiRequest {
403
422
  contents?: GeminiContent[];
@@ -373,16 +373,221 @@ function getAnthropicAPI(config) {
373
373
  return undefined;
374
374
  }
375
375
  }
376
+ const anthropicContentConverter = {
377
+ providerName: "anthropic",
378
+ fromStandardTextBlock(block) {
379
+ return {
380
+ type: "text",
381
+ text: block.text,
382
+ ...("cache_control" in (block.metadata ?? {})
383
+ ? {
384
+ cache_control: block.metadata
385
+ .cache_control,
386
+ }
387
+ : {}),
388
+ };
389
+ },
390
+ fromStandardImageBlock(block) {
391
+ if (block.source_type === "url") {
392
+ const data = (0, messages_1.parseBase64DataUrl)({
393
+ dataUrl: block.url,
394
+ asTypedArray: false,
395
+ });
396
+ if (data) {
397
+ return {
398
+ type: "image",
399
+ source: {
400
+ type: "base64",
401
+ data: data.data,
402
+ media_type: data.mime_type,
403
+ },
404
+ ...("cache_control" in (block.metadata ?? {})
405
+ ? { cache_control: block.metadata.cache_control }
406
+ : {}),
407
+ };
408
+ }
409
+ else {
410
+ return {
411
+ type: "image",
412
+ source: {
413
+ type: "url",
414
+ url: block.url,
415
+ media_type: block.mime_type ?? "",
416
+ },
417
+ ...("cache_control" in (block.metadata ?? {})
418
+ ? { cache_control: block.metadata.cache_control }
419
+ : {}),
420
+ };
421
+ }
422
+ }
423
+ else {
424
+ if (block.source_type === "base64") {
425
+ return {
426
+ type: "image",
427
+ source: {
428
+ type: "base64",
429
+ data: block.data,
430
+ media_type: block.mime_type ?? "",
431
+ },
432
+ ...("cache_control" in (block.metadata ?? {})
433
+ ? { cache_control: block.metadata.cache_control }
434
+ : {}),
435
+ };
436
+ }
437
+ else {
438
+ throw new Error(`Unsupported image source type: ${block.source_type}`);
439
+ }
440
+ }
441
+ },
442
+ fromStandardFileBlock(block) {
443
+ const mime_type = (block.mime_type ?? "").split(";")[0];
444
+ if (block.source_type === "url") {
445
+ if (mime_type === "application/pdf" || mime_type === "") {
446
+ return {
447
+ type: "document",
448
+ source: {
449
+ type: "url",
450
+ url: block.url,
451
+ media_type: block.mime_type ?? "",
452
+ },
453
+ ...("cache_control" in (block.metadata ?? {})
454
+ ? {
455
+ cache_control: block.metadata
456
+ .cache_control,
457
+ }
458
+ : {}),
459
+ ...("citations" in (block.metadata ?? {})
460
+ ? {
461
+ citations: block.metadata.citations,
462
+ }
463
+ : {}),
464
+ ...("context" in (block.metadata ?? {})
465
+ ? { context: block.metadata.context }
466
+ : {}),
467
+ ...(block.metadata?.title ||
468
+ block.metadata?.filename ||
469
+ block.metadata?.name
470
+ ? {
471
+ title: (block.metadata?.title ||
472
+ block.metadata?.filename ||
473
+ block.metadata?.name),
474
+ }
475
+ : {}),
476
+ };
477
+ }
478
+ throw new Error(`Unsupported file mime type for file url source: ${block.mime_type}`);
479
+ }
480
+ else if (block.source_type === "text") {
481
+ if (mime_type === "text/plain" || mime_type === "") {
482
+ return {
483
+ type: "document",
484
+ source: {
485
+ type: "text",
486
+ data: block.text,
487
+ media_type: block.mime_type ?? "",
488
+ },
489
+ ...("cache_control" in (block.metadata ?? {})
490
+ ? {
491
+ cache_control: block.metadata
492
+ .cache_control,
493
+ }
494
+ : {}),
495
+ ...("citations" in (block.metadata ?? {})
496
+ ? {
497
+ citations: block.metadata.citations,
498
+ }
499
+ : {}),
500
+ ...("context" in (block.metadata ?? {})
501
+ ? { context: block.metadata.context }
502
+ : {}),
503
+ ...("title" in (block.metadata ?? {})
504
+ ? { title: block.metadata.title }
505
+ : {}),
506
+ };
507
+ }
508
+ else {
509
+ throw new Error(`Unsupported file mime type for file text source: ${block.mime_type}`);
510
+ }
511
+ }
512
+ else if (block.source_type === "base64") {
513
+ if (mime_type === "application/pdf" || mime_type === "") {
514
+ return {
515
+ type: "document",
516
+ source: {
517
+ type: "base64",
518
+ data: block.data,
519
+ media_type: "application/pdf",
520
+ },
521
+ ...("cache_control" in (block.metadata ?? {})
522
+ ? {
523
+ cache_control: block.metadata
524
+ .cache_control,
525
+ }
526
+ : {}),
527
+ ...("citations" in (block.metadata ?? {})
528
+ ? {
529
+ citations: block.metadata.citations,
530
+ }
531
+ : {}),
532
+ ...("context" in (block.metadata ?? {})
533
+ ? { context: block.metadata.context }
534
+ : {}),
535
+ ...("title" in (block.metadata ?? {})
536
+ ? { title: block.metadata.title }
537
+ : {}),
538
+ };
539
+ }
540
+ else if (["image/jpeg", "image/png", "image/gif", "image/webp"].includes(mime_type)) {
541
+ return {
542
+ type: "document",
543
+ source: {
544
+ type: "content",
545
+ content: [
546
+ {
547
+ type: "image",
548
+ source: {
549
+ type: "base64",
550
+ data: block.data,
551
+ media_type: mime_type,
552
+ },
553
+ },
554
+ ],
555
+ },
556
+ ...("cache_control" in (block.metadata ?? {})
557
+ ? {
558
+ cache_control: block.metadata
559
+ .cache_control,
560
+ }
561
+ : {}),
562
+ ...("citations" in (block.metadata ?? {})
563
+ ? {
564
+ citations: block.metadata.citations,
565
+ }
566
+ : {}),
567
+ ...("context" in (block.metadata ?? {})
568
+ ? { context: block.metadata.context }
569
+ : {}),
570
+ ...("title" in (block.metadata ?? {})
571
+ ? { title: block.metadata.title }
572
+ : {}),
573
+ };
574
+ }
575
+ else {
576
+ throw new Error(`Unsupported file mime type for file base64 source: ${block.mime_type}`);
577
+ }
578
+ }
579
+ else {
580
+ throw new Error(`Unsupported file source type: ${block.source_type}`);
581
+ }
582
+ },
583
+ };
376
584
  function contentToAnthropicContent(content) {
377
- const ret = [];
378
585
  const ca = typeof content === "string" ? [{ type: "text", text: content }] : content;
379
- ca.forEach((complex) => {
380
- const ac = contentComplexToAnthropicContent(complex);
381
- if (ac) {
382
- ret.push(ac);
383
- }
384
- });
385
- return ret;
586
+ return ca
587
+ .map((complex) => (0, messages_1.isDataContentBlock)(complex)
588
+ ? (0, messages_1.convertToProviderContentBlock)(complex, anthropicContentConverter)
589
+ : contentComplexToAnthropicContent(complex))
590
+ .filter(Boolean);
386
591
  }
387
592
  function toolCallToAnthropicContent(toolCall) {
388
593
  return {
@@ -439,6 +644,9 @@ function getAnthropicAPI(config) {
439
644
  return aiMessageToAnthropicMessage(base);
440
645
  case "tool":
441
646
  return toolMessageToAnthropicMessage(base);
647
+ case "system":
648
+ // System messages are handled in formatSystem()
649
+ return undefined;
442
650
  default:
443
651
  console.warn(`Unknown BaseMessage type: ${type}`, base);
444
652
  return undefined;
@@ -1,5 +1,5 @@
1
1
  import { ChatGenerationChunk, } from "@langchain/core/outputs";
2
- import { AIMessageChunk, } from "@langchain/core/messages";
2
+ import { AIMessageChunk, isDataContentBlock, convertToProviderContentBlock, parseBase64DataUrl, } from "@langchain/core/messages";
3
3
  export function getAnthropicAPI(config) {
4
4
  function partToString(part) {
5
5
  return "text" in part ? part.text : "";
@@ -370,16 +370,221 @@ export function getAnthropicAPI(config) {
370
370
  return undefined;
371
371
  }
372
372
  }
373
+ const anthropicContentConverter = {
374
+ providerName: "anthropic",
375
+ fromStandardTextBlock(block) {
376
+ return {
377
+ type: "text",
378
+ text: block.text,
379
+ ...("cache_control" in (block.metadata ?? {})
380
+ ? {
381
+ cache_control: block.metadata
382
+ .cache_control,
383
+ }
384
+ : {}),
385
+ };
386
+ },
387
+ fromStandardImageBlock(block) {
388
+ if (block.source_type === "url") {
389
+ const data = parseBase64DataUrl({
390
+ dataUrl: block.url,
391
+ asTypedArray: false,
392
+ });
393
+ if (data) {
394
+ return {
395
+ type: "image",
396
+ source: {
397
+ type: "base64",
398
+ data: data.data,
399
+ media_type: data.mime_type,
400
+ },
401
+ ...("cache_control" in (block.metadata ?? {})
402
+ ? { cache_control: block.metadata.cache_control }
403
+ : {}),
404
+ };
405
+ }
406
+ else {
407
+ return {
408
+ type: "image",
409
+ source: {
410
+ type: "url",
411
+ url: block.url,
412
+ media_type: block.mime_type ?? "",
413
+ },
414
+ ...("cache_control" in (block.metadata ?? {})
415
+ ? { cache_control: block.metadata.cache_control }
416
+ : {}),
417
+ };
418
+ }
419
+ }
420
+ else {
421
+ if (block.source_type === "base64") {
422
+ return {
423
+ type: "image",
424
+ source: {
425
+ type: "base64",
426
+ data: block.data,
427
+ media_type: block.mime_type ?? "",
428
+ },
429
+ ...("cache_control" in (block.metadata ?? {})
430
+ ? { cache_control: block.metadata.cache_control }
431
+ : {}),
432
+ };
433
+ }
434
+ else {
435
+ throw new Error(`Unsupported image source type: ${block.source_type}`);
436
+ }
437
+ }
438
+ },
439
+ fromStandardFileBlock(block) {
440
+ const mime_type = (block.mime_type ?? "").split(";")[0];
441
+ if (block.source_type === "url") {
442
+ if (mime_type === "application/pdf" || mime_type === "") {
443
+ return {
444
+ type: "document",
445
+ source: {
446
+ type: "url",
447
+ url: block.url,
448
+ media_type: block.mime_type ?? "",
449
+ },
450
+ ...("cache_control" in (block.metadata ?? {})
451
+ ? {
452
+ cache_control: block.metadata
453
+ .cache_control,
454
+ }
455
+ : {}),
456
+ ...("citations" in (block.metadata ?? {})
457
+ ? {
458
+ citations: block.metadata.citations,
459
+ }
460
+ : {}),
461
+ ...("context" in (block.metadata ?? {})
462
+ ? { context: block.metadata.context }
463
+ : {}),
464
+ ...(block.metadata?.title ||
465
+ block.metadata?.filename ||
466
+ block.metadata?.name
467
+ ? {
468
+ title: (block.metadata?.title ||
469
+ block.metadata?.filename ||
470
+ block.metadata?.name),
471
+ }
472
+ : {}),
473
+ };
474
+ }
475
+ throw new Error(`Unsupported file mime type for file url source: ${block.mime_type}`);
476
+ }
477
+ else if (block.source_type === "text") {
478
+ if (mime_type === "text/plain" || mime_type === "") {
479
+ return {
480
+ type: "document",
481
+ source: {
482
+ type: "text",
483
+ data: block.text,
484
+ media_type: block.mime_type ?? "",
485
+ },
486
+ ...("cache_control" in (block.metadata ?? {})
487
+ ? {
488
+ cache_control: block.metadata
489
+ .cache_control,
490
+ }
491
+ : {}),
492
+ ...("citations" in (block.metadata ?? {})
493
+ ? {
494
+ citations: block.metadata.citations,
495
+ }
496
+ : {}),
497
+ ...("context" in (block.metadata ?? {})
498
+ ? { context: block.metadata.context }
499
+ : {}),
500
+ ...("title" in (block.metadata ?? {})
501
+ ? { title: block.metadata.title }
502
+ : {}),
503
+ };
504
+ }
505
+ else {
506
+ throw new Error(`Unsupported file mime type for file text source: ${block.mime_type}`);
507
+ }
508
+ }
509
+ else if (block.source_type === "base64") {
510
+ if (mime_type === "application/pdf" || mime_type === "") {
511
+ return {
512
+ type: "document",
513
+ source: {
514
+ type: "base64",
515
+ data: block.data,
516
+ media_type: "application/pdf",
517
+ },
518
+ ...("cache_control" in (block.metadata ?? {})
519
+ ? {
520
+ cache_control: block.metadata
521
+ .cache_control,
522
+ }
523
+ : {}),
524
+ ...("citations" in (block.metadata ?? {})
525
+ ? {
526
+ citations: block.metadata.citations,
527
+ }
528
+ : {}),
529
+ ...("context" in (block.metadata ?? {})
530
+ ? { context: block.metadata.context }
531
+ : {}),
532
+ ...("title" in (block.metadata ?? {})
533
+ ? { title: block.metadata.title }
534
+ : {}),
535
+ };
536
+ }
537
+ else if (["image/jpeg", "image/png", "image/gif", "image/webp"].includes(mime_type)) {
538
+ return {
539
+ type: "document",
540
+ source: {
541
+ type: "content",
542
+ content: [
543
+ {
544
+ type: "image",
545
+ source: {
546
+ type: "base64",
547
+ data: block.data,
548
+ media_type: mime_type,
549
+ },
550
+ },
551
+ ],
552
+ },
553
+ ...("cache_control" in (block.metadata ?? {})
554
+ ? {
555
+ cache_control: block.metadata
556
+ .cache_control,
557
+ }
558
+ : {}),
559
+ ...("citations" in (block.metadata ?? {})
560
+ ? {
561
+ citations: block.metadata.citations,
562
+ }
563
+ : {}),
564
+ ...("context" in (block.metadata ?? {})
565
+ ? { context: block.metadata.context }
566
+ : {}),
567
+ ...("title" in (block.metadata ?? {})
568
+ ? { title: block.metadata.title }
569
+ : {}),
570
+ };
571
+ }
572
+ else {
573
+ throw new Error(`Unsupported file mime type for file base64 source: ${block.mime_type}`);
574
+ }
575
+ }
576
+ else {
577
+ throw new Error(`Unsupported file source type: ${block.source_type}`);
578
+ }
579
+ },
580
+ };
373
581
  function contentToAnthropicContent(content) {
374
- const ret = [];
375
582
  const ca = typeof content === "string" ? [{ type: "text", text: content }] : content;
376
- ca.forEach((complex) => {
377
- const ac = contentComplexToAnthropicContent(complex);
378
- if (ac) {
379
- ret.push(ac);
380
- }
381
- });
382
- return ret;
583
+ return ca
584
+ .map((complex) => isDataContentBlock(complex)
585
+ ? convertToProviderContentBlock(complex, anthropicContentConverter)
586
+ : contentComplexToAnthropicContent(complex))
587
+ .filter(Boolean);
383
588
  }
384
589
  function toolCallToAnthropicContent(toolCall) {
385
590
  return {
@@ -436,6 +641,9 @@ export function getAnthropicAPI(config) {
436
641
  return aiMessageToAnthropicMessage(base);
437
642
  case "tool":
438
643
  return toolMessageToAnthropicMessage(base);
644
+ case "system":
645
+ // System messages are handled in formatSystem()
646
+ return undefined;
439
647
  default:
440
648
  console.warn(`Unknown BaseMessage type: ${type}`, base);
441
649
  return undefined;
@@ -69,7 +69,7 @@ function convertToGeminiTools(tools) {
69
69
  geminiTools[functionDeclarationsIndex].functionDeclarations.push(...funcs);
70
70
  }
71
71
  else if ((0, function_calling_1.isLangChainTool)(tool)) {
72
- const jsonSchema = (0, zod_to_gemini_parameters_js_1.zodToGeminiParameters)(tool.schema);
72
+ const jsonSchema = (0, zod_to_gemini_parameters_js_1.schemaToGeminiParameters)(tool.schema);
73
73
  geminiTools[functionDeclarationsIndex].functionDeclarations.push({
74
74
  name: tool.name,
75
75
  description: tool.description ?? `A function available to call.`,
@@ -91,6 +91,22 @@ function convertToGeminiTools(tools) {
91
91
  return geminiTools;
92
92
  }
93
93
  exports.convertToGeminiTools = convertToGeminiTools;
94
+ function reasoningEffortToReasoningTokens(_modelName, effort) {
95
+ if (effort === undefined) {
96
+ return undefined;
97
+ }
98
+ const maxEffort = 24 * 1024; // Max for Gemini 2.5 Flash
99
+ switch (effort) {
100
+ case "low":
101
+ return maxEffort / 3;
102
+ case "medium":
103
+ return (2 * maxEffort) / 3;
104
+ case "high":
105
+ return maxEffort;
106
+ default:
107
+ return undefined;
108
+ }
109
+ }
94
110
  function copyAIModelParamsInto(params, options, target) {
95
111
  const ret = target || {};
96
112
  const model = options?.model ?? params?.model ?? target.model;
@@ -103,6 +119,16 @@ function copyAIModelParamsInto(params, options, target) {
103
119
  options?.maxOutputTokens ??
104
120
  params?.maxOutputTokens ??
105
121
  target.maxOutputTokens;
122
+ ret.maxReasoningTokens =
123
+ options?.maxReasoningTokens ??
124
+ params?.maxReasoningTokens ??
125
+ target?.maxReasoningTokens ??
126
+ options?.thinkingBudget ??
127
+ params?.thinkingBudget ??
128
+ target?.thinkingBudget ??
129
+ reasoningEffortToReasoningTokens(ret.modelName, params?.reasoningEffort) ??
130
+ reasoningEffortToReasoningTokens(ret.modelName, target?.reasoningEffort) ??
131
+ reasoningEffortToReasoningTokens(ret.modelName, options?.reasoningEffort);
106
132
  ret.topP = options?.topP ?? params?.topP ?? target.topP;
107
133
  ret.topK = options?.topK ?? params?.topK ?? target.topK;
108
134
  ret.presencePenalty =
@@ -2,7 +2,7 @@ import { isOpenAITool } from "@langchain/core/language_models/base";
2
2
  import { isLangChainTool } from "@langchain/core/utils/function_calling";
3
3
  import { isModelGemini, isModelGemma, validateGeminiParams } from "./gemini.js";
4
4
  import { GeminiToolAttributes, } from "../types.js";
5
- import { jsonSchemaToGeminiParameters, zodToGeminiParameters, } from "./zod_to_gemini_parameters.js";
5
+ import { jsonSchemaToGeminiParameters, schemaToGeminiParameters, } from "./zod_to_gemini_parameters.js";
6
6
  import { isModelClaude, validateClaudeParams } from "./anthropic.js";
7
7
  export function copyAIModelParams(params, options) {
8
8
  return copyAIModelParamsInto(params, options, {});
@@ -65,7 +65,7 @@ export function convertToGeminiTools(tools) {
65
65
  geminiTools[functionDeclarationsIndex].functionDeclarations.push(...funcs);
66
66
  }
67
67
  else if (isLangChainTool(tool)) {
68
- const jsonSchema = zodToGeminiParameters(tool.schema);
68
+ const jsonSchema = schemaToGeminiParameters(tool.schema);
69
69
  geminiTools[functionDeclarationsIndex].functionDeclarations.push({
70
70
  name: tool.name,
71
71
  description: tool.description ?? `A function available to call.`,
@@ -86,6 +86,22 @@ export function convertToGeminiTools(tools) {
86
86
  });
87
87
  return geminiTools;
88
88
  }
89
+ function reasoningEffortToReasoningTokens(_modelName, effort) {
90
+ if (effort === undefined) {
91
+ return undefined;
92
+ }
93
+ const maxEffort = 24 * 1024; // Max for Gemini 2.5 Flash
94
+ switch (effort) {
95
+ case "low":
96
+ return maxEffort / 3;
97
+ case "medium":
98
+ return (2 * maxEffort) / 3;
99
+ case "high":
100
+ return maxEffort;
101
+ default:
102
+ return undefined;
103
+ }
104
+ }
89
105
  export function copyAIModelParamsInto(params, options, target) {
90
106
  const ret = target || {};
91
107
  const model = options?.model ?? params?.model ?? target.model;
@@ -98,6 +114,16 @@ export function copyAIModelParamsInto(params, options, target) {
98
114
  options?.maxOutputTokens ??
99
115
  params?.maxOutputTokens ??
100
116
  target.maxOutputTokens;
117
+ ret.maxReasoningTokens =
118
+ options?.maxReasoningTokens ??
119
+ params?.maxReasoningTokens ??
120
+ target?.maxReasoningTokens ??
121
+ options?.thinkingBudget ??
122
+ params?.thinkingBudget ??
123
+ target?.thinkingBudget ??
124
+ reasoningEffortToReasoningTokens(ret.modelName, params?.reasoningEffort) ??
125
+ reasoningEffortToReasoningTokens(ret.modelName, target?.reasoningEffort) ??
126
+ reasoningEffortToReasoningTokens(ret.modelName, options?.reasoningEffort);
101
127
  ret.topP = options?.topP ?? params?.topP ?? target.topP;
102
128
  ret.topK = options?.topK ?? params?.topK ?? target.topK;
103
129
  ret.presencePenalty =
@@ -198,6 +198,109 @@ function getGeminiAPI(config) {
198
198
  }
199
199
  throw new Error(`Invalid media content: ${JSON.stringify(content, null, 1)}`);
200
200
  }
201
+ const standardContentBlockConverter = {
202
+ providerName: "Google Gemini",
203
+ fromStandardTextBlock(block) {
204
+ return {
205
+ text: block.text,
206
+ };
207
+ },
208
+ fromStandardImageBlock(block) {
209
+ if (block.source_type === "url") {
210
+ const data = (0, messages_1.parseBase64DataUrl)({ dataUrl: block.url });
211
+ if (data) {
212
+ return {
213
+ inlineData: {
214
+ mimeType: data.mime_type,
215
+ data: data.data,
216
+ },
217
+ };
218
+ }
219
+ else {
220
+ return {
221
+ fileData: {
222
+ mimeType: block.mime_type ?? "",
223
+ fileUri: block.url,
224
+ },
225
+ };
226
+ }
227
+ }
228
+ if (block.source_type === "base64") {
229
+ return {
230
+ inlineData: {
231
+ mimeType: block.mime_type ?? "",
232
+ data: block.data,
233
+ },
234
+ };
235
+ }
236
+ throw new Error(`Unsupported source type: ${block.source_type}`);
237
+ },
238
+ fromStandardAudioBlock(block) {
239
+ if (block.source_type === "url") {
240
+ const data = (0, messages_1.parseBase64DataUrl)({ dataUrl: block.url });
241
+ if (data) {
242
+ return {
243
+ inlineData: {
244
+ mimeType: data.mime_type,
245
+ data: data.data,
246
+ },
247
+ };
248
+ }
249
+ else {
250
+ return {
251
+ fileData: {
252
+ mimeType: block.mime_type ?? "",
253
+ fileUri: block.url,
254
+ },
255
+ };
256
+ }
257
+ }
258
+ if (block.source_type === "base64") {
259
+ return {
260
+ inlineData: {
261
+ mimeType: block.mime_type ?? "",
262
+ data: block.data,
263
+ },
264
+ };
265
+ }
266
+ throw new Error(`Unsupported source type: ${block.source_type}`);
267
+ },
268
+ fromStandardFileBlock(block) {
269
+ if (block.source_type === "text") {
270
+ return {
271
+ text: block.text,
272
+ };
273
+ }
274
+ if (block.source_type === "url") {
275
+ const data = (0, messages_1.parseBase64DataUrl)({ dataUrl: block.url });
276
+ if (data) {
277
+ return {
278
+ inlineData: {
279
+ mimeType: data.mime_type,
280
+ data: data.data,
281
+ },
282
+ };
283
+ }
284
+ else {
285
+ return {
286
+ fileData: {
287
+ mimeType: block.mime_type ?? "",
288
+ fileUri: block.url,
289
+ },
290
+ };
291
+ }
292
+ }
293
+ if (block.source_type === "base64") {
294
+ return {
295
+ inlineData: {
296
+ mimeType: block.mime_type ?? "",
297
+ data: block.data,
298
+ },
299
+ };
300
+ }
301
+ throw new Error(`Unsupported source type: ${block.source_type}`);
302
+ },
303
+ };
201
304
  async function messageContentComplexToPart(content) {
202
305
  switch (content.type) {
203
306
  case "text":
@@ -219,7 +322,9 @@ function getGeminiAPI(config) {
219
322
  throw new Error(`Cannot coerce "${content.type}" message part into a string.`);
220
323
  }
221
324
  async function messageContentComplexToParts(content) {
222
- const contents = content.map(messageContentComplexToPart);
325
+ const contents = content.map((m) => (0, messages_1.isDataContentBlock)(m)
326
+ ? (0, messages_1.convertToProviderContentBlock)(m, standardContentBlockConverter)
327
+ : messageContentComplexToPart(m));
223
328
  return Promise.all(contents);
224
329
  }
225
330
  async function messageContentToParts(content) {
@@ -951,6 +1056,13 @@ function getGeminiAPI(config) {
951
1056
  ret.logprobs = parameters.topLogprobs;
952
1057
  }
953
1058
  }
1059
+ // Add thinking configuration if explicitly set
1060
+ if (typeof parameters.maxReasoningTokens !== "undefined") {
1061
+ ret.thinkingConfig = {
1062
+ thinkingBudget: parameters.maxReasoningTokens,
1063
+ includeThoughts: true,
1064
+ };
1065
+ }
954
1066
  // Remove any undefined properties, so we don't send them
955
1067
  let attribute;
956
1068
  for (attribute in ret) {
@@ -994,7 +1106,7 @@ function getGeminiAPI(config) {
994
1106
  }
995
1107
  }
996
1108
  function structuredToolToFunctionDeclaration(tool) {
997
- const jsonSchema = (0, zod_to_gemini_parameters_js_1.zodToGeminiParameters)(tool.schema);
1109
+ const jsonSchema = (0, zod_to_gemini_parameters_js_1.schemaToGeminiParameters)(tool.schema);
998
1110
  return {
999
1111
  name: tool.name,
1000
1112
  description: tool.description ?? `A function available to call.`,
@@ -1113,6 +1225,16 @@ function validateGeminiParams(params) {
1113
1225
  if (params.maxOutputTokens && params.maxOutputTokens < 0) {
1114
1226
  throw new Error("`maxOutputTokens` must be a positive integer");
1115
1227
  }
1228
+ if (typeof params.maxReasoningTokens !== "undefined") {
1229
+ if (params.maxReasoningTokens < 0) {
1230
+ throw new Error("`maxReasoningTokens` must be non-negative integer");
1231
+ }
1232
+ if (typeof params.maxOutputTokens !== "undefined") {
1233
+ if (params.maxReasoningTokens >= params.maxOutputTokens) {
1234
+ throw new Error("`maxOutputTokens` must be greater than `maxReasoningTokens`");
1235
+ }
1236
+ }
1237
+ }
1116
1238
  if (params.temperature &&
1117
1239
  (params.temperature < 0 || params.temperature > 2)) {
1118
1240
  throw new Error("`temperature` must be in the range of [0.0,2.0]");
@@ -1,11 +1,11 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
- import { AIMessage, AIMessageChunk, isAIMessage, } from "@langchain/core/messages";
2
+ import { AIMessage, AIMessageChunk, isAIMessage, parseBase64DataUrl, isDataContentBlock, convertToProviderContentBlock, } from "@langchain/core/messages";
3
3
  import { ChatGenerationChunk, } from "@langchain/core/outputs";
4
4
  import { isLangChainTool } from "@langchain/core/utils/function_calling";
5
5
  import { concat } from "@langchain/core/utils/stream";
6
6
  import { GoogleAISafetyError } from "./safety.js";
7
7
  import { GeminiSearchToolAttributes, } from "../types.js";
8
- import { zodToGeminiParameters } from "./zod_to_gemini_parameters.js";
8
+ import { schemaToGeminiParameters } from "./zod_to_gemini_parameters.js";
9
9
  export class DefaultGeminiSafetyHandler {
10
10
  constructor(settings) {
11
11
  Object.defineProperty(this, "errorFinish", {
@@ -193,6 +193,109 @@ export function getGeminiAPI(config) {
193
193
  }
194
194
  throw new Error(`Invalid media content: ${JSON.stringify(content, null, 1)}`);
195
195
  }
196
+ const standardContentBlockConverter = {
197
+ providerName: "Google Gemini",
198
+ fromStandardTextBlock(block) {
199
+ return {
200
+ text: block.text,
201
+ };
202
+ },
203
+ fromStandardImageBlock(block) {
204
+ if (block.source_type === "url") {
205
+ const data = parseBase64DataUrl({ dataUrl: block.url });
206
+ if (data) {
207
+ return {
208
+ inlineData: {
209
+ mimeType: data.mime_type,
210
+ data: data.data,
211
+ },
212
+ };
213
+ }
214
+ else {
215
+ return {
216
+ fileData: {
217
+ mimeType: block.mime_type ?? "",
218
+ fileUri: block.url,
219
+ },
220
+ };
221
+ }
222
+ }
223
+ if (block.source_type === "base64") {
224
+ return {
225
+ inlineData: {
226
+ mimeType: block.mime_type ?? "",
227
+ data: block.data,
228
+ },
229
+ };
230
+ }
231
+ throw new Error(`Unsupported source type: ${block.source_type}`);
232
+ },
233
+ fromStandardAudioBlock(block) {
234
+ if (block.source_type === "url") {
235
+ const data = parseBase64DataUrl({ dataUrl: block.url });
236
+ if (data) {
237
+ return {
238
+ inlineData: {
239
+ mimeType: data.mime_type,
240
+ data: data.data,
241
+ },
242
+ };
243
+ }
244
+ else {
245
+ return {
246
+ fileData: {
247
+ mimeType: block.mime_type ?? "",
248
+ fileUri: block.url,
249
+ },
250
+ };
251
+ }
252
+ }
253
+ if (block.source_type === "base64") {
254
+ return {
255
+ inlineData: {
256
+ mimeType: block.mime_type ?? "",
257
+ data: block.data,
258
+ },
259
+ };
260
+ }
261
+ throw new Error(`Unsupported source type: ${block.source_type}`);
262
+ },
263
+ fromStandardFileBlock(block) {
264
+ if (block.source_type === "text") {
265
+ return {
266
+ text: block.text,
267
+ };
268
+ }
269
+ if (block.source_type === "url") {
270
+ const data = parseBase64DataUrl({ dataUrl: block.url });
271
+ if (data) {
272
+ return {
273
+ inlineData: {
274
+ mimeType: data.mime_type,
275
+ data: data.data,
276
+ },
277
+ };
278
+ }
279
+ else {
280
+ return {
281
+ fileData: {
282
+ mimeType: block.mime_type ?? "",
283
+ fileUri: block.url,
284
+ },
285
+ };
286
+ }
287
+ }
288
+ if (block.source_type === "base64") {
289
+ return {
290
+ inlineData: {
291
+ mimeType: block.mime_type ?? "",
292
+ data: block.data,
293
+ },
294
+ };
295
+ }
296
+ throw new Error(`Unsupported source type: ${block.source_type}`);
297
+ },
298
+ };
196
299
  async function messageContentComplexToPart(content) {
197
300
  switch (content.type) {
198
301
  case "text":
@@ -214,7 +317,9 @@ export function getGeminiAPI(config) {
214
317
  throw new Error(`Cannot coerce "${content.type}" message part into a string.`);
215
318
  }
216
319
  async function messageContentComplexToParts(content) {
217
- const contents = content.map(messageContentComplexToPart);
320
+ const contents = content.map((m) => isDataContentBlock(m)
321
+ ? convertToProviderContentBlock(m, standardContentBlockConverter)
322
+ : messageContentComplexToPart(m));
218
323
  return Promise.all(contents);
219
324
  }
220
325
  async function messageContentToParts(content) {
@@ -946,6 +1051,13 @@ export function getGeminiAPI(config) {
946
1051
  ret.logprobs = parameters.topLogprobs;
947
1052
  }
948
1053
  }
1054
+ // Add thinking configuration if explicitly set
1055
+ if (typeof parameters.maxReasoningTokens !== "undefined") {
1056
+ ret.thinkingConfig = {
1057
+ thinkingBudget: parameters.maxReasoningTokens,
1058
+ includeThoughts: true,
1059
+ };
1060
+ }
949
1061
  // Remove any undefined properties, so we don't send them
950
1062
  let attribute;
951
1063
  for (attribute in ret) {
@@ -989,7 +1101,7 @@ export function getGeminiAPI(config) {
989
1101
  }
990
1102
  }
991
1103
  function structuredToolToFunctionDeclaration(tool) {
992
- const jsonSchema = zodToGeminiParameters(tool.schema);
1104
+ const jsonSchema = schemaToGeminiParameters(tool.schema);
993
1105
  return {
994
1106
  name: tool.name,
995
1107
  description: tool.description ?? `A function available to call.`,
@@ -1107,6 +1219,16 @@ export function validateGeminiParams(params) {
1107
1219
  if (params.maxOutputTokens && params.maxOutputTokens < 0) {
1108
1220
  throw new Error("`maxOutputTokens` must be a positive integer");
1109
1221
  }
1222
+ if (typeof params.maxReasoningTokens !== "undefined") {
1223
+ if (params.maxReasoningTokens < 0) {
1224
+ throw new Error("`maxReasoningTokens` must be non-negative integer");
1225
+ }
1226
+ if (typeof params.maxOutputTokens !== "undefined") {
1227
+ if (params.maxReasoningTokens >= params.maxOutputTokens) {
1228
+ throw new Error("`maxOutputTokens` must be greater than `maxReasoningTokens`");
1229
+ }
1230
+ }
1231
+ }
1110
1232
  if (params.temperature &&
1111
1233
  (params.temperature < 0 || params.temperature > 2)) {
1112
1234
  throw new Error("`temperature` must be in the range of [0.0,2.0]");
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  /* eslint-disable @typescript-eslint/no-unused-vars */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.jsonSchemaToGeminiParameters = exports.zodToGeminiParameters = exports.removeAdditionalProperties = void 0;
4
+ exports.jsonSchemaToGeminiParameters = exports.schemaToGeminiParameters = exports.removeAdditionalProperties = void 0;
5
+ const types_1 = require("@langchain/core/utils/types");
5
6
  const zod_to_json_schema_1 = require("zod-to-json-schema");
6
7
  function removeAdditionalProperties(
7
8
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -26,17 +27,14 @@ obj) {
26
27
  return obj;
27
28
  }
28
29
  exports.removeAdditionalProperties = removeAdditionalProperties;
29
- function zodToGeminiParameters(
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- zodObj) {
30
+ function schemaToGeminiParameters(schema) {
32
31
  // Gemini doesn't accept either the $schema or additionalProperties
33
32
  // attributes, so we need to explicitly remove them.
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- const jsonSchema = removeAdditionalProperties((0, zod_to_json_schema_1.zodToJsonSchema)(zodObj));
33
+ const jsonSchema = removeAdditionalProperties((0, types_1.isZodSchema)(schema) ? (0, zod_to_json_schema_1.zodToJsonSchema)(schema) : schema);
36
34
  const { $schema, ...rest } = jsonSchema;
37
35
  return rest;
38
36
  }
39
- exports.zodToGeminiParameters = zodToGeminiParameters;
37
+ exports.schemaToGeminiParameters = schemaToGeminiParameters;
40
38
  function jsonSchemaToGeminiParameters(
41
39
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
40
  schema) {
@@ -1,5 +1,6 @@
1
1
  import type { z } from "zod";
2
+ import { type JsonSchema7Type } from "zod-to-json-schema";
2
3
  import { GeminiFunctionSchema, GeminiJsonSchema } from "../types.js";
3
4
  export declare function removeAdditionalProperties(obj: Record<string, any>): GeminiJsonSchema;
4
- export declare function zodToGeminiParameters(zodObj: z.ZodType<any>): GeminiFunctionSchema;
5
+ export declare function schemaToGeminiParameters<RunOutput extends Record<string, any> = Record<string, any>>(schema: z.ZodType<RunOutput> | z.ZodEffects<z.ZodType<RunOutput>> | JsonSchema7Type): GeminiFunctionSchema;
5
6
  export declare function jsonSchemaToGeminiParameters(schema: Record<string, any>): GeminiFunctionSchema;
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import { isZodSchema } from "@langchain/core/utils/types";
2
3
  import { zodToJsonSchema } from "zod-to-json-schema";
3
4
  export function removeAdditionalProperties(
4
5
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -22,13 +23,10 @@ obj) {
22
23
  }
23
24
  return obj;
24
25
  }
25
- export function zodToGeminiParameters(
26
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
- zodObj) {
26
+ export function schemaToGeminiParameters(schema) {
28
27
  // Gemini doesn't accept either the $schema or additionalProperties
29
28
  // attributes, so we need to explicitly remove them.
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- const jsonSchema = removeAdditionalProperties(zodToJsonSchema(zodObj));
29
+ const jsonSchema = removeAdditionalProperties(isZodSchema(schema) ? zodToJsonSchema(schema) : schema);
32
30
  const { $schema, ...rest } = jsonSchema;
33
31
  return rest;
34
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/google-common",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Core types and classes for Google services.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -36,11 +36,11 @@
36
36
  "zod-to-json-schema": "^3.22.4"
37
37
  },
38
38
  "peerDependencies": {
39
- "@langchain/core": ">=0.2.21 <0.4.0"
39
+ "@langchain/core": ">=0.3.48 <0.4.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@jest/globals": "^29.5.0",
43
- "@langchain/core": "workspace:*",
43
+ "@langchain/core": "0.3.48",
44
44
  "@langchain/scripts": ">=0.1.0 <0.2.0",
45
45
  "@swc/core": "^1.3.90",
46
46
  "@swc/jest": "^0.2.29",
@@ -58,7 +58,7 @@
58
58
  "jest": "^29.5.0",
59
59
  "jest-environment-node": "^29.6.4",
60
60
  "prettier": "^2.8.3",
61
- "release-it": "^17.6.0",
61
+ "release-it": "^18.1.2",
62
62
  "rollup": "^4.5.2",
63
63
  "ts-jest": "^29.1.0",
64
64
  "typescript": "<5.2.0",
@@ -138,4 +138,4 @@
138
138
  "experimental/utils/media_core.d.ts",
139
139
  "experimental/utils/media_core.d.cts"
140
140
  ]
141
- }
141
+ }