@tanstack/ai-llmgateway 0.0.0

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.
@@ -0,0 +1,516 @@
1
+ import type { LLMGatewayTextProviderOptions } from './text/text-provider-options'
2
+
3
+ /**
4
+ * Internal metadata structure describing an LLM Gateway model's capabilities
5
+ * and pricing.
6
+ *
7
+ * LLM Gateway routes hundreds of models from many providers through one
8
+ * OpenAI-compatible endpoint. This file curates a set of flagship models
9
+ * with per-model metadata for type safety; any model listed on
10
+ * https://llmgateway.io/models works at runtime — pass its id with a type
11
+ * assertion, or prefer a curated model for full type support. Prices are
12
+ * USD per million tokens and follow the gateway's provider-passthrough
13
+ * pricing (they may drift; the models page is the source of truth).
14
+ *
15
+ * Model ids accept an optional `provider/` prefix (e.g. `openai/gpt-5.5`)
16
+ * to pin routing to a specific provider — the unprefixed ids below let the
17
+ * gateway pick the best available provider.
18
+ */
19
+ interface ModelMeta<TProviderOptions = unknown> {
20
+ name: string
21
+ context_window?: number
22
+ max_completion_tokens?: number
23
+ pricing: {
24
+ input?: { normal: number; cached?: number }
25
+ output?: { normal: number }
26
+ }
27
+ supports: {
28
+ input: Array<'text' | 'image' | 'audio'>
29
+ output: Array<'text'>
30
+ endpoints: Array<'chat'>
31
+ features: Array<
32
+ | 'streaming'
33
+ | 'tools'
34
+ | 'json_object'
35
+ | 'json_schema'
36
+ | 'reasoning'
37
+ | 'vision'
38
+ >
39
+ tools?: ReadonlyArray<never>
40
+ }
41
+ /**
42
+ * Type-level description of which provider options this model supports.
43
+ */
44
+ providerOptions?: TProviderOptions
45
+ }
46
+
47
+ const GPT_5_6_TERRA = {
48
+ name: 'gpt-5.6-terra',
49
+ context_window: 1_050_000,
50
+ max_completion_tokens: 128_000,
51
+ pricing: {
52
+ input: {
53
+ normal: 2.5,
54
+ cached: 0.25,
55
+ },
56
+ output: {
57
+ normal: 15,
58
+ },
59
+ },
60
+ supports: {
61
+ input: ['text', 'image'],
62
+ output: ['text'],
63
+ endpoints: ['chat'],
64
+ features: [
65
+ 'streaming',
66
+ 'tools',
67
+ 'json_object',
68
+ 'json_schema',
69
+ 'reasoning',
70
+ 'vision',
71
+ ],
72
+ tools: [] as const,
73
+ },
74
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
75
+
76
+ const GPT_5_5 = {
77
+ name: 'gpt-5.5',
78
+ context_window: 1_050_000,
79
+ max_completion_tokens: 128_000,
80
+ pricing: {
81
+ input: {
82
+ normal: 5,
83
+ cached: 0.5,
84
+ },
85
+ output: {
86
+ normal: 30,
87
+ },
88
+ },
89
+ supports: {
90
+ input: ['text', 'image'],
91
+ output: ['text'],
92
+ endpoints: ['chat'],
93
+ features: [
94
+ 'streaming',
95
+ 'tools',
96
+ 'json_object',
97
+ 'json_schema',
98
+ 'reasoning',
99
+ 'vision',
100
+ ],
101
+ tools: [] as const,
102
+ },
103
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
104
+
105
+ const GPT_5_4_MINI = {
106
+ name: 'gpt-5.4-mini',
107
+ context_window: 400_000,
108
+ max_completion_tokens: 128_000,
109
+ pricing: {
110
+ input: {
111
+ normal: 0.75,
112
+ cached: 0.075,
113
+ },
114
+ output: {
115
+ normal: 4.5,
116
+ },
117
+ },
118
+ supports: {
119
+ input: ['text', 'image'],
120
+ output: ['text'],
121
+ endpoints: ['chat'],
122
+ features: [
123
+ 'streaming',
124
+ 'tools',
125
+ 'json_object',
126
+ 'json_schema',
127
+ 'reasoning',
128
+ 'vision',
129
+ ],
130
+ tools: [] as const,
131
+ },
132
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
133
+
134
+ const CLAUDE_OPUS_5 = {
135
+ name: 'claude-opus-5',
136
+ context_window: 1_000_000,
137
+ max_completion_tokens: 128_000,
138
+ pricing: {
139
+ input: {
140
+ normal: 5,
141
+ cached: 0.5,
142
+ },
143
+ output: {
144
+ normal: 25,
145
+ },
146
+ },
147
+ supports: {
148
+ input: ['text', 'image'],
149
+ output: ['text'],
150
+ endpoints: ['chat'],
151
+ features: ['streaming', 'tools', 'reasoning', 'vision'],
152
+ tools: [] as const,
153
+ },
154
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
155
+
156
+ const CLAUDE_SONNET_5 = {
157
+ name: 'claude-sonnet-5',
158
+ context_window: 1_000_000,
159
+ max_completion_tokens: 128_000,
160
+ pricing: {
161
+ input: {
162
+ normal: 2,
163
+ cached: 0.2,
164
+ },
165
+ output: {
166
+ normal: 10,
167
+ },
168
+ },
169
+ supports: {
170
+ input: ['text', 'image'],
171
+ output: ['text'],
172
+ endpoints: ['chat'],
173
+ features: ['streaming', 'tools', 'reasoning', 'vision'],
174
+ tools: [] as const,
175
+ },
176
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
177
+
178
+ const CLAUDE_HAIKU_4_5 = {
179
+ name: 'claude-haiku-4-5',
180
+ context_window: 200_000,
181
+ max_completion_tokens: 64_000,
182
+ pricing: {
183
+ input: {
184
+ normal: 1,
185
+ cached: 0.1,
186
+ },
187
+ output: {
188
+ normal: 5,
189
+ },
190
+ },
191
+ supports: {
192
+ input: ['text', 'image'],
193
+ output: ['text'],
194
+ endpoints: ['chat'],
195
+ features: [
196
+ 'streaming',
197
+ 'tools',
198
+ 'json_object',
199
+ 'json_schema',
200
+ 'reasoning',
201
+ 'vision',
202
+ ],
203
+ tools: [] as const,
204
+ },
205
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
206
+
207
+ const GEMINI_PRO_LATEST = {
208
+ name: 'gemini-pro-latest',
209
+ context_window: 1_048_576,
210
+ max_completion_tokens: 65_536,
211
+ pricing: {
212
+ input: {
213
+ normal: 2,
214
+ cached: 0.2,
215
+ },
216
+ output: {
217
+ normal: 12,
218
+ },
219
+ },
220
+ supports: {
221
+ input: ['text', 'image'],
222
+ output: ['text'],
223
+ endpoints: ['chat'],
224
+ features: [
225
+ 'streaming',
226
+ 'tools',
227
+ 'json_object',
228
+ 'json_schema',
229
+ 'reasoning',
230
+ 'vision',
231
+ ],
232
+ tools: [] as const,
233
+ },
234
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
235
+
236
+ const GEMINI_3_6_FLASH = {
237
+ name: 'gemini-3.6-flash',
238
+ context_window: 1_048_576,
239
+ max_completion_tokens: 65_536,
240
+ pricing: {
241
+ input: {
242
+ normal: 1.5,
243
+ cached: 0.15,
244
+ },
245
+ output: {
246
+ normal: 7.5,
247
+ },
248
+ },
249
+ supports: {
250
+ input: ['text', 'image'],
251
+ output: ['text'],
252
+ endpoints: ['chat'],
253
+ features: [
254
+ 'streaming',
255
+ 'tools',
256
+ 'json_object',
257
+ 'json_schema',
258
+ 'reasoning',
259
+ 'vision',
260
+ ],
261
+ tools: [] as const,
262
+ },
263
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
264
+
265
+ const KIMI_K3 = {
266
+ name: 'kimi-k3',
267
+ context_window: 1_048_576,
268
+ max_completion_tokens: 1_048_576,
269
+ pricing: {
270
+ input: {
271
+ normal: 3,
272
+ cached: 0.3,
273
+ },
274
+ output: {
275
+ normal: 15,
276
+ },
277
+ },
278
+ supports: {
279
+ input: ['text', 'image'],
280
+ output: ['text'],
281
+ endpoints: ['chat'],
282
+ features: [
283
+ 'streaming',
284
+ 'tools',
285
+ 'json_object',
286
+ 'json_schema',
287
+ 'reasoning',
288
+ 'vision',
289
+ ],
290
+ tools: [] as const,
291
+ },
292
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
293
+
294
+ const GLM_5_2 = {
295
+ name: 'glm-5.2',
296
+ context_window: 1_000_000,
297
+ max_completion_tokens: 128_000,
298
+ pricing: {
299
+ input: {
300
+ normal: 1.4,
301
+ cached: 0.26,
302
+ },
303
+ output: {
304
+ normal: 4.4,
305
+ },
306
+ },
307
+ supports: {
308
+ input: ['text'],
309
+ output: ['text'],
310
+ endpoints: ['chat'],
311
+ features: ['streaming', 'tools', 'json_object', 'json_schema', 'reasoning'],
312
+ tools: [] as const,
313
+ },
314
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
315
+
316
+ const DEEPSEEK_V4_PRO = {
317
+ name: 'deepseek-v4-pro',
318
+ context_window: 1_050_000,
319
+ max_completion_tokens: 393_216,
320
+ pricing: {
321
+ input: {
322
+ normal: 0.435,
323
+ },
324
+ output: {
325
+ normal: 0.87,
326
+ },
327
+ },
328
+ supports: {
329
+ input: ['text'],
330
+ output: ['text'],
331
+ endpoints: ['chat'],
332
+ features: ['streaming', 'tools', 'json_object', 'json_schema', 'reasoning'],
333
+ tools: [] as const,
334
+ },
335
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
336
+
337
+ const QWEN_3_7_MAX = {
338
+ name: 'qwen3.7-max',
339
+ context_window: 1_000_000,
340
+ max_completion_tokens: 65_536,
341
+ pricing: {
342
+ input: {
343
+ normal: 2.5,
344
+ cached: 0.5,
345
+ },
346
+ output: {
347
+ normal: 7.5,
348
+ },
349
+ },
350
+ supports: {
351
+ input: ['text'],
352
+ output: ['text'],
353
+ endpoints: ['chat'],
354
+ features: ['streaming', 'tools', 'json_object', 'json_schema', 'reasoning'],
355
+ tools: [] as const,
356
+ },
357
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
358
+
359
+ const MINIMAX_M2_5 = {
360
+ name: 'minimax-m2.5',
361
+ context_window: 204_800,
362
+ max_completion_tokens: 131_100,
363
+ pricing: {
364
+ input: {
365
+ normal: 0.3,
366
+ cached: 0.03,
367
+ },
368
+ output: {
369
+ normal: 1.2,
370
+ },
371
+ },
372
+ supports: {
373
+ input: ['text'],
374
+ output: ['text'],
375
+ endpoints: ['chat'],
376
+ features: ['streaming', 'tools', 'reasoning'],
377
+ tools: [] as const,
378
+ },
379
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
380
+
381
+ const GROK_4_5 = {
382
+ name: 'grok-4-5',
383
+ context_window: 500_000,
384
+ pricing: {
385
+ input: {
386
+ normal: 2,
387
+ cached: 0.5,
388
+ },
389
+ output: {
390
+ normal: 6,
391
+ },
392
+ },
393
+ supports: {
394
+ input: ['text', 'image'],
395
+ output: ['text'],
396
+ endpoints: ['chat'],
397
+ features: [
398
+ 'streaming',
399
+ 'tools',
400
+ 'json_object',
401
+ 'json_schema',
402
+ 'reasoning',
403
+ 'vision',
404
+ ],
405
+ tools: [] as const,
406
+ },
407
+ } as const satisfies ModelMeta<LLMGatewayTextProviderOptions>
408
+
409
+ /**
410
+ * Curated LLM Gateway chat model identifiers.
411
+ *
412
+ * Any model on https://llmgateway.io/models works at runtime; these curated
413
+ * entries carry per-model type metadata (input modalities, provider
414
+ * options).
415
+ */
416
+ export const LLMGATEWAY_CHAT_MODELS = [
417
+ GPT_5_6_TERRA.name,
418
+ GPT_5_5.name,
419
+ GPT_5_4_MINI.name,
420
+ CLAUDE_OPUS_5.name,
421
+ CLAUDE_SONNET_5.name,
422
+ CLAUDE_HAIKU_4_5.name,
423
+ GEMINI_PRO_LATEST.name,
424
+ GEMINI_3_6_FLASH.name,
425
+ KIMI_K3.name,
426
+ GLM_5_2.name,
427
+ DEEPSEEK_V4_PRO.name,
428
+ QWEN_3_7_MAX.name,
429
+ MINIMAX_M2_5.name,
430
+ GROK_4_5.name,
431
+ ] as const
432
+
433
+ /**
434
+ * Union type of all curated LLM Gateway chat model names.
435
+ */
436
+ export type LLMGatewayChatModels = (typeof LLMGATEWAY_CHAT_MODELS)[number]
437
+
438
+ /**
439
+ * Model id accepted by the LLM Gateway adapters: a curated model name (with
440
+ * autocomplete and per-model type metadata) or any other model id from
441
+ * https://llmgateway.io/models, optionally prefixed with `provider/` to pin
442
+ * routing to a specific provider. Uncurated ids fall back to text-only
443
+ * input and the generic provider options.
444
+ */
445
+ export type LLMGatewayModelId = LLMGatewayChatModels | (string & {})
446
+
447
+ /**
448
+ * Type-only map from LLM Gateway chat model name to its supported input
449
+ * modalities.
450
+ */
451
+ export type LLMGatewayModelInputModalitiesByName = {
452
+ [GPT_5_6_TERRA.name]: typeof GPT_5_6_TERRA.supports.input
453
+ [GPT_5_5.name]: typeof GPT_5_5.supports.input
454
+ [GPT_5_4_MINI.name]: typeof GPT_5_4_MINI.supports.input
455
+ [CLAUDE_OPUS_5.name]: typeof CLAUDE_OPUS_5.supports.input
456
+ [CLAUDE_SONNET_5.name]: typeof CLAUDE_SONNET_5.supports.input
457
+ [CLAUDE_HAIKU_4_5.name]: typeof CLAUDE_HAIKU_4_5.supports.input
458
+ [GEMINI_PRO_LATEST.name]: typeof GEMINI_PRO_LATEST.supports.input
459
+ [GEMINI_3_6_FLASH.name]: typeof GEMINI_3_6_FLASH.supports.input
460
+ [KIMI_K3.name]: typeof KIMI_K3.supports.input
461
+ [GLM_5_2.name]: typeof GLM_5_2.supports.input
462
+ [DEEPSEEK_V4_PRO.name]: typeof DEEPSEEK_V4_PRO.supports.input
463
+ [QWEN_3_7_MAX.name]: typeof QWEN_3_7_MAX.supports.input
464
+ [MINIMAX_M2_5.name]: typeof MINIMAX_M2_5.supports.input
465
+ [GROK_4_5.name]: typeof GROK_4_5.supports.input
466
+ }
467
+
468
+ /**
469
+ * Type-only map from LLM Gateway chat model name to its provider options
470
+ * type.
471
+ */
472
+ export type LLMGatewayChatModelProviderOptionsByName = {
473
+ [K in (typeof LLMGATEWAY_CHAT_MODELS)[number]]: LLMGatewayTextProviderOptions
474
+ }
475
+
476
+ /**
477
+ * Type-only map from LLM Gateway chat model name to its supported provider
478
+ * tools. LLM Gateway exposes no provider-specific tool factories, so every
479
+ * model gets an empty tuple. This ensures that passing an Anthropic/OpenAI
480
+ * ProviderTool to an LLM Gateway adapter produces a compile-time type error.
481
+ */
482
+ export type LLMGatewayChatModelToolCapabilitiesByName = {
483
+ [GPT_5_6_TERRA.name]: typeof GPT_5_6_TERRA.supports.tools
484
+ [GPT_5_5.name]: typeof GPT_5_5.supports.tools
485
+ [GPT_5_4_MINI.name]: typeof GPT_5_4_MINI.supports.tools
486
+ [CLAUDE_OPUS_5.name]: typeof CLAUDE_OPUS_5.supports.tools
487
+ [CLAUDE_SONNET_5.name]: typeof CLAUDE_SONNET_5.supports.tools
488
+ [CLAUDE_HAIKU_4_5.name]: typeof CLAUDE_HAIKU_4_5.supports.tools
489
+ [GEMINI_PRO_LATEST.name]: typeof GEMINI_PRO_LATEST.supports.tools
490
+ [GEMINI_3_6_FLASH.name]: typeof GEMINI_3_6_FLASH.supports.tools
491
+ [KIMI_K3.name]: typeof KIMI_K3.supports.tools
492
+ [GLM_5_2.name]: typeof GLM_5_2.supports.tools
493
+ [DEEPSEEK_V4_PRO.name]: typeof DEEPSEEK_V4_PRO.supports.tools
494
+ [QWEN_3_7_MAX.name]: typeof QWEN_3_7_MAX.supports.tools
495
+ [MINIMAX_M2_5.name]: typeof MINIMAX_M2_5.supports.tools
496
+ [GROK_4_5.name]: typeof GROK_4_5.supports.tools
497
+ }
498
+
499
+ /**
500
+ * Resolves the provider options type for a specific LLM Gateway model.
501
+ * Falls back to the generic options for uncurated model ids.
502
+ */
503
+ export type ResolveProviderOptions<TModel extends string> =
504
+ TModel extends keyof LLMGatewayChatModelProviderOptionsByName
505
+ ? LLMGatewayChatModelProviderOptionsByName[TModel]
506
+ : LLMGatewayTextProviderOptions
507
+
508
+ /**
509
+ * Resolve input modalities for a specific model.
510
+ * If the model has explicit modalities in the map, use those; otherwise use
511
+ * text only.
512
+ */
513
+ export type ResolveInputModalities<TModel extends string> =
514
+ TModel extends keyof LLMGatewayModelInputModalitiesByName
515
+ ? LLMGatewayModelInputModalitiesByName[TModel]
516
+ : readonly ['text']
@@ -0,0 +1,128 @@
1
+ import type {
2
+ ChatCompletionToolChoiceOption,
3
+ ResponseFormatJsonObject,
4
+ ResponseFormatJsonSchema,
5
+ ResponseFormatText,
6
+ } from '../message-types'
7
+
8
+ /**
9
+ * LLM Gateway provider options for text/chat models.
10
+ *
11
+ * LLM Gateway exposes the OpenAI Chat Completions wire format and routes
12
+ * each request to the underlying provider, so these are the standard Chat
13
+ * Completions parameters. Parameters a routed provider doesn't support are
14
+ * stripped by the gateway before the request is forwarded upstream.
15
+ *
16
+ * @see https://docs.llmgateway.io
17
+ */
18
+ export interface LLMGatewayTextProviderOptions {
19
+ /**
20
+ * Number between -2.0 and 2.0. Positive values penalize new tokens based on
21
+ * their existing frequency in the text so far, decreasing the model's
22
+ * likelihood to repeat the same line verbatim.
23
+ */
24
+ frequency_penalty?: number | null
25
+
26
+ /**
27
+ * The maximum number of tokens that can be generated in the chat
28
+ * completion. Deprecated by OpenAI in favor of `max_completion_tokens`,
29
+ * but still accepted by the gateway and translated per provider.
30
+ */
31
+ max_tokens?: number | null
32
+
33
+ /**
34
+ * An upper bound for the number of tokens that can be generated for a
35
+ * completion, including visible output tokens and reasoning tokens.
36
+ */
37
+ max_completion_tokens?: number | null
38
+
39
+ /** Whether to enable parallel function calling during tool use. */
40
+ parallel_tool_calls?: boolean | null
41
+
42
+ /**
43
+ * Number between -2.0 and 2.0. Positive values penalize new tokens based on
44
+ * whether they appear in the text so far, increasing the model's likelihood
45
+ * to talk about new topics.
46
+ */
47
+ presence_penalty?: number | null
48
+
49
+ /**
50
+ * Controls reasoning effort for reasoning-capable models.
51
+ *
52
+ * The gateway accepts the extended effort scale in addition to OpenAI's
53
+ * `low` / `medium` / `high`; which tiers a given model honors depends on
54
+ * the model and the provider it is routed to. See the model's page on
55
+ * https://llmgateway.io/models for the tiers it supports.
56
+ */
57
+ reasoning_effort?:
58
+ | 'none'
59
+ | 'minimal'
60
+ | 'low'
61
+ | 'medium'
62
+ | 'high'
63
+ | 'xhigh'
64
+ | 'max'
65
+ | null
66
+
67
+ /**
68
+ * An object specifying the format that the model must output.
69
+ *
70
+ * - `json_schema` — enables Structured Outputs (preferred)
71
+ * - `json_object` — enables the older JSON mode
72
+ * - `text` — plain text output (default)
73
+ */
74
+ response_format?:
75
+ | ResponseFormatText
76
+ | ResponseFormatJsonSchema
77
+ | ResponseFormatJsonObject
78
+ | null
79
+
80
+ /**
81
+ * If specified, the gateway forwards the seed so providers that support it
82
+ * can sample deterministically. Determinism is not guaranteed.
83
+ */
84
+ seed?: number | null
85
+
86
+ /**
87
+ * Up to 4 sequences where the API will stop generating further tokens.
88
+ * The returned text will not contain the stop sequence.
89
+ */
90
+ stop?: string | null | Array<string>
91
+
92
+ /**
93
+ * Sampling temperature between 0 and 2. Higher values like 0.8 make the
94
+ * output more random, while lower values like 0.2 make it more focused and
95
+ * deterministic. We generally recommend altering this or `top_p` but not
96
+ * both.
97
+ */
98
+ temperature?: number | null
99
+
100
+ /**
101
+ * Controls which (if any) tool is called by the model.
102
+ *
103
+ * - `none` — never call tools
104
+ * - `auto` — model decides (default when tools are present)
105
+ * - `required` — model must call tools
106
+ * - Named choice — forces a specific tool
107
+ */
108
+ tool_choice?: ChatCompletionToolChoiceOption | null
109
+
110
+ /**
111
+ * An alternative to sampling with temperature, called nucleus sampling,
112
+ * where the model considers the results of the tokens with top_p
113
+ * probability mass. So 0.1 means only the tokens comprising the top 10%
114
+ * probability mass are considered.
115
+ */
116
+ top_p?: number | null
117
+
118
+ /**
119
+ * A unique identifier representing your end-user, which can help monitor
120
+ * and detect abuse.
121
+ */
122
+ user?: string | null
123
+ }
124
+
125
+ /**
126
+ * External provider options (what users pass in)
127
+ */
128
+ export type ExternalTextProviderOptions = LLMGatewayTextProviderOptions
@@ -0,0 +1,36 @@
1
+ import { getApiKeyFromEnv } from '@tanstack/ai-utils'
2
+ import type { ClientOptions } from 'openai'
3
+
4
+ export interface LLMGatewayClientConfig extends Omit<ClientOptions, 'apiKey'> {
5
+ apiKey: string
6
+ }
7
+
8
+ /**
9
+ * Gets the LLM Gateway API key from environment variables
10
+ * @throws Error if LLM_GATEWAY_API_KEY is not found
11
+ */
12
+ export function getLLMGatewayApiKeyFromEnv(): string {
13
+ try {
14
+ return getApiKeyFromEnv('LLM_GATEWAY_API_KEY')
15
+ } catch (cause) {
16
+ throw new Error(
17
+ 'LLM_GATEWAY_API_KEY is required. Please set it in your environment variables or use the factory function with an explicit API key.',
18
+ { cause },
19
+ )
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Returns an LLM Gateway client config with the gateway's OpenAI-compatible
25
+ * base URL applied when not already set. LLM Gateway accepts the OpenAI SDK
26
+ * verbatim, so the adapter drives it via the OpenAI SDK with this baseURL.
27
+ * Point `baseURL` at your own deployment when self-hosting.
28
+ */
29
+ export function withLLMGatewayDefaults(
30
+ config: LLMGatewayClientConfig,
31
+ ): LLMGatewayClientConfig {
32
+ return {
33
+ ...config,
34
+ baseURL: config.baseURL || 'https://api.llmgateway.io/v1',
35
+ }
36
+ }