@gullabs/google 0.10.0 → 0.11.0
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/README.md +3 -5
- package/dist/index.cjs +151 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -26
- package/dist/index.d.ts +33 -26
- package/dist/index.js +152 -43
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -22,10 +22,8 @@ pnpm add @gullabs/google @gullabs/core @google/genai
|
|
|
22
22
|
| `isGeminiCapacityError(err)` | Detects Gemini Flex shared-capacity errors for built-in fallback |
|
|
23
23
|
| `geminiModelDescriptors`, `gemmaModelDescriptors`, `defaultGeminiRegistry` | Built-in model descriptors + pre-built registry |
|
|
24
24
|
| `geminiPricingSource()`, `GEMINI_PRICING`, `TIER_FACTOR` | Built-in Gemini pricing snapshot and tier-factor map |
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
| `GoogleFileStore` | Files API: upload + poll ACTIVE + delete |
|
|
28
|
-
| `FileDeleteOptions` | `{ failClosed?, signal? }` — opt-in fail-closed delete (parity with `@gullabs/xai`) |
|
|
25
|
+
| `GoogleFileStore` | Files API: upload + poll ACTIVE + delete |
|
|
26
|
+
| `FileDeleteOptions` | `{ failClosed?, signal? }` — opt-in fail-closed delete (parity with `@gullabs/xai`) |
|
|
29
27
|
|
|
30
28
|
## File store delete modes
|
|
31
29
|
|
|
@@ -67,7 +65,7 @@ const result = await client.generate(
|
|
|
67
65
|
- `output.jsonSchema` → `responseMimeType: 'application/json'` + verbatim `responseSchema` when native structured output is enabled; the engine returns parsed output and `outputParsed` without validating shape
|
|
68
66
|
- `providerOptions.google.*` → typed provider-extension lane for admitted keys such as `cachedContent`, `safetySettings`, and exact tool declarations
|
|
69
67
|
- Usage: `promptTokenCount`→`inputTokens`, `candidatesTokenCount`+`thoughtsTokenCount`→`outputTokens` (GROSS)
|
|
70
|
-
- Errors: `401
|
|
68
|
+
- Errors: `401` and a bare `403` default to `invalid_auth`; `429`→`rate_limited`; `5xx`→`server`; timeouts; Gemini safety blocks are a 200-path `content_filter` (`promptFeedback.blockReason` / no candidates), not an HTTP 403
|
|
71
69
|
|
|
72
70
|
## Strict model-config expectations
|
|
73
71
|
|
package/dist/index.cjs
CHANGED
|
@@ -42,6 +42,49 @@ 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
|
+
|
|
45
88
|
// src/flex-fallback.ts
|
|
46
89
|
var CAPACITY_PATTERNS = [
|
|
47
90
|
/capacity/i,
|
|
@@ -389,6 +432,12 @@ function mapUsage(meta) {
|
|
|
389
432
|
};
|
|
390
433
|
return usage;
|
|
391
434
|
}
|
|
435
|
+
function mapGoogleToolChoice(choice) {
|
|
436
|
+
if (choice === "auto") return { mode: "AUTO" };
|
|
437
|
+
if (choice === "required") return { mode: "ANY" };
|
|
438
|
+
if (choice === "none") return { mode: "NONE" };
|
|
439
|
+
return { mode: "ANY", allowedFunctionNames: [choice.name] };
|
|
440
|
+
}
|
|
392
441
|
function mapPart(p) {
|
|
393
442
|
switch (p.kind) {
|
|
394
443
|
case "text":
|
|
@@ -416,6 +465,20 @@ function mapPart(p) {
|
|
|
416
465
|
"Google Gemini expects FileUriPart with a Files API uri; got file-ref (provider file id). Upload via GoogleFileStore and pass the returned uri.",
|
|
417
466
|
{ kind: "bad_request", retryable: false, provider: "google" }
|
|
418
467
|
);
|
|
468
|
+
case "tool-call":
|
|
469
|
+
return {
|
|
470
|
+
functionCall: {
|
|
471
|
+
name: p.toolName,
|
|
472
|
+
args: p.args
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
case "tool-result":
|
|
476
|
+
return {
|
|
477
|
+
functionResponse: {
|
|
478
|
+
name: p.toolName,
|
|
479
|
+
response: p.isError === true ? { error: p.result } : p.result
|
|
480
|
+
}
|
|
481
|
+
};
|
|
419
482
|
default:
|
|
420
483
|
return core.assertNever(p);
|
|
421
484
|
}
|
|
@@ -559,6 +622,34 @@ function geminiAdapter(opts) {
|
|
|
559
622
|
if (googleProviderConfig.tools !== void 0) {
|
|
560
623
|
config.tools = googleProviderConfig.tools;
|
|
561
624
|
}
|
|
625
|
+
if (req.tools !== void 0 && req.tools.length > 0) {
|
|
626
|
+
if (req.modelDescriptor?.capabilities?.functionCalling !== true) {
|
|
627
|
+
throw new core.LlmError(
|
|
628
|
+
`tools is not supported for google model "${model}" (capabilities.functionCalling is not true).`,
|
|
629
|
+
{ kind: "bad_request", retryable: false, provider: "google" }
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
if (googleProviderConfig.tools !== void 0) {
|
|
633
|
+
throw new core.LlmError(
|
|
634
|
+
"tools cannot be combined with providerOptions.google.tools (googleSearch) in this iteration.",
|
|
635
|
+
{ kind: "bad_request", retryable: false, provider: "google" }
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
config.tools = [
|
|
639
|
+
{
|
|
640
|
+
functionDeclarations: req.tools.map((tool) => ({
|
|
641
|
+
name: tool.name,
|
|
642
|
+
description: tool.description,
|
|
643
|
+
parameters: tool.inputJsonSchema
|
|
644
|
+
}))
|
|
645
|
+
}
|
|
646
|
+
];
|
|
647
|
+
if (req.toolChoice !== void 0) {
|
|
648
|
+
config.toolConfig = {
|
|
649
|
+
functionCallingConfig: mapGoogleToolChoice(req.toolChoice)
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
}
|
|
562
653
|
assertSamplingAllowed(config, model, req.modelDescriptor?.capabilities?.sampling);
|
|
563
654
|
let tierTimeoutHandle;
|
|
564
655
|
const clearTierTimeout = () => {
|
|
@@ -676,7 +767,15 @@ function geminiAdapter(opts) {
|
|
|
676
767
|
const parts = candidate.content?.parts ?? [];
|
|
677
768
|
const textParts = [];
|
|
678
769
|
const thoughtParts = [];
|
|
770
|
+
const toolCalls = [];
|
|
679
771
|
for (const part of parts) {
|
|
772
|
+
if (part.functionCall !== void 0 && typeof part.functionCall.name === "string") {
|
|
773
|
+
toolCalls.push({
|
|
774
|
+
toolCallId: part.functionCall.name,
|
|
775
|
+
toolName: part.functionCall.name,
|
|
776
|
+
args: part.functionCall.args ?? {}
|
|
777
|
+
});
|
|
778
|
+
}
|
|
680
779
|
if (part.text !== void 0) {
|
|
681
780
|
if (part.thought === true) {
|
|
682
781
|
thoughtParts.push(part.text);
|
|
@@ -704,7 +803,7 @@ function geminiAdapter(opts) {
|
|
|
704
803
|
...text.length > 0 ? { text } : {},
|
|
705
804
|
...reasoningText !== void 0 ? { reasoningText } : {},
|
|
706
805
|
...rawStructured !== void 0 ? { rawStructured } : {},
|
|
707
|
-
...finishReason !== void 0 ? { finishReason } : {},
|
|
806
|
+
...toolCalls.length > 0 ? { toolCalls, finishReason: "tool_calls" } : finishReason !== void 0 ? { finishReason } : {},
|
|
708
807
|
...response.modelVersion !== void 0 ? { modelVersion: response.modelVersion } : {},
|
|
709
808
|
...response.responseId !== void 0 ? { responseId: response.responseId } : {},
|
|
710
809
|
// Build providerMetadata — merge promptFeedback + groundingMetadata when present.
|
|
@@ -720,6 +819,12 @@ function geminiAdapter(opts) {
|
|
|
720
819
|
meta["groundingMetadata"] = gm;
|
|
721
820
|
}
|
|
722
821
|
return { providerMetadata: meta };
|
|
822
|
+
})(),
|
|
823
|
+
...(() => {
|
|
824
|
+
const gm = candidate.groundingMetadata;
|
|
825
|
+
if (gm === void 0) return {};
|
|
826
|
+
const citations = normalizeGroundingCitations(gm);
|
|
827
|
+
return citations.length > 0 ? { citations } : {};
|
|
723
828
|
})()
|
|
724
829
|
};
|
|
725
830
|
return result;
|
|
@@ -732,13 +837,23 @@ function geminiAdapter(opts) {
|
|
|
732
837
|
);
|
|
733
838
|
}
|
|
734
839
|
const contents = mapMessagesToGeminiContents(req.messages);
|
|
840
|
+
const countTools = req.tools !== void 0 && req.tools.length > 0 ? [
|
|
841
|
+
{
|
|
842
|
+
functionDeclarations: req.tools.map((tool) => ({
|
|
843
|
+
name: tool.name,
|
|
844
|
+
description: tool.description,
|
|
845
|
+
parameters: tool.inputJsonSchema
|
|
846
|
+
}))
|
|
847
|
+
}
|
|
848
|
+
] : void 0;
|
|
735
849
|
const params = {
|
|
736
850
|
model: req.model,
|
|
737
851
|
contents,
|
|
738
|
-
...req.system !== void 0 || ctx.signal !== void 0 ? {
|
|
852
|
+
...req.system !== void 0 || ctx.signal !== void 0 || countTools !== void 0 ? {
|
|
739
853
|
config: {
|
|
740
854
|
...req.system !== void 0 ? { systemInstruction: { parts: [{ text: req.system }] } } : {},
|
|
741
|
-
...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
|
|
855
|
+
...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {},
|
|
856
|
+
...countTools !== void 0 ? { tools: countTools } : {}
|
|
742
857
|
}
|
|
743
858
|
} : {}
|
|
744
859
|
};
|
|
@@ -755,6 +870,7 @@ function geminiAdapter(opts) {
|
|
|
755
870
|
const details = response.cachedContentTokenCount !== void 0 ? { cached: response.cachedContentTokenCount } : void 0;
|
|
756
871
|
return {
|
|
757
872
|
totalTokens: response.totalTokens,
|
|
873
|
+
accuracy: "exact",
|
|
758
874
|
...details !== void 0 ? { details } : {},
|
|
759
875
|
raw: response
|
|
760
876
|
};
|
|
@@ -2538,6 +2654,7 @@ var geminiModelDescriptors = [
|
|
|
2538
2654
|
sampling: "tunable",
|
|
2539
2655
|
caching: { explicit: true, minTokens: 2048 },
|
|
2540
2656
|
grounding: true,
|
|
2657
|
+
functionCalling: true,
|
|
2541
2658
|
serviceTiers: ["flex", "standard"]
|
|
2542
2659
|
},
|
|
2543
2660
|
configSchema: Gemini25ProConfigSchema,
|
|
@@ -2558,6 +2675,7 @@ var geminiModelDescriptors = [
|
|
|
2558
2675
|
sampling: "tunable",
|
|
2559
2676
|
caching: { explicit: true, minTokens: 2048 },
|
|
2560
2677
|
grounding: true,
|
|
2678
|
+
functionCalling: true,
|
|
2561
2679
|
serviceTiers: ["flex", "standard"]
|
|
2562
2680
|
},
|
|
2563
2681
|
configSchema: Gemini25FlashConfigSchema,
|
|
@@ -2578,6 +2696,7 @@ var geminiModelDescriptors = [
|
|
|
2578
2696
|
sampling: "tunable",
|
|
2579
2697
|
caching: { explicit: true, minTokens: 2048 },
|
|
2580
2698
|
grounding: true,
|
|
2699
|
+
functionCalling: true,
|
|
2581
2700
|
serviceTiers: ["flex", "standard"]
|
|
2582
2701
|
},
|
|
2583
2702
|
configSchema: Gemini25FlashLiteConfigSchema,
|
|
@@ -2598,6 +2717,7 @@ var geminiModelDescriptors = [
|
|
|
2598
2717
|
sampling: "fixed",
|
|
2599
2718
|
caching: { explicit: true, minTokens: 2048 },
|
|
2600
2719
|
grounding: true,
|
|
2720
|
+
functionCalling: true,
|
|
2601
2721
|
serviceTiers: ["flex", "standard"]
|
|
2602
2722
|
},
|
|
2603
2723
|
configSchema: Gemini35FlashConfigSchema,
|
|
@@ -2618,6 +2738,7 @@ var geminiModelDescriptors = [
|
|
|
2618
2738
|
sampling: "fixed",
|
|
2619
2739
|
caching: { explicit: true, minTokens: 2048 },
|
|
2620
2740
|
grounding: true,
|
|
2741
|
+
functionCalling: true,
|
|
2621
2742
|
serviceTiers: ["flex", "standard"]
|
|
2622
2743
|
},
|
|
2623
2744
|
configSchema: Gemini31FlashLiteConfigSchema,
|
|
@@ -2638,6 +2759,7 @@ var geminiModelDescriptors = [
|
|
|
2638
2759
|
sampling: "fixed",
|
|
2639
2760
|
caching: { explicit: true, minTokens: 2048 },
|
|
2640
2761
|
grounding: true,
|
|
2762
|
+
functionCalling: true,
|
|
2641
2763
|
serviceTiers: ["flex", "standard"]
|
|
2642
2764
|
},
|
|
2643
2765
|
configSchema: Gemini31ProPreviewConfigSchema,
|
|
@@ -2658,6 +2780,7 @@ var geminiModelDescriptors = [
|
|
|
2658
2780
|
sampling: "fixed",
|
|
2659
2781
|
caching: { explicit: true, minTokens: 2048 },
|
|
2660
2782
|
grounding: true,
|
|
2783
|
+
functionCalling: true,
|
|
2661
2784
|
serviceTiers: ["flex", "standard"]
|
|
2662
2785
|
},
|
|
2663
2786
|
configSchema: Gemini3FlashPreviewConfigSchema,
|
|
@@ -3193,44 +3316,6 @@ var GoogleCacheStore = class {
|
|
|
3193
3316
|
}
|
|
3194
3317
|
}
|
|
3195
3318
|
};
|
|
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
3319
|
function badRequest(message) {
|
|
3235
3320
|
return new core.LlmError(message, { kind: "bad_request", retryable: false });
|
|
3236
3321
|
}
|
|
@@ -3273,13 +3358,37 @@ function convertPart(part, location) {
|
|
|
3273
3358
|
(key) => key === "text" || key === "inlineData" || key === "fileData"
|
|
3274
3359
|
);
|
|
3275
3360
|
if (baseKeys.length === 0) {
|
|
3361
|
+
if (keys.includes("functionCall") && keys.every((k) => k === "functionCall")) {
|
|
3362
|
+
const fc = part.functionCall;
|
|
3363
|
+
if (fc === void 0 || typeof fc.name !== "string" || fc.name.length === 0) {
|
|
3364
|
+
throw badRequest(`${location}: functionCall.name is required.`);
|
|
3365
|
+
}
|
|
3366
|
+
return {
|
|
3367
|
+
kind: "tool-call",
|
|
3368
|
+
toolCallId: fc.name,
|
|
3369
|
+
toolName: fc.name,
|
|
3370
|
+
args: fc.args ?? {}
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
if (keys.includes("functionResponse") && keys.every((k) => k === "functionResponse")) {
|
|
3374
|
+
const fr = part.functionResponse;
|
|
3375
|
+
if (fr === void 0 || typeof fr.name !== "string" || fr.name.length === 0) {
|
|
3376
|
+
throw badRequest(`${location}: functionResponse.name is required.`);
|
|
3377
|
+
}
|
|
3378
|
+
return {
|
|
3379
|
+
kind: "tool-result",
|
|
3380
|
+
toolCallId: fr.name,
|
|
3381
|
+
toolName: fr.name,
|
|
3382
|
+
result: fr.response ?? null
|
|
3383
|
+
};
|
|
3384
|
+
}
|
|
3276
3385
|
if (keys.length === 0) {
|
|
3277
3386
|
throw badRequest(
|
|
3278
3387
|
`${location}: Part has no recognized fields set (expected exactly one of text, inlineData, fileData).`
|
|
3279
3388
|
);
|
|
3280
3389
|
}
|
|
3281
3390
|
throw badRequest(
|
|
3282
|
-
`${location}: Part keys [${keys.join(", ")}] are not supported by geminiContentToMessages \u2014 only text, inlineData, and
|
|
3391
|
+
`${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
3392
|
);
|
|
3284
3393
|
}
|
|
3285
3394
|
if (baseKeys.length > 1) {
|
|
@@ -3418,7 +3527,6 @@ exports.geminiPricingSource = geminiPricingSource;
|
|
|
3418
3527
|
exports.gemmaModelDescriptors = gemmaModelDescriptors;
|
|
3419
3528
|
exports.googleProvider = googleProvider;
|
|
3420
3529
|
exports.isGeminiCapacityError = isGeminiCapacityError;
|
|
3421
|
-
exports.normalizeGroundingCitations = normalizeGroundingCitations;
|
|
3422
3530
|
exports.pricingVersion = pricingVersion;
|
|
3423
3531
|
exports.requireApiKey = requireApiKey;
|
|
3424
3532
|
//# sourceMappingURL=index.cjs.map
|