@veryfront/ext-llm-google 0.1.1185 → 0.1.1189

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 CHANGED
@@ -36,7 +36,7 @@ const response = await ai.chat("google/gemini-2.5-pro", {
36
36
  ### Embeddings
37
37
 
38
38
  ```ts
39
- const result = await ai.embed("google/text-embedding-005", {
39
+ const result = await ai.embed("google/gemini-embedding-2", {
40
40
  values: ["search query"],
41
41
  });
42
42
  ```
@@ -47,7 +47,7 @@ Any model accessible through the Google Generative Language API:
47
47
 
48
48
  - **Flagship:** `gemini-2.5-pro`, `gemini-2.5-flash`
49
49
  - **Stable:** `gemini-2.0-flash`, `gemini-1.5-pro`, `gemini-1.5-flash`
50
- - **Embeddings:** `text-embedding-005`, `text-embedding-004`
50
+ - **Embeddings:** `gemini-embedding-2`
51
51
 
52
52
  ## Configuration
53
53
 
@@ -98,8 +98,17 @@ Set `budgetTokens` directly to override the effort mapping:
98
98
  reasoning: { enabled: true, budgetTokens: 4096 }
99
99
  ```
100
100
 
101
+ Explicit budgets must be non-negative safe integers. The `-1` dynamic-budget
102
+ sentinel is reserved for `effort: "max"` and is rejected when supplied through
103
+ `budgetTokens`.
104
+
101
105
  When thinking is enabled, Gemini returns `thought` parts that the runtime emits as `reasoning-start` / `reasoning-delta` / `reasoning-end` stream events.
102
106
 
107
+ Gemini `thoughtSignature` fields are retained with the exact assistant parts that produced them and replayed automatically on later turns, including parallel function-call responses.
108
+ Streaming and replay share one deterministic raw-position tool-ID registry.
109
+ Exact replay retains at most 4,096 raw assistant parts and 8 MiB; surviving
110
+ canonical calls and results must match the raw history in occurrence order.
111
+
103
112
  ## Prompt Caching
104
113
 
105
114
  Gemini uses a separate cached-content resource model. Create a cache via the Gemini REST API or SDK, then pass the resource name on each request:
@@ -111,12 +120,24 @@ const response = await ai.chat("google/gemini-2.5-pro", {
111
120
  });
112
121
  ```
113
122
 
114
- When a cached content resource is attached, the response `usageMetadata.cachedContentTokenCount` is surfaced as `cacheReadInputTokens` on the result.
123
+ When a cached content resource is attached, the response
124
+ `usageMetadata.cachedContentTokenCount` is surfaced as the canonical
125
+ `cacheReadInputTokens` field and the compatible `cachedInputTokens` alias on
126
+ the result.
115
127
 
116
128
  ## Provider Tools
117
129
 
118
130
  Gemini supports provider-native tools alongside function declarations. Use the `provider` tool type with a `google.*` id:
119
131
 
132
+ The extension intentionally supports only the provider tools whose request and
133
+ response contracts are normalized end to end:
134
+
135
+ - `google.code_execution` with name `code_execution`
136
+ - `google.google_search` with name `google_search`
137
+
138
+ Unknown or duplicate provider-tool IDs, tools for another provider, mismatched
139
+ names, and unsupported argument fields throw before the HTTP request is sent.
140
+
120
141
  ### Code Execution
121
142
 
122
143
  ```ts
@@ -125,15 +146,47 @@ tools: [
125
146
  ];
126
147
  ```
127
148
 
149
+ Google `executableCode` / `codeExecutionResult` parts are exposed as correlated
150
+ `code_execution` tool calls and results with `providerExecuted: true`. Failed
151
+ and deadline-exceeded outcomes are marked as tool errors. The original ordered
152
+ Google parts, including provider IDs and thought signatures, are retained for
153
+ exact replay on subsequent turns.
154
+
128
155
  ### Google Search
129
156
 
130
157
  ```ts
131
158
  tools: [
132
- { type: "provider", name: "google_search", id: "google.google_search", args: {} },
159
+ {
160
+ type: "provider",
161
+ name: "google_search",
162
+ id: "google.google_search",
163
+ args: {
164
+ searchTypes: { webSearch: {}, imageSearch: {} },
165
+ timeRangeFilter: {
166
+ startTime: "2026-01-01T00:00:00Z",
167
+ endTime: "2026-07-01T00:00:00Z",
168
+ },
169
+ },
170
+ },
133
171
  ];
134
172
  ```
135
173
 
136
- Provider tools can be combined with regular function tools in the same request. When Google Search is used, the response includes `groundingMetadata` with web search queries, grounding chunks, and citation indices.
174
+ Both Google Search argument groups are optional; `{}` keeps Google's default web
175
+ search behavior. A time range requires both RFC 3339 timestamps. The nested
176
+ `webSearch` and `imageSearch` configurations are currently empty objects, as
177
+ defined by Google's API.
178
+
179
+ Provider tools can be combined with regular function tools in the same request.
180
+ Google Search does not produce a client-executed tool call. Instead, Google
181
+ returns a candidate-level `groundingMetadata` object containing queries,
182
+ grounding chunks, and citation indices. The direct adapter result retains the
183
+ legacy top-level `groundingMetadata` property, and direct and streaming results
184
+ also expose the same opaque object at
185
+ `providerMetadata.google.groundingMetadata`, which survives runtime
186
+ normalization. The object envelope and stable citation list fields
187
+ (`groundingChunks`, `groundingSupports`, `webSearchQueries`, and
188
+ `imageSearchQueries`) are validated for shape. Other nested fields remain
189
+ Google-owned so new metadata can pass through without an extension release.
137
190
 
138
191
  ## Safety Settings
139
192
 
@@ -199,12 +252,18 @@ The following settings emit `unsupported-setting` warnings and are silently drop
199
252
 
200
253
  The extension surfaces typed provider errors:
201
254
 
202
- | Error Class | Trigger | Retryable |
203
- | ------------------------- | ----------------------------- | --------- |
204
- | `ProviderOverloadedError` | HTTP 503 | Yes |
205
- | `ProviderQuotaError` | HTTP 429 `RESOURCE_EXHAUSTED` | No |
206
- | `ProviderRateLimitError` | HTTP 429 with `Retry-After` | Yes |
207
- | `ProviderRequestError` | Other HTTP errors | No |
255
+ | Error Class | Trigger | Retryable |
256
+ | ------------------------- | --------------------------------------------- | --------- |
257
+ | `ProviderOverloadedError` | HTTP 503 | Yes |
258
+ | `ProviderQuotaError` | HTTP 429 `RESOURCE_EXHAUSTED`, no retry delay | No |
259
+ | `ProviderRateLimitError` | HTTP 429 with `Retry-After` or `RetryInfo` | Yes |
260
+ | `ProviderRequestError` | Other HTTP errors | No |
261
+
262
+ Google returns `RESOURCE_EXHAUSTED` for both the daily quota and short-window
263
+ per-minute limits. A retry delay — the `Retry-After` header or a
264
+ `google.rpc.RetryInfo` entry in `error.details` — separates them: with one the
265
+ error is a retryable rate limit carrying the delay, without one it is a hard
266
+ quota error that cannot succeed again until the daily window resets.
208
267
 
209
268
  If the extension is not installed and a `google/*` model is requested:
210
269
 
@@ -226,22 +285,22 @@ The unified `toolChoice` option maps to Gemini's `functionCallingConfig`:
226
285
 
227
286
  ```bash
228
287
  # From the repository root
229
- deno test --no-check --allow-all extensions/ext-google/
288
+ deno test --no-check --allow-all extensions/ext-llm-google/src/
230
289
 
231
290
  # Or from the extension directory
232
- cd extensions/ext-google
291
+ cd extensions/ext-llm-google
233
292
  deno task test
234
293
  ```
235
294
 
236
295
  The test suite covers:
237
296
 
238
297
  - Generate and stream request/response mapping
239
- - Extended thinking (thinkingConfig budget mapping, thought-part streaming)
298
+ - Extended thinking (validated thinkingConfig budgets, thought-part streaming)
240
299
  - Embedding runtime (single and batch)
241
300
  - Error classification (503, 429 RESOURCE_EXHAUSTED)
242
301
  - Unsupported-setting warnings (presencePenalty, frequencyPenalty)
243
302
  - User ID and request label forwarding
244
303
  - Tool choice normalization (auto, any, none, single-tool, multi-tool)
245
304
  - Grounding metadata pass-through (google_search)
246
- - Provider tools (code_execution, google_search)
305
+ - Provider tools (correlated code_execution calls/results and google_search)
247
306
  - Safety settings and cached content
@@ -0,0 +1,12 @@
1
+ declare global {
2
+ interface Object {
3
+ /**
4
+ * Determines whether an object has a property with the specified name.
5
+ * @param o An object.
6
+ * @param v A property name.
7
+ */
8
+ hasOwn(o: object, v: PropertyKey): boolean;
9
+ }
10
+ }
11
+ export {};
12
+ //# sourceMappingURL=_dnt.polyfills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_dnt.polyfills.d.ts","sourceRoot":"","sources":["../src/_dnt.polyfills.ts"],"names":[],"mappings":"AAeA,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd;;;;WAIG;QACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;KAC5C;CACF;AAED,OAAO,EAAE,CAAC"}
@@ -0,0 +1,15 @@
1
+ // https://github.com/tc39/proposal-accessible-object-hasownproperty/blob/main/polyfill.js
2
+ if (!Object.hasOwn) {
3
+ Object.defineProperty(Object, "hasOwn", {
4
+ value: function (object, property) {
5
+ if (object == null) {
6
+ throw new TypeError("Cannot convert undefined or null to object");
7
+ }
8
+ return Object.prototype.hasOwnProperty.call(Object(object), property);
9
+ },
10
+ configurable: true,
11
+ enumerable: false,
12
+ writable: true,
13
+ });
14
+ }
15
+ export {};
@@ -0,0 +1,45 @@
1
+ export declare const GOOGLE_CODE_EXECUTION_TOOL_NAME = "code_execution";
2
+ export type GoogleSupportedPartDataField = "text" | "functionCall" | "executableCode" | "codeExecutionResult";
3
+ export type GoogleExecutableCode = {
4
+ providerId?: string;
5
+ language: "PYTHON";
6
+ code: string;
7
+ };
8
+ export type GoogleCodeExecutionResult = {
9
+ providerId?: string;
10
+ outcome: "OUTCOME_OK" | "OUTCOME_FAILED" | "OUTCOME_DEADLINE_EXCEEDED";
11
+ output: string;
12
+ isError: boolean;
13
+ };
14
+ export type GoogleToolCallCorrelationRegistry = {
15
+ registerFunctionCall(partIndex: number, providerId: string | undefined): string;
16
+ registerCodeExecution(providerId: string | undefined): string;
17
+ resolveCodeExecutionResult(providerId: string | undefined): string;
18
+ assertSettled(): void;
19
+ };
20
+ /**
21
+ * Owns Gemini's tool-call id allocation and code-execution pairing rules.
22
+ *
23
+ * The response normalizer and exact-replay validator must derive identical
24
+ * ids for anonymous code execution. Keeping the allocator here prevents those
25
+ * two protocol boundaries from drifting independently.
26
+ */
27
+ export declare function createGoogleToolCallCorrelationRegistry(): GoogleToolCallCorrelationRegistry;
28
+ /**
29
+ * Validates the documented `Part.data` oneof and returns the supported field.
30
+ *
31
+ * The extension intentionally fails closed for media/file/function-response
32
+ * output parts until it has a canonical runtime representation for them.
33
+ */
34
+ export declare function readGooglePartDataField(part: Record<string, unknown>): GoogleSupportedPartDataField;
35
+ export declare function readGoogleExecutableCode(value: unknown): GoogleExecutableCode;
36
+ export declare function readGoogleCodeExecutionResult(value: unknown): GoogleCodeExecutionResult;
37
+ export declare function googleCodeExecutionInput(executableCode: GoogleExecutableCode): {
38
+ language: "PYTHON";
39
+ code: string;
40
+ };
41
+ export declare function googleCodeExecutionOutput(result: GoogleCodeExecutionResult): {
42
+ outcome: GoogleCodeExecutionResult["outcome"];
43
+ output: string;
44
+ };
45
+ //# sourceMappingURL=google-content-parts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-content-parts.d.ts","sourceRoot":"","sources":["../src/google-content-parts.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,+BAA+B,mBAAmB,CAAC;AAsBhE,MAAM,MAAM,4BAA4B,GACpC,MAAM,GACN,cAAc,GACd,gBAAgB,GAChB,qBAAqB,CAAC;AAE1B,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,YAAY,GAAG,gBAAgB,GAAG,2BAA2B,CAAC;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAChF,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAC9D,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IACnE,aAAa,IAAI,IAAI,CAAC;CACvB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uCAAuC,IAAI,iCAAiC,CAgE3F;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,4BAA4B,CAyB9B;AAeD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAiB7E;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,yBAAyB,CAyBvF;AAED,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,oBAAoB,GACnC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAKtC;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,yBAAyB,GAChC;IACD,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC;IAC9C,MAAM,EAAE,MAAM,CAAC;CAChB,CAKA"}
@@ -0,0 +1,164 @@
1
+ import { readRecord } from "veryfront/provider/shared";
2
+ export const GOOGLE_CODE_EXECUTION_TOOL_NAME = "code_execution";
3
+ const GOOGLE_PART_DATA_FIELDS = [
4
+ "text",
5
+ "inlineData",
6
+ "functionCall",
7
+ "functionResponse",
8
+ "fileData",
9
+ "executableCode",
10
+ "codeExecutionResult",
11
+ "toolCall",
12
+ "toolResponse",
13
+ ];
14
+ const GOOGLE_PART_METADATA_FIELDS = new Set([
15
+ "mediaResolution",
16
+ "partMetadata",
17
+ "thought",
18
+ "thoughtSignature",
19
+ "videoMetadata",
20
+ ]);
21
+ /**
22
+ * Owns Gemini's tool-call id allocation and code-execution pairing rules.
23
+ *
24
+ * The response normalizer and exact-replay validator must derive identical
25
+ * ids for anonymous code execution. Keeping the allocator here prevents those
26
+ * two protocol boundaries from drifting independently.
27
+ */
28
+ export function createGoogleToolCallCorrelationRegistry() {
29
+ const usedToolCallIds = new Set();
30
+ const pendingCodeExecutionsByProviderId = new Map();
31
+ const pendingAnonymousCodeExecutions = [];
32
+ let anonymousCodeExecutionIndex = 0;
33
+ const reserve = (id) => {
34
+ if (usedToolCallIds.has(id)) {
35
+ throw new TypeError("Google tool call id was duplicated");
36
+ }
37
+ usedToolCallIds.add(id);
38
+ return id;
39
+ };
40
+ return {
41
+ registerFunctionCall(partIndex, providerId) {
42
+ return reserve(providerId ?? `tool-${partIndex}`);
43
+ },
44
+ registerCodeExecution(providerId) {
45
+ if (providerId !== undefined) {
46
+ const id = reserve(providerId);
47
+ pendingCodeExecutionsByProviderId.set(providerId, id);
48
+ return id;
49
+ }
50
+ let id;
51
+ do {
52
+ id = `google-code-execution-${anonymousCodeExecutionIndex++}`;
53
+ } while (usedToolCallIds.has(id));
54
+ usedToolCallIds.add(id);
55
+ pendingAnonymousCodeExecutions.push(id);
56
+ return id;
57
+ },
58
+ resolveCodeExecutionResult(providerId) {
59
+ if (providerId === undefined) {
60
+ const id = pendingAnonymousCodeExecutions.shift();
61
+ if (id === undefined) {
62
+ throw new TypeError("Google code execution result had no matching executable code");
63
+ }
64
+ return id;
65
+ }
66
+ const id = pendingCodeExecutionsByProviderId.get(providerId);
67
+ if (id === undefined) {
68
+ throw new TypeError("Google code execution result id did not match executable code");
69
+ }
70
+ pendingCodeExecutionsByProviderId.delete(providerId);
71
+ return id;
72
+ },
73
+ assertSettled() {
74
+ if (pendingCodeExecutionsByProviderId.size > 0 ||
75
+ pendingAnonymousCodeExecutions.length > 0) {
76
+ throw new TypeError("Google executable code had no matching execution result");
77
+ }
78
+ },
79
+ };
80
+ }
81
+ /**
82
+ * Validates the documented `Part.data` oneof and returns the supported field.
83
+ *
84
+ * The extension intentionally fails closed for media/file/function-response
85
+ * output parts until it has a canonical runtime representation for them.
86
+ */
87
+ export function readGooglePartDataField(part) {
88
+ const unknownField = Object.keys(part).find((field) => !GOOGLE_PART_DATA_FIELDS.includes(field) && !GOOGLE_PART_METADATA_FIELDS.has(field));
89
+ if (unknownField !== undefined) {
90
+ throw new TypeError(`Google part field "${unknownField}" is unknown`);
91
+ }
92
+ const presentFields = GOOGLE_PART_DATA_FIELDS.filter((field) => part[field] !== undefined);
93
+ if (presentFields.length !== 1) {
94
+ throw new TypeError("Google part must contain exactly one data field");
95
+ }
96
+ const field = presentFields[0];
97
+ switch (field) {
98
+ case "text":
99
+ case "functionCall":
100
+ case "executableCode":
101
+ case "codeExecutionResult":
102
+ return field;
103
+ default:
104
+ throw new TypeError(`Google part data field "${field}" is unsupported`);
105
+ }
106
+ }
107
+ function readOptionalProviderId(record, subject) {
108
+ if (record.id === undefined) {
109
+ return undefined;
110
+ }
111
+ if (typeof record.id !== "string" || record.id.length === 0) {
112
+ throw new TypeError(`Google ${subject} id must be a non-empty string`);
113
+ }
114
+ return record.id;
115
+ }
116
+ export function readGoogleExecutableCode(value) {
117
+ const record = readRecord(value);
118
+ if (!record ||
119
+ record.language !== "PYTHON" ||
120
+ typeof record.code !== "string" ||
121
+ record.code.length === 0) {
122
+ throw new TypeError("Google executable code is malformed");
123
+ }
124
+ const providerId = readOptionalProviderId(record, "executable code");
125
+ return {
126
+ ...(providerId !== undefined ? { providerId } : {}),
127
+ language: "PYTHON",
128
+ code: record.code,
129
+ };
130
+ }
131
+ export function readGoogleCodeExecutionResult(value) {
132
+ const record = readRecord(value);
133
+ if (!record) {
134
+ throw new TypeError("Google code execution result is malformed");
135
+ }
136
+ const providerId = readOptionalProviderId(record, "code execution result");
137
+ const outcome = record.outcome;
138
+ if (outcome !== "OUTCOME_OK" &&
139
+ outcome !== "OUTCOME_FAILED" &&
140
+ outcome !== "OUTCOME_DEADLINE_EXCEEDED") {
141
+ throw new TypeError("Google code execution result outcome is malformed");
142
+ }
143
+ if (record.output !== undefined && typeof record.output !== "string") {
144
+ throw new TypeError("Google code execution result output is malformed");
145
+ }
146
+ return {
147
+ ...(providerId !== undefined ? { providerId } : {}),
148
+ outcome,
149
+ output: typeof record.output === "string" ? record.output : "",
150
+ isError: outcome !== "OUTCOME_OK",
151
+ };
152
+ }
153
+ export function googleCodeExecutionInput(executableCode) {
154
+ return {
155
+ language: executableCode.language,
156
+ code: executableCode.code,
157
+ };
158
+ }
159
+ export function googleCodeExecutionOutput(result) {
160
+ return {
161
+ outcome: result.outcome,
162
+ output: result.output,
163
+ };
164
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Validate the stable list fields needed to preserve citation integrity while
3
+ * retaining all other Google-owned metadata fields opaquely.
4
+ */
5
+ export declare function readGoogleGroundingMetadata(value: unknown): Record<string, unknown>;
6
+ /**
7
+ * Merge one streaming GroundingMetadata delta into the aggregate result.
8
+ *
9
+ * Google documents groundingChunks as incremental in streaming responses and
10
+ * defines support indices across every response. Supports are therefore
11
+ * appended too, while query strings are accumulated without duplicates.
12
+ * Scalar/object fields and unknown future fields use the latest value.
13
+ */
14
+ export declare function mergeGoogleGroundingMetadata(current: Record<string, unknown> | undefined, incoming: unknown): Record<string, unknown>;
15
+ //# sourceMappingURL=google-grounding-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-grounding-metadata.d.ts","sourceRoot":"","sources":["../src/google-grounding-metadata.ts"],"names":[],"mappings":"AAwCA;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,GACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBzB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5C,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgCzB"}
@@ -0,0 +1,87 @@
1
+ import { readRecord } from "veryfront/provider/shared";
2
+ const APPENDED_OBJECT_ARRAY_FIELDS = [
3
+ "groundingChunks",
4
+ "groundingSupports",
5
+ ];
6
+ const MERGED_STRING_ARRAY_FIELDS = [
7
+ "webSearchQueries",
8
+ "imageSearchQueries",
9
+ ];
10
+ function readObjectArray(value, field) {
11
+ if (!Array.isArray(value)) {
12
+ throw new TypeError(`Google grounding metadata ${field} must be an array`);
13
+ }
14
+ return value.map((item) => {
15
+ const record = readRecord(item);
16
+ if (!record) {
17
+ throw new TypeError(`Google grounding metadata ${field} item must be an object`);
18
+ }
19
+ return record;
20
+ });
21
+ }
22
+ function readStringArray(value, field) {
23
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
24
+ throw new TypeError(`Google grounding metadata ${field} must be a string array`);
25
+ }
26
+ return value;
27
+ }
28
+ /**
29
+ * Validate the stable list fields needed to preserve citation integrity while
30
+ * retaining all other Google-owned metadata fields opaquely.
31
+ */
32
+ export function readGoogleGroundingMetadata(value) {
33
+ const metadata = readRecord(value);
34
+ if (!metadata) {
35
+ throw new TypeError("Google grounding metadata must be an object");
36
+ }
37
+ const normalized = { ...metadata };
38
+ for (const field of APPENDED_OBJECT_ARRAY_FIELDS) {
39
+ if (metadata[field] !== undefined) {
40
+ normalized[field] = readObjectArray(metadata[field], field);
41
+ }
42
+ }
43
+ for (const field of MERGED_STRING_ARRAY_FIELDS) {
44
+ if (metadata[field] !== undefined) {
45
+ normalized[field] = readStringArray(metadata[field], field);
46
+ }
47
+ }
48
+ return normalized;
49
+ }
50
+ /**
51
+ * Merge one streaming GroundingMetadata delta into the aggregate result.
52
+ *
53
+ * Google documents groundingChunks as incremental in streaming responses and
54
+ * defines support indices across every response. Supports are therefore
55
+ * appended too, while query strings are accumulated without duplicates.
56
+ * Scalar/object fields and unknown future fields use the latest value.
57
+ */
58
+ export function mergeGoogleGroundingMetadata(current, incoming) {
59
+ const normalizedIncoming = readGoogleGroundingMetadata(incoming);
60
+ const merged = {
61
+ ...(current ?? {}),
62
+ ...normalizedIncoming,
63
+ };
64
+ for (const field of APPENDED_OBJECT_ARRAY_FIELDS) {
65
+ const previousItems = current?.[field];
66
+ const incomingItems = normalizedIncoming[field];
67
+ if (incomingItems !== undefined) {
68
+ merged[field] = [
69
+ ...(Array.isArray(previousItems) ? previousItems : []),
70
+ ...incomingItems,
71
+ ];
72
+ }
73
+ }
74
+ for (const field of MERGED_STRING_ARRAY_FIELDS) {
75
+ const previousItems = current?.[field];
76
+ const incomingItems = normalizedIncoming[field];
77
+ if (incomingItems !== undefined) {
78
+ merged[field] = [
79
+ ...new Set([
80
+ ...(Array.isArray(previousItems) ? previousItems : []),
81
+ ...incomingItems,
82
+ ]),
83
+ ];
84
+ }
85
+ }
86
+ return merged;
87
+ }
@@ -7,8 +7,9 @@
7
7
  * @module extensions/ext-llm-google/google-provider
8
8
  */
9
9
  import type { LLMProvider, LLMProviderConfig } from "veryfront/extensions/llm";
10
- import type { EmbeddingRuntime, ModelRuntime } from "veryfront/provider/types";
10
+ import type { EmbeddingRuntime, ModelRuntime, RuntimeAssistantContentPart } from "veryfront/provider/types";
11
11
  import { buildProviderError, isNumberArray, mergeUsage, parseRetryAfterMs, parseSseChunk, ProviderError, ProviderOverloadedError, ProviderQuotaError, ProviderRateLimitError, ProviderRequestError, TOOL_INPUT_PENDING_THRESHOLD_MS, unwrapToolInputSchema } from "veryfront/provider/shared";
12
+ import { type OpenAICompatibleLanguageOptions } from "./google-request-builder.js";
12
13
  export { buildProviderError, isNumberArray, mergeUsage, parseRetryAfterMs, parseSseChunk, ProviderError, ProviderOverloadedError, ProviderQuotaError, ProviderRateLimitError, ProviderRequestError, TOOL_INPUT_PENDING_THRESHOLD_MS, unwrapToolInputSchema, };
13
14
  export interface GoogleRuntimeConfig {
14
15
  apiKey: string;
@@ -16,11 +17,11 @@ export interface GoogleRuntimeConfig {
16
17
  name?: string;
17
18
  fetch?: typeof globalThis.fetch;
18
19
  }
19
- export declare function createGoogleModelRuntime(config: GoogleRuntimeConfig, modelId: string): ModelRuntime;
20
+ export declare function createGoogleModelRuntime(config: GoogleRuntimeConfig, modelId: string): ModelRuntime<OpenAICompatibleLanguageOptions, RuntimeAssistantContentPart>;
20
21
  export declare function createGoogleEmbeddingRuntime(config: GoogleRuntimeConfig, modelId: string): EmbeddingRuntime;
21
22
  export declare class GoogleProvider implements LLMProvider {
22
23
  readonly id = "google";
23
- createModel(modelId: string, config: LLMProviderConfig): ModelRuntime;
24
+ createModel(modelId: string, config: LLMProviderConfig): ModelRuntime<OpenAICompatibleLanguageOptions, RuntimeAssistantContentPart>;
24
25
  createEmbedding(modelId: string, config: LLMProviderConfig): EmbeddingRuntime;
25
26
  }
26
27
  //# sourceMappingURL=google-provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-provider.d.ts","sourceRoot":"","sources":["../src/google-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAMlB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EAKpB,+BAA+B,EAC/B,qBAAqB,EACtB,MAAM,2BAA2B,CAAC;AAgBnC,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EACpB,+BAA+B,EAC/B,qBAAqB,GACtB,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAsFD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAkEd;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,gBAAgB,CA6ClB;AAED,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,EAAE,YAAY;IAEvB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,YAAY;IAYrE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,gBAAgB;CAW9E"}
1
+ {"version":3,"file":"google-provider.d.ts","sourceRoot":"","sources":["../src/google-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,2BAA2B,EAC5B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,kBAAkB,EAMlB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EAKpB,+BAA+B,EAC/B,qBAAqB,EACtB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,6BAA6B,CAAC;AAwBrC,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EACpB,+BAA+B,EAC/B,qBAAqB,GACtB,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAmdD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC,CA2E5E;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,gBAAgB,CAiFlB;AAED,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,EAAE,YAAY;IAEvB,WAAW,CACT,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,iBAAiB,GACxB,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC;IAY7E,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,gBAAgB;CAW9E"}