@ai-sdk/gateway 4.0.0-beta.10 → 4.0.0-beta.109
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 +758 -4
- package/dist/index.d.ts +314 -42
- package/dist/index.js +1413 -397
- package/dist/index.js.map +1 -1
- package/docs/00-ai-gateway.mdx +447 -61
- package/package.json +14 -14
- package/src/errors/as-gateway-error.ts +2 -1
- package/src/errors/create-gateway-error.ts +17 -3
- package/src/errors/gateway-authentication-error.ts +8 -5
- package/src/errors/gateway-error.ts +8 -0
- package/src/errors/gateway-failed-dependency-error.ts +35 -0
- package/src/errors/gateway-forbidden-error.ts +34 -0
- package/src/errors/gateway-response-error.ts +1 -1
- package/src/errors/index.ts +2 -0
- package/src/errors/parse-auth-method.ts +1 -2
- package/src/gateway-config.ts +1 -1
- package/src/gateway-embedding-model-settings.ts +1 -0
- package/src/gateway-embedding-model.ts +62 -15
- package/src/gateway-fetch-metadata.ts +51 -38
- package/src/gateway-generation-info.ts +149 -0
- package/src/gateway-headers.ts +3 -0
- package/src/gateway-image-model-settings.ts +8 -1
- package/src/gateway-image-model.ts +46 -21
- package/src/gateway-language-model-settings.ts +44 -26
- package/src/gateway-language-model.ts +72 -42
- package/src/gateway-model-entry.ts +15 -3
- package/src/gateway-provider-options.ts +50 -78
- package/src/gateway-provider.ts +296 -35
- package/src/gateway-realtime-auth.ts +126 -0
- package/src/gateway-realtime-model-settings.ts +1 -0
- package/src/gateway-realtime-model.ts +118 -0
- package/src/gateway-reranking-model-settings.ts +7 -0
- package/src/gateway-reranking-model.ts +142 -0
- package/src/gateway-speech-model-settings.ts +1 -0
- package/src/gateway-speech-model.ts +145 -0
- package/src/gateway-spend-report.ts +193 -0
- package/src/gateway-transcription-model-settings.ts +1 -0
- package/src/gateway-transcription-model.ts +155 -0
- package/src/gateway-video-model-settings.ts +4 -0
- package/src/gateway-video-model.ts +29 -19
- package/src/index.ts +30 -5
- package/src/tool/parallel-search.ts +10 -11
- package/src/tool/perplexity-search.ts +10 -11
- package/dist/index.d.mts +0 -602
- package/dist/index.mjs +0 -1539
- package/dist/index.mjs.map +0 -1
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LanguageModelV4 } from '@ai-sdk/provider';
|
|
2
|
+
|
|
3
|
+
export const KNOWN_MODEL_TYPES = [
|
|
4
|
+
'embedding',
|
|
5
|
+
'image',
|
|
6
|
+
'language',
|
|
7
|
+
'reranking',
|
|
8
|
+
'speech',
|
|
9
|
+
'transcription',
|
|
10
|
+
'video',
|
|
11
|
+
] as const;
|
|
12
|
+
|
|
13
|
+
export type KnownModelType = (typeof KNOWN_MODEL_TYPES)[number];
|
|
2
14
|
|
|
3
15
|
export interface GatewayLanguageModelEntry {
|
|
4
16
|
/**
|
|
@@ -49,10 +61,10 @@ export interface GatewayLanguageModelEntry {
|
|
|
49
61
|
/**
|
|
50
62
|
* Optional field to differentiate between model types.
|
|
51
63
|
*/
|
|
52
|
-
modelType?:
|
|
64
|
+
modelType?: KnownModelType | null;
|
|
53
65
|
}
|
|
54
66
|
|
|
55
67
|
export type GatewayLanguageModelSpecification = Pick<
|
|
56
|
-
|
|
68
|
+
LanguageModelV4,
|
|
57
69
|
'specificationVersion' | 'provider' | 'modelId'
|
|
58
70
|
>;
|
|
@@ -1,80 +1,52 @@
|
|
|
1
|
-
import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
|
|
2
|
-
import { z } from 'zod/v4';
|
|
3
|
-
|
|
4
1
|
// https://vercel.com/docs/ai-gateway/provider-options
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
byok: z
|
|
53
|
-
.record(z.string(), z.array(z.record(z.string(), z.unknown())))
|
|
54
|
-
.optional(),
|
|
55
|
-
/**
|
|
56
|
-
* Whether to filter by only providers that state they have zero data
|
|
57
|
-
* retention with Vercel AI Gateway. When enabled, only providers that
|
|
58
|
-
* have agreements with Vercel AI Gateway for zero data retention will be
|
|
59
|
-
* used.
|
|
60
|
-
*/
|
|
61
|
-
zeroDataRetention: z.boolean().optional(),
|
|
62
|
-
/**
|
|
63
|
-
* Per-provider timeouts for BYOK credentials in milliseconds.
|
|
64
|
-
* Controls how long to wait for a provider to start responding
|
|
65
|
-
* before falling back to the next available provider.
|
|
66
|
-
*
|
|
67
|
-
* Example: `{ byok: { openai: 5000, anthropic: 2000 } }`
|
|
68
|
-
*/
|
|
69
|
-
providerTimeouts: z
|
|
70
|
-
.object({
|
|
71
|
-
byok: z.record(z.string(), z.number().int().min(1000)).optional(),
|
|
72
|
-
})
|
|
73
|
-
.optional(),
|
|
74
|
-
}),
|
|
75
|
-
),
|
|
76
|
-
);
|
|
2
|
+
export type GatewayProviderOptions = {
|
|
3
|
+
/**
|
|
4
|
+
* Service-owned options may be added by the Gateway without requiring an SDK
|
|
5
|
+
* release. The Gateway service validates and applies the runtime schema.
|
|
6
|
+
*/
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
|
|
9
|
+
/** Request-scoped BYOK credentials to use instead of cached credentials. */
|
|
10
|
+
byok?: Record<string, Array<Record<string, unknown>>>;
|
|
11
|
+
|
|
12
|
+
/** Enables automatic caching behavior when supported by the Gateway. */
|
|
13
|
+
caching?: 'auto';
|
|
14
|
+
|
|
15
|
+
/** Filter to providers that do not train on prompt data. */
|
|
16
|
+
disallowPromptTraining?: boolean;
|
|
17
|
+
|
|
18
|
+
/** Filter to providers that are HIPAA compliant with Vercel AI Gateway. */
|
|
19
|
+
hipaaCompliant?: boolean;
|
|
20
|
+
|
|
21
|
+
/** Array of model slugs specifying fallback models to use in order. */
|
|
22
|
+
models?: string[];
|
|
23
|
+
|
|
24
|
+
/** Array of provider slugs that are the only ones allowed to be used. */
|
|
25
|
+
only?: string[];
|
|
26
|
+
|
|
27
|
+
/** Array of provider slugs specifying the provider attempt order. */
|
|
28
|
+
order?: string[];
|
|
29
|
+
|
|
30
|
+
/** Per-provider timeouts for BYOK credentials in milliseconds. */
|
|
31
|
+
providerTimeouts?: {
|
|
32
|
+
byok?: Record<string, number>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** Entity identifier against which quota is tracked. */
|
|
36
|
+
quotaEntityId?: string;
|
|
37
|
+
|
|
38
|
+
/** Unified service tier intent. */
|
|
39
|
+
serviceTier?: 'flex' | 'priority';
|
|
40
|
+
|
|
41
|
+
/** Sort providers by a performance or cost metric before routing. */
|
|
42
|
+
sort?: 'cost' | 'tps' | 'ttft';
|
|
43
|
+
|
|
44
|
+
/** User-specified tags for reporting and filtering usage. */
|
|
45
|
+
tags?: string[];
|
|
46
|
+
|
|
47
|
+
/** End-user identifier for spend tracking and attribution. */
|
|
48
|
+
user?: string;
|
|
77
49
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
50
|
+
/** Filter to providers with zero data retention agreements. */
|
|
51
|
+
zeroDataRetention?: boolean;
|
|
52
|
+
};
|
package/src/gateway-provider.ts
CHANGED
|
@@ -1,50 +1,78 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createJsonErrorResponseHandler,
|
|
3
|
+
createJsonResponseHandler,
|
|
2
4
|
loadOptionalSetting,
|
|
5
|
+
postJsonToApi,
|
|
3
6
|
withoutTrailingSlash,
|
|
7
|
+
withUserAgentSuffix,
|
|
4
8
|
type FetchFunction,
|
|
5
9
|
} from '@ai-sdk/provider-utils';
|
|
10
|
+
import { z } from 'zod/v4';
|
|
6
11
|
import { asGatewayError, GatewayAuthenticationError } from './errors';
|
|
7
12
|
import {
|
|
8
13
|
GATEWAY_AUTH_METHOD_HEADER,
|
|
9
|
-
|
|
10
|
-
} from './
|
|
14
|
+
VERCEL_AI_GATEWAY_TEAM_HEADER,
|
|
15
|
+
} from './gateway-headers';
|
|
16
|
+
import { parseAuthMethod } from './errors/parse-auth-method';
|
|
11
17
|
import {
|
|
12
18
|
GatewayFetchMetadata,
|
|
13
19
|
type GatewayFetchMetadataResponse,
|
|
14
20
|
type GatewayCreditsResponse,
|
|
15
21
|
} from './gateway-fetch-metadata';
|
|
22
|
+
import {
|
|
23
|
+
GatewaySpendReport,
|
|
24
|
+
type GatewaySpendReportParams,
|
|
25
|
+
type GatewaySpendReportResponse,
|
|
26
|
+
} from './gateway-spend-report';
|
|
27
|
+
import {
|
|
28
|
+
GatewayGenerationInfoFetcher,
|
|
29
|
+
type GatewayGenerationInfoParams,
|
|
30
|
+
type GatewayGenerationInfo,
|
|
31
|
+
} from './gateway-generation-info';
|
|
16
32
|
import { GatewayLanguageModel } from './gateway-language-model';
|
|
17
33
|
import { GatewayEmbeddingModel } from './gateway-embedding-model';
|
|
18
34
|
import { GatewayImageModel } from './gateway-image-model';
|
|
19
35
|
import { GatewayVideoModel } from './gateway-video-model';
|
|
36
|
+
import { GatewayRerankingModel } from './gateway-reranking-model';
|
|
37
|
+
import { GatewaySpeechModel } from './gateway-speech-model';
|
|
38
|
+
import { GatewayTranscriptionModel } from './gateway-transcription-model';
|
|
39
|
+
import { GatewayRealtimeModel } from './gateway-realtime-model';
|
|
20
40
|
import type { GatewayEmbeddingModelId } from './gateway-embedding-model-settings';
|
|
21
41
|
import type { GatewayImageModelId } from './gateway-image-model-settings';
|
|
42
|
+
import type { GatewayRerankingModelId } from './gateway-reranking-model-settings';
|
|
43
|
+
import type { GatewaySpeechModelId } from './gateway-speech-model-settings';
|
|
44
|
+
import type { GatewayTranscriptionModelId } from './gateway-transcription-model-settings';
|
|
45
|
+
import type { GatewayRealtimeModelId } from './gateway-realtime-model-settings';
|
|
22
46
|
import type { GatewayVideoModelId } from './gateway-video-model-settings';
|
|
23
47
|
import { gatewayTools } from './gateway-tools';
|
|
24
48
|
import { getVercelOidcToken, getVercelRequestId } from './vercel-environment';
|
|
25
49
|
import type { GatewayModelId } from './gateway-language-model-settings';
|
|
26
50
|
import type {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
51
|
+
LanguageModelV4,
|
|
52
|
+
EmbeddingModelV4,
|
|
53
|
+
ImageModelV4,
|
|
54
|
+
RerankingModelV4,
|
|
55
|
+
SpeechModelV4,
|
|
56
|
+
TranscriptionModelV4,
|
|
57
|
+
Experimental_VideoModelV4,
|
|
58
|
+
Experimental_RealtimeFactoryV4 as RealtimeFactoryV4,
|
|
59
|
+
Experimental_RealtimeFactoryV4GetTokenOptions as RealtimeFactoryV4GetTokenOptions,
|
|
60
|
+
ProviderV4,
|
|
32
61
|
} from '@ai-sdk/provider';
|
|
33
|
-
import { withUserAgentSuffix } from '@ai-sdk/provider-utils';
|
|
34
62
|
import { VERSION } from './version';
|
|
35
63
|
|
|
36
|
-
export interface GatewayProvider extends
|
|
37
|
-
(modelId: GatewayModelId):
|
|
64
|
+
export interface GatewayProvider extends ProviderV4 {
|
|
65
|
+
(modelId: GatewayModelId): LanguageModelV4;
|
|
38
66
|
|
|
39
67
|
/**
|
|
40
68
|
* Creates a model for text generation.
|
|
41
69
|
*/
|
|
42
|
-
chat(modelId: GatewayModelId):
|
|
70
|
+
chat(modelId: GatewayModelId): LanguageModelV4;
|
|
43
71
|
|
|
44
72
|
/**
|
|
45
73
|
* Creates a model for text generation.
|
|
46
74
|
*/
|
|
47
|
-
languageModel(modelId: GatewayModelId):
|
|
75
|
+
languageModel(modelId: GatewayModelId): LanguageModelV4;
|
|
48
76
|
|
|
49
77
|
/**
|
|
50
78
|
* Returns available providers and models for use with the remote provider.
|
|
@@ -56,40 +84,94 @@ export interface GatewayProvider extends ProviderV3 {
|
|
|
56
84
|
*/
|
|
57
85
|
getCredits(): Promise<GatewayCreditsResponse>;
|
|
58
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Returns a spend report with cost, token, and request count data,
|
|
89
|
+
* aggregated by the specified dimension.
|
|
90
|
+
*/
|
|
91
|
+
getSpendReport(
|
|
92
|
+
params: GatewaySpendReportParams,
|
|
93
|
+
): Promise<GatewaySpendReportResponse>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Returns detailed information about a specific generation by its ID,
|
|
97
|
+
* including cost, token usage, latency, and provider details.
|
|
98
|
+
*/
|
|
99
|
+
getGenerationInfo(
|
|
100
|
+
params: GatewayGenerationInfoParams,
|
|
101
|
+
): Promise<GatewayGenerationInfo>;
|
|
102
|
+
|
|
59
103
|
/**
|
|
60
104
|
* Creates a model for generating text embeddings.
|
|
61
105
|
*/
|
|
62
|
-
embedding(modelId: GatewayEmbeddingModelId):
|
|
106
|
+
embedding(modelId: GatewayEmbeddingModelId): EmbeddingModelV4;
|
|
63
107
|
|
|
64
108
|
/**
|
|
65
109
|
* Creates a model for generating text embeddings.
|
|
66
110
|
*/
|
|
67
|
-
embeddingModel(modelId: GatewayEmbeddingModelId):
|
|
111
|
+
embeddingModel(modelId: GatewayEmbeddingModelId): EmbeddingModelV4;
|
|
68
112
|
|
|
69
113
|
/**
|
|
70
114
|
* @deprecated Use `embeddingModel` instead.
|
|
71
115
|
*/
|
|
72
|
-
textEmbeddingModel(modelId: GatewayEmbeddingModelId):
|
|
116
|
+
textEmbeddingModel(modelId: GatewayEmbeddingModelId): EmbeddingModelV4;
|
|
73
117
|
|
|
74
118
|
/**
|
|
75
119
|
* Creates a model for generating images.
|
|
76
120
|
*/
|
|
77
|
-
image(modelId: GatewayImageModelId):
|
|
121
|
+
image(modelId: GatewayImageModelId): ImageModelV4;
|
|
78
122
|
|
|
79
123
|
/**
|
|
80
124
|
* Creates a model for generating images.
|
|
81
125
|
*/
|
|
82
|
-
imageModel(modelId: GatewayImageModelId):
|
|
126
|
+
imageModel(modelId: GatewayImageModelId): ImageModelV4;
|
|
83
127
|
|
|
84
128
|
/**
|
|
85
129
|
* Creates a model for generating videos.
|
|
86
130
|
*/
|
|
87
|
-
video(modelId: GatewayVideoModelId):
|
|
131
|
+
video(modelId: GatewayVideoModelId): Experimental_VideoModelV4;
|
|
88
132
|
|
|
89
133
|
/**
|
|
90
134
|
* Creates a model for generating videos.
|
|
91
135
|
*/
|
|
92
|
-
videoModel(modelId: GatewayVideoModelId):
|
|
136
|
+
videoModel(modelId: GatewayVideoModelId): Experimental_VideoModelV4;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Creates a model for reranking documents.
|
|
140
|
+
*/
|
|
141
|
+
reranking(modelId: GatewayRerankingModelId): RerankingModelV4;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Creates a model for reranking documents.
|
|
145
|
+
*/
|
|
146
|
+
rerankingModel(modelId: GatewayRerankingModelId): RerankingModelV4;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Creates a model for text-to-speech generation.
|
|
150
|
+
*/
|
|
151
|
+
speech(modelId: GatewaySpeechModelId): SpeechModelV4;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Creates a model for text-to-speech generation.
|
|
155
|
+
*/
|
|
156
|
+
speechModel(modelId: GatewaySpeechModelId): SpeechModelV4;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Creates a model for audio transcription.
|
|
160
|
+
*/
|
|
161
|
+
transcription(modelId: GatewayTranscriptionModelId): TranscriptionModelV4;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Creates a model for audio transcription.
|
|
165
|
+
*/
|
|
166
|
+
transcriptionModel(
|
|
167
|
+
modelId: GatewayTranscriptionModelId,
|
|
168
|
+
): TranscriptionModelV4;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Creates an experimental realtime model for bidirectional audio/text
|
|
172
|
+
* communication over WebSocket, normalized through the AI Gateway.
|
|
173
|
+
*/
|
|
174
|
+
experimental_realtime: RealtimeFactoryV4;
|
|
93
175
|
|
|
94
176
|
/**
|
|
95
177
|
* Gateway-specific tools executed server-side.
|
|
@@ -99,15 +181,22 @@ export interface GatewayProvider extends ProviderV3 {
|
|
|
99
181
|
|
|
100
182
|
export interface GatewayProviderSettings {
|
|
101
183
|
/**
|
|
102
|
-
* The base URL prefix for API calls. Defaults to `https://ai-gateway.vercel.sh/
|
|
184
|
+
* The base URL prefix for API calls. Defaults to `https://ai-gateway.vercel.sh/v4/ai`.
|
|
103
185
|
*/
|
|
104
186
|
baseURL?: string;
|
|
105
187
|
|
|
106
188
|
/**
|
|
107
|
-
* API key that is being sent using the `Authorization`
|
|
189
|
+
* API key or Vercel access token that is being sent using the `Authorization`
|
|
190
|
+
* header. It defaults to the `AI_GATEWAY_API_KEY` environment variable.
|
|
108
191
|
*/
|
|
109
192
|
apiKey?: string;
|
|
110
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Vercel team ID or slug to scope requests for access tokens that can access
|
|
196
|
+
* multiple teams.
|
|
197
|
+
*/
|
|
198
|
+
teamIdOrSlug?: string;
|
|
199
|
+
|
|
111
200
|
/**
|
|
112
201
|
* Custom headers to include in the requests.
|
|
113
202
|
*/
|
|
@@ -134,10 +223,16 @@ export interface GatewayProviderSettings {
|
|
|
134
223
|
|
|
135
224
|
const AI_GATEWAY_PROTOCOL_VERSION = '0.0.1';
|
|
136
225
|
|
|
226
|
+
/** Response shape of `POST /v1/realtime/client-secrets`. `expiresAt` is epoch seconds. */
|
|
227
|
+
const gatewayClientSecretResponseSchema = z.object({
|
|
228
|
+
token: z.string(),
|
|
229
|
+
expiresAt: z.number().nullish(),
|
|
230
|
+
});
|
|
231
|
+
|
|
137
232
|
/**
|
|
138
233
|
* Create a remote provider instance.
|
|
139
234
|
*/
|
|
140
|
-
export function
|
|
235
|
+
export function createGateway(
|
|
141
236
|
options: GatewayProviderSettings = {},
|
|
142
237
|
): GatewayProvider {
|
|
143
238
|
let pendingMetadata: Promise<GatewayFetchMetadataResponse> | null = null;
|
|
@@ -148,20 +243,28 @@ export function createGatewayProvider(
|
|
|
148
243
|
|
|
149
244
|
const baseURL =
|
|
150
245
|
withoutTrailingSlash(options.baseURL) ??
|
|
151
|
-
'https://ai-gateway.vercel.sh/
|
|
246
|
+
'https://ai-gateway.vercel.sh/v4/ai';
|
|
247
|
+
|
|
248
|
+
const createAuthHeaders = (auth: {
|
|
249
|
+
token: string;
|
|
250
|
+
authMethod: 'api-key' | 'oidc';
|
|
251
|
+
}) =>
|
|
252
|
+
withUserAgentSuffix(
|
|
253
|
+
{
|
|
254
|
+
Authorization: `Bearer ${auth.token}`,
|
|
255
|
+
'ai-gateway-protocol-version': AI_GATEWAY_PROTOCOL_VERSION,
|
|
256
|
+
[GATEWAY_AUTH_METHOD_HEADER]: auth.authMethod,
|
|
257
|
+
...(options.teamIdOrSlug != null
|
|
258
|
+
? { [VERCEL_AI_GATEWAY_TEAM_HEADER]: options.teamIdOrSlug }
|
|
259
|
+
: {}),
|
|
260
|
+
...options.headers,
|
|
261
|
+
},
|
|
262
|
+
`ai-sdk/gateway/${VERSION}`,
|
|
263
|
+
);
|
|
152
264
|
|
|
153
265
|
const getHeaders = async () => {
|
|
154
266
|
try {
|
|
155
|
-
|
|
156
|
-
return withUserAgentSuffix(
|
|
157
|
-
{
|
|
158
|
-
Authorization: `Bearer ${auth.token}`,
|
|
159
|
-
'ai-gateway-protocol-version': AI_GATEWAY_PROTOCOL_VERSION,
|
|
160
|
-
[GATEWAY_AUTH_METHOD_HEADER]: auth.authMethod,
|
|
161
|
-
...options.headers,
|
|
162
|
-
},
|
|
163
|
-
`ai-sdk/gateway/${VERSION}`,
|
|
164
|
-
);
|
|
267
|
+
return createAuthHeaders(await getGatewayAuthToken(options));
|
|
165
268
|
} catch (error) {
|
|
166
269
|
throw GatewayAuthenticationError.createContextualError({
|
|
167
270
|
apiKeyProvided: false,
|
|
@@ -172,6 +275,62 @@ export function createGatewayProvider(
|
|
|
172
275
|
}
|
|
173
276
|
};
|
|
174
277
|
|
|
278
|
+
const getRealtimeAuthToken = async () => {
|
|
279
|
+
try {
|
|
280
|
+
return await getGatewayAuthToken(options);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
throw GatewayAuthenticationError.createContextualError({
|
|
283
|
+
apiKeyProvided: false,
|
|
284
|
+
oidcTokenProvided: false,
|
|
285
|
+
statusCode: 401,
|
|
286
|
+
cause: error,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// Mints a short-lived realtime client secret (`vcst_`) via the Gateway's
|
|
292
|
+
// `/v1/realtime/client-secrets` route, authenticated with the long-lived
|
|
293
|
+
// Gateway credential. Server-side only (asserted) — the credential never
|
|
294
|
+
// belongs in a browser; the browser receives only the minted token. The
|
|
295
|
+
// mint route lives at the gateway origin's `/v1/realtime/client-secrets`,
|
|
296
|
+
// not under the realtime `baseURL` path (which targets `/v4/ai`), so the
|
|
297
|
+
// URL is resolved against the origin.
|
|
298
|
+
const mintRealtimeClientSecret = async (params: {
|
|
299
|
+
modelId: string;
|
|
300
|
+
expiresAfterSeconds?: number;
|
|
301
|
+
}): Promise<{ token: string; expiresAt?: number }> => {
|
|
302
|
+
assertGatewayRealtimeServerEnvironment();
|
|
303
|
+
const auth = await getRealtimeAuthToken();
|
|
304
|
+
const headers = createAuthHeaders(auth);
|
|
305
|
+
const url = new URL('/v1/realtime/client-secrets', baseURL).toString();
|
|
306
|
+
try {
|
|
307
|
+
const { value } = await postJsonToApi({
|
|
308
|
+
url,
|
|
309
|
+
headers,
|
|
310
|
+
body: {
|
|
311
|
+
model: params.modelId,
|
|
312
|
+
...(params.expiresAfterSeconds != null && {
|
|
313
|
+
expiresIn: params.expiresAfterSeconds,
|
|
314
|
+
}),
|
|
315
|
+
},
|
|
316
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
317
|
+
gatewayClientSecretResponseSchema,
|
|
318
|
+
),
|
|
319
|
+
failedResponseHandler: createJsonErrorResponseHandler({
|
|
320
|
+
errorSchema: z.any(),
|
|
321
|
+
errorToMessage: data => data,
|
|
322
|
+
}),
|
|
323
|
+
fetch: options.fetch,
|
|
324
|
+
});
|
|
325
|
+
return {
|
|
326
|
+
token: value.token,
|
|
327
|
+
...(value.expiresAt != null && { expiresAt: value.expiresAt }),
|
|
328
|
+
};
|
|
329
|
+
} catch (error) {
|
|
330
|
+
throw await asGatewayError(error, await parseAuthMethod(headers));
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
175
334
|
const createO11yHeaders = () => {
|
|
176
335
|
const deploymentId = loadOptionalSetting({
|
|
177
336
|
settingValue: undefined,
|
|
@@ -253,6 +412,36 @@ export function createGatewayProvider(
|
|
|
253
412
|
});
|
|
254
413
|
};
|
|
255
414
|
|
|
415
|
+
const getSpendReport = async (params: GatewaySpendReportParams) => {
|
|
416
|
+
return new GatewaySpendReport({
|
|
417
|
+
baseURL,
|
|
418
|
+
headers: getHeaders,
|
|
419
|
+
fetch: options.fetch,
|
|
420
|
+
})
|
|
421
|
+
.getSpendReport(params)
|
|
422
|
+
.catch(async (error: unknown) => {
|
|
423
|
+
throw await asGatewayError(
|
|
424
|
+
error,
|
|
425
|
+
await parseAuthMethod(await getHeaders()),
|
|
426
|
+
);
|
|
427
|
+
});
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
const getGenerationInfo = async (params: GatewayGenerationInfoParams) => {
|
|
431
|
+
return new GatewayGenerationInfoFetcher({
|
|
432
|
+
baseURL,
|
|
433
|
+
headers: getHeaders,
|
|
434
|
+
fetch: options.fetch,
|
|
435
|
+
})
|
|
436
|
+
.getGenerationInfo(params)
|
|
437
|
+
.catch(async (error: unknown) => {
|
|
438
|
+
throw await asGatewayError(
|
|
439
|
+
error,
|
|
440
|
+
await parseAuthMethod(await getHeaders()),
|
|
441
|
+
);
|
|
442
|
+
});
|
|
443
|
+
};
|
|
444
|
+
|
|
256
445
|
const provider = function (modelId: GatewayModelId) {
|
|
257
446
|
if (new.target) {
|
|
258
447
|
throw new Error(
|
|
@@ -263,9 +452,11 @@ export function createGatewayProvider(
|
|
|
263
452
|
return createLanguageModel(modelId);
|
|
264
453
|
};
|
|
265
454
|
|
|
266
|
-
provider.specificationVersion = '
|
|
455
|
+
provider.specificationVersion = 'v4' as const;
|
|
267
456
|
provider.getAvailableModels = getAvailableModels;
|
|
268
457
|
provider.getCredits = getCredits;
|
|
458
|
+
provider.getSpendReport = getSpendReport;
|
|
459
|
+
provider.getGenerationInfo = getGenerationInfo;
|
|
269
460
|
provider.imageModel = (modelId: GatewayImageModelId) => {
|
|
270
461
|
return new GatewayImageModel(modelId, {
|
|
271
462
|
provider: 'gateway',
|
|
@@ -296,6 +487,68 @@ export function createGatewayProvider(
|
|
|
296
487
|
o11yHeaders: createO11yHeaders(),
|
|
297
488
|
});
|
|
298
489
|
};
|
|
490
|
+
const createRerankingModel = (modelId: GatewayRerankingModelId) => {
|
|
491
|
+
return new GatewayRerankingModel(modelId, {
|
|
492
|
+
provider: 'gateway',
|
|
493
|
+
baseURL,
|
|
494
|
+
headers: getHeaders,
|
|
495
|
+
fetch: options.fetch,
|
|
496
|
+
o11yHeaders: createO11yHeaders(),
|
|
497
|
+
});
|
|
498
|
+
};
|
|
499
|
+
provider.rerankingModel = createRerankingModel;
|
|
500
|
+
provider.reranking = createRerankingModel;
|
|
501
|
+
const createSpeechModel = (modelId: GatewaySpeechModelId) => {
|
|
502
|
+
return new GatewaySpeechModel(modelId, {
|
|
503
|
+
provider: 'gateway',
|
|
504
|
+
baseURL,
|
|
505
|
+
headers: getHeaders,
|
|
506
|
+
fetch: options.fetch,
|
|
507
|
+
o11yHeaders: createO11yHeaders(),
|
|
508
|
+
});
|
|
509
|
+
};
|
|
510
|
+
provider.speechModel = createSpeechModel;
|
|
511
|
+
provider.speech = createSpeechModel;
|
|
512
|
+
const createTranscriptionModel = (modelId: GatewayTranscriptionModelId) => {
|
|
513
|
+
return new GatewayTranscriptionModel(modelId, {
|
|
514
|
+
provider: 'gateway',
|
|
515
|
+
baseURL,
|
|
516
|
+
headers: getHeaders,
|
|
517
|
+
fetch: options.fetch,
|
|
518
|
+
o11yHeaders: createO11yHeaders(),
|
|
519
|
+
});
|
|
520
|
+
};
|
|
521
|
+
provider.transcriptionModel = createTranscriptionModel;
|
|
522
|
+
provider.transcription = createTranscriptionModel;
|
|
523
|
+
|
|
524
|
+
// No server-environment guard here: building the realtime model is just the
|
|
525
|
+
// event codec + WebSocket-config helper, which the browser legitimately
|
|
526
|
+
// needs to drive the transport with a server-minted client secret. The
|
|
527
|
+
// server-only boundary is enforced on minting itself
|
|
528
|
+
// (`mintRealtimeClientSecret`), which requires the Gateway credential.
|
|
529
|
+
const createRealtimeModel = (modelId: GatewayRealtimeModelId) =>
|
|
530
|
+
new GatewayRealtimeModel(modelId, {
|
|
531
|
+
provider: 'gateway.realtime',
|
|
532
|
+
baseURL,
|
|
533
|
+
teamIdOrSlug: options.teamIdOrSlug,
|
|
534
|
+
createClientSecret: mintRealtimeClientSecret,
|
|
535
|
+
});
|
|
536
|
+
provider.experimental_realtime = Object.assign(
|
|
537
|
+
(modelId: GatewayRealtimeModelId) => createRealtimeModel(modelId),
|
|
538
|
+
{
|
|
539
|
+
getToken: async (tokenOptions: RealtimeFactoryV4GetTokenOptions) => {
|
|
540
|
+
const { model: modelId, ...secretOptions } = tokenOptions;
|
|
541
|
+
const model = createRealtimeModel(modelId);
|
|
542
|
+
const secret = await model.doCreateClientSecret(secretOptions);
|
|
543
|
+
return {
|
|
544
|
+
token: secret.token,
|
|
545
|
+
url: secret.url,
|
|
546
|
+
...(secret.expiresAt != null && { expiresAt: secret.expiresAt }),
|
|
547
|
+
};
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
) as RealtimeFactoryV4;
|
|
551
|
+
|
|
299
552
|
provider.chat = provider.languageModel;
|
|
300
553
|
provider.embedding = provider.embeddingModel;
|
|
301
554
|
provider.image = provider.imageModel;
|
|
@@ -304,7 +557,7 @@ export function createGatewayProvider(
|
|
|
304
557
|
return provider;
|
|
305
558
|
}
|
|
306
559
|
|
|
307
|
-
export const gateway =
|
|
560
|
+
export const gateway = createGateway();
|
|
308
561
|
|
|
309
562
|
export async function getGatewayAuthToken(
|
|
310
563
|
options: GatewayProviderSettings,
|
|
@@ -327,3 +580,11 @@ export async function getGatewayAuthToken(
|
|
|
327
580
|
authMethod: 'oidc',
|
|
328
581
|
};
|
|
329
582
|
}
|
|
583
|
+
|
|
584
|
+
function assertGatewayRealtimeServerEnvironment(): void {
|
|
585
|
+
if (typeof globalThis.window !== 'undefined') {
|
|
586
|
+
throw new Error(
|
|
587
|
+
'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.',
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
}
|