@langchain/google-common 0.1.5 → 0.1.7

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.
@@ -3,6 +3,7 @@ import { AIMessage, AIMessageChunk, isAIMessage, } from "@langchain/core/message
3
3
  import { ChatGenerationChunk, } from "@langchain/core/outputs";
4
4
  import { isLangChainTool } from "@langchain/core/utils/function_calling";
5
5
  import { GoogleAISafetyError } from "./safety.js";
6
+ import { GeminiSearchToolAttributes, } from "../types.js";
6
7
  import { zodToGeminiParameters } from "./zod_to_gemini_parameters.js";
7
8
  export class DefaultGeminiSafetyHandler {
8
9
  constructor(settings) {
@@ -500,6 +501,33 @@ export function getGeminiAPI(config) {
500
501
  function safeResponseToString(response) {
501
502
  return safeResponseTo(response, responseToString);
502
503
  }
504
+ function logprobResultToLogprob(result) {
505
+ const token = result?.token;
506
+ const logprob = result?.logProbability;
507
+ const encoder = new TextEncoder();
508
+ const bytes = Array.from(encoder.encode(token));
509
+ return {
510
+ token,
511
+ logprob,
512
+ bytes,
513
+ };
514
+ }
515
+ function candidateToLogprobs(candidate) {
516
+ const logprobs = candidate?.logprobsResult;
517
+ const chosenTokens = logprobs?.chosenCandidates ?? [];
518
+ const topTokens = logprobs?.topCandidates ?? [];
519
+ const content = [];
520
+ for (let co = 0; co < chosenTokens.length; co += 1) {
521
+ const chosen = chosenTokens[co];
522
+ const top = topTokens[co]?.candidates ?? [];
523
+ const logprob = logprobResultToLogprob(chosen);
524
+ logprob.top_logprobs = top.map((l) => logprobResultToLogprob(l));
525
+ content.push(logprob);
526
+ }
527
+ return {
528
+ content,
529
+ };
530
+ }
503
531
  function responseToGenerationInfo(response) {
504
532
  if (!Array.isArray(response.data)) {
505
533
  return {};
@@ -518,7 +546,11 @@ export function getGeminiAPI(config) {
518
546
  severity: rating.severity,
519
547
  severity_score: rating.severityScore,
520
548
  })),
549
+ citation_metadata: data.candidates[0]?.citationMetadata,
550
+ grounding_metadata: data.candidates[0]?.groundingMetadata,
521
551
  finish_reason: data.candidates[0]?.finishReason,
552
+ avgLogprobs: data.candidates[0]?.avgLogprobs,
553
+ logprobs: candidateToLogprobs(data.candidates[0]),
522
554
  };
523
555
  }
524
556
  function responseToChatGeneration(response) {
@@ -572,12 +604,59 @@ export function getGeminiAPI(config) {
572
604
  message,
573
605
  });
574
606
  }
575
- function responseToChatGenerations(response) {
607
+ function groundingSupportByPart(groundingSupports) {
608
+ const ret = [];
609
+ if (!groundingSupports || groundingSupports.length === 0) {
610
+ return [];
611
+ }
612
+ groundingSupports?.forEach((groundingSupport) => {
613
+ const segment = groundingSupport?.segment;
614
+ const partIndex = segment?.partIndex ?? 0;
615
+ if (ret[partIndex]) {
616
+ ret[partIndex].push(groundingSupport);
617
+ }
618
+ else {
619
+ ret[partIndex] = [groundingSupport];
620
+ }
621
+ });
622
+ return ret;
623
+ }
624
+ function responseToGroundedChatGenerations(response) {
576
625
  const parts = responseToParts(response);
577
626
  if (parts.length === 0) {
578
627
  return [];
579
628
  }
580
- let ret = parts.map((part) => partToChatGeneration(part));
629
+ // Citation and grounding information connected to each part / ChatGeneration
630
+ // to make sure they are available in downstream filters.
631
+ const candidate = response?.data
632
+ ?.candidates?.[0];
633
+ const groundingMetadata = candidate?.groundingMetadata;
634
+ const citationMetadata = candidate?.citationMetadata;
635
+ const groundingParts = groundingSupportByPart(groundingMetadata?.groundingSupports);
636
+ const ret = parts.map((part, index) => {
637
+ const gen = partToChatGeneration(part);
638
+ if (!gen.generationInfo) {
639
+ gen.generationInfo = {};
640
+ }
641
+ if (groundingMetadata) {
642
+ gen.generationInfo.groundingMetadata = groundingMetadata;
643
+ const groundingPart = groundingParts[index];
644
+ if (groundingPart) {
645
+ gen.generationInfo.groundingSupport = groundingPart;
646
+ }
647
+ }
648
+ if (citationMetadata) {
649
+ gen.generationInfo.citationMetadata = citationMetadata;
650
+ }
651
+ return gen;
652
+ });
653
+ return ret;
654
+ }
655
+ function responseToChatGenerations(response) {
656
+ let ret = responseToGroundedChatGenerations(response);
657
+ if (ret.length === 0) {
658
+ return [];
659
+ }
581
660
  if (ret.every((item) => typeof item.message.content === "string")) {
582
661
  const combinedContent = ret.map((item) => item.message.content).join("");
583
662
  const combinedText = ret.map((item) => item.text).join("");
@@ -610,6 +689,18 @@ export function getGeminiAPI(config) {
610
689
  }),
611
690
  ];
612
691
  }
