@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 +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
|
@@ -1,4 +1,234 @@
|
|
|
1
|
-
import { readProviderOptions, readRecord, unwrapToolInputSchema } from "veryfront/provider/shared";
|
|
1
|
+
import { jsonValuesEqual, readProviderOptions, readRecord, unwrapToolInputSchema, } from "veryfront/provider/shared";
|
|
2
|
+
import { createGoogleToolCallCorrelationRegistry, GOOGLE_CODE_EXECUTION_TOOL_NAME, googleCodeExecutionInput, googleCodeExecutionOutput, readGoogleCodeExecutionResult, readGoogleExecutableCode, readGooglePartDataField, } from "./google-content-parts.js";
|
|
3
|
+
import { readGoogleRawAssistantParts } from "./google-thought-signatures.js";
|
|
4
|
+
function invalidGoogleProviderHistory() {
|
|
5
|
+
return new TypeError("Google raw assistant metadata did not match canonical provider tool history");
|
|
6
|
+
}
|
|
7
|
+
function readGoogleRawToolHistory(rawAssistantParts) {
|
|
8
|
+
const registry = createGoogleToolCallCorrelationRegistry();
|
|
9
|
+
const ordinaryCalls = [];
|
|
10
|
+
const legacyOrdinaryCalls = [];
|
|
11
|
+
const providerCalls = [];
|
|
12
|
+
const providerResults = [];
|
|
13
|
+
const toolEvents = [];
|
|
14
|
+
const legacyToolEvents = [];
|
|
15
|
+
let anonymousFunctionCallIndex = 0;
|
|
16
|
+
for (let partIndex = 0; partIndex < rawAssistantParts.length; partIndex += 1) {
|
|
17
|
+
const part = rawAssistantParts[partIndex];
|
|
18
|
+
if (part === undefined) {
|
|
19
|
+
throw invalidGoogleProviderHistory();
|
|
20
|
+
}
|
|
21
|
+
const dataField = readGooglePartDataField(part);
|
|
22
|
+
if (dataField === "functionCall") {
|
|
23
|
+
const functionCall = readRecord(part.functionCall);
|
|
24
|
+
const functionCallArgs = functionCall?.args === undefined
|
|
25
|
+
? {}
|
|
26
|
+
: readRecord(functionCall.args);
|
|
27
|
+
if (!functionCall ||
|
|
28
|
+
typeof functionCall.name !== "string" ||
|
|
29
|
+
!functionCallArgs) {
|
|
30
|
+
throw invalidGoogleProviderHistory();
|
|
31
|
+
}
|
|
32
|
+
const providerId = typeof functionCall.id === "string" ? functionCall.id : undefined;
|
|
33
|
+
const id = registry.registerFunctionCall(partIndex, providerId);
|
|
34
|
+
// Histories persisted before raw-position ids used the anonymous-call
|
|
35
|
+
// occurrence instead. Build both complete projections so validation
|
|
36
|
+
// cannot accept a mixture that no implementation ever emitted.
|
|
37
|
+
const legacyId = providerId === undefined ? `tool-${anonymousFunctionCallIndex++}` : id;
|
|
38
|
+
const call = {
|
|
39
|
+
name: functionCall.name,
|
|
40
|
+
input: functionCallArgs,
|
|
41
|
+
};
|
|
42
|
+
ordinaryCalls.push({ id, ...call });
|
|
43
|
+
legacyOrdinaryCalls.push({ id: legacyId, ...call });
|
|
44
|
+
toolEvents.push({ kind: "ordinary-call", id });
|
|
45
|
+
legacyToolEvents.push({ kind: "ordinary-call", id: legacyId });
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (dataField === "executableCode") {
|
|
49
|
+
const executableCode = readGoogleExecutableCode(part.executableCode);
|
|
50
|
+
const id = registry.registerCodeExecution(executableCode.providerId);
|
|
51
|
+
providerCalls.push({
|
|
52
|
+
id,
|
|
53
|
+
name: GOOGLE_CODE_EXECUTION_TOOL_NAME,
|
|
54
|
+
input: googleCodeExecutionInput(executableCode),
|
|
55
|
+
});
|
|
56
|
+
toolEvents.push({ kind: "provider-call", id });
|
|
57
|
+
legacyToolEvents.push({ kind: "provider-call", id });
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (dataField !== "codeExecutionResult") {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const result = readGoogleCodeExecutionResult(part.codeExecutionResult);
|
|
64
|
+
const id = registry.resolveCodeExecutionResult(result.providerId);
|
|
65
|
+
providerResults.push({
|
|
66
|
+
id,
|
|
67
|
+
name: GOOGLE_CODE_EXECUTION_TOOL_NAME,
|
|
68
|
+
result: googleCodeExecutionOutput(result),
|
|
69
|
+
isError: result.isError,
|
|
70
|
+
});
|
|
71
|
+
toolEvents.push({ kind: "provider-result", id });
|
|
72
|
+
legacyToolEvents.push({ kind: "provider-result", id });
|
|
73
|
+
}
|
|
74
|
+
registry.assertSettled();
|
|
75
|
+
return {
|
|
76
|
+
ordinaryCalls,
|
|
77
|
+
legacyOrdinaryCalls,
|
|
78
|
+
providerCalls,
|
|
79
|
+
providerResults,
|
|
80
|
+
toolEvents,
|
|
81
|
+
legacyToolEvents,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function callsMatch(left, right) {
|
|
85
|
+
return left.id === right.id &&
|
|
86
|
+
left.name === right.name &&
|
|
87
|
+
jsonValuesEqual(left.input, right.input, true);
|
|
88
|
+
}
|
|
89
|
+
function resultsMatch(left, right) {
|
|
90
|
+
return left.id === right.id &&
|
|
91
|
+
left.name === right.name &&
|
|
92
|
+
left.isError === right.isError &&
|
|
93
|
+
jsonValuesEqual(left.result, right.result);
|
|
94
|
+
}
|
|
95
|
+
function orderedProjectionMatches(left, right, entryMatches) {
|
|
96
|
+
if (left.length !== right.length) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
100
|
+
const entry = left[index];
|
|
101
|
+
const matchingEntry = right[index];
|
|
102
|
+
if (entry === undefined ||
|
|
103
|
+
matchingEntry === undefined ||
|
|
104
|
+
!entryMatches(entry, matchingEntry)) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
function rejectDuplicateIds(entries) {
|
|
111
|
+
const ids = new Set();
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
if (ids.has(entry.id)) {
|
|
114
|
+
throw invalidGoogleProviderHistory();
|
|
115
|
+
}
|
|
116
|
+
ids.add(entry.id);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function survivingToolEvents(events, activeKinds) {
|
|
120
|
+
const surviving = [];
|
|
121
|
+
for (const event of events) {
|
|
122
|
+
if (activeKinds.has(event.kind)) {
|
|
123
|
+
surviving.push(event);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return surviving;
|
|
127
|
+
}
|
|
128
|
+
function validateGoogleToolReplay(message, rawAssistantParts) {
|
|
129
|
+
const providerToolCalls = (message.providerToolCalls ?? []).map((call) => ({
|
|
130
|
+
id: call.toolCallId,
|
|
131
|
+
name: call.toolName,
|
|
132
|
+
input: call.input,
|
|
133
|
+
}));
|
|
134
|
+
rejectDuplicateIds(providerToolCalls);
|
|
135
|
+
const contentProviderCalls = [];
|
|
136
|
+
const ordinaryCalls = [];
|
|
137
|
+
const providerResults = [];
|
|
138
|
+
const contentToolEvents = [];
|
|
139
|
+
const contentCallIds = new Set();
|
|
140
|
+
for (const part of message.content) {
|
|
141
|
+
if (part.type === "tool-call") {
|
|
142
|
+
if (contentCallIds.has(part.toolCallId)) {
|
|
143
|
+
throw invalidGoogleProviderHistory();
|
|
144
|
+
}
|
|
145
|
+
contentCallIds.add(part.toolCallId);
|
|
146
|
+
const call = {
|
|
147
|
+
id: part.toolCallId,
|
|
148
|
+
name: part.toolName,
|
|
149
|
+
input: part.input,
|
|
150
|
+
};
|
|
151
|
+
const callKind = part.providerExecuted === true ? "provider" : "ordinary";
|
|
152
|
+
(callKind === "provider" ? contentProviderCalls : ordinaryCalls).push(call);
|
|
153
|
+
contentToolEvents.push({
|
|
154
|
+
kind: callKind === "provider" ? "provider-call" : "ordinary-call",
|
|
155
|
+
id: call.id,
|
|
156
|
+
});
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (part.type !== "tool-result" || part.providerExecuted !== true) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
providerResults.push({
|
|
163
|
+
id: part.toolCallId,
|
|
164
|
+
name: part.toolName,
|
|
165
|
+
result: part.result,
|
|
166
|
+
isError: part.isError === true,
|
|
167
|
+
});
|
|
168
|
+
contentToolEvents.push({
|
|
169
|
+
kind: "provider-result",
|
|
170
|
+
id: part.toolCallId,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
rejectDuplicateIds(providerResults);
|
|
174
|
+
let canonicalProviderCalls;
|
|
175
|
+
if (providerToolCalls.length > 0 && contentProviderCalls.length > 0) {
|
|
176
|
+
if (!orderedProjectionMatches(providerToolCalls, contentProviderCalls, callsMatch)) {
|
|
177
|
+
throw invalidGoogleProviderHistory();
|
|
178
|
+
}
|
|
179
|
+
// `providerToolCalls` is the historical message-level projection of the
|
|
180
|
+
// same provider-executed content. Validate both sources above, but compare
|
|
181
|
+
// the replay only once.
|
|
182
|
+
canonicalProviderCalls = providerToolCalls;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
canonicalProviderCalls = providerToolCalls.length > 0
|
|
186
|
+
? providerToolCalls
|
|
187
|
+
: contentProviderCalls;
|
|
188
|
+
}
|
|
189
|
+
rejectDuplicateIds([...ordinaryCalls, ...canonicalProviderCalls]);
|
|
190
|
+
let rawHistory;
|
|
191
|
+
try {
|
|
192
|
+
rawHistory = readGoogleRawToolHistory(rawAssistantParts);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
throw invalidGoogleProviderHistory();
|
|
196
|
+
}
|
|
197
|
+
// Exact wire history may outlive an absent canonical projection, for example
|
|
198
|
+
// after compaction. Once any projection survives, however, it must correlate
|
|
199
|
+
// one-for-one and in occurrence order; maps or sets would silently accept
|
|
200
|
+
// reordered or duplicated calls/results.
|
|
201
|
+
if (canonicalProviderCalls.length > 0 &&
|
|
202
|
+
!orderedProjectionMatches(rawHistory.providerCalls, canonicalProviderCalls, callsMatch)) {
|
|
203
|
+
throw invalidGoogleProviderHistory();
|
|
204
|
+
}
|
|
205
|
+
if (providerResults.length > 0 &&
|
|
206
|
+
!orderedProjectionMatches(rawHistory.providerResults, providerResults, resultsMatch)) {
|
|
207
|
+
throw invalidGoogleProviderHistory();
|
|
208
|
+
}
|
|
209
|
+
const activeContentEventKinds = new Set();
|
|
210
|
+
if (ordinaryCalls.length > 0) {
|
|
211
|
+
activeContentEventKinds.add("ordinary-call");
|
|
212
|
+
}
|
|
213
|
+
if (contentProviderCalls.length > 0) {
|
|
214
|
+
activeContentEventKinds.add("provider-call");
|
|
215
|
+
}
|
|
216
|
+
if (providerResults.length > 0) {
|
|
217
|
+
activeContentEventKinds.add("provider-result");
|
|
218
|
+
}
|
|
219
|
+
const currentRawSurvivingEvents = survivingToolEvents(rawHistory.toolEvents, activeContentEventKinds);
|
|
220
|
+
const legacyRawSurvivingEvents = survivingToolEvents(rawHistory.legacyToolEvents, activeContentEventKinds);
|
|
221
|
+
const canonicalSurvivingEvents = survivingToolEvents(contentToolEvents, activeContentEventKinds);
|
|
222
|
+
const currentIdsMatch = (ordinaryCalls.length === 0 ||
|
|
223
|
+
orderedProjectionMatches(rawHistory.ordinaryCalls, ordinaryCalls, callsMatch)) &&
|
|
224
|
+
orderedProjectionMatches(currentRawSurvivingEvents, canonicalSurvivingEvents, (left, right) => left.kind === right.kind && left.id === right.id);
|
|
225
|
+
const legacyIdsMatch = (ordinaryCalls.length === 0 ||
|
|
226
|
+
orderedProjectionMatches(rawHistory.legacyOrdinaryCalls, ordinaryCalls, callsMatch)) &&
|
|
227
|
+
orderedProjectionMatches(legacyRawSurvivingEvents, canonicalSurvivingEvents, (left, right) => left.kind === right.kind && left.id === right.id);
|
|
228
|
+
if (!currentIdsMatch && !legacyIdsMatch) {
|
|
229
|
+
throw invalidGoogleProviderHistory();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
2
232
|
function toGoogleContents(prompt) {
|
|
3
233
|
const systemParts = [];
|
|
4
234
|
const contents = [];
|
|
@@ -16,6 +246,12 @@ function toGoogleContents(prompt) {
|
|
|
16
246
|
});
|
|
17
247
|
break;
|
|
18
248
|
case "assistant": {
|
|
249
|
+
const rawAssistantParts = readGoogleRawAssistantParts(message.providerMetadata);
|
|
250
|
+
if (rawAssistantParts) {
|
|
251
|
+
validateGoogleToolReplay(message, rawAssistantParts);
|
|
252
|
+
contents.push({ role: "model", parts: rawAssistantParts });
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
19
255
|
const parts = [];
|
|
20
256
|
for (const part of message.content) {
|
|
21
257
|
if (part.type === "text") {
|
|
@@ -25,6 +261,12 @@ function toGoogleContents(prompt) {
|
|
|
25
261
|
if (part.type === "reasoning") {
|
|
26
262
|
continue;
|
|
27
263
|
}
|
|
264
|
+
if (part.type === "tool-result") {
|
|
265
|
+
throw new TypeError("Google provider-executed assistant tool results require exact raw replay metadata");
|
|
266
|
+
}
|
|
267
|
+
if (part.providerExecuted === true) {
|
|
268
|
+
throw new TypeError("Google provider-executed assistant tool calls require exact raw replay metadata");
|
|
269
|
+
}
|
|
28
270
|
parts.push({
|
|
29
271
|
functionCall: {
|
|
30
272
|
id: part.toolCallId,
|
|
@@ -79,12 +321,156 @@ function toGoogleUserParts(parts) {
|
|
|
79
321
|
}
|
|
80
322
|
return content;
|
|
81
323
|
}
|
|
324
|
+
const GOOGLE_CODE_EXECUTION_TOOL_ID = "google.code_execution";
|
|
325
|
+
const GOOGLE_SEARCH_TOOL_ID = "google.google_search";
|
|
326
|
+
const GOOGLE_SEARCH_TOOL_NAME = "google_search";
|
|
327
|
+
const GOOGLE_SEARCH_ARGUMENT_KEYS = new Set(["searchTypes", "timeRangeFilter"]);
|
|
328
|
+
const GOOGLE_SEARCH_TYPE_KEYS = new Set(["webSearch", "imageSearch"]);
|
|
329
|
+
const GOOGLE_TIME_RANGE_KEYS = new Set(["startTime", "endTime"]);
|
|
330
|
+
const RFC_3339_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,9})?(?:Z|[+-](\d{2}):(\d{2}))$/;
|
|
331
|
+
function rejectUnknownKeys(record, allowedKeys, subject) {
|
|
332
|
+
if (Object.keys(record).some((key) => !allowedKeys.has(key))) {
|
|
333
|
+
throw new TypeError(`${subject} contained an unsupported field`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function readEmptyGoogleToolObject(value, subject) {
|
|
337
|
+
const record = readRecord(value);
|
|
338
|
+
if (!record || Object.keys(record).length > 0) {
|
|
339
|
+
throw new TypeError(`${subject} must be an empty object`);
|
|
340
|
+
}
|
|
341
|
+
return {};
|
|
342
|
+
}
|
|
343
|
+
function readGoogleTimestamp(value, subject) {
|
|
344
|
+
const timestamp = typeof value === "string" ? value : undefined;
|
|
345
|
+
const match = timestamp === undefined ? null : RFC_3339_TIMESTAMP.exec(timestamp);
|
|
346
|
+
if (!match || timestamp === undefined) {
|
|
347
|
+
throw new TypeError(`${subject} must be an RFC 3339 timestamp`);
|
|
348
|
+
}
|
|
349
|
+
const [, yearText, monthText, dayText, hourText, minuteText, secondText, offsetHourText, offsetMinuteText,] = match;
|
|
350
|
+
const year = Number(yearText);
|
|
351
|
+
const month = Number(monthText);
|
|
352
|
+
const day = Number(dayText);
|
|
353
|
+
const hour = Number(hourText);
|
|
354
|
+
const minute = Number(minuteText);
|
|
355
|
+
const second = Number(secondText);
|
|
356
|
+
const offsetHour = offsetHourText === undefined ? 0 : Number(offsetHourText);
|
|
357
|
+
const offsetMinute = offsetMinuteText === undefined ? 0 : Number(offsetMinuteText);
|
|
358
|
+
const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
359
|
+
const daysInMonth = [
|
|
360
|
+
31,
|
|
361
|
+
leapYear ? 29 : 28,
|
|
362
|
+
31,
|
|
363
|
+
30,
|
|
364
|
+
31,
|
|
365
|
+
30,
|
|
366
|
+
31,
|
|
367
|
+
31,
|
|
368
|
+
30,
|
|
369
|
+
31,
|
|
370
|
+
30,
|
|
371
|
+
31,
|
|
372
|
+
][month - 1];
|
|
373
|
+
if (year < 1 ||
|
|
374
|
+
daysInMonth === undefined ||
|
|
375
|
+
day < 1 ||
|
|
376
|
+
day > daysInMonth ||
|
|
377
|
+
hour > 23 ||
|
|
378
|
+
minute > 59 ||
|
|
379
|
+
second > 59 ||
|
|
380
|
+
offsetHour > 23 ||
|
|
381
|
+
offsetMinute > 59 ||
|
|
382
|
+
!Number.isFinite(Date.parse(timestamp))) {
|
|
383
|
+
throw new TypeError(`${subject} must be an RFC 3339 timestamp`);
|
|
384
|
+
}
|
|
385
|
+
return timestamp;
|
|
386
|
+
}
|
|
387
|
+
function readGoogleSearchArguments(value) {
|
|
388
|
+
const args = readRecord(value);
|
|
389
|
+
if (!args) {
|
|
390
|
+
throw new TypeError("google.google_search args must be an object");
|
|
391
|
+
}
|
|
392
|
+
rejectUnknownKeys(args, GOOGLE_SEARCH_ARGUMENT_KEYS, "google.google_search args");
|
|
393
|
+
const normalized = {};
|
|
394
|
+
if (args.searchTypes !== undefined) {
|
|
395
|
+
const searchTypes = readRecord(args.searchTypes);
|
|
396
|
+
if (!searchTypes) {
|
|
397
|
+
throw new TypeError("google.google_search searchTypes must be an object");
|
|
398
|
+
}
|
|
399
|
+
rejectUnknownKeys(searchTypes, GOOGLE_SEARCH_TYPE_KEYS, "google.google_search searchTypes");
|
|
400
|
+
normalized.searchTypes = {
|
|
401
|
+
...(searchTypes.webSearch !== undefined
|
|
402
|
+
? {
|
|
403
|
+
webSearch: readEmptyGoogleToolObject(searchTypes.webSearch, "google.google_search webSearch"),
|
|
404
|
+
}
|
|
405
|
+
: {}),
|
|
406
|
+
...(searchTypes.imageSearch !== undefined
|
|
407
|
+
? {
|
|
408
|
+
imageSearch: readEmptyGoogleToolObject(searchTypes.imageSearch, "google.google_search imageSearch"),
|
|
409
|
+
}
|
|
410
|
+
: {}),
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
if (args.timeRangeFilter !== undefined) {
|
|
414
|
+
const timeRangeFilter = readRecord(args.timeRangeFilter);
|
|
415
|
+
if (!timeRangeFilter) {
|
|
416
|
+
throw new TypeError("google.google_search timeRangeFilter must be an object");
|
|
417
|
+
}
|
|
418
|
+
rejectUnknownKeys(timeRangeFilter, GOOGLE_TIME_RANGE_KEYS, "google.google_search timeRangeFilter");
|
|
419
|
+
const hasStart = timeRangeFilter.startTime !== undefined;
|
|
420
|
+
const hasEnd = timeRangeFilter.endTime !== undefined;
|
|
421
|
+
if (hasStart !== hasEnd) {
|
|
422
|
+
throw new TypeError("google.google_search timeRangeFilter requires both startTime and endTime");
|
|
423
|
+
}
|
|
424
|
+
if (hasStart && hasEnd) {
|
|
425
|
+
const startTime = readGoogleTimestamp(timeRangeFilter.startTime, "google.google_search startTime");
|
|
426
|
+
const endTime = readGoogleTimestamp(timeRangeFilter.endTime, "google.google_search endTime");
|
|
427
|
+
if (Date.parse(startTime) > Date.parse(endTime)) {
|
|
428
|
+
throw new TypeError("google.google_search timeRangeFilter startTime must not be after endTime");
|
|
429
|
+
}
|
|
430
|
+
normalized.timeRangeFilter = { startTime, endTime };
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
normalized.timeRangeFilter = {};
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return normalized;
|
|
437
|
+
}
|
|
438
|
+
function toGoogleProviderTool(tool) {
|
|
439
|
+
if (typeof tool.id !== "string") {
|
|
440
|
+
throw new TypeError("Google provider tool id must be a string");
|
|
441
|
+
}
|
|
442
|
+
switch (tool.id) {
|
|
443
|
+
case GOOGLE_CODE_EXECUTION_TOOL_ID:
|
|
444
|
+
if (tool.name !== GOOGLE_CODE_EXECUTION_TOOL_NAME) {
|
|
445
|
+
throw new TypeError("google.code_execution provider tool name must be code_execution");
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
id: tool.id,
|
|
449
|
+
wireTool: {
|
|
450
|
+
codeExecution: readEmptyGoogleToolObject(tool.args, "google.code_execution args"),
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
case GOOGLE_SEARCH_TOOL_ID:
|
|
454
|
+
if (tool.name !== GOOGLE_SEARCH_TOOL_NAME) {
|
|
455
|
+
throw new TypeError("google.google_search provider tool name must be google_search");
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
id: tool.id,
|
|
459
|
+
wireTool: { googleSearch: readGoogleSearchArguments(tool.args) },
|
|
460
|
+
};
|
|
461
|
+
default:
|
|
462
|
+
throw new TypeError(tool.id.startsWith("google.")
|
|
463
|
+
? "Unsupported Google provider tool id"
|
|
464
|
+
: "Google requests cannot contain a provider tool for another provider");
|
|
465
|
+
}
|
|
466
|
+
}
|
|
82
467
|
function toGoogleTools(tools) {
|
|
83
468
|
if (!tools) {
|
|
84
469
|
return undefined;
|
|
85
470
|
}
|
|
86
471
|
const functionDeclarations = [];
|
|
87
472
|
const providerEntries = [];
|
|
473
|
+
const providerToolIds = new Set();
|
|
88
474
|
for (const tool of tools) {
|
|
89
475
|
if (tool.type === "function") {
|
|
90
476
|
functionDeclarations.push({
|
|
@@ -94,15 +480,15 @@ function toGoogleTools(tools) {
|
|
|
94
480
|
});
|
|
95
481
|
continue;
|
|
96
482
|
}
|
|
97
|
-
if (
|
|
98
|
-
|
|
483
|
+
if (tool.type !== "provider") {
|
|
484
|
+
throw new TypeError("Google tool type must be function or provider");
|
|
99
485
|
}
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
102
|
-
|
|
486
|
+
const providerTool = toGoogleProviderTool(tool);
|
|
487
|
+
if (providerToolIds.has(providerTool.id)) {
|
|
488
|
+
throw new TypeError("Google provider tool id was duplicated");
|
|
103
489
|
}
|
|
104
|
-
|
|
105
|
-
providerEntries.push(
|
|
490
|
+
providerToolIds.add(providerTool.id);
|
|
491
|
+
providerEntries.push(providerTool.wireTool);
|
|
106
492
|
}
|
|
107
493
|
const result = [];
|
|
108
494
|
if (functionDeclarations.length > 0) {
|
|
@@ -160,11 +546,15 @@ function normalizeGoogleToolChoice(toolChoice) {
|
|
|
160
546
|
return undefined;
|
|
161
547
|
}
|
|
162
548
|
function resolveGoogleThinkingConfig(option) {
|
|
549
|
+
if (option?.budgetTokens !== undefined &&
|
|
550
|
+
(!Number.isSafeInteger(option.budgetTokens) || option.budgetTokens < 0)) {
|
|
551
|
+
throw new TypeError("Google reasoning budgetTokens must be a non-negative safe integer");
|
|
552
|
+
}
|
|
163
553
|
if (!option || option.enabled !== true) {
|
|
164
554
|
return undefined;
|
|
165
555
|
}
|
|
166
556
|
const config = { includeThoughts: true };
|
|
167
|
-
if (
|
|
557
|
+
if (option.budgetTokens !== undefined) {
|
|
168
558
|
config.thinkingBudget = option.budgetTokens;
|
|
169
559
|
return config;
|
|
170
560
|
}
|
|
@@ -227,6 +617,8 @@ export function buildGoogleGenerateContentRequest(providerName, options, warning
|
|
|
227
617
|
}
|
|
228
618
|
const { systemInstruction, contents } = toGoogleContents(options.prompt);
|
|
229
619
|
const generationConfig = buildGoogleGenerationConfig(options);
|
|
620
|
+
const tools = toGoogleTools(options.tools);
|
|
621
|
+
const toolConfig = normalizeGoogleToolChoice(options.toolChoice);
|
|
230
622
|
const labels = options.requestLabels && Object.keys(options.requestLabels).length > 0
|
|
231
623
|
? options.requestLabels
|
|
232
624
|
: typeof options.userId === "string" && options.userId.length > 0
|
|
@@ -235,10 +627,8 @@ export function buildGoogleGenerateContentRequest(providerName, options, warning
|
|
|
235
627
|
const body = {
|
|
236
628
|
contents,
|
|
237
629
|
...(systemInstruction ? { systemInstruction } : {}),
|
|
238
|
-
...(
|
|
239
|
-
...(
|
|
240
|
-
? { toolConfig: normalizeGoogleToolChoice(options.toolChoice) }
|
|
241
|
-
: {}),
|
|
630
|
+
...(tools ? { tools } : {}),
|
|
631
|
+
...(toolConfig ? { toolConfig } : {}),
|
|
242
632
|
...(generationConfig ? { generationConfig } : {}),
|
|
243
633
|
...(labels ? { labels } : {}),
|
|
244
634
|
...(typeof options.googleCachedContent === "string" && options.googleCachedContent.length > 0
|
package/esm/google-stream.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { type RuntimeUsage } from "veryfront/provider/shared";
|
|
2
|
+
export declare const MAX_GOOGLE_SSE_CHUNK_BYTES: number;
|
|
3
|
+
export declare const MAX_GOOGLE_SSE_BUFFER_CODE_UNITS: number;
|
|
4
|
+
export declare const MAX_GOOGLE_RETAINED_STATE_BYTES: number;
|
|
5
|
+
export declare const MAX_GOOGLE_RETAINED_STATE_ITEMS = 8192;
|
|
2
6
|
export declare function normalizeGoogleFinishReason(raw: unknown): string | {
|
|
3
7
|
unified: string;
|
|
4
8
|
raw: string;
|
|
@@ -6,5 +10,9 @@ export declare function normalizeGoogleFinishReason(raw: unknown): string | {
|
|
|
6
10
|
export declare function extractGoogleUsage(payload: unknown): RuntimeUsage | undefined;
|
|
7
11
|
export declare function extractFirstGoogleCandidate(payload: unknown): Record<string, unknown> | undefined;
|
|
8
12
|
export declare function extractGoogleCandidateParts(payload: unknown): Array<Record<string, unknown>>;
|
|
9
|
-
|
|
13
|
+
type GoogleStreamContext = {
|
|
14
|
+
providerLabel?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function streamGoogleCompatibleParts(stream: ReadableStream<Uint8Array>, context?: GoogleStreamContext): AsyncIterable<unknown>;
|
|
17
|
+
export {};
|
|
10
18
|
//# sourceMappingURL=google-stream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-stream.d.ts","sourceRoot":"","sources":["../src/google-stream.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"google-stream.d.ts","sourceRoot":"","sources":["../src/google-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,YAAY,EAElB,MAAM,2BAA2B,CAAC;AAiBnC,eAAO,MAAM,0BAA0B,QAAkB,CAAC;AAC1D,eAAO,MAAM,gCAAgC,QAAkB,CAAC;AAChE,eAAO,MAAM,+BAA+B,QAAqC,CAAC;AAClF,eAAO,MAAM,+BAA+B,OAAQ,CAAC;AAgBrD,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,OAAO,GACX,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAgBlD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CA4B7E;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAQjG;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAY5F;AAED,KAAK,mBAAmB,GAAG;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AA8BF,wBAAuB,2BAA2B,CAChD,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,GAAE,mBAAwB,GAChC,aAAa,CAAC,OAAO,CAAC,CA2tBxB"}
|