@ai-sdk/google 4.0.110 → 4.0.112
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/CHANGELOG.md +36 -0
- package/dist/index.d.ts +17 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +182 -26
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +81 -21
- package/dist/internal/index.js.map +1 -1
- package/docs/15-google.mdx +9 -3
- package/package.json +3 -3
- package/src/convert-to-google-messages.ts +2 -2
- package/src/google-language-model.ts +197 -145
- package/src/google-speech-model.ts +9 -12
- package/src/google-video-model.ts +1 -1
- package/src/interactions/prepare-google-interactions-tools.ts +7 -4
- package/src/realtime/google-realtime-event-mapper.ts +123 -0
- package/src/realtime/google-realtime-model.ts +58 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @ai-sdk/google
|
|
2
2
|
|
|
3
|
+
## 4.0.112
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fd7e8a7: Preserve the order of text and complete function calls in streamed Google responses, including standalone thought signatures on empty text or reasoning parts.
|
|
8
|
+
|
|
9
|
+
Keep provider metadata on empty text parts when converting results to response messages so it can be passed back in subsequent requests.
|
|
10
|
+
|
|
11
|
+
Omit foreign-provider empty signature text when replaying history through Anthropic or Bedrock, preserving Bedrock’s existing native reasoning-history handling.
|
|
12
|
+
|
|
13
|
+
- ef2dfb5: fix: pass through `seed: 0` instead of dropping it in image and video models. KlingAI now reports `seed: 0` as an unsupported setting like any other seed.
|
|
14
|
+
- 892af4d: feat (provider/google): implement server-side realtime extensions
|
|
15
|
+
|
|
16
|
+
`GoogleRealtimeModel` supports the existing `getServerWebSocketConfig()` contract, returning the unconstrained Gemini Live endpoint with resolved credential headers. Each server connection can create its own event parser. Reported gross token totals include thinking and tool-use counts, with cached input portions and available modality counts normalized without guessing missing values. Usage in a completion frame is attached to `response-done`; other snapshots use `custom` events with `rawType: 'usageMetadata'` and typed `usage`, preserving lifecycle ordering without inferring response associations.
|
|
17
|
+
|
|
18
|
+
- 3c6fb43: Forward explicit speech language codes to Gemini TTS for single- and multi-speaker requests, including the shared Vertex Gemini adapter. Omitted languages and `language: 'auto'` retain automatic detection without an unsupported-language warning.
|
|
19
|
+
- Updated dependencies [36802d4]
|
|
20
|
+
- Updated dependencies [e0143b0]
|
|
21
|
+
- Updated dependencies [934100c]
|
|
22
|
+
- Updated dependencies [892af4d]
|
|
23
|
+
- Updated dependencies [89aff56]
|
|
24
|
+
- Updated dependencies [41465fd]
|
|
25
|
+
- Updated dependencies [9754014]
|
|
26
|
+
- Updated dependencies [4bb73b0]
|
|
27
|
+
- Updated dependencies [2e44144]
|
|
28
|
+
- @ai-sdk/provider@4.0.36
|
|
29
|
+
- @ai-sdk/provider-utils@5.0.75
|
|
30
|
+
|
|
31
|
+
## 4.0.111
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- a32df11: Omit all Google Interactions tools when `toolChoice` is `none`, including provider-defined tools.
|
|
36
|
+
- Updated dependencies [fa15312]
|
|
37
|
+
- @ai-sdk/provider-utils@5.0.74
|
|
38
|
+
|
|
3
39
|
## 4.0.110
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FetchFunction, InferSchema, Resolvable, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, WebSocketConstructor, createToolNameMapping } from "@ai-sdk/provider-utils";
|
|
2
|
-
import { EmbeddingModelV4, Experimental_BatchV4, Experimental_DecisionModelV4, Experimental_RealtimeFactoryV4, Experimental_RealtimeModelV4, Experimental_RealtimeModelV4ClientEvent, Experimental_RealtimeModelV4ClientSecretOptions, Experimental_RealtimeModelV4ClientSecretResult, Experimental_RealtimeModelV4ServerEvent, Experimental_RealtimeModelV4SessionConfig, Experimental_SpeechTranslationModelV4, Experimental_SpeechTranslationModelV4StreamOptions, Experimental_TranscriptionModelV4StreamOptions, Experimental_VideoModelV4, FilesV4, ImageModelV4, JSONObject, LanguageModelV4, ProviderV4, SpeechModelV4, TranscriptionModelV4 } from "@ai-sdk/provider";
|
|
2
|
+
import { EmbeddingModelV4, Experimental_BatchV4, Experimental_DecisionModelV4, Experimental_RealtimeFactoryV4, Experimental_RealtimeModelV4, Experimental_RealtimeModelV4ClientEvent, Experimental_RealtimeModelV4ClientSecretOptions, Experimental_RealtimeModelV4ClientSecretResult, Experimental_RealtimeModelV4ServerConnection, Experimental_RealtimeModelV4ServerEvent, Experimental_RealtimeModelV4SessionConfig, Experimental_RealtimeModelV4SessionIntent, Experimental_SpeechTranslationModelV4, Experimental_SpeechTranslationModelV4StreamOptions, Experimental_TranscriptionModelV4StreamOptions, Experimental_VideoModelV4, FilesV4, ImageModelV4, JSONObject, LanguageModelV4, ProviderV4, SpeechModelV4, TranscriptionModelV4 } from "@ai-sdk/provider";
|
|
3
3
|
import { z } from "zod/v4";
|
|
4
4
|
//#region src/google-error.d.ts
|
|
5
5
|
declare const googleErrorDataSchema: import("@ai-sdk/provider-utils").LazySchema<{
|
|
@@ -797,6 +797,11 @@ type GoogleRealtimeModelConfig = {
|
|
|
797
797
|
};
|
|
798
798
|
declare class GoogleRealtimeModel implements Experimental_RealtimeModelV4 {
|
|
799
799
|
readonly specificationVersion: "v4";
|
|
800
|
+
readonly capabilities: {
|
|
801
|
+
readonly conversation: "turn-based";
|
|
802
|
+
readonly transports: readonly ["websocket"];
|
|
803
|
+
readonly connections: readonly ["client-secret-websocket", "server-websocket"];
|
|
804
|
+
};
|
|
800
805
|
readonly provider: string;
|
|
801
806
|
readonly modelId: string;
|
|
802
807
|
private readonly config;
|
|
@@ -810,9 +815,18 @@ declare class GoogleRealtimeModel implements Experimental_RealtimeModelV4 {
|
|
|
810
815
|
url: string;
|
|
811
816
|
protocols?: string[];
|
|
812
817
|
};
|
|
818
|
+
getServerWebSocketConfig(options?: {
|
|
819
|
+
intent?: Experimental_RealtimeModelV4SessionIntent;
|
|
820
|
+
}): Experimental_RealtimeModelV4ServerConnection | PromiseLike<Experimental_RealtimeModelV4ServerConnection>;
|
|
821
|
+
private assertConversationIntent;
|
|
813
822
|
parseServerEvent(raw: unknown): Experimental_RealtimeModelV4ServerEvent | Experimental_RealtimeModelV4ServerEvent[];
|
|
814
|
-
|
|
815
|
-
|
|
823
|
+
createServerEventParser(): ReturnType<NonNullable<Experimental_RealtimeModelV4['createServerEventParser']>>;
|
|
824
|
+
serializeClientEvent(event: Experimental_RealtimeModelV4ClientEvent, options?: {
|
|
825
|
+
intent?: Experimental_RealtimeModelV4SessionIntent;
|
|
826
|
+
}): ReturnType<Experimental_RealtimeModelV4['serializeClientEvent']>;
|
|
827
|
+
buildSessionConfig(config: Experimental_RealtimeModelV4SessionConfig, options?: {
|
|
828
|
+
intent?: Experimental_RealtimeModelV4SessionIntent;
|
|
829
|
+
}): Record<string, unknown>;
|
|
816
830
|
}
|
|
817
831
|
//#endregion
|
|
818
832
|
//#region src/realtime/google-realtime-model-options.d.ts
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":["DecisionModelV4","BatchV4","SpeechTranslationModelV4","RealtimeFactoryV4","RealtimeModelV4ClientSecretOptions","RealtimeModelV4ClientSecretResult","
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":["DecisionModelV4","BatchV4","SpeechTranslationModelV4","RealtimeFactoryV4","RealtimeModelV4ClientSecretOptions","RealtimeModelV4ClientSecretResult","RealtimeModelV4SessionIntent","RealtimeModelV4ServerConnection","RealtimeModelV4ServerEvent","RealtimeModelV4","RealtimeModelV4ClientEvent","RealtimeModelV4SessionConfig","TranscriptionModelV4StreamOptions","SpeechTranslationModelV4StreamOptions","SpeechTranslationModelV4"],"sources":["../src/google-error.ts","../src/google-language-model-options.ts","../src/google-language-model.ts","../src/google-prompt.ts","../src/tool/google-search.ts","../src/google-image-model-options.ts","../src/google-embedding-model-options.ts","../src/google-video-model-options.ts","../src/google-video-settings.ts","../src/google-speech-model-options.ts","../src/google-files.ts","../src/interactions/google-interactions-language-model-options.ts","../src/interactions/google-interactions-provider-metadata.ts","../src/interactions/google-interactions-agent.ts","../src/google-tools.ts","../src/google-image-settings.ts","../src/transcription/google-transcription-model-options.ts","../src/speech-translation/google-speech-translation-model-options.ts","../src/google-provider.ts","../src/realtime/google-realtime-model.ts","../src/realtime/google-realtime-model-options.ts","../src/transcription/google-transcription-model.ts","../src/speech-translation/google-speech-translation-model.ts","../src/version.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { EXPERIMENTAL_EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, connectToWebSocket, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertInlineFileDataToUint8Array, convertJsonResponseToolStream, convertToBase64, convertUint8ArrayToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonLinesResponseHandler, createJsonResponseHandler, createNullLanguageModelUsage, createProviderExecutedToolFactory, createProviderStreamError, createToolNameMapping, delay, detectMediaType, downloadBlob, encodePathSegment, generateId, getFromApi, getRuntimeEnvironmentUserAgent, getTopLevelMediaType, isAbortError, isCustomReasoning, isFullMediaType, isRecord, isSameOrigin, isUrlSupported, lazySchema, loadApiKey, mapReasoningToProviderBudget, mapReasoningToProviderEffort, normalizeBatchRequestCounts, parseProviderOptions, postJsonToApi, postToApi, resolve, resolveFullMediaType, resolveProviderReference, resolveWith, safeParseJSON, safeValidateTypes, secureJsonParse, serializeModelOptions, stringifyWithBigIntAndCycles, waitForWebSocketBufferDrain, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
|
|
1
|
+
import { EXPERIMENTAL_EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, connectToWebSocket, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertInlineFileDataToUint8Array, convertJsonResponseToolStream, convertToBase64, convertUint8ArrayToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonLinesResponseHandler, createJsonResponseHandler, createNullLanguageModelUsage, createProviderExecutedToolFactory, createProviderStreamError, createToolNameMapping, delay, detectMediaType, downloadBlob, encodePathSegment, generateId, getFromApi, getRuntimeEnvironmentUserAgent, getTopLevelMediaType, isAbortError, isCustomReasoning, isFullMediaType, isRecord, isSameOrigin, isUrlSupported, lazySchema, loadApiKey, mapReasoningToProviderBudget, mapReasoningToProviderEffort, normalizeBatchRequestCounts, parseProviderOptions, postJsonToApi, postToApi, removeUndefinedEntries, resolve, resolveFullMediaType, resolveProviderReference, resolveWith, safeParseJSON, safeValidateTypes, secureJsonParse, serializeModelOptions, stringifyWithBigIntAndCycles, waitForWebSocketBufferDrain, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
|
|
2
2
|
import { Experimental_DecisionLanguageModel } from "@ai-sdk/provider-utils/experimental-decision";
|
|
3
3
|
import { AISDKError, InvalidArgumentError, InvalidResponseDataError, TooManyEmbeddingValuesForCallError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
|
|
4
4
|
import { z } from "zod/v4";
|
|
5
5
|
//#region src/version.ts
|
|
6
|
-
const VERSION = "4.0.
|
|
6
|
+
const VERSION = "4.0.112";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/google-error.ts
|
|
9
9
|
const getGoogleErrorSchema = () => z.object({
|
|
@@ -577,11 +577,11 @@ function convertToGoogleMessages(prompt, options) {
|
|
|
577
577
|
const providerOpts = readProviderOpts(part);
|
|
578
578
|
const thoughtSignature = providerOpts?.thoughtSignature != null ? String(providerOpts.thoughtSignature) : void 0;
|
|
579
579
|
switch (part.type) {
|
|
580
|
-
case "text": return part.text.length === 0 ? void 0 : {
|
|
580
|
+
case "text": return part.text.length === 0 && thoughtSignature == null ? void 0 : {
|
|
581
581
|
text: part.text,
|
|
582
582
|
thoughtSignature
|
|
583
583
|
};
|
|
584
|
-
case "reasoning": return part.text.length === 0 ? void 0 : {
|
|
584
|
+
case "reasoning": return part.text.length === 0 && thoughtSignature == null ? void 0 : {
|
|
585
585
|
text: part.text,
|
|
586
586
|
thought: true,
|
|
587
587
|
thoughtSignature
|
|
@@ -2195,6 +2195,20 @@ var GoogleLanguageModel = class GoogleLanguageModel {
|
|
|
2195
2195
|
const finishActiveStreamingToolCall = (controller) => {
|
|
2196
2196
|
const active = activeStreamingToolCalls.pop();
|
|
2197
2197
|
if (active == null) return;
|
|
2198
|
+
if (currentTextBlockId !== null) {
|
|
2199
|
+
controller.enqueue({
|
|
2200
|
+
type: "text-end",
|
|
2201
|
+
id: currentTextBlockId
|
|
2202
|
+
});
|
|
2203
|
+
currentTextBlockId = null;
|
|
2204
|
+
}
|
|
2205
|
+
if (currentReasoningBlockId !== null) {
|
|
2206
|
+
controller.enqueue({
|
|
2207
|
+
type: "reasoning-end",
|
|
2208
|
+
id: currentReasoningBlockId
|
|
2209
|
+
});
|
|
2210
|
+
currentReasoningBlockId = null;
|
|
2211
|
+
}
|
|
2198
2212
|
const { finalJSON, closingDelta } = active.accumulator.finalize();
|
|
2199
2213
|
if (closingDelta.length > 0) controller.enqueue({
|
|
2200
2214
|
type: "tool-input-delta",
|
|
@@ -2333,12 +2347,40 @@ var GoogleLanguageModel = class GoogleLanguageModel {
|
|
|
2333
2347
|
} else if ("text" in part && part.text != null) {
|
|
2334
2348
|
const thoughtSignatureMetadata = part.thoughtSignature ? wrapProviderMetadata({ thoughtSignature: part.thoughtSignature }) : void 0;
|
|
2335
2349
|
if (part.text.length === 0) {
|
|
2336
|
-
if (thoughtSignatureMetadata != null
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2350
|
+
if (thoughtSignatureMetadata != null) {
|
|
2351
|
+
if (currentTextBlockId !== null) controller.enqueue({
|
|
2352
|
+
type: "text-delta",
|
|
2353
|
+
id: currentTextBlockId,
|
|
2354
|
+
delta: "",
|
|
2355
|
+
providerMetadata: thoughtSignatureMetadata
|
|
2356
|
+
});
|
|
2357
|
+
else {
|
|
2358
|
+
if (currentReasoningBlockId !== null) {
|
|
2359
|
+
controller.enqueue({
|
|
2360
|
+
type: "reasoning-end",
|
|
2361
|
+
id: currentReasoningBlockId
|
|
2362
|
+
});
|
|
2363
|
+
currentReasoningBlockId = null;
|
|
2364
|
+
}
|
|
2365
|
+
const id = String(blockCounter++);
|
|
2366
|
+
const type = part.thought === true ? "reasoning" : "text";
|
|
2367
|
+
controller.enqueue({
|
|
2368
|
+
type: `${type}-start`,
|
|
2369
|
+
id,
|
|
2370
|
+
providerMetadata: thoughtSignatureMetadata
|
|
2371
|
+
});
|
|
2372
|
+
controller.enqueue({
|
|
2373
|
+
type: `${type}-delta`,
|
|
2374
|
+
id,
|
|
2375
|
+
delta: "",
|
|
2376
|
+
providerMetadata: thoughtSignatureMetadata
|
|
2377
|
+
});
|
|
2378
|
+
controller.enqueue({
|
|
2379
|
+
type: `${type}-end`,
|
|
2380
|
+
id
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2342
2384
|
} else if (part.thought === true) {
|
|
2343
2385
|
if (currentTextBlockId !== null) {
|
|
2344
2386
|
controller.enqueue({
|
|
@@ -2442,14 +2484,28 @@ var GoogleLanguageModel = class GoogleLanguageModel {
|
|
|
2442
2484
|
providerMetadata: serverMeta
|
|
2443
2485
|
});
|
|
2444
2486
|
lastServerToolCallId = void 0;
|
|
2445
|
-
}
|
|
2446
|
-
for (const part of parts) {
|
|
2447
|
-
if (!("functionCall" in part)) continue;
|
|
2487
|
+
} else if ("functionCall" in part) {
|
|
2448
2488
|
const providerMeta = part.thoughtSignature ? wrapProviderMetadata({ thoughtSignature: part.thoughtSignature }) : void 0;
|
|
2449
2489
|
const isStreamingChunk = part.functionCall.partialArgs != null || part.functionCall.name != null && part.functionCall.willContinue === true;
|
|
2450
2490
|
const isTerminalChunk = part.functionCall.name == null && part.functionCall.args == null && part.functionCall.partialArgs == null && part.functionCall.willContinue == null;
|
|
2451
2491
|
const isCompleteCall = part.functionCall.name != null && part.functionCall.args != null && part.functionCall.partialArgs == null;
|
|
2452
2492
|
const isNoArgsCompleteCall = part.functionCall.name != null && part.functionCall.args == null && part.functionCall.partialArgs == null && part.functionCall.willContinue !== true;
|
|
2493
|
+
if (!isStreamingChunk && (isCompleteCall || isNoArgsCompleteCall)) {
|
|
2494
|
+
if (currentTextBlockId !== null) {
|
|
2495
|
+
controller.enqueue({
|
|
2496
|
+
type: "text-end",
|
|
2497
|
+
id: currentTextBlockId
|
|
2498
|
+
});
|
|
2499
|
+
currentTextBlockId = null;
|
|
2500
|
+
}
|
|
2501
|
+
if (currentReasoningBlockId !== null) {
|
|
2502
|
+
controller.enqueue({
|
|
2503
|
+
type: "reasoning-end",
|
|
2504
|
+
id: currentReasoningBlockId
|
|
2505
|
+
});
|
|
2506
|
+
currentReasoningBlockId = null;
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2453
2509
|
if (isStreamingChunk) {
|
|
2454
2510
|
if (part.functionCall.name != null) {
|
|
2455
2511
|
const toolCallId = part.functionCall.id || generateId();
|
|
@@ -3963,7 +4019,7 @@ var GoogleVideoModel = class {
|
|
|
3963
4019
|
"3840x2160": "4k"
|
|
3964
4020
|
}[options.resolution] || options.resolution;
|
|
3965
4021
|
if (options.duration) parameters.durationSeconds = options.duration;
|
|
3966
|
-
if (options.seed) parameters.seed = options.seed;
|
|
4022
|
+
if (options.seed != null) parameters.seed = options.seed;
|
|
3967
4023
|
if (googleOptions != null) {
|
|
3968
4024
|
const opts = googleOptions;
|
|
3969
4025
|
if (opts.personGeneration !== void 0 && opts.personGeneration !== null) parameters.personGeneration = opts.personGeneration;
|
|
@@ -4216,7 +4272,14 @@ var GoogleSpeechModel = class GoogleSpeechModel {
|
|
|
4216
4272
|
message: "Custom voices are not supported. Use a prebuilt voice instead."
|
|
4217
4273
|
});
|
|
4218
4274
|
const multiSpeakerVoiceConfig = googleOptions?.multiSpeakerVoiceConfig;
|
|
4219
|
-
const
|
|
4275
|
+
const languageCode = language === "auto" ? void 0 : language;
|
|
4276
|
+
const speechConfig = multiSpeakerVoiceConfig ? {
|
|
4277
|
+
multiSpeakerVoiceConfig,
|
|
4278
|
+
...languageCode != null && { languageCode }
|
|
4279
|
+
} : {
|
|
4280
|
+
voiceConfig: { prebuiltVoiceConfig: { voiceName: voice } },
|
|
4281
|
+
...languageCode != null && { languageCode }
|
|
4282
|
+
};
|
|
4220
4283
|
let promptText = text;
|
|
4221
4284
|
if (instructions != null && !usesStructuredSpeech) {
|
|
4222
4285
|
if (multiSpeakerVoiceConfig) warnings.push({
|
|
@@ -4268,11 +4331,6 @@ var GoogleSpeechModel = class GoogleSpeechModel {
|
|
|
4268
4331
|
feature: "speed",
|
|
4269
4332
|
details: "Google Gemini TTS models do not support the `speed` option. It was ignored."
|
|
4270
4333
|
});
|
|
4271
|
-
if (language != null) warnings.push({
|
|
4272
|
-
type: "unsupported",
|
|
4273
|
-
feature: "language",
|
|
4274
|
-
details: "Google Gemini TTS models do not support the `language` option. Language is detected automatically from the input text."
|
|
4275
|
-
});
|
|
4276
4334
|
const formats = usesStructuredSpeech ? {
|
|
4277
4335
|
wav: "AUDIO_WAV",
|
|
4278
4336
|
"audio/wav": "AUDIO_WAV",
|
|
@@ -6402,7 +6460,7 @@ async function pollGoogleInteractionUntilTerminal({ baseURL, interactionId, head
|
|
|
6402
6460
|
* `toolChoice` shapes:
|
|
6403
6461
|
* - `'auto'` -> `'auto'`
|
|
6404
6462
|
* - `'required'` -> `'any'`
|
|
6405
|
-
* - `'none'` -> `
|
|
6463
|
+
* - `'none'` -> omit all tools and `tool_choice`
|
|
6406
6464
|
* - `{ type: 'tool', toolName }` -> `{ allowed_tools: { mode: 'validated', tools: [name] } }`
|
|
6407
6465
|
* (Interactions `AllowedTools.tools` is an `Array<string>` of function
|
|
6408
6466
|
* names, not tool descriptors -- see `src/interactions/resources/interactions.ts`
|
|
@@ -6410,6 +6468,11 @@ async function pollGoogleInteractionUntilTerminal({ baseURL, interactionId, head
|
|
|
6410
6468
|
*/
|
|
6411
6469
|
function prepareGoogleInteractionsTools({ tools, toolChoice }) {
|
|
6412
6470
|
const toolWarnings = [];
|
|
6471
|
+
if (toolChoice?.type === "none") return {
|
|
6472
|
+
tools: void 0,
|
|
6473
|
+
toolChoice: void 0,
|
|
6474
|
+
toolWarnings
|
|
6475
|
+
};
|
|
6413
6476
|
const normalized = tools?.length ? tools : void 0;
|
|
6414
6477
|
if (normalized == null) return {
|
|
6415
6478
|
tools: void 0,
|
|
@@ -6515,9 +6578,6 @@ function prepareGoogleInteractionsTools({ tools, toolChoice }) {
|
|
|
6515
6578
|
case "required":
|
|
6516
6579
|
mappedToolChoice = "any";
|
|
6517
6580
|
break;
|
|
6518
|
-
case "none":
|
|
6519
|
-
mappedToolChoice = "none";
|
|
6520
|
-
break;
|
|
6521
6581
|
case "tool": mappedToolChoice = { allowed_tools: {
|
|
6522
6582
|
mode: "validated",
|
|
6523
6583
|
tools: [toolChoice.toolName]
|
|
@@ -7294,6 +7354,27 @@ var GoogleRealtimeEventMapper = class {
|
|
|
7294
7354
|
this.inputTranscriptionBuffer = "";
|
|
7295
7355
|
}
|
|
7296
7356
|
parseServerEvent(raw) {
|
|
7357
|
+
const events = this.parseEvent(raw);
|
|
7358
|
+
const usage = mapGoogleUsage(raw.usageMetadata);
|
|
7359
|
+
if (usage == null) return events;
|
|
7360
|
+
const list = Array.isArray(events) ? events : [events];
|
|
7361
|
+
if (list.some((event) => event.type === "response-done")) {
|
|
7362
|
+
const mapped = list.map((event) => event.type === "response-done" ? {
|
|
7363
|
+
...event,
|
|
7364
|
+
usage
|
|
7365
|
+
} : event);
|
|
7366
|
+
return Array.isArray(events) ? mapped : mapped[0];
|
|
7367
|
+
}
|
|
7368
|
+
const update = {
|
|
7369
|
+
type: "custom",
|
|
7370
|
+
rawType: "usageMetadata",
|
|
7371
|
+
usage,
|
|
7372
|
+
raw
|
|
7373
|
+
};
|
|
7374
|
+
if (list.length === 1 && list[0].type === "custom" && list[0].rawType === "usageMetadata") return update;
|
|
7375
|
+
return [...list, update];
|
|
7376
|
+
}
|
|
7377
|
+
parseEvent(raw) {
|
|
7297
7378
|
const data = raw;
|
|
7298
7379
|
if (data.setupComplete != null) return {
|
|
7299
7380
|
type: "session-created",
|
|
@@ -7484,6 +7565,53 @@ var GoogleRealtimeEventMapper = class {
|
|
|
7484
7565
|
}
|
|
7485
7566
|
};
|
|
7486
7567
|
/**
|
|
7568
|
+
* Maps Gemini Live `usageMetadata` to normalized usage. Google reports usage
|
|
7569
|
+
* per modality in `promptTokensDetails` / `responseTokensDetails`.
|
|
7570
|
+
*
|
|
7571
|
+
* Field names are Live-API-specific: the Live `UsageMetadata` uses
|
|
7572
|
+
* `responseTokenCount` / `responseTokensDetails` for output, NOT the
|
|
7573
|
+
* `candidatesTokenCount` / `candidatesTokensDetails` of the regular
|
|
7574
|
+
* `generateContent` response (see google-language-model.ts). Do not "align"
|
|
7575
|
+
* these to `candidates*` — they are different wire shapes.
|
|
7576
|
+
*
|
|
7577
|
+
* Gross totals preserve provider counts even when modality details are absent
|
|
7578
|
+
* or contain modalities without a dedicated normalized bucket. Never guess a
|
|
7579
|
+
* text/audio split from those totals.
|
|
7580
|
+
*/
|
|
7581
|
+
function mapGoogleUsage(usageMetadata) {
|
|
7582
|
+
if (usageMetadata == null) return void 0;
|
|
7583
|
+
const input = sumByModality(usageMetadata.promptTokensDetails);
|
|
7584
|
+
const output = sumByModality(usageMetadata.responseTokensDetails);
|
|
7585
|
+
return compactUsage({
|
|
7586
|
+
inputTokens: usageMetadata.promptTokenCount != null ? usageMetadata.promptTokenCount + (usageMetadata.toolUsePromptTokenCount ?? 0) : void 0,
|
|
7587
|
+
outputTokens: usageMetadata.responseTokenCount != null ? usageMetadata.responseTokenCount + (usageMetadata.thoughtsTokenCount ?? 0) : void 0,
|
|
7588
|
+
cachedInputTokens: usageMetadata.cachedContentTokenCount,
|
|
7589
|
+
inputTextTokens: input.text,
|
|
7590
|
+
inputAudioTokens: input.audio,
|
|
7591
|
+
outputTextTokens: output.text,
|
|
7592
|
+
outputAudioTokens: output.audio
|
|
7593
|
+
});
|
|
7594
|
+
}
|
|
7595
|
+
/** Aggregate Gemini per-modality token details into text/audio buckets. */
|
|
7596
|
+
function sumByModality(details) {
|
|
7597
|
+
if (details == null) return {};
|
|
7598
|
+
const totals = {};
|
|
7599
|
+
for (const detail of details) {
|
|
7600
|
+
const count = detail.tokenCount;
|
|
7601
|
+
if (count == null) continue;
|
|
7602
|
+
const modality = detail.modality?.toUpperCase();
|
|
7603
|
+
if (modality === "AUDIO") totals.audio = (totals.audio ?? 0) + count;
|
|
7604
|
+
else if (modality === "TEXT") totals.text = (totals.text ?? 0) + count;
|
|
7605
|
+
}
|
|
7606
|
+
return totals;
|
|
7607
|
+
}
|
|
7608
|
+
/** Drop `undefined` fields; return `undefined` when nothing is observable. */
|
|
7609
|
+
function compactUsage(usage) {
|
|
7610
|
+
const result = {};
|
|
7611
|
+
for (const [key, value] of Object.entries(usage)) if (value != null) result[key] = value;
|
|
7612
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
7613
|
+
}
|
|
7614
|
+
/**
|
|
7487
7615
|
* The value Gemini accepts for `functionResponse.response`.
|
|
7488
7616
|
*
|
|
7489
7617
|
* The field is typed `google.protobuf.Struct`, which is an object and nothing else, so
|
|
@@ -7568,6 +7696,7 @@ function buildGoogleSessionConfig(config, modelId) {
|
|
|
7568
7696
|
//#endregion
|
|
7569
7697
|
//#region src/realtime/google-realtime-model.ts
|
|
7570
7698
|
const realtimeWebSocketPath = "google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContentConstrained";
|
|
7699
|
+
const realtimeServerWebSocketPath = "google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent";
|
|
7571
7700
|
function getAuthTokensURL(baseURL) {
|
|
7572
7701
|
const url = getRealtimeBaseURL(baseURL);
|
|
7573
7702
|
url.pathname = `${url.pathname.replace(/\/$/, "")}/v1alpha/auth_tokens`;
|
|
@@ -7576,9 +7705,20 @@ function getAuthTokensURL(baseURL) {
|
|
|
7576
7705
|
function getWebSocketURL(baseURL) {
|
|
7577
7706
|
return getRealtimeWebSocketURL(baseURL, realtimeWebSocketPath).toString();
|
|
7578
7707
|
}
|
|
7708
|
+
function getServerWebSocketURL(baseURL) {
|
|
7709
|
+
const url = getRealtimeBaseURL(baseURL);
|
|
7710
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
7711
|
+
url.pathname = `${url.pathname.replace(/\/$/, "")}/ws/${realtimeServerWebSocketPath}`;
|
|
7712
|
+
return url.toString();
|
|
7713
|
+
}
|
|
7579
7714
|
var GoogleRealtimeModel = class {
|
|
7580
7715
|
constructor(modelId, config) {
|
|
7581
7716
|
this.specificationVersion = "v4";
|
|
7717
|
+
this.capabilities = {
|
|
7718
|
+
conversation: "turn-based",
|
|
7719
|
+
transports: ["websocket"],
|
|
7720
|
+
connections: ["client-secret-websocket", "server-websocket"]
|
|
7721
|
+
};
|
|
7582
7722
|
this.mapper = new GoogleRealtimeEventMapper();
|
|
7583
7723
|
this.modelId = modelId;
|
|
7584
7724
|
this.provider = config.provider;
|
|
@@ -7617,13 +7757,29 @@ var GoogleRealtimeModel = class {
|
|
|
7617
7757
|
getWebSocketConfig(options) {
|
|
7618
7758
|
return { url: `${options.url}?access_token=${encodeURIComponent(options.token)}` };
|
|
7619
7759
|
}
|
|
7760
|
+
getServerWebSocketConfig(options) {
|
|
7761
|
+
this.assertConversationIntent(options);
|
|
7762
|
+
return resolveWith(this.config.headers, (headers) => ({
|
|
7763
|
+
url: getServerWebSocketURL(this.config.baseURL),
|
|
7764
|
+
headers: removeUndefinedEntries(headers)
|
|
7765
|
+
}));
|
|
7766
|
+
}
|
|
7767
|
+
assertConversationIntent(options) {
|
|
7768
|
+
if (options?.intent != null && options.intent !== "conversation") throw new Error(`Google realtime does not support the '${options.intent}' session intent.`);
|
|
7769
|
+
}
|
|
7620
7770
|
parseServerEvent(raw) {
|
|
7621
7771
|
return this.mapper.parseServerEvent(raw);
|
|
7622
7772
|
}
|
|
7623
|
-
|
|
7773
|
+
createServerEventParser() {
|
|
7774
|
+
const mapper = new GoogleRealtimeEventMapper();
|
|
7775
|
+
return (raw) => mapper.parseServerEvent(raw);
|
|
7776
|
+
}
|
|
7777
|
+
serializeClientEvent(event, options) {
|
|
7778
|
+
this.assertConversationIntent(options);
|
|
7624
7779
|
return this.mapper.serializeClientEvent(event, this.modelId);
|
|
7625
7780
|
}
|
|
7626
|
-
buildSessionConfig(config) {
|
|
7781
|
+
buildSessionConfig(config, options) {
|
|
7782
|
+
this.assertConversationIntent(options);
|
|
7627
7783
|
return buildGoogleSessionConfig(config, this.modelId);
|
|
7628
7784
|
}
|
|
7629
7785
|
};
|