@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.d.cts CHANGED
@@ -97,6 +97,11 @@ interface GeminiPartShape {
97
97
  * Real field name in @google/genai Candidate.content.parts: `thought`.
98
98
  */
99
99
  thought?: boolean;
100
+ functionCall?: {
101
+ id?: string;
102
+ name?: string;
103
+ args?: unknown;
104
+ };
100
105
  }
101
106
  /** A candidate returned by Gemini generateContent. */
102
107
  interface GeminiCandidateShape {
@@ -199,7 +204,21 @@ interface GeminiFileDataContentPart {
199
204
  * Each member (including the optional per-part `mediaResolution`) is a
200
205
  * structural subset of the real `@google/genai` `Part` type for the fields we use.
201
206
  */
202
- type GeminiContentPart = GeminiTextContentPart | GeminiInlineDataContentPart | GeminiFileDataContentPart;
207
+ interface GeminiFunctionCallPart {
208
+ functionCall: {
209
+ id?: string;
210
+ name: string;
211
+ args?: unknown;
212
+ };
213
+ }
214
+ interface GeminiFunctionResponsePart {
215
+ functionResponse: {
216
+ id?: string;
217
+ name: string;
218
+ response: unknown;
219
+ };
220
+ }
221
+ type GeminiContentPart = GeminiTextContentPart | GeminiInlineDataContentPart | GeminiFileDataContentPart | GeminiFunctionCallPart | GeminiFunctionResponsePart;
203
222
  /** A content object (message) we construct. */
204
223
  interface GeminiContent {
205
224
  role: string;
@@ -271,6 +290,20 @@ interface GeminiGenerateConfig {
271
290
  timeout?: number;
272
291
  headers?: Record<string, string>;
273
292
  };
293
+ tools?: Array<{
294
+ functionDeclarations?: Array<{
295
+ name: string;
296
+ description: string;
297
+ parameters?: unknown;
298
+ }>;
299
+ googleSearch?: Record<string, never>;
300
+ }>;
301
+ toolConfig?: {
302
+ functionCallingConfig?: {
303
+ mode?: 'AUTO' | 'ANY' | 'NONE';
304
+ allowedFunctionNames?: string[];
305
+ };
306
+ };
274
307
  }
275
308
  /**
276
309
  * Parameters for models.generateContent.
@@ -298,6 +331,7 @@ interface GeminiCountTokensParams {
298
331
  * is forwarded here directly, unlike `run()`'s combined timer signal.
299
332
  */
300
333
  abortSignal?: AbortSignal;
334
+ tools?: GeminiGenerateConfig['tools'];
301
335
  };
302
336
  }
303
337
  /**
@@ -859,30 +893,6 @@ declare class GoogleCacheStore {
859
893
  delete(handle: GoogleCacheHandle): Promise<void>;
860
894
  }
861
895
 
862
- /**
863
- * normalizeGroundingCitations — shape Gemini's raw groundingMetadata.groundingChunks
864
- * into a clean, deduplicated citation list.
865
- *
866
- * This is a caller-owned, optional post-processing convenience helper — NOT
867
- * request validation. It NEVER throws: any missing/malformed input yields `[]`.
868
- *
869
- * @module
870
- */
871
- interface Citation {
872
- url: string;
873
- sourceName: string;
874
- }
875
- /**
876
- * Shape Gemini's raw `groundingMetadata.groundingChunks` into a clean,
877
- * deduplicated citation list (deduplicated by URL, first-seen order).
878
- *
879
- * Accepts `unknown` since `groundingMetadata` arrives as raw JSON on
880
- * `providerMetadata` (see `docs/grounded-structured.md`). Never throws —
881
- * any missing/malformed top-level shape returns `[]`; a malformed individual
882
- * chunk is skipped rather than failing the whole array.
883
- */
884
- declare function normalizeGroundingCitations(groundingMetadata: unknown): Citation[];
885
-
886
896
  /**
887
897
  * geminiContentToMessages — migration utility: `@google/genai` `Content[]` →
888
898
  * any-llm's normalized `Message[]`.
@@ -964,4 +974,4 @@ interface GeminiContentToMessagesResult {
964
974
  */
