@ai-sdk/google 4.0.25 → 4.0.26

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.
@@ -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.25",
3
+ "version": "4.0.26",
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.13"
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
+ }
@@ -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';
@@ -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
- const url = getRealtimeBaseURL(baseURL);
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
+ >;