@veryfront/ext-llm-google 0.1.1186 → 0.1.1190
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 +74 -15
- package/esm/_dnt.polyfills.d.ts +12 -0
- package/esm/_dnt.polyfills.d.ts.map +1 -0
- package/esm/_dnt.polyfills.js +15 -0
- package/esm/google-content-parts.d.ts +45 -0
- package/esm/google-content-parts.d.ts.map +1 -0
- package/esm/google-content-parts.js +164 -0
- package/esm/google-grounding-metadata.d.ts +15 -0
- package/esm/google-grounding-metadata.d.ts.map +1 -0
- package/esm/google-grounding-metadata.js +87 -0
- package/esm/google-provider.d.ts +4 -3
- package/esm/google-provider.d.ts.map +1 -1
- package/esm/google-provider.js +407 -77
- package/esm/google-request-builder.d.ts +7 -55
- package/esm/google-request-builder.d.ts.map +1 -1
- package/esm/google-request-builder.js +403 -13
- package/esm/google-stream.d.ts +9 -1
- package/esm/google-stream.d.ts.map +1 -1
- package/esm/google-stream.js +590 -65
- package/esm/google-thought-signatures.d.ts +5 -0
- package/esm/google-thought-signatures.d.ts.map +1 -0
- package/esm/google-thought-signatures.js +296 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +10 -1
- package/package.json +3 -3
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/
|
|
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:** `
|
|
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
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
|
203
|
-
| ------------------------- |
|
|
204
|
-
| `ProviderOverloadedError` | HTTP 503
|
|
205
|
-
| `ProviderQuotaError` | HTTP 429 `RESOURCE_EXHAUSTED
|
|
206
|
-
| `ProviderRateLimitError` | HTTP 429 with `Retry-After`
|
|
207
|
-
| `ProviderRequestError` | Other HTTP errors
|
|
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
|
|
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
|
|
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
|
+
}
|
package/esm/google-provider.d.ts
CHANGED
|
@@ -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,
|
|
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"}
|