965
975
  declare function geminiContentToMessages(input: GeminiContentToMessagesInput): GeminiContentToMessagesResult;
966
976
 
967
- export { type CacheKey, type Citation, FLEX_DEFAULT_TIMEOUT_MS, type FileDeleteOptions, GEMINI_PRICING, type GeminiAdapterOptions, type GeminiCachesClientLike, type GeminiClientLike, type GeminiContentToMessagesInput, type GeminiContentToMessagesResult, type GeminiCountTokensParams, type GeminiCountTokensResponseShape, type GeminiFilesClientLike, type GoogleCacheHandle, GoogleCacheStore, type GoogleCacheStoreOptions, type GoogleFileHandle, GoogleFileStore, type GoogleFileStoreOptions, type GoogleProviderOptions, type GoogleSafetySetting, type GoogleSearchTool, STANDARD_DEFAULT_TIMEOUT_MS, TIER_FACTOR, TRANSPORT_TIMEOUT_BUFFER_MS, buildGoogleClient, defaultGeminiRegistry, geminiAdapter, geminiContentToMessages, geminiModelDescriptors, geminiPricingSource, gemmaModelDescriptors, googleProvider, isGeminiCapacityError, normalizeGroundingCitations, pricingVersion, requireApiKey };
977
+ export { type CacheKey, FLEX_DEFAULT_TIMEOUT_MS, type FileDeleteOptions, GEMINI_PRICING, type GeminiAdapterOptions, type GeminiCachesClientLike, type GeminiClientLike, type GeminiContentToMessagesInput, type GeminiContentToMessagesResult, type GeminiCountTokensParams, type GeminiCountTokensResponseShape, type GeminiFilesClientLike, type GoogleCacheHandle, GoogleCacheStore, type GoogleCacheStoreOptions, type GoogleFileHandle, GoogleFileStore, type GoogleFileStoreOptions, type GoogleProviderOptions, type GoogleSafetySetting, type GoogleSearchTool, STANDARD_DEFAULT_TIMEOUT_MS, TIER_FACTOR, TRANSPORT_TIMEOUT_BUFFER_MS, buildGoogleClient, defaultGeminiRegistry, geminiAdapter, geminiContentToMessages, geminiModelDescriptors, geminiPricingSource, gemmaModelDescriptors, googleProvider, isGeminiCapacityError, pricingVersion, requireApiKey };
package/dist/index.d.ts CHANGED
@@ -97,6 +97,11 @@ interface GeminiPartShape {
97
97
  * Real field name in @google/genai Candidate.content.parts: `thought`.
98
98
  */
99
99
  thought?: boolean;
100
+ functionCall?: {
101
+ id?: string;
102
+ name?: string;
103
+ args?: unknown;
104
+ };
100
105
  }
101
106
  /** A candidate returned by Gemini generateContent. */
102
107
  interface GeminiCandidateShape {
@@ -199,7 +204,21 @@ interface GeminiFileDataContentPart {
199
204
  * Each member (including the optional per-part `mediaResolution`) is a
200
205
  * structural subset of the real `@google/genai` `Part` type for the fields we use.
201
206
  */
202
- type GeminiContentPart = GeminiTextContentPart | GeminiInlineDataContentPart | GeminiFileDataContentPart;
207
+ interface GeminiFunctionCallPart {
208
+ functionCall: {
209
+ id?: string;
210
+ name: string;
211
+ args?: unknown;
212
+ };
213
+ }
214
+ interface GeminiFunctionResponsePart {
215
+ functionResponse: {
216
+ id?: string;
217
+ name: string;
218
+ response: unknown;
219
+ };
220
+ }
221
+ type GeminiContentPart = GeminiTextContentPart | GeminiInlineDataContentPart | GeminiFileDataContentPart | GeminiFunctionCallPart | GeminiFunctionResponsePart;
203
222
  /** A content object (message) we construct. */
204
223
  interface GeminiContent {
205
224
  role: string;
@@ -271,6 +290,20 @@ interface GeminiGenerateConfig {
271
290
  timeout?: number;
272
291
  headers?: Record<string, string>;
273
292
  };
293
+ tools?: Array<{
294
+ functionDeclarations?: Array<{
295
+ name: string;
296
+ description: string;
297
+ parameters?: unknown;
298
+ }>;
299
+ googleSearch?: Record<string, never>;
300
+ }>;
301
+ toolConfig?: {
302
+ functionCallingConfig?: {
303
+ mode?: 'AUTO' | 'ANY' | 'NONE';
304
+ allowedFunctionNames?: string[];
305
+ };
306
+ };
274
307
  }
275
308
  /**
276
309
  * Parameters for models.generateContent.
@@ -298,6 +331,7 @@ interface GeminiCountTokensParams {
298
331
  * is forwarded here directly, unlike `run()`'s combined timer signal.
299
332
  */
300
333
  abortSignal?: AbortSignal;
334
+ tools?: GeminiGenerateConfig['tools'];
301
335
  };
302
336
  }
