@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/CHANGELOG.md +7 -0
- package/dist/index.d.ts +32 -1
- package/dist/index.js +26 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/gateway-language-model-settings.ts +2 -0
- package/src/gateway-provider.ts +80 -11
- package/src/gateway-transcription-model.ts +4 -1
package/package.json
CHANGED
|
@@ -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'
|
package/src/gateway-provider.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
306
|
-
//
|
|
307
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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:
|
|
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
|
|
663
|
+
function assertGatewayClientSecretServerEnvironment(): void {
|
|
595
664
|
if (typeof globalThis.window !== 'undefined') {
|
|
596
665
|
throw new Error(
|
|
597
|
-
'AI Gateway
|
|
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(
|
|
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();
|