@ai-sdk/google 4.0.25 → 4.0.27
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 +16 -0
- package/dist/index.d.ts +50 -3
- package/dist/index.js +516 -30
- package/dist/index.js.map +1 -1
- package/dist/internal/index.js +34 -14
- package/dist/internal/index.js.map +1 -1
- package/docs/15-google.mdx +51 -0
- package/package.json +2 -2
- package/src/get-realtime-base-url.ts +31 -0
- package/src/google-files.ts +0 -1
- package/src/google-provider.ts +32 -0
- package/src/index.ts +6 -0
- package/src/interactions/google-interactions-language-model.ts +21 -0
- package/src/interactions/google-interactions-prompt.ts +1 -0
- package/src/realtime/google-realtime-model.ts +5 -17
- package/src/translation/google-translation-model-options.ts +26 -0
- package/src/translation/google-translation-model.ts +612 -0
package/docs/15-google.mdx
CHANGED
|
@@ -1133,6 +1133,57 @@ Gemini Live Translation accepts audio input and produces translated audio
|
|
|
1133
1133
|
output. Text input, tools, and custom instructions are not supported by this
|
|
1134
1134
|
model.
|
|
1135
1135
|
|
|
1136
|
+
## Translation Models
|
|
1137
|
+
|
|
1138
|
+
<Note type="warning">Speech translation is an experimental feature.</Note>
|
|
1139
|
+
|
|
1140
|
+
For server-side streaming translation, you can create models that call the
|
|
1141
|
+
[Gemini Live API](https://ai.google.dev/gemini-api/docs/live) using the
|
|
1142
|
+
`.translation()` factory method. Translation models are streaming-only and are
|
|
1143
|
+
used with
|
|
1144
|
+
[`experimental_streamTranslate`](/docs/reference/ai-sdk-core/stream-translate).
|
|
1145
|
+
|
|
1146
|
+
The first argument is the model id e.g. `gemini-3.5-live-translate-preview`.
|
|
1147
|
+
|
|
1148
|
+
```ts
|
|
1149
|
+
const model = google.translation('gemini-3.5-live-translate-preview');
|
|
1150
|
+
```
|
|
1151
|
+
|
|
1152
|
+
```ts
|
|
1153
|
+
import { experimental_streamTranslate as streamTranslate } from 'ai';
|
|
1154
|
+
import { google } from '@ai-sdk/google';
|
|
1155
|
+
|
|
1156
|
+
const result = streamTranslate({
|
|
1157
|
+
model: google.translation('gemini-3.5-live-translate-preview'),
|
|
1158
|
+
audio: audioStream, // ReadableStream<Uint8Array | string>
|
|
1159
|
+
inputAudioFormat: { type: 'audio/pcm', rate: 16000 },
|
|
1160
|
+
targetLanguage: 'es',
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
for await (const part of result.fullStream) {
|
|
1164
|
+
if (part.type === 'output-text-delta') {
|
|
1165
|
+
process.stdout.write(part.delta);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
The Gemini Live API auto-detects the source language (`sourceLanguage` is not
|
|
1171
|
+
supported) and always outputs 24kHz 16-bit PCM audio (`outputAudioFormat` is
|
|
1172
|
+
not supported). Unsupported settings surface as call warnings.
|
|
1173
|
+
|
|
1174
|
+
The following provider options are available:
|
|
1175
|
+
|
|
1176
|
+
- **echoTargetLanguage** _boolean_
|
|
1177
|
+
Whether input audio already in the target language should be echoed instead
|
|
1178
|
+
of producing silence.
|
|
1179
|
+
Optional.
|
|
1180
|
+
|
|
1181
|
+
### Model Capabilities
|
|
1182
|
+
|
|
1183
|
+
| Model | Translated Audio | Translated Text | Source Transcript |
|
|
1184
|
+
| ----------------------------------- | ---------------- | --------------- | ----------------- |
|
|
1185
|
+
| `gemini-3.5-live-translate-preview` | <Check /> | <Check /> | <Check /> |
|
|
1186
|
+
|
|
1136
1187
|
## Interactions API
|
|
1137
1188
|
|
|
1138
1189
|
The [Gemini Interactions API](https://ai.google.dev/gemini-api/docs/interactions)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/google",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.27",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@ai-sdk/provider": "4.0.4",
|
|
39
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
39
|
+
"@ai-sdk/provider-utils": "5.0.14"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "22.19.19",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the base URL for Live API (WebSocket) endpoints, stripping a
|
|
3
|
+
* trailing `/v1beta` or `/v1alpha` API version segment: Live API paths carry
|
|
4
|
+
* their own version and are not nested under it.
|
|
5
|
+
*/
|
|
6
|
+
export function getRealtimeBaseURL(baseURL: string): URL {
|
|
7
|
+
const url = new URL(baseURL);
|
|
8
|
+
const pathSegments = url.pathname.split('/');
|
|
9
|
+
const version = pathSegments.at(-1);
|
|
10
|
+
|
|
11
|
+
if (version === 'v1beta' || version === 'v1alpha') {
|
|
12
|
+
pathSegments.pop();
|
|
13
|
+
url.pathname = pathSegments.join('/') || '/';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return url;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Builds a `wss://` Live API WebSocket URL for the given bidi service path
|
|
21
|
+
* (e.g. `google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent`).
|
|
22
|
+
*/
|
|
23
|
+
export function getRealtimeWebSocketURL(
|
|
24
|
+
baseURL: string,
|
|
25
|
+
webSocketPath: string,
|
|
26
|
+
): URL {
|
|
27
|
+
const url = getRealtimeBaseURL(baseURL);
|
|
28
|
+
url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
29
|
+
url.pathname = `${url.pathname.replace(/\/$/, '')}/ws/${webSocketPath}`;
|
|
30
|
+
return url;
|
|
31
|
+
}
|
package/src/google-files.ts
CHANGED
|
@@ -103,7 +103,6 @@ export class GoogleFiles implements FilesV4 {
|
|
|
103
103
|
const uploadResponse = await fetchFn(uploadUrl, {
|
|
104
104
|
method: 'POST',
|
|
105
105
|
headers: {
|
|
106
|
-
'Content-Length': String(fileBytes.length),
|
|
107
106
|
'X-Goog-Upload-Offset': '0',
|
|
108
107
|
'X-Goog-Upload-Command': 'upload, finalize',
|
|
109
108
|
},
|
package/src/google-provider.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
Experimental_RealtimeFactoryV4 as RealtimeFactoryV4,
|
|
9
9
|
Experimental_RealtimeFactoryV4GetTokenOptions as RealtimeFactoryV4GetTokenOptions,
|
|
10
10
|
SpeechModelV4,
|
|
11
|
+
Experimental_SpeechTranslationModelV4 as SpeechTranslationModelV4,
|
|
11
12
|
} from '@ai-sdk/provider';
|
|
12
13
|
import {
|
|
13
14
|
generateId,
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
withoutTrailingSlash,
|
|
16
17
|
withUserAgentSuffix,
|
|
17
18
|
type FetchFunction,
|
|
19
|
+
type WebSocketConstructor,
|
|
18
20
|
} from '@ai-sdk/provider-utils';
|
|
19
21
|
import { VERSION } from './version';
|
|
20
22
|
import { GoogleEmbeddingModel } from './google-embedding-model';
|
|
@@ -40,6 +42,8 @@ import {
|
|
|
40
42
|
import type { GoogleInteractionsModelId } from './interactions/google-interactions-language-model-options';
|
|
41
43
|
import type { GoogleInteractionsAgentName } from './interactions/google-interactions-agent';
|
|
42
44
|
import { GoogleRealtimeModel } from './realtime/google-realtime-model';
|
|
45
|
+
import { GoogleTranslationModel } from './translation/google-translation-model';
|
|
46
|
+
import type { GoogleTranslationModelId } from './translation/google-translation-model-options';
|
|
43
47
|
|
|
44
48
|
export interface GoogleProvider extends ProviderV4 {
|
|
45
49
|
(modelId: GoogleModelId): LanguageModelV4;
|
|
@@ -91,6 +95,18 @@ export interface GoogleProvider extends ProviderV4 {
|
|
|
91
95
|
*/
|
|
92
96
|
videoModel(modelId: GoogleVideoModelId): Experimental_VideoModelV4;
|
|
93
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Creates an experimental model for streaming speech translation.
|
|
100
|
+
*/
|
|
101
|
+
translation(modelId: GoogleTranslationModelId): SpeechTranslationModelV4;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates an experimental model for streaming speech translation.
|
|
105
|
+
*/
|
|
106
|
+
speechTranslationModel(
|
|
107
|
+
modelId: GoogleTranslationModelId,
|
|
108
|
+
): SpeechTranslationModelV4;
|
|
109
|
+
|
|
94
110
|
/**
|
|
95
111
|
* Creates a model for speech generation (text-to-speech).
|
|
96
112
|
*/
|
|
@@ -152,6 +168,12 @@ export interface GoogleProviderSettings {
|
|
|
152
168
|
*/
|
|
153
169
|
generateId?: () => string;
|
|
154
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Custom WebSocket implementation. This is useful for testing or for
|
|
173
|
+
* runtimes that need a WebSocket constructor with header support.
|
|
174
|
+
*/
|
|
175
|
+
webSocket?: WebSocketConstructor;
|
|
176
|
+
|
|
155
177
|
/**
|
|
156
178
|
* Custom provider name
|
|
157
179
|
* Defaults to 'google.generative-ai'.
|
|
@@ -288,6 +310,14 @@ export function createGoogle(
|
|
|
288
310
|
fetch: options.fetch,
|
|
289
311
|
});
|
|
290
312
|
|
|
313
|
+
const createTranslationModel = (modelId: GoogleTranslationModelId) =>
|
|
314
|
+
new GoogleTranslationModel(modelId, {
|
|
315
|
+
provider: `${providerName}.translation`,
|
|
316
|
+
baseURL,
|
|
317
|
+
headers: getHeaders,
|
|
318
|
+
webSocket: options.webSocket,
|
|
319
|
+
});
|
|
320
|
+
|
|
291
321
|
const createSpeechModel = (modelId: GoogleSpeechModelId) =>
|
|
292
322
|
new GoogleSpeechModel(modelId, {
|
|
293
323
|
provider: `${providerName}.speech`,
|
|
@@ -358,6 +388,8 @@ export function createGoogle(
|
|
|
358
388
|
provider.files = createFiles;
|
|
359
389
|
provider.speech = createSpeechModel;
|
|
360
390
|
provider.speechModel = createSpeechModel;
|
|
391
|
+
provider.translation = createTranslationModel;
|
|
392
|
+
provider.speechTranslationModel = createTranslationModel;
|
|
361
393
|
provider.interactions = createInteractionsModel;
|
|
362
394
|
provider.tools = googleTools;
|
|
363
395
|
|
package/src/index.ts
CHANGED
|
@@ -60,5 +60,11 @@ export type {
|
|
|
60
60
|
GoogleRealtimeModelId as Experimental_GoogleRealtimeModelId,
|
|
61
61
|
GoogleRealtimeModelOptions as Experimental_GoogleRealtimeModelOptions,
|
|
62
62
|
} from './realtime/google-realtime-model-options';
|
|
63
|
+
export { GoogleTranslationModel as Experimental_GoogleTranslationModel } from './translation/google-translation-model';
|
|
64
|
+
export type { GoogleTranslationModelConfig as Experimental_GoogleTranslationModelConfig } from './translation/google-translation-model';
|
|
65
|
+
export type {
|
|
66
|
+
GoogleTranslationModelId as Experimental_GoogleTranslationModelId,
|
|
67
|
+
GoogleTranslationModelOptions as Experimental_GoogleTranslationModelOptions,
|
|
68
|
+
} from './translation/google-translation-model-options';
|
|
63
69
|
|
|
64
70
|
export { VERSION } from './version';
|
|
@@ -153,6 +153,21 @@ export class GoogleInteractionsLanguageModel implements LanguageModelV4 {
|
|
|
153
153
|
|
|
154
154
|
const isAgent = this.agent != null;
|
|
155
155
|
|
|
156
|
+
if (!isAgent) {
|
|
157
|
+
if (options.frequencyPenalty != null) {
|
|
158
|
+
warnings.push({
|
|
159
|
+
type: 'unsupported',
|
|
160
|
+
feature: 'frequencyPenalty',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if (options.presencePenalty != null) {
|
|
164
|
+
warnings.push({
|
|
165
|
+
type: 'unsupported',
|
|
166
|
+
feature: 'presencePenalty',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
156
171
|
const hasTools = options.tools != null && options.tools.length > 0;
|
|
157
172
|
|
|
158
173
|
let toolsForBody: Array<GoogleInteractionsTool> | undefined;
|
|
@@ -276,6 +291,11 @@ export class GoogleInteractionsLanguageModel implements LanguageModelV4 {
|
|
|
276
291
|
const droppedFields: Array<string> = [];
|
|
277
292
|
if (options.temperature != null) droppedFields.push('temperature');
|
|
278
293
|
if (options.topP != null) droppedFields.push('topP');
|
|
294
|
+
if (options.topK != null) droppedFields.push('topK');
|
|
295
|
+
if (options.frequencyPenalty != null)
|
|
296
|
+
droppedFields.push('frequencyPenalty');
|
|
297
|
+
if (options.presencePenalty != null)
|
|
298
|
+
droppedFields.push('presencePenalty');
|
|
279
299
|
if (options.seed != null) droppedFields.push('seed');
|
|
280
300
|
if (options.stopSequences != null && options.stopSequences.length > 0) {
|
|
281
301
|
droppedFields.push('stopSequences');
|
|
@@ -299,6 +319,7 @@ export class GoogleInteractionsLanguageModel implements LanguageModelV4 {
|
|
|
299
319
|
generationConfig = pruneUndefined({
|
|
300
320
|
temperature: options.temperature ?? undefined,
|
|
301
321
|
top_p: options.topP ?? undefined,
|
|
322
|
+
top_k: options.topK ?? undefined,
|
|
302
323
|
seed: options.seed ?? undefined,
|
|
303
324
|
stop_sequences:
|
|
304
325
|
options.stopSequences != null && options.stopSequences.length > 0
|
|
@@ -461,6 +461,7 @@ export type GoogleInteractionsResponseFormatEntry =
|
|
|
461
461
|
export type GoogleInteractionsGenerationConfig = {
|
|
462
462
|
temperature?: number;
|
|
463
463
|
top_p?: number;
|
|
464
|
+
top_k?: number;
|
|
464
465
|
seed?: number;
|
|
465
466
|
stop_sequences?: Array<string>;
|
|
466
467
|
max_output_tokens?: number;
|
|
@@ -7,6 +7,10 @@ import type {
|
|
|
7
7
|
Experimental_RealtimeModelV4SessionConfig as RealtimeModelV4SessionConfig,
|
|
8
8
|
} from '@ai-sdk/provider';
|
|
9
9
|
import type { FetchFunction } from '@ai-sdk/provider-utils';
|
|
10
|
+
import {
|
|
11
|
+
getRealtimeBaseURL,
|
|
12
|
+
getRealtimeWebSocketURL,
|
|
13
|
+
} from '../get-realtime-base-url';
|
|
10
14
|
import {
|
|
11
15
|
GoogleRealtimeEventMapper,
|
|
12
16
|
buildGoogleSessionConfig,
|
|
@@ -15,19 +19,6 @@ import {
|
|
|
15
19
|
const realtimeWebSocketPath =
|
|
16
20
|
'google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContentConstrained';
|
|
17
21
|
|
|
18
|
-
function getRealtimeBaseURL(baseURL: string): URL {
|
|
19
|
-
const url = new URL(baseURL);
|
|
20
|
-
const pathSegments = url.pathname.split('/');
|
|
21
|
-
const version = pathSegments.at(-1);
|
|
22
|
-
|
|
23
|
-
if (version === 'v1beta' || version === 'v1alpha') {
|
|
24
|
-
pathSegments.pop();
|
|
25
|
-
url.pathname = pathSegments.join('/') || '/';
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return url;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
22
|
function getAuthTokensURL(baseURL: string): string {
|
|
32
23
|
const url = getRealtimeBaseURL(baseURL);
|
|
33
24
|
url.pathname = `${url.pathname.replace(/\/$/, '')}/v1alpha/auth_tokens`;
|
|
@@ -35,10 +26,7 @@ function getAuthTokensURL(baseURL: string): string {
|
|
|
35
26
|
}
|
|
36
27
|
|
|
37
28
|
function getWebSocketURL(baseURL: string): string {
|
|
38
|
-
|
|
39
|
-
url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
40
|
-
url.pathname = `${url.pathname.replace(/\/$/, '')}/ws/${realtimeWebSocketPath}`;
|
|
41
|
-
return url.toString();
|
|
29
|
+
return getRealtimeWebSocketURL(baseURL, realtimeWebSocketPath).toString();
|
|
42
30
|
}
|
|
43
31
|
|
|
44
32
|
export type GoogleRealtimeModelConfig = {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lazySchema,
|
|
3
|
+
zodSchema,
|
|
4
|
+
type InferSchema,
|
|
5
|
+
} from '@ai-sdk/provider-utils';
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
|
+
|
|
8
|
+
export type GoogleTranslationModelId =
|
|
9
|
+
| 'gemini-3.5-live-translate-preview'
|
|
10
|
+
| (string & {});
|
|
11
|
+
|
|
12
|
+
export const googleTranslationModelOptions = lazySchema(() =>
|
|
13
|
+
zodSchema(
|
|
14
|
+
z.object({
|
|
15
|
+
/**
|
|
16
|
+
* Whether input audio already in the target language should be echoed
|
|
17
|
+
* instead of producing silence.
|
|
18
|
+
*/
|
|
19
|
+
echoTargetLanguage: z.boolean().optional(),
|
|
20
|
+
}),
|
|
21
|
+
),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export type GoogleTranslationModelOptions = InferSchema<
|
|
25
|
+
typeof googleTranslationModelOptions
|
|
26
|
+
>;
|