303
337
  /**
@@ -859,30 +893,6 @@ declare class GoogleCacheStore {
859
893
  delete(handle: GoogleCacheHandle): Promise<void>;
860
894
  }
861
895
 
862
- /**
863
- * normalizeGroundingCitations — shape Gemini's raw groundingMetadata.groundingChunks
864
- * into a clean, deduplicated citation list.
865
- *
866
- * This is a caller-owned, optional post-processing convenience helper — NOT
867
- * request validation. It NEVER throws: any missing/malformed input yields `[]`.
868
- *
869
- * @module
870
- */
871
- interface Citation {
872
- url: string;
873
- sourceName: string;
874
- }
875
- /**
876
- * Shape Gemini's raw `groundingMetadata.groundingChunks` into a clean,
877
- * deduplicated citation list (deduplicated by URL, first-seen order).
878
- *
879
- * Accepts `unknown` since `groundingMetadata` arrives as raw JSON on
880
- * `providerMetadata` (see `docs/grounded-structured.md`). Never throws —
881
- * any missing/malformed top-level shape returns `[]`; a malformed individual
882
- * chunk is skipped rather than failing the whole array.
883
- */
884
- declare function normalizeGroundingCitations(groundingMetadata: unknown): Citation[];
885
-
886
896
  /**
887
897
  * geminiContentToMessages — migration utility: `@google/genai` `Content[]` →
888
898
  * any-llm's normalized `Message[]`.
@@ -964,4 +974,4 @@ interface GeminiContentToMessagesResult {
964
974
  */
965
975
  declare function geminiContentToMessages(input: GeminiContentToMessagesInput): GeminiContentToMessagesResult;
966
976
 
967
- export { type CacheKey, type Citation, FLEX_DEFAULT_TIMEOUT_MS, type FileDeleteOptions, GEMINI_PRICING, type GeminiAdapterOptions, type GeminiCachesClientLike, type GeminiClientLike, type GeminiContentToMessagesInput, type GeminiContentToMessagesResult, type GeminiCountTokensParams, type GeminiCountTokensResponseShape, type GeminiFilesClientLike, type GoogleCacheHandle, GoogleCacheStore, type GoogleCacheStoreOptions, type GoogleFileHandle, GoogleFileStore, type GoogleFileStoreOptions, type GoogleProviderOptions, type GoogleSafetySetting, type GoogleSearchTool, STANDARD_DEFAULT_TIMEOUT_MS, TIER_FACTOR, TRANSPORT_TIMEOUT_BUFFER_MS, buildGoogleClient, defaultGeminiRegistry, geminiAdapter, geminiContentToMessages, geminiModelDescriptors, geminiPricingSource, gemmaModelDescriptors, googleProvider, isGeminiCapacityError, normalizeGroundingCitations, pricingVersion, requireApiKey };
977
+ export { type CacheKey, FLEX_DEFAULT_TIMEOUT_MS, type FileDeleteOptions, GEMINI_PRICING, type GeminiAdapterOptions, type GeminiCachesClientLike, type GeminiClientLike, type GeminiContentToMessagesInput, type GeminiContentToMessagesResult, type GeminiCountTokensParams, type GeminiCountTokensResponseShape, type GeminiFilesClientLike, type GoogleCacheHandle, GoogleCacheStore, type GoogleCacheStoreOptions, type GoogleFileHandle, GoogleFileStore, type GoogleFileStoreOptions, type GoogleProviderOptions, type GoogleSafetySetting, type GoogleSearchTool, STANDARD_DEFAULT_TIMEOUT_MS, TIER_FACTOR, TRANSPORT_TIMEOUT_BUFFER_MS, buildGoogleClient, defaultGeminiRegistry, geminiAdapter, geminiContentToMessages, geminiModelDescriptors, geminiPricingSource, gemmaModelDescriptors, googleProvider, isGeminiCapacityError, pricingVersion, requireApiKey };
package/dist/index.js CHANGED
@@ -40,6 +40,74 @@ var GOOGLE_REASONING_EFFORT_BUDGET = {
40
40
  high: 24576
41
41
  };
