@gullabs/google 0.10.1 → 0.11.1

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/dist/index.cjs CHANGED
@@ -42,6 +42,74 @@ var GOOGLE_REASONING_EFFORT_BUDGET = {
42
42
  high: 24576
43
43
  };
44
44
 
45
+ // src/grounding.ts
46
+ function hostnameFrom(url) {
47
+ return url.hostname.startsWith("www.") ? url.hostname.slice(4) : url.hostname;
48
+ }
49
+ function toCitation(chunk) {
50
+ if (chunk === null || typeof chunk !== "object") return void 0;
51
+ const web = chunk["web"];
52
+ if (web === null || typeof web !== "object") return void 0;
53
+ const uri = web["uri"];
54
+ if (typeof uri !== "string" || uri.length === 0) return void 0;
55
+ let parsed;
56
+ try {
57
+ parsed = new URL(uri);
58
+ } catch {
59
+ return void 0;
60
+ }
61
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
62
+ if (parsed.hostname === "") return void 0;
63
+ const title = web["title"];
64
+ const hasTitle = typeof title === "string" && title.length > 0;
65
+ const sourceName = hasTitle ? title : hostnameFrom(parsed);
66
+ return {
67
+ url: uri,
68
+ ...hasTitle ? { title } : {},
69
+ sourceName
70
+ };
71
+ }
72
+ function normalizeGroundingCitations(groundingMetadata) {
73
+ if (groundingMetadata === null || typeof groundingMetadata !== "object") return [];
74
+ const chunks = groundingMetadata["groundingChunks"];
75
+ if (!Array.isArray(chunks)) return [];
76
+ const seen = /* @__PURE__ */ new Set();
77
+ const citations = [];
78
+ for (const chunk of chunks) {
79
+ const citation = toCitation(chunk);
80
+ if (citation === void 0) continue;
81
+ if (seen.has(citation.url)) continue;
82
+ seen.add(citation.url);
83
+ citations.push(citation);
84
+ }
85
+ return citations;
86
+ }
87
+
88
+ // src/tool-call-id.ts
89
+ function reserveProviderToolCallIds(ids) {
90
+ const reserved = /* @__PURE__ */ new Set();
91
+ for (const id of ids) {
92
+ if (typeof id === "string" && id.length > 0) reserved.add(id);
93
+ }
94
+ return reserved;
95
+ }
96
+ function nextFallbackToolCallId(toolName, counters, reserved, counterKey = toolName) {
97
+ let n = counters.get(counterKey) ?? 0;
98
+ let id;
99
+ do {
100
+ n += 1;
101
+ id = `call_${toolName}_${n}`;
102
+ } while (reserved.has(id));
103
+ counters.set(counterKey, n);
104
+ return id;
105
+ }
106
+ function resolveToolCallId(providerId, toolName, counters, reserved, counterKey) {
107
+ if (typeof providerId === "string" && providerId.length > 0) {
108
+ return providerId;
109
+ }
110
+ return nextFallbackToolCallId(toolName, counters, reserved, counterKey ?? toolName);
111
+ }
112
+
45
113
  // src/flex-fallback.ts
46
114
  var CAPACITY_PATTERNS = [
47
115
  /capacity/i,
@@ -389,6 +457,12 @@ function mapUsage(meta) {
389
457
  };
390
458
  return usage;
391
459
  }
