@ai-sdk/gateway 4.0.20 → 4.0.21

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ai-sdk/gateway",
3
3
  "private": false,
4
- "version": "4.0.20",
4
+ "version": "4.0.21",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "sideEffects": false,
@@ -35,7 +35,9 @@ export type GatewayModelId =
35
35
  | 'anthropic/claude-opus-4.5'
36
36
  | 'anthropic/claude-opus-4.6'
37
37
  | 'anthropic/claude-opus-4.7'
38
+ | 'anthropic/claude-opus-4.7-fast'
38
39
  | 'anthropic/claude-opus-4.8'
40
+ | 'anthropic/claude-opus-4.8-fast'
39
41
  | 'anthropic/claude-sonnet-4'
40
42
  | 'anthropic/claude-sonnet-4.5'
41
43
  | 'anthropic/claude-sonnet-4.6'
@@ -36,7 +36,10 @@ import { GatewayImageModel } from './gateway-image-model';
36
36
  import { GatewayVideoModel } from './gateway-video-model';
37
37
  import { GatewayRerankingModel } from './gateway-reranking-model';
38
38
  import { GatewaySpeechModel } from './gateway-speech-model';
39
- import { GatewayTranscriptionModel } from './gateway-transcription-model';
39
+ import {
40
+ GatewayTranscriptionModel,
41
+ toGatewayTranscriptionUrl,
42
+ } from './gateway-transcription-model';
40
43
  import { GatewayRealtimeModel } from './gateway-realtime-model';
41
44
  import type { GatewayEmbeddingModelId } from './gateway-embedding-model-settings';
42
45
  import type { GatewayImageModelId } from './gateway-image-model-settings';
@@ -174,12 +177,50 @@ export interface GatewayProvider extends ProviderV4 {
174
177
  */
175
178
  experimental_realtime: RealtimeFactoryV4;
176
179
 
180
+ /**
181
+ * Experimental streaming-transcription entry point. Callable like
182
+ * `transcription(modelId)`, plus `getToken` for minting a short-lived
183
+ * client secret (`vcst_`) a browser can use to open the streaming
184
+ * transcription WebSocket without holding the Gateway credential.
185
+ */
186
+ experimental_transcription: GatewayTranscriptionFactory;
187
+
177
188
  /**
178
189
  * Gateway-specific tools executed server-side.
179
190
  */
180
191
  tools: typeof gatewayTools;
181
192
  }
182
193
 