42
42
 
43
+ // src/grounding.ts
44
+ function hostnameFrom(url) {
45
+ return url.hostname.startsWith("www.") ? url.hostname.slice(4) : url.hostname;
46
+ }
47
+ function toCitation(chunk) {
48
+ if (chunk === null || typeof chunk !== "object") return void 0;
49
+ const web = chunk["web"];
50
+ if (web === null || typeof web !== "object") return void 0;
51
+ const uri = web["uri"];
52
+ if (typeof uri !== "string" || uri.length === 0) return void 0;
53
+ let parsed;
54
+ try {
55
+ parsed = new URL(uri);
56
+ } catch {
57
+ return void 0;
58
+ }
59
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
60
+ if (parsed.hostname === "") return void 0;
61
+ const title = web["title"];
62
+ const hasTitle = typeof title === "string" && title.length > 0;
63
+ const sourceName = hasTitle ? title : hostnameFrom(parsed);
64
+ return {
65
+ url: uri,
66
+ ...hasTitle ? { title } : {},
67
+ sourceName
68
+ };
69
+ }
70
+ function normalizeGroundingCitations(groundingMetadata) {
71
+ if (groundingMetadata === null || typeof groundingMetadata !== "object") return [];
72
+ const chunks = groundingMetadata["groundingChunks"];
73
+ if (!Array.isArray(chunks)) return [];
74
+ const seen = /* @__PURE__ */ new Set();
75
+ const citations = [];
76
+ for (const chunk of chunks) {
77
+ const citation = toCitation(chunk);
78
+ if (citation === void 0) continue;
79
+ if (seen.has(citation.url)) continue;
80
+ seen.add(citation.url);
81
+ citations.push(citation);
82
+ }
83
+ return citations;
84
+ }
85
+
86
+ // src/tool-call-id.ts
87
+ function reserveProviderToolCallIds(ids) {
88
+ const reserved = /* @__PURE__ */ new Set();
89
+ for (const id of ids) {
90
+ if (typeof id === "string" && id.length > 0) reserved.add(id);
91
+ }
92
+ return reserved;
93
+ }
94
+ function nextFallbackToolCallId(toolName, counters, reserved, counterKey = toolName) {
95
+ let n = counters.get(counterKey) ?? 0;
96
+ let id;
97
+ do {
98
+ n += 1;
99
+ id = `call_${toolName}_${n}`;
100
+ } while (reserved.has(id));
101
+ counters.set(counterKey, n);
102
+ return id;
103
+ }
104
+ function resolveToolCallId(providerId, toolName, counters, reserved, counterKey) {
105
+ if (typeof providerId === "string" && providerId.length > 0) {
106
+ return providerId;
107
+ }
108
+ return nextFallbackToolCallId(toolName, counters, reserved, counterKey ?? toolName);
109
+ }
110
+
43
111
  // src/flex-fallback.ts
44
112
  var CAPACITY_PATTERNS = [
45
113
  /capacity/i,
@@ -387,6 +455,12 @@ function mapUsage(meta) {
387
455
  };
388
456
  return usage;
389
457
  }
