@ai-sdk/gateway 0.0.0-02dba89b-20251009204516 → 0.0.0-4115c213-20260122152721

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +886 -167
  2. package/dist/index.d.mts +205 -34
  3. package/dist/index.d.ts +205 -34
  4. package/dist/index.js +459 -180
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +450 -148
  7. package/dist/index.mjs.map +1 -1
  8. package/docs/00-ai-gateway.mdx +625 -0
  9. package/package.json +19 -6
  10. package/src/errors/as-gateway-error.ts +33 -0
  11. package/src/errors/create-gateway-error.ts +132 -0
  12. package/src/errors/extract-api-call-response.ts +15 -0
  13. package/src/errors/gateway-authentication-error.ts +84 -0
  14. package/src/errors/gateway-error.ts +47 -0
  15. package/src/errors/gateway-internal-server-error.ts +33 -0
  16. package/src/errors/gateway-invalid-request-error.ts +33 -0
  17. package/src/errors/gateway-model-not-found-error.ts +47 -0
  18. package/src/errors/gateway-rate-limit-error.ts +33 -0
  19. package/src/errors/gateway-response-error.ts +42 -0
  20. package/src/errors/index.ts +16 -0
  21. package/src/errors/parse-auth-method.ts +23 -0
  22. package/src/gateway-config.ts +7 -0
  23. package/src/gateway-embedding-model-settings.ts +22 -0
  24. package/src/gateway-embedding-model.ts +109 -0
  25. package/src/gateway-fetch-metadata.ts +127 -0
  26. package/src/gateway-image-model-settings.ts +12 -0
  27. package/src/gateway-image-model.ts +145 -0
  28. package/src/gateway-language-model-settings.ts +159 -0
  29. package/src/gateway-language-model.ts +212 -0
  30. package/src/gateway-model-entry.ts +58 -0
  31. package/src/gateway-provider-options.ts +66 -0
  32. package/src/gateway-provider.ts +284 -0
  33. package/src/gateway-tools.ts +15 -0
  34. package/src/index.ts +27 -0
  35. package/src/tool/perplexity-search.ts +294 -0
  36. package/src/vercel-environment.ts +6 -0
  37. package/src/version.ts +6 -0