692
+ // Add logprobs information to the message
693
+ const candidate = response?.data
694
+ ?.candidates?.[0];
695
+ const avgLogprobs = candidate?.avgLogprobs;
696
+ const logprobs = candidateToLogprobs(candidate);
697
+ if (logprobs) {
698
+ ret[0].message.response_metadata = {
699
+ ...ret[0].message.response_metadata,
700
+ logprobs,
701
+ avgLogprobs,
702
+ };
703
+ }
613
704
  return ret;
614
705
  }
615
706
  function responseToBaseMessageFields(response) {
@@ -737,9 +828,13 @@ export function getGeminiAPI(config) {
737
828
  temperature: parameters.temperature,
738
829
  topK: parameters.topK,
739
830
  topP: parameters.topP,
831
+ presencePenalty: parameters.presencePenalty,
832
+ frequencyPenalty: parameters.frequencyPenalty,
740
833
  maxOutputTokens: parameters.maxOutputTokens,
741
834
  stopSequences: parameters.stopSequences,
742
835
  responseMimeType: parameters.responseMimeType,
836
+ responseLogprobs: parameters.logprobs,
837
+ logprobs: parameters.topLogprobs,
743
838
  };
744
839
  }
745
840
  function formatSafetySettings(parameters) {
@@ -783,14 +878,43 @@ export function getGeminiAPI(config) {
783
878
  parameters: jsonSchema,
784
879
  };
785
880
  }
881
+ function searchToolName(tool) {
882
+ for (const name of GeminiSearchToolAttributes) {
883
+ if (name in tool) {
884
+ return name;
885
+ }
886
+ }
887
+ return undefined;
888
+ }
889
+ function cleanGeminiTool(tool) {
890
+ const orig = searchToolName(tool);
891
+ const adj = config?.googleSearchToolAdjustment;
892
+ if (orig && adj && adj !== orig) {
893
+ return {
894
+ [adj]: {},
895
+ };
896
+ }
897
+ else {
898
+ return tool;
899
+ }
900
+ }
786
901
  function formatTools(parameters) {
787
902
  const tools = parameters?.tools;
788
903
  if (!tools || tools.length === 0) {
789
904
  return [];
790
905
  }
791
- // Group all LangChain tools into a single functionDeclarations array
792
- const langChainTools = tools.filter(isLangChainTool);
793
- const otherTools = tools.filter((tool) => !isLangChainTool(tool));
906
+ // Group all LangChain tools into a single functionDeclarations array.
907
+ // Gemini Tools may be normalized to different tool names
908
+ const langChainTools = [];
909
+ const otherTools = [];
910
+ tools.forEach((tool) => {
911
+ if (isLangChainTool(tool)) {
912
+ langChainTools.push(tool);
913
+ }
914
+ else {
915
+ otherTools.push(cleanGeminiTool(tool));
916
+ }
917
+ });
794
918
  const result = [...otherTools];
795
919
  if (langChainTools.length > 0) {
796
920
  result.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/google-common",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Core types and classes for Google services.",
5
5
  "type": "module",
6
6
  "engines": {