458
+ function mapGoogleToolChoice(choice) {
459
+ if (choice === "auto") return { mode: "AUTO" };
460
+ if (choice === "required") return { mode: "ANY" };
461
+ if (choice === "none") return { mode: "NONE" };
462
+ return { mode: "ANY", allowedFunctionNames: [choice.name] };
463
+ }
390
464
  function mapPart(p) {
391
465
  switch (p.kind) {
392
466
  case "text":
@@ -414,6 +488,22 @@ function mapPart(p) {
414
488
  "Google Gemini expects FileUriPart with a Files API uri; got file-ref (provider file id). Upload via GoogleFileStore and pass the returned uri.",
415
489
  { kind: "bad_request", retryable: false, provider: "google" }
416
490
  );
491
+ case "tool-call":
492
+ return {
493
+ functionCall: {
494
+ id: p.toolCallId,
495
+ name: p.toolName,
496
+ args: p.args
497
+ }
498
+ };
499
+ case "tool-result":
500
+ return {
501
+ functionResponse: {
502
+ id: p.toolCallId,
503
+ name: p.toolName,
504
+ response: p.isError === true ? { error: p.result } : p.result
505
+ }
506
+ };
417
507
  default:
418
508
  return assertNever(p);
419
509
  }
@@ -557,6 +647,34 @@ function geminiAdapter(opts) {
557
647
  if (googleProviderConfig.tools !== void 0) {
558
648
  config.tools = googleProviderConfig.tools;
559
649
  }
650
+ if (req.tools !== void 0 && req.tools.length > 0) {
651
+ if (req.modelDescriptor?.capabilities?.functionCalling !== true) {
652
+ throw new LlmError(
653
+ `tools is not supported for google model "${model}" (capabilities.functionCalling is not true).`,
654
+ { kind: "bad_request", retryable: false, provider: "google" }
655
+ );
656
+ }
657
+ if (googleProviderConfig.tools !== void 0) {
658
+ throw new LlmError(
659
+ "tools cannot be combined with providerOptions.google.tools (googleSearch) in this iteration.",
660
+ { kind: "bad_request", retryable: false, provider: "google" }
661
+ );
662
+ }
663
+ config.tools = [
664
+ {
665
+ functionDeclarations: req.tools.map((tool) => ({
666
+ name: tool.name,
667
+ description: tool.description,
668
+ parameters: tool.inputJsonSchema
669
+ }))
670
+ }
671
+ ];
672
+ if (req.toolChoice !== void 0) {
673
+ config.toolConfig = {
674
+ functionCallingConfig: mapGoogleToolChoice(req.toolChoice)
675
+ };
676
+ }
677
+ }
560
678
  assertSamplingAllowed(config, model, req.modelDescriptor?.capabilities?.sampling);
561
679
  let tierTimeoutHandle;
562
680
  const clearTierTimeout = () => {
@@ -674,7 +792,25 @@ function geminiAdapter(opts) {
674
792
  const parts = candidate.content?.parts ?? [];
675
793
  const textParts = [];
676
794
  const thoughtParts = [];
795
+ const toolCalls = [];
796
+ const nameCounts = /* @__PURE__ */ new Map();
797
+ const reservedIds = reserveProviderToolCallIds(
798
+ parts.map((part) => part.functionCall?.id)
799
+ );
677
800
  for (const part of parts) {
801
+ if (part.functionCall !== void 0 && typeof part.functionCall.name === "string") {
802
+ const toolName = part.functionCall.name;
803
+ toolCalls.push({
804
+ toolCallId: resolveToolCallId(
805
+ part.functionCall.id,
806
+ toolName,
807
+ nameCounts,
808
+ reservedIds
809
+ ),
810
+ toolName,
811
+ args: part.functionCall.args ?? {}
812
+ });
813
+ }
678
814
  if (part.text !== void 0) {
679
815
  if (part.thought === true) {
680
816
  thoughtParts.push(part.text);
@@ -702,7 +838,7 @@ function geminiAdapter(opts) {
702
838
  ...text.length > 0 ? { text } : {},
703
839
  ...reasoningText !== void 0 ? { reasoningText } : {},
704
840
  ...rawStructured !== void 0 ? { rawStructured } : {},
705
- ...finishReason !== void 0 ? { finishReason } : {},
841
+ ...toolCalls.length > 0 ? { toolCalls, finishReason: "tool_calls" } : finishReason !== void 0 ? { finishReason } : {},
706
842
  ...response.modelVersion !== void 0 ? { modelVersion: response.modelVersion } : {},
707
843
  ...response.responseId !== void 0 ? { responseId: response.responseId } : {},
708
844
  // Build providerMetadata — merge promptFeedback + groundingMetadata when present.
@@ -718,6 +854,12 @@ function geminiAdapter(opts) {
718
854
  meta["groundingMetadata"] = gm;
719
855
  }
720
856
  return { providerMetadata: meta };
857
+ })(),
858
+ ...(() => {
859
+ const gm = candidate.groundingMetadata;
860
+ if (gm === void 0) return {};
861
+ const citations = normalizeGroundingCitations(gm);
862
+ return citations.length > 0 ? { citations } : {};
721
863
  })()
722
864
  };
723
865
  return result;
@@ -730,13 +872,23 @@ function geminiAdapter(opts) {
730
872
  );
731
873
  }
732
874
  const contents = mapMessagesToGeminiContents(req.messages);
875
+ const countTools = req.tools !== void 0 && req.tools.length > 0 ? [
876
+ {
877
+ functionDeclarations: req.tools.map((tool) => ({
878
+ name: tool.name,
879
+ description: tool.description,
880
+ parameters: tool.inputJsonSchema
881
+ }))
882
+ }
883
+ ] : void 0;
733
884
  const params = {
734
885
  model: req.model,
735
886
  contents,
736
- ...req.system !== void 0 || ctx.signal !== void 0 ? {
887
+ ...req.system !== void 0 || ctx.signal !== void 0 || countTools !== void 0 ? {
737
888
  config: {
738
889
  ...req.system !== void 0 ? { systemInstruction: { parts: [{ text: req.system }] } } : {},
739
- ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
890
+ ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {},
891
+ ...countTools !== void 0 ? { tools: countTools } : {}
740
892
  }
741
893
  } : {}
742
894
  };
@@ -753,6 +905,7 @@ function geminiAdapter(opts) {
753
905
  const details = response.cachedContentTokenCount !== void 0 ? { cached: response.cachedContentTokenCount } : void 0;
754
906
  return {
755
907
  totalTokens: response.totalTokens,
908
+ accuracy: "exact",
756
909
  ...details !== void 0 ? { details } : {},
757
910
  raw: response
758
911
  };
@@ -2536,6 +2689,7 @@ var geminiModelDescriptors = [
2536
2689
  sampling: "tunable",
2537
2690
  caching: { explicit: true, minTokens: 2048 },
2538
2691
  grounding: true,
2692
+ functionCalling: true,
2539
2693
  serviceTiers: ["flex", "standard"]
2540
2694
  },
2541
2695
  configSchema: Gemini25ProConfigSchema,
@@ -2556,6 +2710,7 @@ var geminiModelDescriptors = [
2556
2710
  sampling: "tunable",
2557
2711
  caching: { explicit: true, minTokens: 2048 },
2558
2712
  grounding: true,
2713
+ functionCalling: true,
2559
2714
  serviceTiers: ["flex", "standard"]
2560
2715
  },
2561
2716
  configSchema: Gemini25FlashConfigSchema,
@@ -2576,6 +2731,7 @@ var geminiModelDescriptors = [
2576
2731
  sampling: "tunable",
2577
2732
  caching: { explicit: true, minTokens: 2048 },
2578
2733
  grounding: true,
2734
+ functionCalling: true,
2579
2735
  serviceTiers: ["flex", "standard"]
2580
2736
  },
2581
2737
  configSchema: Gemini25FlashLiteConfigSchema,
@@ -2596,6 +2752,7 @@ var geminiModelDescriptors = [
2596
2752
  sampling: "fixed",
2597
2753
  caching: { explicit: true, minTokens: 2048 },
2598
2754
  grounding: true,
2755
+ functionCalling: true,
2599
2756
  serviceTiers: ["flex", "standard"]
2600
2757
  },
2601
2758
  configSchema: Gemini35FlashConfigSchema,
@@ -2616,6 +2773,7 @@ var geminiModelDescriptors = [
2616
2773
  sampling: "fixed",
2617
2774
  caching: { explicit: true, minTokens: 2048 },
2618
2775
  grounding: true,
2776
+ functionCalling: true,
2619
2777
  serviceTiers: ["flex", "standard"]
2620
2778
  },
2621
2779
  configSchema: Gemini31FlashLiteConfigSchema,
@@ -2636,6 +2794,7 @@ var geminiModelDescriptors = [
2636
2794
  sampling: "fixed",
2637
2795
  caching: { explicit: true, minTokens: 2048 },
2638
2796
  grounding: true,
2797
+ functionCalling: true,
2639
2798
  serviceTiers: ["flex", "standard"]
2640
2799
  },
2641
2800
  configSchema: Gemini31ProPreviewConfigSchema,
@@ -2656,6 +2815,7 @@ var geminiModelDescriptors = [
2656
2815
  sampling: "fixed",
2657
2816
  caching: { explicit: true, minTokens: 2048 },
2658
2817
  grounding: true,
2818
+ functionCalling: true,
2659
2819
  serviceTiers: ["flex", "standard"]
2660
2820
  },
2661
2821
  configSchema: Gemini3FlashPreviewConfigSchema,
@@ -3191,44 +3351,6 @@ var GoogleCacheStore = class {
3191
3351
  }
3192
3352
  }
3193
3353
  };
3194
-
3195
- // src/grounding.ts
3196
- function hostnameFrom(url) {
3197
- return url.hostname.startsWith("www.") ? url.hostname.slice(4) : url.hostname;
3198
- }
3199
- function toCitation(chunk) {
3200
- if (chunk === null || typeof chunk !== "object") return void 0;
3201
- const web = chunk["web"];
3202
- if (web === null || typeof web !== "object") return void 0;
3203
- const uri = web["uri"];
3204
- if (typeof uri !== "string" || uri.length === 0) return void 0;
3205
- let parsed;
3206
- try {
3207
- parsed = new URL(uri);
3208
- } catch {
3209
- return void 0;
3210
- }
3211
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
3212
- if (parsed.hostname === "") return void 0;
3213
- const title = web["title"];
3214
- const sourceName = typeof title === "string" && title.length > 0 ? title : hostnameFrom(parsed);
3215
- return { url: uri, sourceName };
3216
- }
3217
- function normalizeGroundingCitations(groundingMetadata) {
3218
- if (groundingMetadata === null || typeof groundingMetadata !== "object") return [];
3219
- const chunks = groundingMetadata["groundingChunks"];
3220
- if (!Array.isArray(chunks)) return [];
3221
- const seen = /* @__PURE__ */ new Set();
3222
- const citations = [];
3223
- for (const chunk of chunks) {
3224
- const citation = toCitation(chunk);
3225
- if (citation === void 0) continue;
3226
- if (seen.has(citation.url)) continue;
3227
- seen.add(citation.url);
3228
- citations.push(citation);
3229
- }
3230
- return citations;
3231
- }
3232
3354
  function badRequest(message) {
3233
3355
  return new LlmError(message, { kind: "bad_request", retryable: false });
3234
3356
  }
@@ -3265,19 +3387,49 @@ function convertMediaResolution(mediaResolution, location) {
3265
3387
  }
3266
3388
  return mapMediaResolutionLevel(mediaResolution.level, location);
3267
3389
  }
3268
- function convertPart(part, location) {
3390
+ function convertPart(part, location, nameCounts, reservedIds) {
3269
3391
  const keys = definedKeys(part);
3270
3392
  const baseKeys = keys.filter(
3271
3393
  (key) => key === "text" || key === "inlineData" || key === "fileData"
3272
3394
  );
3273
3395
  if (baseKeys.length === 0) {
3396
+ if (keys.includes("functionCall") && keys.every((k) => k === "functionCall")) {
3397
+ const fc = part.functionCall;
3398
+ if (fc === void 0 || typeof fc.name !== "string" || fc.name.length === 0) {
3399
+ throw badRequest(`${location}: functionCall.name is required.`);
3400
+ }
3401
+ return {
3402
+ kind: "tool-call",
3403
+ toolCallId: resolveToolCallId(fc.id, fc.name, nameCounts, reservedIds),
3404
+ toolName: fc.name,
3405
+ args: fc.args ?? {}
3406
+ };
3407
+ }
3408
+ if (keys.includes("functionResponse") && keys.every((k) => k === "functionResponse")) {
3409
+ const fr = part.functionResponse;
3410
+ if (fr === void 0 || typeof fr.name !== "string" || fr.name.length === 0) {
3411
+ throw badRequest(`${location}: functionResponse.name is required.`);
3412
+ }
3413
+ return {
3414
+ kind: "tool-result",
3415
+ toolCallId: resolveToolCallId(
3416
+ fr.id,
3417
+ fr.name,
3418
+ nameCounts,
3419
+ reservedIds,
3420
+ `result:${fr.name}`
3421
+ ),
3422
+ toolName: fr.name,
3423
+ result: fr.response ?? null
3424
+ };
3425
+ }
3274
3426
  if (keys.length === 0) {
3275
3427
  throw badRequest(
3276
3428
  `${location}: Part has no recognized fields set (expected exactly one of text, inlineData, fileData).`
3277
3429
  );
3278
3430
  }
3279
3431
  throw badRequest(
3280
- `${location}: Part keys [${keys.join(", ")}] are not supported by geminiContentToMessages \u2014 only text, inlineData, and fileData parts can be represented in any-llm.`
3432
+ `${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.`
3281
3433
  );
3282
3434
  }
3283
3435
  if (baseKeys.length > 1) {
@@ -3381,6 +3533,15 @@ function convertSystemInstruction(systemInstruction) {
3381
3533
  }
3382
3534
  function geminiContentToMessages(input) {
3383
3535
  const system = input.systemInstruction !== void 0 ? convertSystemInstruction(input.systemInstruction) : void 0;
3536
+ const nameCounts = /* @__PURE__ */ new Map();
3537
+ const reservedIds = reserveProviderToolCallIds(
3538
+ input.contents.flatMap(
3539
+ (content) => (content.parts ?? []).flatMap((part) => {
3540
+ const p = part;
3541
+ return [p.functionCall?.id, p.functionResponse?.id];
3542
+ })
3543
+ )
3544
+ );
3384
3545
  const messages = input.contents.map((content, contentIndex) => {
3385
3546
  const location = `contents[${contentIndex}]`;
3386
3547
  const envelopeExtraKeys = definedKeys(content).filter(
@@ -3393,13 +3554,13 @@ function geminiContentToMessages(input) {
3393
3554
  }
3394
3555
  const role = convertRole(content.role, location);
3395
3556
  const parts = (content.parts ?? []).map(
3396
- (part, partIndex) => convertPart(part, `${location}.parts[${partIndex}]`)
3557
+ (part, partIndex) => convertPart(part, `${location}.parts[${partIndex}]`, nameCounts, reservedIds)
3397
3558
  );
3398
3559
  return { role, parts };
3399
3560
  });
3400
3561
  return { ...system !== void 0 ? { system } : {}, messages };
3401
3562
  }
3402
3563
 
3403
- export { FLEX_DEFAULT_TIMEOUT_MS, GEMINI_PRICING, GoogleCacheStore, GoogleFileStore, STANDARD_DEFAULT_TIMEOUT_MS, TIER_FACTOR, TRANSPORT_TIMEOUT_BUFFER_MS, buildGoogleClient, defaultGeminiRegistry, geminiAdapter, geminiContentToMessages, geminiModelDescriptors, geminiPricingSource, gemmaModelDescriptors, googleProvider, isGeminiCapacityError, normalizeGroundingCitations, pricingVersion, requireApiKey };
3564
+ export { FLEX_DEFAULT_TIMEOUT_MS, GEMINI_PRICING, GoogleCacheStore, GoogleFileStore, STANDARD_DEFAULT_TIMEOUT_MS, TIER_FACTOR, TRANSPORT_TIMEOUT_BUFFER_MS, buildGoogleClient, defaultGeminiRegistry, geminiAdapter, geminiContentToMessages, geminiModelDescriptors, geminiPricingSource, gemmaModelDescriptors, googleProvider, isGeminiCapacityError, pricingVersion, requireApiKey };
3404
3565
  //# sourceMappingURL=index.js.map
3405
3566
  //# sourceMappingURL=index.js.map