@@ -0,0 +1,127 @@
1
+ import {
2
+ createJsonErrorResponseHandler,
3
+ createJsonResponseHandler,
4
+ getFromApi,
5
+ lazySchema,
6
+ resolve,
7
+ zodSchema,
8
+ } from '@ai-sdk/provider-utils';
9
+ import { z } from 'zod/v4';
10
+ import { asGatewayError } from './errors';
11
+ import type { GatewayConfig } from './gateway-config';
12
+ import type { GatewayLanguageModelEntry } from './gateway-model-entry';
13
+
14
+ type GatewayFetchMetadataConfig = GatewayConfig;
15
+
16
+ export interface GatewayFetchMetadataResponse {
17
+ models: GatewayLanguageModelEntry[];
18
+ }
19
+
20
+ export interface GatewayCreditsResponse {
21
+ /** The remaining gateway credit balance available for API usage */
22
+ balance: string;
23
+ /** The total amount of gateway credits that have been consumed */
24
+ totalUsed: string;
25
+ }
26
+
27
+ export class GatewayFetchMetadata {
28
+ constructor(private readonly config: GatewayFetchMetadataConfig) {}
29
+
30
+ async getAvailableModels(): Promise<GatewayFetchMetadataResponse> {
31
+ try {
32
+ const { value } = await getFromApi({
33
+ url: `${this.config.baseURL}/config`,
34
+ headers: await resolve(this.config.headers()),
35
+ successfulResponseHandler: createJsonResponseHandler(
36
+ gatewayAvailableModelsResponseSchema,
37
+ ),
38
+ failedResponseHandler: createJsonErrorResponseHandler({
39
+ errorSchema: z.any(),
40
+ errorToMessage: data => data,
41
+ }),
42
+ fetch: this.config.fetch,
43
+ });
44
+
45
+ return value;
46
+ } catch (error) {
47
+ throw await asGatewayError(error);
48
+ }
49
+ }
50
+
51
+ async getCredits(): Promise<GatewayCreditsResponse> {
52
+ try {
53
+ const baseUrl = new URL(this.config.baseURL);
54
+
55
+ const { value } = await getFromApi({
56
+ url: `${baseUrl.origin}/v1/credits`,
57
+ headers: await resolve(this.config.headers()),
58
+ successfulResponseHandler: createJsonResponseHandler(
59
+ gatewayCreditsResponseSchema,
60
+ ),
61
+ failedResponseHandler: createJsonErrorResponseHandler({
62
+ errorSchema: z.any(),
63
+ errorToMessage: data => data,
64
+ }),
65
+ fetch: this.config.fetch,
66
+ });
67
+
68
+ return value;
69
+ } catch (error) {
70
+ throw await asGatewayError(error);
71
+ }
72
+ }
73
+ }
74
+
75
+ const gatewayAvailableModelsResponseSchema = lazySchema(() =>
76
+ zodSchema(
77
+ z.object({
78
+ models: z.array(
79
+ z.object({
80
+ id: z.string(),
81
+ name: z.string(),
82
+ description: z.string().nullish(),
83
+ pricing: z
84
+ .object({
85
+ input: z.string(),
86
+ output: z.string(),
87
+ input_cache_read: z.string().nullish(),
88
+ input_cache_write: z.string().nullish(),
89
+ })
90
+ .transform(
91
+ ({ input, output, input_cache_read, input_cache_write }) => ({
92
+ input,
93
+ output,
94
+ ...(input_cache_read
95
+ ? { cachedInputTokens: input_cache_read }
96
+ : {}),
97
+ ...(input_cache_write
98
+ ? { cacheCreationInputTokens: input_cache_write }
99
+ : {}),
100
+ }),
101
+ )
102
+ .nullish(),
103
+ specification: z.object({
104
+ specificationVersion: z.literal('v3'),
105
+ provider: z.string(),
106
+ modelId: z.string(),
107
+ }),
108
+ modelType: z.enum(['language', 'embedding', 'image']).nullish(),
109
+ }),
110
+ ),
111
+ }),
112
+ ),
113
+ );
114
+
115
+ const gatewayCreditsResponseSchema = lazySchema(() =>
116
+ zodSchema(
117
+ z
118
+ .object({
119
+ balance: z.string(),
120
+ total_used: z.string(),
121
+ })
122
+ .transform(({ balance, total_used }) => ({
123
+ balance,
124
+ totalUsed: total_used,
125
+ })),
126
+ ),
127
+ );
@@ -0,0 +1,12 @@
1
+ export type GatewayImageModelId =
2
+ | 'bfl/flux-kontext-max'
3
+ | 'bfl/flux-kontext-pro'
4
+ | 'bfl/flux-pro-1.0-fill'
5
+ | 'bfl/flux-pro-1.1'
6
+ | 'bfl/flux-pro-1.1-ultra'
7
+ | 'google/imagen-4.0-fast-generate-001'
8
+ | 'google/imagen-4.0-generate-001'
9
+ | 'google/imagen-4.0-ultra-generate-001'
10
+ | 'recraft/recraft-v2'
11
+ | 'recraft/recraft-v3'
12
+ | (string & {});
@@ -0,0 +1,145 @@
1
+ import type {
2
+ ImageModelV3,
3
+ ImageModelV3File,
4
+ ImageModelV3ProviderMetadata,
5
+ } from '@ai-sdk/provider';
6
+ import {
7
+ combineHeaders,
8
+ convertUint8ArrayToBase64,
9
+ createJsonResponseHandler,
10
+ createJsonErrorResponseHandler,
11
+ postJsonToApi,
12
+ resolve,
13
+ type Resolvable,
14
+ } from '@ai-sdk/provider-utils';
15
+ import { z } from 'zod/v4';
16
+ import type { GatewayConfig } from './gateway-config';
17
+ import { asGatewayError } from './errors';
18
+ import { parseAuthMethod } from './errors/parse-auth-method';
19
+
20
+ export class GatewayImageModel implements ImageModelV3 {
21
+ readonly specificationVersion = 'v3' as const;
22
+ // Set a very large number to prevent client-side splitting of requests
23
+ readonly maxImagesPerCall = Number.MAX_SAFE_INTEGER;
24
+
25
+ constructor(
26
+ readonly modelId: string,
27
+ private readonly config: GatewayConfig & {
28
+ provider: string;
29
+ o11yHeaders: Resolvable<Record<string, string>>;
30
+ },
31
+ ) {}
32
+
33
+ get provider(): string {
34
+ return this.config.provider;
35
+ }
36
+
37
+ async doGenerate({
38
+ prompt,
39
+ n,
40
+ size,
41
+ aspectRatio,
42
+ seed,
43
+ files,
44
+ mask,
45
+ providerOptions,
46
+ headers,
47
+ abortSignal,
48
+ }: Parameters<ImageModelV3['doGenerate']>[0]): Promise<
49
+ Awaited<ReturnType<ImageModelV3['doGenerate']>>
50
+ > {
51
+ const resolvedHeaders = await resolve(this.config.headers());
52
+ try {
53
+ const {
54
+ responseHeaders,
55
+ value: responseBody,
56
+ rawValue,
57
+ } = await postJsonToApi({
58
+ url: this.getUrl(),
59
+ headers: combineHeaders(
60
+ resolvedHeaders,
61
+ headers ?? {},
62
+ this.getModelConfigHeaders(),
63
+ await resolve(this.config.o11yHeaders),
64
+ ),
65
+ body: {
66
+ prompt,
67
+ n,
68
+ ...(size && { size }),
69
+ ...(aspectRatio && { aspectRatio }),
70
+ ...(seed && { seed }),
71
+ ...(providerOptions && { providerOptions }),
72
+ ...(files && {
73
+ files: files.map(file => maybeEncodeImageFile(file)),
74
+ }),
75
+ ...(mask && { mask: maybeEncodeImageFile(mask) }),
76
+ },
77
+ successfulResponseHandler: createJsonResponseHandler(
78
+ gatewayImageResponseSchema,
79
+ ),
80
+ failedResponseHandler: createJsonErrorResponseHandler({
81
+ errorSchema: z.any(),
82
+ errorToMessage: data => data,
83
+ }),
84
+ ...(abortSignal && { abortSignal }),
85
+ fetch: this.config.fetch,
86
+ });
87
+
88
+ return {
89
+ images: responseBody.images, // Always base64 strings from server
90
+ warnings: responseBody.warnings ?? [],
91
+ providerMetadata:
92
+ responseBody.providerMetadata as ImageModelV3ProviderMetadata,
93
+ response: {
94
+ timestamp: new Date(),
95
+ modelId: this.modelId,
96
+ headers: responseHeaders,
97
+ },
98
+ };
99
+ } catch (error) {
100
+ throw asGatewayError(error, await parseAuthMethod(resolvedHeaders));
101
+ }
102
+ }
103
+
104
+ private getUrl() {
105
+ return `${this.config.baseURL}/image-model`;
106
+ }
107
+
108
+ private getModelConfigHeaders() {
109
+ return {
110
+ 'ai-image-model-specification-version': '3',
111
+ 'ai-model-id': this.modelId,
112
+ };
113
+ }
114
+ }
115
+
116
+ function maybeEncodeImageFile(file: ImageModelV3File) {
117
+ if (file.type === 'file' && file.data instanceof Uint8Array) {
118
+ return {
119
+ ...file,
120
+ data: convertUint8ArrayToBase64(file.data),
121
+ };
122
+ }
123
+ return file;
124
+ }
125
+
126
+ const providerMetadataEntrySchema = z
127
+ .object({
128
+ images: z.array(z.unknown()).optional(),
129
+ })
130
+ .catchall(z.unknown());
131
+
132
+ const gatewayImageResponseSchema = z.object({
133
+ images: z.array(z.string()), // Always base64 strings over the wire
134
+ warnings: z
135
+ .array(
136
+ z.object({
137
+ type: z.literal('other'),
138
+ message: z.string(),
139
+ }),
140
+ )
141
+ .optional(),
142
+ providerMetadata: z
143
+ .record(z.string(), providerMetadataEntrySchema)
144
+ .optional(),
145
+ });
@@ -0,0 +1,159 @@
1
+ export type GatewayModelId =
2
+ | 'alibaba/qwen-3-14b'
3
+ | 'alibaba/qwen-3-235b'
4
+ | 'alibaba/qwen-3-30b'
5
+ | 'alibaba/qwen-3-32b'
6
+ | 'alibaba/qwen3-235b-a22b-thinking'
7
+ | 'alibaba/qwen3-coder'
8
+ | 'alibaba/qwen3-coder-30b-a3b'
9
+ | 'alibaba/qwen3-coder-plus'
10
+ | 'alibaba/qwen3-max'
11
+ | 'alibaba/qwen3-max-preview'
12
+ | 'alibaba/qwen3-next-80b-a3b-instruct'
13
+ | 'alibaba/qwen3-next-80b-a3b-thinking'
14
+ | 'alibaba/qwen3-vl-instruct'
15
+ | 'alibaba/qwen3-vl-thinking'
16
+ | 'amazon/nova-2-lite'
17
+ | 'amazon/nova-lite'
18
+ | 'amazon/nova-micro'
19
+ | 'amazon/nova-pro'
20
+ | 'anthropic/claude-3-haiku'
21
+ | 'anthropic/claude-3-opus'
22
+ | 'anthropic/claude-3.5-haiku'
23
+ | 'anthropic/claude-3.5-sonnet'
24
+ | 'anthropic/claude-3.5-sonnet-20240620'
25
+ | 'anthropic/claude-3.7-sonnet'
26
+ | 'anthropic/claude-haiku-4.5'
27
+ | 'anthropic/claude-opus-4'
28
+ | 'anthropic/claude-opus-4.1'
29
+ | 'anthropic/claude-opus-4.5'
30
+ | 'anthropic/claude-sonnet-4'
31
+ | 'anthropic/claude-sonnet-4.5'
32
+ | 'arcee-ai/trinity-mini'
33
+ | 'bytedance/seed-1.6'
34
+ | 'bytedance/seed-1.8'
35
+ | 'cohere/command-a'
36
+ | 'deepseek/deepseek-r1'
37
+ | 'deepseek/deepseek-v3'
38
+ | 'deepseek/deepseek-v3.1'
39
+ | 'deepseek/deepseek-v3.1-terminus'
40
+ | 'deepseek/deepseek-v3.2'
41
+ | 'deepseek/deepseek-v3.2-exp'
42
+ | 'deepseek/deepseek-v3.2-thinking'
43
+ | 'google/gemini-2.0-flash'
44
+ | 'google/gemini-2.0-flash-lite'
45
+ | 'google/gemini-2.5-flash'
46
+ | 'google/gemini-2.5-flash-image'
47
+ | 'google/gemini-2.5-flash-image-preview'
48
+ | 'google/gemini-2.5-flash-lite'
49
+ | 'google/gemini-2.5-flash-lite-preview-09-2025'
50
+ | 'google/gemini-2.5-flash-preview-09-2025'
51
+ | 'google/gemini-2.5-pro'
52
+ | 'google/gemini-3-flash'
53
+ | 'google/gemini-3-pro-image'
54
+ | 'google/gemini-3-pro-preview'
55
+ | 'inception/mercury-coder-small'
56
+ | 'kwaipilot/kat-coder-pro-v1'
57
+ | 'meituan/longcat-flash-chat'
58
+ | 'meituan/longcat-flash-thinking'
59
+ | 'meta/llama-3.1-70b'
60
+ | 'meta/llama-3.1-8b'
61
+ | 'meta/llama-3.2-11b'
62
+ | 'meta/llama-3.2-1b'
63
+ | 'meta/llama-3.2-3b'
64
+ | 'meta/llama-3.2-90b'
65
+ | 'meta/llama-3.3-70b'
66
+ | 'meta/llama-4-maverick'
67
+ | 'meta/llama-4-scout'
68
+ | 'minimax/minimax-m2'
69
+ | 'minimax/minimax-m2.1'
70
+ | 'minimax/minimax-m2.1-lightning'
71
+ | 'mistral/codestral'
72
+ | 'mistral/devstral-2'
73
+ | 'mistral/devstral-small'
74
+ | 'mistral/devstral-small-2'
75
+ | 'mistral/magistral-medium'
76
+ | 'mistral/magistral-small'
77
+ | 'mistral/ministral-14b'
78
+ | 'mistral/ministral-3b'
79
+ | 'mistral/ministral-8b'
80
+ | 'mistral/mistral-large-3'
81
+ | 'mistral/mistral-medium'
82
+ | 'mistral/mistral-nemo'
83
+ | 'mistral/mistral-small'
84
+ | 'mistral/mixtral-8x22b-instruct'
85
+ | 'mistral/pixtral-12b'
86
+ | 'mistral/pixtral-large'
87
+ | 'moonshotai/kimi-k2'
88
+ | 'moonshotai/kimi-k2-0905'
89
+ | 'moonshotai/kimi-k2-thinking'
90
+ | 'moonshotai/kimi-k2-thinking-turbo'
91
+ | 'moonshotai/kimi-k2-turbo'
92
+ | 'morph/morph-v3-fast'
93
+ | 'morph/morph-v3-large'
94
+ | 'nvidia/nemotron-3-nano-30b-a3b'
95
+ | 'nvidia/nemotron-nano-12b-v2-vl'
96
+ | 'nvidia/nemotron-nano-9b-v2'
97
+ | 'openai/codex-mini'
98
+ | 'openai/gpt-3.5-turbo'
99
+ | 'openai/gpt-3.5-turbo-instruct'
100
+ | 'openai/gpt-4-turbo'
101
+ | 'openai/gpt-4.1'
102
+ | 'openai/gpt-4.1-mini'
103
+ | 'openai/gpt-4.1-nano'
104
+ | 'openai/gpt-4o'
105
+ | 'openai/gpt-4o-mini'
106
+ | 'openai/gpt-5'
107
+ | 'openai/gpt-5-chat'
108
+ | 'openai/gpt-5-codex'
109
+ | 'openai/gpt-5-mini'
110
+ | 'openai/gpt-5-nano'
111
+ | 'openai/gpt-5-pro'
112
+ | 'openai/gpt-5.1-codex'
113
+ | 'openai/gpt-5.1-codex-max'
114
+ | 'openai/gpt-5.1-codex-mini'
115
+ | 'openai/gpt-5.1-instant'
116
+ | 'openai/gpt-5.1-thinking'
117
+ | 'openai/gpt-5.2'
118
+ | 'openai/gpt-5.2-chat'
119
+ | 'openai/gpt-5.2-codex'
120
+ | 'openai/gpt-5.2-pro'
121
+ | 'openai/gpt-oss-120b'
122
+ | 'openai/gpt-oss-20b'
123
+ | 'openai/gpt-oss-safeguard-20b'
124
+ | 'openai/o1'
125
+ | 'openai/o3'
126
+ | 'openai/o3-deep-research'
127
+ | 'openai/o3-mini'
128
+ | 'openai/o3-pro'
129
+ | 'openai/o4-mini'
130
+ | 'perplexity/sonar'
131
+ | 'perplexity/sonar-pro'
132
+ | 'perplexity/sonar-reasoning'
133
+ | 'perplexity/sonar-reasoning-pro'
134
+ | 'prime-intellect/intellect-3'
135
+ | 'stealth/sonoma-dusk-alpha'
136
+ | 'stealth/sonoma-sky-alpha'
137
+ | 'vercel/v0-1.0-md'
138
+ | 'vercel/v0-1.5-md'
139
+ | 'xai/grok-2-vision'
140
+ | 'xai/grok-3'
141
+ | 'xai/grok-3-fast'
142
+ | 'xai/grok-3-mini'
143
+ | 'xai/grok-3-mini-fast'
144
+ | 'xai/grok-4'
145
+ | 'xai/grok-4-fast-non-reasoning'
146
+ | 'xai/grok-4-fast-reasoning'
147
+ | 'xai/grok-4.1-fast-non-reasoning'
148
+ | 'xai/grok-4.1-fast-reasoning'
149
+ | 'xai/grok-code-fast-1'
150
+ | 'xiaomi/mimo-v2-flash'
151
+ | 'zai/glm-4.5'
152
+ | 'zai/glm-4.5-air'
153
+ | 'zai/glm-4.5v'
154
+ | 'zai/glm-4.6'
155
+ | 'zai/glm-4.6v'
156
+ | 'zai/glm-4.6v-flash'
157
+ | 'zai/glm-4.7'
158
+ | 'zai/glm-4.7-flashx'
159
+ | (string & {});
@@ -0,0 +1,212 @@
1
+ import type {
2
+ LanguageModelV3,
3
+ LanguageModelV3CallOptions,
4
+ SharedV3Warning,
5
+ LanguageModelV3FilePart,
6
+ LanguageModelV3StreamPart,
7
+ LanguageModelV3GenerateResult,
8
+ LanguageModelV3StreamResult,
9
+ } from '@ai-sdk/provider';
10
+ import {
11
+ combineHeaders,
12
+ createEventSourceResponseHandler,
13
+ createJsonErrorResponseHandler,
14
+ createJsonResponseHandler,
15
+ postJsonToApi,
16
+ resolve,
17
+ type ParseResult,
18
+ type Resolvable,
19
+ } from '@ai-sdk/provider-utils';
20
+ import { z } from 'zod/v4';
21
+ import type { GatewayConfig } from './gateway-config';
22
+ import type { GatewayModelId } from './gateway-language-model-settings';
23
+ import { asGatewayError } from './errors';
24
+ import { parseAuthMethod } from './errors/parse-auth-method';
25
+
26
+ type GatewayChatConfig = GatewayConfig & {
27
+ provider: string;
28
+ o11yHeaders: Resolvable<Record<string, string>>;
29
+ };
30
+
31
+ export class GatewayLanguageModel implements LanguageModelV3 {
32
+ readonly specificationVersion = 'v3';
33
+ readonly supportedUrls = { '*/*': [/.*/] };
34
+
35
+ constructor(
36
+ readonly modelId: GatewayModelId,
37
+ private readonly config: GatewayChatConfig,
38
+ ) {}
39
+
40
+ get provider(): string {
41
+ return this.config.provider;
42
+ }
43
+
44
+ private async getArgs(options: LanguageModelV3CallOptions) {
45
+ const { abortSignal: _abortSignal, ...optionsWithoutSignal } = options;
46
+
47
+ return {
48
+ args: this.maybeEncodeFileParts(optionsWithoutSignal),
49
+ warnings: [],
50
+ };
51
+ }
52
+
53
+ async doGenerate(
54
+ options: LanguageModelV3CallOptions,
55
+ ): Promise<LanguageModelV3GenerateResult> {
56
+ const { args, warnings } = await this.getArgs(options);
57
+ const { abortSignal } = options;
58
+
59
+ const resolvedHeaders = await resolve(this.config.headers());
60
+
61
+ try {
62
+ const {
63
+ responseHeaders,
64
+ value: responseBody,
65
+ rawValue: rawResponse,
66
+ } = await postJsonToApi({
67
+ url: this.getUrl(),
68
+ headers: combineHeaders(
69
+ resolvedHeaders,
70
+ options.headers,
71
+ this.getModelConfigHeaders(this.modelId, false),
72
+ await resolve(this.config.o11yHeaders),
73
+ ),
74
+ body: args,
75
+ successfulResponseHandler: createJsonResponseHandler(z.any()),
76
+ failedResponseHandler: createJsonErrorResponseHandler({
77
+ errorSchema: z.any(),
78
+ errorToMessage: data => data,
79
+ }),
80
+ ...(abortSignal && { abortSignal }),
81
+ fetch: this.config.fetch,
82
+ });
83
+
84
+ return {
85
+ ...responseBody,
86
+ request: { body: args },
87
+ response: { headers: responseHeaders, body: rawResponse },
88
+ warnings,
89
+ };
90
+ } catch (error) {
91
+ throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
92
+ }
93
+ }
94
+
95
+ async doStream(
96
+ options: LanguageModelV3CallOptions,
97
+ ): Promise<LanguageModelV3StreamResult> {
98
+ const { args, warnings } = await this.getArgs(options);
99
+ const { abortSignal } = options;
100
+
101
+ const resolvedHeaders = await resolve(this.config.headers());
102
+
103
+ try {
104
+ const { value: response, responseHeaders } = await postJsonToApi({
105
+ url: this.getUrl(),
106
+ headers: combineHeaders(
107
+ resolvedHeaders,
108
+ options.headers,
109
+ this.getModelConfigHeaders(this.modelId, true),
110
+ await resolve(this.config.o11yHeaders),
111
+ ),
112
+ body: args,
113
+ successfulResponseHandler: createEventSourceResponseHandler(z.any()),
114
+ failedResponseHandler: createJsonErrorResponseHandler({
115
+ errorSchema: z.any(),
116
+ errorToMessage: data => data,
117
+ }),
118
+ ...(abortSignal && { abortSignal }),
119
+ fetch: this.config.fetch,
120
+ });
121
+
122
+ return {
123
+ stream: response.pipeThrough(
124
+ new TransformStream<
125
+ ParseResult<LanguageModelV3StreamPart>,
126
+ LanguageModelV3StreamPart
127
+ >({
128
+ start(controller) {
129
+ if (warnings.length > 0) {
130
+ controller.enqueue({ type: 'stream-start', warnings });
131
+ }
132
+ },
133
+ transform(chunk, controller) {
134
+ if (chunk.success) {
135
+ const streamPart = chunk.value;
136
+
137
+ // Handle raw chunks: if this is a raw chunk from the gateway API,
138
+ // only emit it if includeRawChunks is true
139
+ if (streamPart.type === 'raw' && !options.includeRawChunks) {
140
+ return; // Skip raw chunks if not requested
141
+ }
142
+
143
+ if (
144
+ streamPart.type === 'response-metadata' &&
145
+ streamPart.timestamp &&
146
+ typeof streamPart.timestamp === 'string'
147
+ ) {
148
+ streamPart.timestamp = new Date(streamPart.timestamp);
149
+ }
150
+
151
+ controller.enqueue(streamPart);
152
+ } else {
153
+ controller.error(
154
+ (chunk as { success: false; error: unknown }).error,
155
+ );
156
+ }
157
+ },
158
+ }),
159
+ ),
160
+ request: { body: args },
161
+ response: { headers: responseHeaders },
162
+ };
163
+ } catch (error) {
164
+ throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
165
+ }
166
+ }
167
+
168
+ private isFilePart(part: unknown) {
169
+ return (
170
+ part && typeof part === 'object' && 'type' in part && part.type === 'file'
171
+ );
172
+ }
173
+
174
+ /**
175
+ * Encodes file parts in the prompt to base64. Mutates the passed options
176
+ * instance directly to avoid copying the file data.
177
+ * @param options - The options to encode.
178
+ * @returns The options with the file parts encoded.
179
+ */
180
+ private maybeEncodeFileParts(options: LanguageModelV3CallOptions) {
181
+ for (const message of options.prompt) {
182
+ for (const part of message.content) {
183
+ if (this.isFilePart(part)) {
184
+ const filePart = part as LanguageModelV3FilePart;
185
+ // If the file part is a URL it will get cleanly converted to a string.
186
+ // If it's a binary file attachment we convert it to a data url.
187
+ // In either case, server-side we should only ever see URLs as strings.
188
+ if (filePart.data instanceof Uint8Array) {
189
+ const buffer = Uint8Array.from(filePart.data);
190
+ const base64Data = Buffer.from(buffer).toString('base64');
191
+ filePart.data = new URL(
192
+ `data:${filePart.mediaType || 'application/octet-stream'};base64,${base64Data}`,
193
+ );
194
+ }
195
+ }
196
+ }
197
+ }
198
+ return options;
199
+ }
200
+
201
+ private getUrl() {
202
+ return `${this.config.baseURL}/language-model`;
203
+ }
204
+
205
+ private getModelConfigHeaders(modelId: string, streaming: boolean) {
206
+ return {
207
+ 'ai-language-model-specification-version': '3',
208
+ 'ai-language-model-id': modelId,
209
+ 'ai-language-model-streaming': String(streaming),
210
+ };
211
+ }
212
+ }