194
+ export type GatewayTranscriptionFactoryGetTokenOptions = {
195
+ model: GatewayTranscriptionModelId;
196
+ /** Token lifetime in seconds. Gateway default is 60s (max 300s). */
197
+ expiresAfterSeconds?: number;
198
+ };
199
+
200
+ export type GatewayTranscriptionFactoryGetTokenResult = {
201
+ /** The minted `vcst_` client secret. */
202
+ token: string;
203
+ /** WebSocket URL of the streaming transcription surface for this model. */
204
+ url: string;
205
+ /** Token expiry, epoch seconds. */
206
+ expiresAt?: number;
207
+ };
208
+
209
+ /**
210
+ * Streaming-transcription factory: callable like `transcription(modelId)`,
211
+ * plus a server-side `getToken` that mints a transcription-bound short-lived
212
+ * client secret (`vcst_`). The browser connects with
213
+ * `createGateway({ apiKey: token }).transcription(modelId)` — the token rides
214
+ * the same auth subprotocol an API key does, without exposing the credential.
215
+ */
216
+ export interface GatewayTranscriptionFactory {
217
+ (modelId: GatewayTranscriptionModelId): TranscriptionModelV4;
218
+
219
+ getToken(
220
+ options: GatewayTranscriptionFactoryGetTokenOptions,
221
+ ): Promise<GatewayTranscriptionFactoryGetTokenResult>;
222
+ }
223
+
183
224
  export interface GatewayProviderSettings {
184
225
  /**
185
226
  * The base URL prefix for API calls. Defaults to `https://ai-gateway.vercel.sh/v4/ai`.
@@ -297,18 +338,21 @@ export function createGateway(
297
338
  }
298
339
  };
299
340
 
300
- // Mints a short-lived realtime client secret (`vcst_`) via the Gateway's
341
+ // Mints a short-lived client secret (`vcst_`) via the Gateway's
301
342
  // `/v1/realtime/client-secrets` route, authenticated with the long-lived
302
343
  // Gateway credential. Server-side only (asserted) — the credential never
303
344
  // belongs in a browser; the browser receives only the minted token. The
304
345
  // mint route lives at the gateway origin's `/v1/realtime/client-secrets`,
305
- // not under the realtime `baseURL` path (which targets `/v4/ai`), so the
306
- // URL is resolved against the origin.
307
- const mintRealtimeClientSecret = async (params: {
346
+ // not under the `baseURL` path (which targets `/v4/ai`), so the URL is
347
+ // resolved against the origin. `routeKind` binds the token to a WebSocket
348
+ // surface; it is omitted for realtime (the gateway default) so older
349
+ // gateway deployments keep accepting realtime mints.
350
+ const mintClientSecret = async (params: {
308
351
  modelId: string;
309
352
  expiresAfterSeconds?: number;
353
+ routeKind?: 'transcription';
310
354
  }): Promise<{ token: string; expiresAt?: number }> => {
311
- assertGatewayRealtimeServerEnvironment();
355
+ assertGatewayClientSecretServerEnvironment();
312
356
  const auth = await getRealtimeAuthToken();
313
357
  const headers = createAuthHeaders(auth);
314
358
  const url = new URL('/v1/realtime/client-secrets', baseURL).toString();
@@ -318,6 +362,7 @@ export function createGateway(
318
362
  headers,
319
363
  body: {
320
364
  model: params.modelId,
365
+ ...(params.routeKind != null && { routeKind: params.routeKind }),
321
366
  ...(params.expiresAfterSeconds != null && {
322
367
  expiresIn: params.expiresAfterSeconds,
323
368
  }),
@@ -530,18 +575,42 @@ export function createGateway(
530
575
  };
531
576
  provider.transcriptionModel = createTranscriptionModel;
532
577
  provider.transcription = createTranscriptionModel;
578
+ // Callable like `transcription(modelId)`; `getToken` mints a
579
+ // transcription-bound client secret (server-side only) the browser uses to
580
+ // connect via `createGateway({ apiKey: token }).transcription(modelId)`.
581
+ provider.experimental_transcription = Object.assign(
582
+ (modelId: GatewayTranscriptionModelId) => createTranscriptionModel(modelId),
583
+ {
584
+ getToken: async (
585
+ tokenOptions: GatewayTranscriptionFactoryGetTokenOptions,
586
+ ): Promise<GatewayTranscriptionFactoryGetTokenResult> => {
587
+ const secret = await mintClientSecret({
588
+ modelId: tokenOptions.model,
589
+ routeKind: 'transcription',
590
+ ...(tokenOptions.expiresAfterSeconds != null && {
591
+ expiresAfterSeconds: tokenOptions.expiresAfterSeconds,
592
+ }),
593
+ });
594
+ return {
595
+ token: secret.token,
596
+ url: toGatewayTranscriptionUrl(baseURL, tokenOptions.model),
597
+ ...(secret.expiresAt != null && { expiresAt: secret.expiresAt }),
598
+ };
599
+ },
600
+ },
601
+ ) as GatewayTranscriptionFactory;
533
602
 
534
603
  // No server-environment guard here: building the realtime model is just the
535
604
  // event codec + WebSocket-config helper, which the browser legitimately
536
605
  // needs to drive the transport with a server-minted client secret. The
537
- // server-only boundary is enforced on minting itself
538
- // (`mintRealtimeClientSecret`), which requires the Gateway credential.
606
+ // server-only boundary is enforced on minting itself (`mintClientSecret`),
607
+ // which requires the Gateway credential.
539
608
  const createRealtimeModel = (modelId: GatewayRealtimeModelId) =>
540
609
  new GatewayRealtimeModel(modelId, {
541
610
  provider: 'gateway.realtime',
542
611
  baseURL,
543
612
  teamIdOrSlug: options.teamIdOrSlug,
544
- createClientSecret: mintRealtimeClientSecret,
613
+ createClientSecret: mintClientSecret,
545
614
  });
546
615
  provider.experimental_realtime = Object.assign(
547
616
  (modelId: GatewayRealtimeModelId) => createRealtimeModel(modelId),
@@ -591,10 +660,10 @@ export async function getGatewayAuthToken(
591
660
  };
592
661
  }
593
662
 
594
- function assertGatewayRealtimeServerEnvironment(): void {
663
+ function assertGatewayClientSecretServerEnvironment(): void {
595
664
  if (typeof globalThis.window !== 'undefined') {
596
665
  throw new Error(
597
- 'AI Gateway realtime client secrets must be minted server-side: minting needs your Gateway credential, which must never reach the browser. Call gateway.experimental_realtime.getToken() from your server and pass the returned token to the client.',
666
+ '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.',
598
667
  );
599
668
  }
600
669
  }
@@ -181,7 +181,10 @@ export class GatewayTranscriptionModel implements TranscriptionModelV4 {
181
181
  * WS(S), model id in `?ai-model-id=` (browser `WebSocket` cannot set headers;
182
182
  * slash-safe for qualified ids like `openai/gpt-realtime-whisper`).
183
183
  */
184
- function toGatewayTranscriptionUrl(baseURL: string, modelId: string): string {
184
+ export function toGatewayTranscriptionUrl(
185
+ baseURL: string,
186
+ modelId: string,
187
+ ): string {
185
188
  const url = new URL(`${baseURL.replace(/^http/, 'ws')}/transcription-model`);
186
189
  url.searchParams.set('ai-model-id', modelId);
187
190
  return url.toString();