460
+ function mapGoogleToolChoice(choice) {
461
+ if (choice === "auto") return { mode: "AUTO" };
462
+ if (choice === "required") return { mode: "ANY" };
463
+ if (choice === "none") return { mode: "NONE" };
464
+ return { mode: "ANY", allowedFunctionNames: [choice.name] };
465
+ }
392
466
  function mapPart(p) {
393
467
  switch (p.kind) {
394
468
  case "text":
@@ -416,6 +490,22 @@ function mapPart(p) {
416
490
  "Google Gemini expects FileUriPart with a Files API uri; got file-ref (provider file id). Upload via GoogleFileStore and pass the returned uri.",
417
491
  { kind: "bad_request", retryable: false, provider: "google" }
418
492
  );
493
+ case "tool-call":
494
+ return {
495
+ functionCall: {
496
+ id: p.toolCallId,
497
+ name: p.toolName,
498
+ args: p.args
499
+ }
500
+ };
501
+ case "tool-result":
502
+ return {
503
+ functionResponse: {
504
+ id: p.toolCallId,
505
+ name: p.toolName,
506
+ response: p.isError === true ? { error: p.result } : p.result
507
+ }
508
+ };
419
509
  default:
420
510
  return core.assertNever(p);
421
511
  }
@@ -559,6 +649,34 @@ function geminiAdapter(opts) {
559
649
  if (googleProviderConfig.tools !== void 0) {
560
650
  config.tools = googleProviderConfig.tools;
561
651
  }
652
+ if (req.tools !== void 0 && req.tools.length > 0) {
653
+ if (req.modelDescriptor?.capabilities?.functionCalling !== true) {
654
+ throw new core.LlmError(
655
+ `tools is not supported for google model "${model}" (capabilities.functionCalling is not true).`,
656
+ { kind: "bad_request", retryable: false, provider: "google" }
657
+ );
658
+ }
659
+ if (googleProviderConfig.tools !== void 0) {
660
+ throw new core.LlmError(
661
+ "tools cannot be combined with providerOptions.google.tools (googleSearch) in this iteration.",
662
+ { kind: "bad_request", retryable: false, provider: "google" }
663
+ );
664
+ }
665
+ config.tools = [
666
+ {
667
+ functionDeclarations: req.tools.map((tool) => ({
668
+ name: tool.name,
669
+ description: tool.description,
670
+ parameters: tool.inputJsonSchema
671
+ }))
672
+ }
673
+ ];
674
+ if (req.toolChoice !== void 0) {
675
+ config.toolConfig = {
676
+ functionCallingConfig: mapGoogleToolChoice(req.toolChoice)
677
+ };
678
+ }
679
+ }
562
680
  assertSamplingAllowed(config, model, req.modelDescriptor?.capabilities?.sampling);
563
681
  let tierTimeoutHandle;
564
682
  const clearTierTimeout = () => {
@@ -676,7 +794,25 @@ function geminiAdapter(opts) {
676
794
  const parts = candidate.content?.parts ?? [];
677
795
  const textParts = [];
678
796
  const thoughtParts = [];
797
+ const toolCalls = [];
798
+ const nameCounts = /* @__PURE__ */ new Map();
799
+ const reservedIds = reserveProviderToolCallIds(
800
+ parts.map((part) => part.functionCall?.id)
801
+ );
679
802
  for (const part of parts) {
803
+ if (part.functionCall !== void 0 && typeof part.functionCall.name === "string") {
804
+ const toolName = part.functionCall.name;
805
+ toolCalls.push({
806
+ toolCallId: resolveToolCallId(
807
+ part.functionCall.id,
808
+ toolName,
809
+ nameCounts,
810
+ reservedIds
811
+ ),
812
+ toolName,
813
+ args: part.functionCall.args ?? {}
814
+ });
815
+ }
680
816
  if (part.text !== void 0) {
681
817
  if (part.thought === true) {
682
818
  thoughtParts.push(part.text);
@@ -704,7 +840,7 @@ function geminiAdapter(opts) {
704
840
  ...text.length > 0 ? { text } : {},
705
841
  ...reasoningText !== void 0 ? { reasoningText } : {},
706
842
  ...rawStructured !== void 0 ? { rawStructured } : {},
707
- ...finishReason !== void 0 ? { finishReason } : {},
843
+ ...toolCalls.length > 0 ? { toolCalls, finishReason: "tool_calls" } : finishReason !== void 0 ? { finishReason } : {},
708
844
  ...response.modelVersion !== void 0 ? { modelVersion: response.modelVersion } : {},
709
845
  ...response.responseId !== void 0 ? { responseId: response.responseId } : {},
710
846
  // Build providerMetadata — merge promptFeedback + groundingMetadata when present.
@@ -720,6 +856,12 @@ function geminiAdapter(opts) {
720
856
  meta["groundingMetadata"] = gm;
721
857
  }
722
858
  return { providerMetadata: meta };
859
+ })(),
860
+ ...(() => {
861
+ const gm = candidate.groundingMetadata;
862
+ if (gm === void 0) return {};
863
+ const citations = normalizeGroundingCitations(gm);
864
+ return citations.length > 0 ? { citations } : {};
723
865
  })()
724
866
  };
725
867
  return result;
@@ -732,13 +874,23 @@ function geminiAdapter(opts) {
732
874
  );
733
875
  }
734
876
  const contents = mapMessagesToGeminiContents(req.messages);
877
+ const countTools = req.tools !== void 0 && req.tools.length > 0 ? [
878
+ {
879
+ functionDeclarations: req.tools.map((tool) => ({
880
+ name: tool.name,
881
+ description: tool.description,
882
+ parameters: tool.inputJsonSchema
883
+ }))
884
+ }
885
+ ] : void 0;
735
886
  const params = {
736
887
  model: req.model,
737
888
  contents,
738
- ...req.system !== void 0 || ctx.signal !== void 0 ? {
889
+ ...req.system !== void 0 || ctx.signal !== void 0 || countTools !== void 0 ? {
739
890
  config: {
740
891
  ...req.system !== void 0 ? { systemInstruction: { parts: [{ text: req.system }] } } : {},
741
- ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
892
+ ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {},
893
+ ...countTools !== void 0 ? { tools: countTools } : {}
742
894
  }
743
895
  } : {}
744
896
  };
@@ -755,6 +907,7 @@ function geminiAdapter(opts) {
755
907
  const details = response.cachedContentTokenCount !== void 0 ? { cached: response.cachedContentTokenCount } : void 0;
756
908
  return {
757
909
  totalTokens: response.totalTokens,
910
+ accuracy: "exact",
758
911
  ...details !== void 0 ? { details } : {},
759
912
  raw: response
760
913
  };
@@ -2538,6 +2691,7 @@ var geminiModelDescriptors = [
2538
2691
  sampling: "tunable",
2539
2692
  caching: { explicit: true, minTokens: 2048 },
2540
2693
  grounding: true,
2694
+ functionCalling: true,
2541
2695
  serviceTiers: ["flex", "standard"]
2542
2696
  },
2543
2697
  configSchema: Gemini25ProConfigSchema,
@@ -2558,6 +2712,7 @@ var geminiModelDescriptors = [
2558
2712
  sampling: "tunable",
2559
2713
  caching: { explicit: true, minTokens: 2048 },
2560
2714
  grounding: true,
2715
+ functionCalling: true,
2561
2716
  serviceTiers: ["flex", "standard"]
2562
2717
  },
2563
2718
  configSchema: Gemini25FlashConfigSchema,
@@ -2578,6 +2733,7 @@ var geminiModelDescriptors = [
2578
2733
  sampling: "tunable",
2579
2734
  caching: { explicit: true, minTokens: 2048 },
2580
2735
  grounding: true,
2736
+ functionCalling: true,
2581
2737
  serviceTiers: ["flex", "standard"]
2582
2738
  },
2583
2739
  configSchema: Gemini25FlashLiteConfigSchema,
@@ -2598,6 +2754,7 @@ var geminiModelDescriptors = [
2598
2754
  sampling: "fixed",
2599
2755
  caching: { explicit: true, minTokens: 2048 },
2600
2756
  grounding: true,
2757
+ functionCalling: true,
2601
2758
  serviceTiers: ["flex", "standard"]
2602
2759
  },
2603
2760
  configSchema: Gemini35FlashConfigSchema,
@@ -2618,6 +2775,7 @@ var geminiModelDescriptors = [
2618
2775
  sampling: "fixed",
2619
2776
  caching: { explicit: true, minTokens: 2048 },
2620
2777
  grounding: true,
2778
+ functionCalling: true,
2621
2779
  serviceTiers: ["flex", "standard"]
2622
2780
  },
2623
2781
  configSchema: Gemini31FlashLiteConfigSchema,
@@ -2638,6 +2796,7 @@ var geminiModelDescriptors = [
2638
2796
  sampling: "fixed",
2639
2797
  caching: { explicit: true, minTokens: 2048 },
2640
2798
  grounding: true,
2799
+ functionCalling: true,
2641
2800
  serviceTiers: ["flex", "standard"]
2642
2801
  },
2643
2802
  configSchema: Gemini31ProPreviewConfigSchema,
@@ -2658,6 +2817,7 @@ var geminiModelDescriptors = [
2658
2817
  sampling: "fixed",
2659
2818
  caching: { explicit: true, minTokens: 2048 },
2660
2819
  grounding: true,
2820
+ functionCalling: true,
2661
2821
  serviceTiers: ["flex", "standard"]
2662
2822
  },
2663
2823
  configSchema: Gemini3FlashPreviewConfigSchema,
@@ -3193,44 +3353,6 @@ var GoogleCacheStore = class {
3193
3353
  }
3194
3354
  }
3195
3355
  };
3196
-
3197
- // src/grounding.ts
3198
- function hostnameFrom(url) {
3199
- return url.hostname.startsWith("www.") ? url.hostname.slice(4) : url.hostname;
3200
- }
3201
- function toCitation(chunk) {
3202
- if (chunk === null || typeof chunk !== "object") return void 0;
3203
- const web = chunk["web"];
3204
- if (web === null || typeof web !== "object") return void 0;
3205
- const uri = web["uri"];
3206
- if (typeof uri !== "string" || uri.length === 0) return void 0;
3207
- let parsed;
3208
- try {
3209
- parsed = new URL(uri);
3210
- } catch {
3211
- return void 0;
3212
- }
3213
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
3214
- if (parsed.hostname === "") return void 0;
3215
- const title = web["title"];
3216
- const sourceName = typeof title === "string" && title.length > 0 ? title : hostnameFrom(parsed);
3217
- return { url: uri, sourceName };
3218
- }
3219
- function normalizeGroundingCitations(groundingMetadata) {
3220
- if (groundingMetadata === null || typeof groundingMetadata !== "object") return [];
3221
- const chunks = groundingMetadata["groundingChunks"];
3222
- if (!Array.isArray(chunks)) return [];
3223
- const seen = /* @__PURE__ */ new Set();
3224
- const citations = [];
3225
- for (const chunk of chunks) {
3226
- const citation = toCitation(chunk);
3227
- if (citation === void 0) continue;
3228
- if (seen.has(citation.url)) continue;
3229
- seen.add(citation.url);
3230
- citations.push(citation);
3231
- }
3232
- return citations;
3233
- }
3234
3356
  function badRequest(message) {
3235
3357
  return new core.LlmError(message, { kind: "bad_request", retryable: false });
3236
3358
  }
@@ -3267,19 +3389,49 @@ function convertMediaResolution(mediaResolution, location) {
3267
3389
  }
3268
3390
  return mapMediaResolutionLevel(mediaResolution.level, location);
3269
3391
  }
3270
- function convertPart(part, location) {
3392
+ function convertPart(part, location, nameCounts, reservedIds) {
3271
3393
  const keys = definedKeys(part);
3272
3394
  const baseKeys = keys.filter(
3273
3395
  (key) => key === "text" || key === "inlineData" || key === "fileData"
3274
3396
  );
3275
3397
  if (baseKeys.length === 0) {
3398
+ if (keys.includes("functionCall") && keys.every((k) => k === "functionCall")) {
3399
+ const fc = part.functionCall;
3400
+ if (fc === void 0 || typeof fc.name !== "string" || fc.name.length === 0) {
3401
+ throw badRequest(`${location}: functionCall.name is required.`);
3402
+ }
3403
+ return {
3404
+ kind: "tool-call",
3405
+ toolCallId: resolveToolCallId(fc.id, fc.name, nameCounts, reservedIds),
3406
+ toolName: fc.name,
3407
+ args: fc.args ?? {}
3408
+ };
3409
+ }
3410
+ if (keys.includes("functionResponse") && keys.every((k) => k === "functionResponse")) {
3411
+ const fr = part.functionResponse;
3412
+ if (fr === void 0 || typeof fr.name !== "string" || fr.name.length === 0) {
3413
+ throw badRequest(`${location}: functionResponse.name is required.`);
3414
+ }
3415
+ return {
3416
+ kind: "tool-result",
3417
+ toolCallId: resolveToolCallId(
3418
+ fr.id,
3419
+ fr.name,
3420
+ nameCounts,
3421
+ reservedIds,
3422
+ `result:${fr.name}`
3423
+ ),
3424
+ toolName: fr.name,
3425
+ result: fr.response ?? null
3426
+ };
3427
+ }
3276
3428
  if (keys.length === 0) {
3277
3429
  throw badRequest(
3278
3430
  `${location}: Part has no recognized fields set (expected exactly one of text, inlineData, fileData).`
3279
3431
  );
3280
3432
  }
3281
3433
  throw badRequest(
3282
- `${location}: Part keys [${keys.join(", ")}] are not supported by geminiContentToMessages \u2014 only text, inlineData, and fileData parts can be represented in any-llm.`
3434
+ `${location}: Part keys [${keys.join(", ")}] are not supported by geminiContentToMessages \u2014 only text, inlineData, fileData, functionCall, and functionResponse parts can be represented in any-llm.`
3283
3435
  );
3284
3436
  }
3285
3437
  if (baseKeys.length > 1) {
@@ -3383,6 +3535,15 @@ function convertSystemInstruction(systemInstruction) {
3383
3535
  }
3384
3536
  function geminiContentToMessages(input) {
3385
3537
  const system = input.systemInstruction !== void 0 ? convertSystemInstruction(input.systemInstruction) : void 0;
3538
+ const nameCounts = /* @__PURE__ */ new Map();
3539
+ const reservedIds = reserveProviderToolCallIds(
3540
+ input.contents.flatMap(
3541
+ (content) => (content.parts ?? []).flatMap((part) => {
3542
+ const p = part;
3543
+ return [p.functionCall?.id, p.functionResponse?.id];
3544
+ })
3545
+ )
3546
+ );
3386
3547
  const messages = input.contents.map((content, contentIndex) => {
3387
3548
  const location = `contents[${contentIndex}]`;
3388
3549
  const envelopeExtraKeys = definedKeys(content).filter(
@@ -3395,7 +3556,7 @@ function geminiContentToMessages(input) {
3395
3556
  }
3396
3557
  const role = convertRole(content.role, location);
3397
3558
  const parts = (content.parts ?? []).map(
3398
- (part, partIndex) => convertPart(part, `${location}.parts[${partIndex}]`)
3559
+ (part, partIndex) => convertPart(part, `${location}.parts[${partIndex}]`, nameCounts, reservedIds)
3399
3560
  );
3400
3561
  return { role, parts };
3401
3562
  });
@@ -3418,7 +3579,6 @@ exports.geminiPricingSource = geminiPricingSource;
3418
3579
  exports.gemmaModelDescriptors = gemmaModelDescriptors;
3419
3580
  exports.googleProvider = googleProvider;
3420
3581
  exports.isGeminiCapacityError = isGeminiCapacityError;
3421
- exports.normalizeGroundingCitations = normalizeGroundingCitations;
3422
3582
  exports.pricingVersion = pricingVersion;
3423
3583
  exports.requireApiKey = requireApiKey;
3424
3584
  //# sourceMappingURL=index.cjs.map