@ai-sdk/gateway 4.0.121 → 4.0.123

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.
@@ -464,6 +464,69 @@ console.log(ranking);
464
464
 
465
465
  Reranking models are useful for improving search results in retrieval-augmented generation (RAG) pipelines by re-scoring candidate documents after an initial retrieval step.
466
466
 
467
+ ## Streaming Speech Models
468
+
469
+ <Note type="warning">
470
+ Streaming speech is experimental and the API may change in patch releases.
471
+ </Note>
472
+
473
+ Speech models that support streaming can be used with
474
+ `experimental_streamSpeech`. The gateway provider connects to AI Gateway over a
475
+ WebSocket, forwards text deltas as they arrive, and streams audio chunks back.
476
+ Gateway WebSocket auth is carried in the subprotocols, so no header-capable
477
+ WebSocket implementation is needed.
478
+
479
+ Streaming speech works only with models that the
480
+ [AI Gateway model catalog](https://vercel.com/ai-gateway/models) lists with
481
+ streaming speech support. The model ID below is illustrative; check the catalog
482
+ for current availability.
483
+
484
+ ```ts
485
+ import { experimental_streamSpeech as streamSpeech } from 'ai';
486
+
487
+ const result = streamSpeech({
488
+ model: 'elevenlabs/eleven-flash-v2.5',
489
+ text: textStream, // a string, or an array or stream of strings and/or text parts
490
+ outputFormat: { type: 'audio/pcm', rate: 24000 },
491
+ });
492
+
493
+ for await (const chunk of result.audioStream) {
494
+ // Uint8Array audio bytes
495
+ }
496
+
497
+ console.log(await result.usage); // { inputCharacters: ... }
498
+ ```
499
+
500
+ ### Streaming Speech in the Browser
501
+
502
+ To stream speech from browser code without exposing your Gateway credential,
503
+ mint a short-lived client secret on your server with
504
+ `gateway.experimental_speech.getToken()` and pass the token to the browser.
505
+ The token is bound to the streaming speech surface and the requested model.
506
+
507
+ ```ts
508
+ // Server
509
+ import { gateway } from '@ai-sdk/gateway';
510
+
511
+ const { token } = await gateway.experimental_speech.getToken({
512
+ model: 'elevenlabs/eleven-flash-v2.5',
513
+ expiresAfterSeconds: 60,
514
+ });
515
+ ```
516
+
517
+ ```ts
518
+ // Browser
519
+ import { createGateway } from '@ai-sdk/gateway';
520
+ import { experimental_streamSpeech as streamSpeech } from 'ai';
521
+
522
+ const gateway = createGateway({ apiKey: token });
523
+
524
+ const result = streamSpeech({
525
+ model: gateway.experimental_speech('elevenlabs/eleven-flash-v2.5'),
526
+ text: textStream,
527
+ });
528
+ ```
529
+
467
530
  ## Realtime Models
468
531
 
469
532
  <Note type="warning">
@@ -1232,7 +1295,7 @@ for await (const part of result.stream) {
1232
1295
 
1233
1296
  #### Parallel Search
1234
1297
 
1235
- The Parallel Search tool enables models to search the web using [Parallel AI's Search API](https://docs.parallel.ai/api-reference/search-beta/search). This tool is optimized for LLM consumption, returning relevant excerpts from web pages that can replace multiple keyword searches with a single call.
1298
+ The Parallel Search tool enables models to search the web using [Parallel AI's Search API](https://docs.parallel.ai/api-reference/search/search). The model provides a research objective and a few keyword queries, and the tool returns relevant excerpts from web pages, optimized for LLM consumption.
1236
1299
 
1237
1300
  ```ts
1238
1301
  import { gateway, generateText } from 'ai';
@@ -1260,7 +1323,8 @@ const result = await generateText({
1260
1323
  prompt: 'Find detailed information about TypeScript 5.0 features.',
1261
1324
  tools: {
1262
1325
  parallel_search: gateway.tools.parallelSearch({
1263
- mode: 'agentic',
1326
+ mode: 'advanced',
1327
+ location: 'us',
1264
1328
  maxResults: 5,
1265
1329
  sourcePolicy: {
1266
1330
  includeDomains: ['typescriptlang.org', 'github.com'],
@@ -1279,11 +1343,15 @@ console.log('Tool results:', JSON.stringify(result.toolResults, null, 2));
1279
1343
 
1280
1344
  The Parallel Search tool supports the following optional configuration options:
1281
1345
 
1282
- - **mode** _'one-shot' | 'agentic'_
1346
+ - **mode** _'turbo' | 'fast' | 'basic' | 'advanced'_
1347
+
1348
+ Search mode. Defaults to `'basic'`. See the [AI Gateway web search docs](https://vercel.com/docs/ai-gateway/models-and-providers/web-search#using-parallel-search) for pricing.
1349
+ - `'turbo'` - Lowest latency, shorter excerpts. Supports English and Japanese only.
1350
+ - `'fast'` - Low latency, shorter excerpts.
1351
+ - `'basic'` - Balanced latency and excerpt depth (default).
1352
+ - `'advanced'` - Most thorough retrieval, higher latency.
1283
1353
 
1284
- Mode preset for different use cases:
1285
- - `'one-shot'` - Comprehensive results with longer excerpts for single-response answers (default)
1286
- - `'agentic'` - Concise, token-efficient results optimized for multi-step agentic workflows
1354
+ `'one-shot'` and `'agentic'` are deprecated but still accepted: `'one-shot'` runs as `'basic'` and `'agentic'` runs as `'advanced'`.
1287
1355
 
1288
1356
  - **maxResults** _number_
1289
1357
 
@@ -1292,20 +1360,34 @@ The Parallel Search tool supports the following optional configuration options:
1292
1360
  - **sourcePolicy** _object_
1293
1361
 
1294
1362
  Source policy for controlling which domains to include/exclude:
1295
- - `includeDomains` - List of domains to include in search results
1296
- - `excludeDomains` - List of domains to exclude from search results
1297
- - `afterDate` - Only include results published after this date (ISO 8601 format)
1363
+ - `includeDomains` - Domains or domain/path prefixes to include, such as `'wikipedia.org'` or `'docs.python.org/3'`. When set, `excludeDomains` is ignored.
1364
+ - `excludeDomains` - Domains or domain/path prefixes to exclude
1365
+ - `afterDate` - Only include results published on or after this date (`YYYY-MM-DD`)
1366
+
1367
+ The include and exclude lists can hold up to 200 entries combined.
1368
+
1369
+ - **maxCharsTotal** _number_
1370
+
1371
+ Maximum total characters across all result excerpts.
1298
1372
 
1299
1373
  - **excerpts** _object_
1300
1374
 
1301
1375
  Excerpt configuration for controlling result length:
1302
1376
  - `maxCharsPerResult` - Maximum characters per result
1303
- - `maxCharsTotal` - Maximum total characters across all results
1377
+ - `maxCharsTotal` - Deprecated; use the top-level `maxCharsTotal`
1304
1378
 
1305
1379
  - **fetchPolicy** _object_
1306
1380
 
1307
1381
  Fetch policy for controlling content freshness:
1308
- - `maxAgeSeconds` - Maximum age in seconds for cached content (set to 0 for always fresh)
1382
+ - `maxAgeSeconds` - Maximum age of cached content, in seconds, before a live fetch is attempted. Minimum 600; lower values are raised to 600.
1383
+ - `timeoutSeconds` - Timeout for a live fetch, in seconds. The gateway caps it to stay within its own tool timeout.
1384
+ - `disableCacheFallback` - Return an error instead of older cached content when a live fetch fails. Defaults to `false`.
1385
+
1386
+ - **location** _string_
1387
+
1388
+ ISO 3166-1 alpha-2 country code to localize results, such as `'us'`. Invalid codes are ignored with a warning.
1389
+
1390
+ Each tool result contains a `search_id` and `results`, ordered by decreasing relevance, and may include a `session_id`. Each result has a `url`, a `title`, a `publish_date` (both may be `null`), and `excerpts` (an array of markdown strings). The result can also include `warnings`, for example when an invalid `location` is ignored.
1309
1391
 
1310
1392
  The tool works with both `generateText` and `streamText`:
1311
1393
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ai-sdk/gateway",
3
3
  "private": false,
4
- "version": "4.0.121",
4
+ "version": "4.0.123",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "sideEffects": false,
@@ -30,8 +30,8 @@
30
30
  }
31
31
  },
32
32
  "dependencies": {
33
- "@ai-sdk/provider": "4.0.31",
34
- "@ai-sdk/provider-utils": "5.0.65",
33
+ "@ai-sdk/provider": "4.0.33",
34
+ "@ai-sdk/provider-utils": "5.0.67",
35
35
  "@vercel/oidc": "3.2.0"
36
36
  },
37
37
  "devDependencies": {
@@ -1,4 +1,6 @@
1
1
  export type GatewayDecisionModelId =
2
+ | 'baseten/elephant-1'
3
+ | 'baseten/mammoth-1'
2
4
  | 'convaiinnovations/laya'
3
5
  | 'convaiinnovations/laya-free'
4
6
  | 'liquid/d1'
@@ -271,6 +271,8 @@ export type GatewayModelId =
271
271
  | 'sakana/fugu-ultra'
272
272
  | 'sakana/fugu-ultra-v2'
273
273
  | 'sakana/namazu'
274
+ | 'scaledown/scaledown-extract-1'
275
+ | 'scaledown/scaledown-summarize-1'
274
276
  | 'spacexai/grok-4.1-fast-non-reasoning'
275
277
  | 'spacexai/grok-4.1-fast-reasoning'
276
278
  | 'spacexai/grok-4.20-multi-agent'
@@ -40,7 +40,7 @@ import { GatewayImageModel } from './gateway-image-model';
40
40
  import { GatewayVideoModel } from './gateway-video-model';
41
41
  import { GatewayDecisionModel } from './gateway-decision-model';
42
42
  import { GatewayRerankingModel } from './gateway-reranking-model';
43
- import { GatewaySpeechModel } from './gateway-speech-model';
43
+ import { GatewaySpeechModel, toGatewaySpeechUrl } from './gateway-speech-model';
44
44
  import {
45
45
  GatewayTranscriptionModel,
46
46
  toGatewayTranscriptionUrl,
@@ -66,6 +66,7 @@ import type {
66
66
  TranscriptionModelV4,
67
67
  Experimental_VideoModelV4,
68
68
  Experimental_DecisionModelV4,
69
+ Experimental_StreamingSpeechModelV4,
69
70
  Experimental_RealtimeFactoryV4 as RealtimeFactoryV4,
70
71
  Experimental_RealtimeFactoryV4GetTokenOptions as RealtimeFactoryV4GetTokenOptions,
71
72
  ProviderV4,
@@ -216,6 +217,14 @@ export interface GatewayProvider extends ProviderV4 {
216
217
  */
217
218
  experimental_transcription: GatewayTranscriptionFactory;
218
219
 
220
+ /**
221
+ * Experimental streaming-speech entry point. Callable like
222
+ * `speech(modelId)`, plus `getToken` for minting a short-lived client
223
+ * secret (`vcst_`) a browser can use to open the streaming speech
224
+ * WebSocket without holding the Gateway credential.
225
+ */
226
+ experimental_speech: GatewaySpeechFactory;
227
+
219
228
  /**
220
229
  * Gateway-specific tools executed server-side.
221
230
  */
@@ -252,6 +261,36 @@ export interface GatewayTranscriptionFactory {
252
261
  ): Promise<GatewayTranscriptionFactoryGetTokenResult>;
253
262
  }
254
263
 
264
+ export type GatewaySpeechFactoryGetTokenOptions = {
265
+ model: GatewaySpeechModelId;
266
+ /** Token lifetime in seconds. Gateway default is 60s (max 300s). */
267
+ expiresAfterSeconds?: number;
268
+ };
269
+
270
+ export type GatewaySpeechFactoryGetTokenResult = {
271
+ /** The minted `vcst_` client secret. */
272
+ token: string;
273
+ /** WebSocket URL of the streaming speech surface for this model. */
274
+ url: string;
275
+ /** Token expiry, epoch seconds. */
276
+ expiresAt?: number;
277
+ };
278
+
279
+ /**
280
+ * Streaming-speech factory: callable like `speech(modelId)`, plus a
281
+ * server-side `getToken` that mints a speech-bound short-lived client secret
282
+ * (`vcst_`). The browser connects with
283
+ * `createGateway({ apiKey: token }).speech(modelId)`; the token rides the
284
+ * same auth subprotocol an API key does, without exposing the credential.
285
+ */
286
+ export interface GatewaySpeechFactory {
287
+ (modelId: GatewaySpeechModelId): Experimental_StreamingSpeechModelV4;
288
+
289
+ getToken(
290
+ options: GatewaySpeechFactoryGetTokenOptions,
291
+ ): Promise<GatewaySpeechFactoryGetTokenResult>;
292
+ }
293
+
255
294
  export interface GatewayProviderSettings {
256
295
  /** Settings for downloading JSON Lines batch results. */
257
296
  batchResultDownloads?: {
@@ -288,10 +327,10 @@ export interface GatewayProviderSettings {
288
327
  fetch?: FetchFunction;
289
328
 
290
329
  /**
291
- * Custom WebSocket implementation used for streaming transcription. This is
292
- * useful for testing or for runtimes without a global WebSocket. A
293
- * header-capable implementation is not required — Gateway WebSocket auth is
294
- * carried in the subprotocols.
330
+ * Custom WebSocket implementation used for streaming transcription and
331
+ * streaming speech. This is useful for testing or for runtimes without a
332
+ * global WebSocket. A header-capable implementation is not required —
333
+ * Gateway WebSocket auth is carried in the subprotocols.
295
334
  */
296
335
  webSocket?: WebSocketConstructor;
297
336
 
@@ -391,7 +430,7 @@ export function createGateway(
391
430
  const mintClientSecret = async (params: {
392
431
  modelId: string;
393
432
  expiresAfterSeconds?: number;
394
- routeKind?: 'transcription';
433
+ routeKind?: 'speech' | 'transcription';
395
434
  }): Promise<{ token: string; expiresAt?: number }> => {
396
435
  assertGatewayClientSecretServerEnvironment();
397
436
  const auth = await getRealtimeAuthToken();
@@ -624,10 +663,35 @@ export function createGateway(
624
663
  headers: getHeaders,
625
664
  fetch: options.fetch,
626
665
  o11yHeaders: createO11yHeaders(),
666
+ webSocket: options.webSocket,
627
667
  });
628
668
  };
629
669
  provider.speechModel = createSpeechModel;
630
670
  provider.speech = createSpeechModel;
671
+ // Callable like `speech(modelId)`; `getToken` mints a speech-bound client
672
+ // secret (server-side only) the browser uses to connect via
673
+ // `createGateway({ apiKey: token }).speech(modelId)`.
674
+ provider.experimental_speech = Object.assign(
675
+ (modelId: GatewaySpeechModelId) => createSpeechModel(modelId),
676
+ {
677
+ getToken: async (
678
+ tokenOptions: GatewaySpeechFactoryGetTokenOptions,
679
+ ): Promise<GatewaySpeechFactoryGetTokenResult> => {
680
+ const secret = await mintClientSecret({
681
+ modelId: tokenOptions.model,
682
+ routeKind: 'speech',
683
+ ...(tokenOptions.expiresAfterSeconds != null && {
684
+ expiresAfterSeconds: tokenOptions.expiresAfterSeconds,
685
+ }),
686
+ });
687
+ return {
688
+ token: secret.token,
689
+ url: toGatewaySpeechUrl(baseURL, tokenOptions.model),
690
+ ...(secret.expiresAt != null && { expiresAt: secret.expiresAt }),
691
+ };
692
+ },
693
+ },
694
+ ) as GatewaySpeechFactory;
631
695
  const createTranscriptionModel = (modelId: GatewayTranscriptionModelId) => {
632
696
  return new GatewayTranscriptionModel(modelId, {
633
697
  provider: 'gateway',
@@ -728,7 +792,7 @@ export async function getGatewayAuthToken(
728
792
  function assertGatewayClientSecretServerEnvironment(): void {
729
793
  if (typeof globalThis.window !== 'undefined') {
730
794
  throw new Error(
731
- 'AI Gateway client secrets must be minted server-side: minting needs your Gateway credential, which must never reach the browser. Call gateway.experimental_realtime.getToken() or gateway.experimental_transcription.getToken() from your server and pass the returned token to the client.',
795
+ 'AI Gateway client secrets must be minted server-side: minting needs your Gateway credential, which must never reach the browser. Call gateway.experimental_realtime.getToken(), gateway.experimental_transcription.getToken(), or gateway.experimental_speech.getToken() from your server and pass the returned token to the client.',
732
796
  );
733
797
  }
734
798
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Shared WebSocket subprotocol contract for AI Gateway realtime and streaming
3
- * transcription auth.
2
+ * Shared WebSocket subprotocol contract for AI Gateway realtime, streaming
3
+ * transcription, and streaming speech auth.
4
4
  *
5
5
  * The browser `WebSocket` API cannot set request headers, so the Gateway auth
6
6
  * (bearer) token is carried through the `Sec-WebSocket-Protocol` handshake
@@ -9,7 +9,8 @@
9
9
  *
10
10
  * This module is the single source of truth for that contract so the client and
11
11
  * the Gateway server can't drift: the client encodes values with
12
- * `getGatewayRealtimeProtocols` / `getGatewayTranscriptionProtocols`, and the
12
+ * `getGatewayRealtimeProtocols` / `getGatewayTranscriptionProtocols` /
13
+ * `getGatewaySpeechProtocols`, and the
13
14
  * Gateway server decodes them with `getGatewayRealtimeAuthToken` /
14
15
  * `getGatewayRealtimeTeamIdOrSlug`.
15
16
  *
@@ -33,6 +34,12 @@ export const GATEWAY_REALTIME_SUBPROTOCOL = 'ai-gateway-realtime.v1';
33
34
  */
34
35
  export const GATEWAY_TRANSCRIPTION_SUBPROTOCOL = 'ai-gateway-transcription.v1';
35
36
 
37
+ /**
38
+ * Marker subprotocol for streaming speech handshakes (same negotiation
39
+ * purpose as `GATEWAY_REALTIME_SUBPROTOCOL`).
40
+ */
41
+ export const GATEWAY_SPEECH_SUBPROTOCOL = 'ai-gateway-speech.v1';
42
+
36
43
  /** Subprotocol prefix that carries the Gateway auth (bearer) token. */
37
44
  export const GATEWAY_AUTH_SUBPROTOCOL_PREFIX = 'ai-gateway-auth.';
38
45
 
@@ -65,6 +72,17 @@ export function getGatewayTranscriptionProtocols(
65
72
  );
66
73
  }
67
74
 
75
+ /**
76
+ * Client-side: `getGatewayRealtimeProtocols`, but with the streaming speech
77
+ * marker subprotocol.
78
+ */
79
+ export function getGatewaySpeechProtocols(
80
+ token: string,
81
+ options?: { teamIdOrSlug?: string },
82
+ ): string[] {
83
+ return buildGatewayProtocols(GATEWAY_SPEECH_SUBPROTOCOL, token, options);
84
+ }
85
+
68
86
  function buildGatewayProtocols(
69
87
  marker: string,
70
88
  token: string,
@@ -6,6 +6,6 @@ export type GatewayRealtimeModelId =
6
6
  | 'openai/gpt-realtime-2'
7
7
  | 'openai/gpt-realtime-2.1'
8
8
  | 'openai/gpt-realtime-mini'
9
- | 'spacexai/grok-voice-think-fast-1.0'
9
+ | 'spacexai/grok-voice-3.0'
10
10
  | 'spacexai/grok-voice-think-fast-2.0'
11
11
  | (string & {});
@@ -2,6 +2,8 @@ export type GatewayRerankingModelId =
2
2
  | 'cohere/rerank-v3.5'
3
3
  | 'cohere/rerank-v4-fast'
4
4
  | 'cohere/rerank-v4-pro'
5
+ | 'cohere/rerank-v5-fast'
6
+ | 'cohere/rerank-v5-pro'
5
7
  | 'voyage/rerank-2.5'
6
8
  | 'voyage/rerank-2.5-lite'
7
9
  | 'voyage/rerank-3'
@@ -9,6 +9,7 @@ export type GatewaySpeechModelId =
9
9
  | 'microsoft/mai-voice-2-flash'
10
10
  | 'microsoft/mai-voice-2.1'
11
11
  | 'microsoft/mai-voice-2.1-flash'
12
+ | 'mistral/voxtral-mini-tts-3'
12
13
  | 'openai/tts-1'
13
14
  | 'openai/tts-1-hd'
14
15
  | 'spacexai/grok-tts'