@dexto/core 1.8.0 → 1.8.2

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 (166) hide show
  1. package/dist/agent/DextoAgent.cjs +10 -16
  2. package/dist/agent/DextoAgent.d.ts +2 -2
  3. package/dist/agent/DextoAgent.d.ts.map +1 -1
  4. package/dist/agent/DextoAgent.js +8 -5
  5. package/dist/agent/types.d.ts +1 -1
  6. package/dist/agent/types.d.ts.map +1 -1
  7. package/dist/context/compaction/overflow.d.ts +1 -1
  8. package/dist/context/compaction/overflow.d.ts.map +1 -1
  9. package/dist/context/manager.cjs +8 -8
  10. package/dist/context/manager.d.ts +1 -1
  11. package/dist/context/manager.d.ts.map +1 -1
  12. package/dist/context/manager.js +1 -1
  13. package/dist/context/types.d.ts +1 -1
  14. package/dist/context/types.d.ts.map +1 -1
  15. package/dist/context/utils.cjs +3 -3
  16. package/dist/context/utils.d.ts +1 -1
  17. package/dist/context/utils.d.ts.map +1 -1
  18. package/dist/context/utils.js +1 -1
  19. package/dist/events/index.d.ts +2 -2
  20. package/dist/events/index.d.ts.map +1 -1
  21. package/dist/index.browser.cjs +9 -9
  22. package/dist/index.browser.d.ts +4 -4
  23. package/dist/index.browser.d.ts.map +1 -1
  24. package/dist/index.browser.js +1 -1
  25. package/dist/llm/auth/index.cjs +16 -0
  26. package/dist/llm/auth/index.d.ts +2 -0
  27. package/dist/llm/auth/index.d.ts.map +1 -0
  28. package/dist/llm/auth/index.js +0 -0
  29. package/dist/llm/auth/types.cjs +16 -0
  30. package/dist/llm/auth/types.d.ts +25 -0
  31. package/dist/llm/auth/types.d.ts.map +1 -0
  32. package/dist/llm/auth/types.js +0 -0
  33. package/dist/llm/curation-config.cjs +3 -3
  34. package/dist/llm/curation-config.d.ts +1 -1
  35. package/dist/llm/curation-config.js +3 -3
  36. package/dist/llm/curation.cjs +2 -2
  37. package/dist/llm/curation.d.ts +2 -2
  38. package/dist/llm/curation.d.ts.map +1 -1
  39. package/dist/llm/curation.js +1 -1
  40. package/dist/llm/errors.cjs +3 -3
  41. package/dist/llm/errors.d.ts +1 -1
  42. package/dist/llm/errors.d.ts.map +1 -1
  43. package/dist/llm/errors.js +1 -1
  44. package/dist/llm/executor/provider-options.cjs +22 -25
  45. package/dist/llm/executor/provider-options.d.ts +1 -1
  46. package/dist/llm/executor/provider-options.d.ts.map +1 -1
  47. package/dist/llm/executor/provider-options.js +17 -16
  48. package/dist/llm/executor/stream-processor.d.ts +1 -1
  49. package/dist/llm/executor/stream-processor.d.ts.map +1 -1
  50. package/dist/llm/executor/turn-executor.d.ts +1 -1
  51. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  52. package/dist/llm/executor/types.d.ts +1 -1
  53. package/dist/llm/executor/types.d.ts.map +1 -1
  54. package/dist/llm/formatters/vercel.cjs +2 -2
  55. package/dist/llm/formatters/vercel.d.ts +1 -1
  56. package/dist/llm/formatters/vercel.d.ts.map +1 -1
  57. package/dist/llm/index.cjs +0 -4
  58. package/dist/llm/index.d.ts +1 -2
  59. package/dist/llm/index.d.ts.map +1 -1
  60. package/dist/llm/index.js +0 -2
  61. package/dist/llm/registry/auto-update.cjs +5 -5
  62. package/dist/llm/registry/auto-update.d.ts.map +1 -1
  63. package/dist/llm/registry/auto-update.js +2 -2
  64. package/dist/llm/registry/index.cjs +96 -789
  65. package/dist/llm/registry/index.d.ts +4 -323
  66. package/dist/llm/registry/index.d.ts.map +1 -1
  67. package/dist/llm/registry/index.js +99 -762
  68. package/dist/llm/registry/sync.d.ts +2 -2
  69. package/dist/llm/registry/sync.d.ts.map +1 -1
  70. package/dist/llm/resolver.cjs +7 -6
  71. package/dist/llm/resolver.d.ts +1 -1
  72. package/dist/llm/resolver.js +4 -4
  73. package/dist/llm/schemas.cjs +14 -14
  74. package/dist/llm/schemas.d.ts +1 -1
  75. package/dist/llm/schemas.d.ts.map +1 -1
  76. package/dist/llm/schemas.js +5 -4
  77. package/dist/llm/services/factory.cjs +124 -33
  78. package/dist/llm/services/factory.d.ts.map +1 -1
  79. package/dist/llm/services/factory.js +128 -35
  80. package/dist/llm/services/types.d.ts +8 -1
  81. package/dist/llm/services/types.d.ts.map +1 -1
  82. package/dist/llm/usage-metadata.cjs +3 -3
  83. package/dist/llm/usage-metadata.d.ts +2 -2
  84. package/dist/llm/usage-metadata.d.ts.map +1 -1
  85. package/dist/llm/usage-metadata.js +1 -4
  86. package/dist/llm/usage-summary.d.ts +1 -1
  87. package/dist/llm/validation.cjs +4 -4
  88. package/dist/llm/validation.d.ts +1 -1
  89. package/dist/llm/validation.js +1 -1
  90. package/dist/session/chat-session.cjs +2 -12
  91. package/dist/session/chat-session.d.ts +2 -0
  92. package/dist/session/chat-session.d.ts.map +1 -1
  93. package/dist/session/chat-session.js +2 -13
  94. package/dist/session/session-manager.cjs +4 -1
  95. package/dist/session/session-manager.d.ts +5 -1
  96. package/dist/session/session-manager.d.ts.map +1 -1
  97. package/dist/session/session-manager.js +4 -1
  98. package/dist/utils/api-key-resolver.d.ts +1 -1
  99. package/dist/utils/api-key-resolver.d.ts.map +1 -1
  100. package/dist/utils/result.cjs +1 -1
  101. package/dist/utils/result.js +1 -1
  102. package/dist/utils/service-initializer.cjs +3 -0
  103. package/dist/utils/service-initializer.d.ts +2 -0
  104. package/dist/utils/service-initializer.d.ts.map +1 -1
  105. package/dist/utils/service-initializer.js +3 -0
  106. package/package.json +3 -2
  107. package/dist/llm/reasoning/anthropic-betas.cjs +0 -31
  108. package/dist/llm/reasoning/anthropic-betas.d.ts +0 -3
  109. package/dist/llm/reasoning/anthropic-betas.d.ts.map +0 -1
  110. package/dist/llm/reasoning/anthropic-betas.js +0 -7
  111. package/dist/llm/reasoning/anthropic-thinking.cjs +0 -79
  112. package/dist/llm/reasoning/anthropic-thinking.d.ts +0 -15
  113. package/dist/llm/reasoning/anthropic-thinking.d.ts.map +0 -1
  114. package/dist/llm/reasoning/anthropic-thinking.js +0 -52
  115. package/dist/llm/reasoning/openai-reasoning-effort.cjs +0 -86
  116. package/dist/llm/reasoning/openai-reasoning-effort.d.ts +0 -5
  117. package/dist/llm/reasoning/openai-reasoning-effort.d.ts.map +0 -1
  118. package/dist/llm/reasoning/openai-reasoning-effort.js +0 -61
  119. package/dist/llm/reasoning/profile.cjs +0 -113
  120. package/dist/llm/reasoning/profile.d.ts +0 -13
  121. package/dist/llm/reasoning/profile.d.ts.map +0 -1
  122. package/dist/llm/reasoning/profile.js +0 -92
  123. package/dist/llm/reasoning/profiles/anthropic.cjs +0 -61
  124. package/dist/llm/reasoning/profiles/anthropic.d.ts +0 -8
  125. package/dist/llm/reasoning/profiles/anthropic.d.ts.map +0 -1
  126. package/dist/llm/reasoning/profiles/anthropic.js +0 -45
  127. package/dist/llm/reasoning/profiles/bedrock.cjs +0 -54
  128. package/dist/llm/reasoning/profiles/bedrock.d.ts +0 -3
  129. package/dist/llm/reasoning/profiles/bedrock.d.ts.map +0 -1
  130. package/dist/llm/reasoning/profiles/bedrock.js +0 -36
  131. package/dist/llm/reasoning/profiles/google.cjs +0 -45
  132. package/dist/llm/reasoning/profiles/google.d.ts +0 -9
  133. package/dist/llm/reasoning/profiles/google.d.ts.map +0 -1
  134. package/dist/llm/reasoning/profiles/google.js +0 -21
  135. package/dist/llm/reasoning/profiles/openai-compatible.cjs +0 -39
  136. package/dist/llm/reasoning/profiles/openai-compatible.d.ts +0 -3
  137. package/dist/llm/reasoning/profiles/openai-compatible.d.ts.map +0 -1
  138. package/dist/llm/reasoning/profiles/openai-compatible.js +0 -16
  139. package/dist/llm/reasoning/profiles/openai.cjs +0 -41
  140. package/dist/llm/reasoning/profiles/openai.d.ts +0 -3
  141. package/dist/llm/reasoning/profiles/openai.d.ts.map +0 -1
  142. package/dist/llm/reasoning/profiles/openai.js +0 -18
  143. package/dist/llm/reasoning/profiles/openrouter.cjs +0 -83
  144. package/dist/llm/reasoning/profiles/openrouter.d.ts +0 -10
  145. package/dist/llm/reasoning/profiles/openrouter.d.ts.map +0 -1
  146. package/dist/llm/reasoning/profiles/openrouter.js +0 -59
  147. package/dist/llm/reasoning/profiles/shared.cjs +0 -80
  148. package/dist/llm/reasoning/profiles/shared.d.ts +0 -25
  149. package/dist/llm/reasoning/profiles/shared.d.ts.map +0 -1
  150. package/dist/llm/reasoning/profiles/shared.js +0 -53
  151. package/dist/llm/reasoning/profiles/vertex.cjs +0 -46
  152. package/dist/llm/reasoning/profiles/vertex.d.ts +0 -3
  153. package/dist/llm/reasoning/profiles/vertex.d.ts.map +0 -1
  154. package/dist/llm/reasoning/profiles/vertex.js +0 -23
  155. package/dist/llm/registry/models.generated.cjs +0 -10741
  156. package/dist/llm/registry/models.generated.d.ts +0 -2945
  157. package/dist/llm/registry/models.generated.d.ts.map +0 -1
  158. package/dist/llm/registry/models.generated.js +0 -10717
  159. package/dist/llm/registry/models.manual.cjs +0 -44
  160. package/dist/llm/registry/models.manual.d.ts +0 -22
  161. package/dist/llm/registry/models.manual.d.ts.map +0 -1
  162. package/dist/llm/registry/models.manual.js +0 -21
  163. package/dist/llm/types.cjs +0 -55
  164. package/dist/llm/types.d.ts +0 -39
  165. package/dist/llm/types.d.ts.map +0 -1
  166. package/dist/llm/types.js +0 -30
@@ -1,559 +1,65 @@
1
1
  import "../../chunk-C6A6W6XS.js";
2
+ import {
3
+ acceptsAnyModel,
4
+ DEFAULT_MAX_INPUT_TOKENS,
5
+ getAllModelsForProvider as getSharedAllModelsForProvider,
6
+ getModel,
7
+ getProviderFromModel as getSharedProviderFromModel,
8
+ getSupportedFileTypesForModel as getSharedSupportedFileTypesForModel,
9
+ getSupportedModels,
10
+ hasAllRegistryModelsSupport,
11
+ LLM_REGISTRY,
12
+ LlmCatalogError,
13
+ supportsCustomModels
14
+ } from "@dexto/llm";
2
15
  import { LLMError } from "../errors.js";
3
16
  import { LLMErrorCode } from "../error-codes.js";
4
17
  import { DextoRuntimeError } from "../../errors/DextoRuntimeError.js";
5
- import {
6
- LLM_PROVIDERS
7
- } from "../types.js";
8
18
  import {
9
19
  getCachedOpenRouterModelsWithInfo,
10
- getOpenRouterModelCacheInfo,
11
- getOpenRouterModelContextLength,
12
- scheduleOpenRouterModelRefresh
20
+ getOpenRouterModelContextLength
13
21
  } from "../providers/openrouter-model-registry.js";
14
- import {
15
- MODELS_BY_PROVIDER,
16
- MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER
17
- } from "./models.generated.js";
18
- import { MANUAL_MODELS_BY_PROVIDER } from "./models.manual.js";
19
- const LEGACY_MODEL_ID_ALIASES = {
20
- anthropic: {
21
- // Older Dexto configs/tests used "claude-4-{tier}-{date}".
22
- // models.dev (and our generated snapshot) use "claude-{tier}-4-{date}".
23
- "claude-4-sonnet-20250514": "claude-sonnet-4-20250514",
24
- "claude-4-opus-20250514": "claude-opus-4-20250514"
25
- }
26
- };
27
- function getNormalizedModelIdForLookup(provider, model) {
28
- const stripped = stripBedrockRegionPrefix(model);
29
- const lower = stripped.toLowerCase();
30
- const aliases = LEGACY_MODEL_ID_ALIASES[provider];
31
- return aliases?.[lower] ?? lower;
32
- }
33
- function mergeModels(base, extra) {
34
- if (!extra || extra.length === 0) return base;
35
- const merged = [...base];
36
- const indexByName = /* @__PURE__ */ new Map();
37
- for (let i = 0; i < merged.length; i++) {
38
- indexByName.set(merged[i].name.toLowerCase(), i);
39
- }
40
- for (const m of extra) {
41
- const key = m.name.toLowerCase();
42
- const existingIndex = indexByName.get(key);
43
- if (existingIndex != null) {
44
- merged[existingIndex] = m;
45
- } else {
46
- indexByName.set(key, merged.length);
47
- merged.push(m);
48
- }
49
- }
50
- return merged;
51
- }
52
- const MIME_TYPE_TO_FILE_TYPE = {
53
- "application/pdf": "pdf",
54
- "audio/mp3": "audio",
55
- "audio/mpeg": "audio",
56
- "audio/wav": "audio",
57
- "audio/x-wav": "audio",
58
- "audio/wave": "audio",
59
- "audio/webm": "audio",
60
- "audio/ogg": "audio",
61
- "audio/m4a": "audio",
62
- "audio/aac": "audio",
63
- "video/mp4": "video",
64
- "video/webm": "video",
65
- "video/ogg": "video",
66
- "video/quicktime": "video",
67
- "video/x-msvideo": "video",
68
- "video/x-matroska": "video",
69
- // Common image MIME types
70
- "image/jpeg": "image",
71
- "image/jpg": "image",
72
- "image/png": "image",
73
- "image/webp": "image",
74
- "image/gif": "image",
75
- // Common document, presentation, and spreadsheet MIME types
76
- "text/plain": "document",
77
- "text/markdown": "document",
78
- "text/html": "document",
79
- "text/xml": "document",
80
- "text/csv": "document",
81
- "text/tab-separated-values": "document",
82
- "application/json": "document",
83
- "application/xml": "document",
84
- "application/msword": "document",
85
- "application/rtf": "document",
86
- "text/rtf": "document",
87
- "application/vnd.oasis.opendocument.text": "document",
88
- "application/vnd.ms-powerpoint": "document",
89
- "application/vnd.openxmlformats-officedocument.presentationml.presentation": "document",
90
- "application/vnd.ms-excel": "document",
91
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "document",
92
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "document"
93
- };
94
- const GENERIC_UPLOAD_FILE_TYPES = [
95
- "pdf",
96
- "image",
97
- "audio",
98
- "video",
99
- "document"
100
- ];
101
- function getAllowedMimeTypes() {
102
- return Object.keys(MIME_TYPE_TO_FILE_TYPE);
22
+ function isUnknownCatalogModelError(error) {
23
+ return error instanceof LlmCatalogError && error.code === "MODEL_UNKNOWN";
103
24
  }
104
- const DEFAULT_MAX_INPUT_TOKENS = 128e3;
105
- const LLM_REGISTRY = {
106
- openai: {
107
- models: mergeModels(MODELS_BY_PROVIDER.openai, MANUAL_MODELS_BY_PROVIDER.openai),
108
- baseURLSupport: "none",
109
- supportedFileTypes: [],
110
- // No defaults - models must explicitly specify support
111
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.openai
112
- },
113
- "openai-compatible": {
114
- models: [],
115
- // Empty - accepts any model name for custom endpoints
116
- baseURLSupport: "required",
117
- supportedFileTypes: GENERIC_UPLOAD_FILE_TYPES,
118
- // Allow all generic file categories for custom endpoints
119
- supportsCustomModels: true
120
- },
121
- anthropic: {
122
- models: MODELS_BY_PROVIDER.anthropic,
123
- baseURLSupport: "none",
124
- supportedFileTypes: [],
125
- // No defaults - models must explicitly specify support
126
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.anthropic
127
- },
128
- google: {
129
- models: MODELS_BY_PROVIDER.google,
130
- baseURLSupport: "none",
131
- supportedFileTypes: [],
132
- // No defaults - models must explicitly specify support
133
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.google
134
- },
135
- // https://console.groq.com/docs/models
136
- groq: {
137
- models: MODELS_BY_PROVIDER.groq,
138
- baseURLSupport: "none",
139
- supportedFileTypes: [],
140
- // Groq currently doesn't support file uploads
141
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.groq
142
- },
143
- // https://docs.x.ai/docs/models
144
- // Note: XAI API only supports image uploads (JPG/PNG up to 20MB), not PDFs
145
- xai: {
146
- models: MODELS_BY_PROVIDER.xai,
147
- baseURLSupport: "none",
148
- supportedFileTypes: [],
149
- // No defaults - models must explicitly specify support
150
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.xai
151
- },
152
- // https://docs.cohere.com/reference/models
153
- cohere: {
154
- models: MODELS_BY_PROVIDER.cohere,
155
- baseURLSupport: "none",
156
- supportedFileTypes: [],
157
- // No defaults - models must explicitly specify support
158
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.cohere
159
- },
160
- // https://platform.minimax.io/docs/api-reference/text-openai-api
161
- // MiniMax provides an OpenAI-compatible endpoint at https://api.minimax.chat/v1
162
- minimax: {
163
- models: MODELS_BY_PROVIDER.minimax,
164
- baseURLSupport: "none",
165
- supportedFileTypes: [],
166
- // No defaults - models must explicitly specify support
167
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.minimax
168
- },
169
- // https://open.bigmodel.cn/dev/api/normal-model/glm-4
170
- // GLM (Zhipu AI) provides an OpenAI-compatible endpoint
171
- glm: {
172
- models: MODELS_BY_PROVIDER.glm,
173
- baseURLSupport: "none",
174
- supportedFileTypes: [],
175
- // No defaults - models must explicitly specify support
176
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.glm
177
- },
178
- // https://openrouter.ai/docs
179
- // OpenRouter is a unified API gateway providing access to 100+ models from various providers.
180
- // Model validation is handled dynamically via openrouter-model-registry.ts
181
- openrouter: {
182
- models: MODELS_BY_PROVIDER.openrouter,
183
- baseURLSupport: "none",
184
- // Fixed endpoint - baseURL auto-injected in resolver, no user override allowed
185
- supportedFileTypes: GENERIC_UPLOAD_FILE_TYPES,
186
- // Allow all generic file categories - user assumes responsibility
187
- supportsCustomModels: true,
188
- supportsAllRegistryModels: true,
189
- // Can serve models from all other providers
190
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.openrouter
191
- },
192
- // https://docs.litellm.ai/
193
- // LiteLLM is an OpenAI-compatible proxy that unifies 100+ LLM providers.
194
- // User must host their own LiteLLM proxy and provide the baseURL.
195
- litellm: {
196
- models: [],
197
- baseURLSupport: "required",
198
- supportedFileTypes: GENERIC_UPLOAD_FILE_TYPES,
199
- supportsCustomModels: true
200
- },
201
- // https://glama.ai/
202
- // Glama is an OpenAI-compatible gateway providing unified access to multiple LLM providers.
203
- // Fixed endpoint: https://glama.ai/api/gateway/openai/v1
204
- glama: {
205
- models: [],
206
- baseURLSupport: "none",
207
- supportedFileTypes: GENERIC_UPLOAD_FILE_TYPES,
208
- supportsCustomModels: true
209
- },
210
- // https://cloud.google.com/vertex-ai
211
- vertex: {
212
- models: MODELS_BY_PROVIDER.vertex,
213
- baseURLSupport: "none",
214
- supportedFileTypes: [],
215
- // No defaults - models must explicitly specify support
216
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.vertex
217
- },
218
- // https://docs.aws.amazon.com/bedrock/latest/userguide/models.html
219
- bedrock: {
220
- models: MODELS_BY_PROVIDER.bedrock,
221
- baseURLSupport: "none",
222
- supportedFileTypes: [],
223
- // No defaults - models must explicitly specify support
224
- supportsCustomModels: true,
225
- modelsDev: MODELS_DEV_PROVIDER_METADATA_BY_PROVIDER.bedrock
226
- },
227
- // Native local model execution via node-llama-cpp
228
- local: {
229
- models: [],
230
- // Populated dynamically from local model registry
231
- baseURLSupport: "none",
232
- supportedFileTypes: ["image"],
233
- supportsCustomModels: true
234
- },
235
- // Ollama server integration
236
- ollama: {
237
- models: [],
238
- // Populated dynamically from Ollama API
239
- baseURLSupport: "optional",
240
- supportedFileTypes: ["image"],
241
- supportsCustomModels: true
242
- },
243
- // Dexto Gateway - OpenAI-compatible proxy through api.dexto.ai
244
- // Routes to OpenRouter with per-request billing (balance decrement)
245
- // Requires DEXTO_API_KEY from dexto login
246
- //
247
- // Model IDs are in OpenRouter format (e.g., 'anthropic/claude-sonnet-4.5')
248
- "dexto-nova": {
249
- models: [
250
- // Claude models (Anthropic via OpenRouter)
251
- {
252
- name: "anthropic/claude-haiku-4.5",
253
- displayName: "Claude Haiku 4.5",
254
- maxInputTokens: 2e5,
255
- default: true,
256
- supportedFileTypes: ["pdf", "image"],
257
- pricing: {
258
- inputPerM: 1,
259
- outputPerM: 5,
260
- cacheWritePerM: 1.25,
261
- cacheReadPerM: 0.1,
262
- currency: "USD",
263
- unit: "per_million_tokens"
264
- }
265
- },
266
- {
267
- name: "anthropic/claude-sonnet-4.5",
268
- displayName: "Claude Sonnet 4.5",
269
- maxInputTokens: 2e5,
270
- supportedFileTypes: ["pdf", "image"],
271
- pricing: {
272
- inputPerM: 3,
273
- outputPerM: 15,
274
- cacheWritePerM: 3.75,
275
- cacheReadPerM: 0.3,
276
- currency: "USD",
277
- unit: "per_million_tokens"
278
- }
279
- },
280
- {
281
- name: "anthropic/claude-opus-4.5",
282
- displayName: "Claude Opus 4.5",
283
- maxInputTokens: 2e5,
284
- supportedFileTypes: ["pdf", "image"],
285
- pricing: {
286
- inputPerM: 5,
287
- outputPerM: 25,
288
- cacheWritePerM: 6.25,
289
- cacheReadPerM: 0.5,
290
- currency: "USD",
291
- unit: "per_million_tokens"
292
- }
293
- },
294
- // OpenAI models (via OpenRouter)
295
- {
296
- name: "openai/gpt-5.2",
297
- displayName: "GPT-5.2",
298
- maxInputTokens: 4e5,
299
- supportedFileTypes: ["pdf", "image", "document"],
300
- pricing: {
301
- inputPerM: 1.75,
302
- outputPerM: 14,
303
- cacheReadPerM: 0.175,
304
- currency: "USD",
305
- unit: "per_million_tokens"
306
- }
307
- },
308
- {
309
- name: "openai/gpt-5.2-codex",
310
- displayName: "GPT-5.2 Codex",
311
- maxInputTokens: 4e5,
312
- supportedFileTypes: ["pdf", "image", "document"],
313
- pricing: {
314
- inputPerM: 1.75,
315
- outputPerM: 14,
316
- cacheReadPerM: 0.175,
317
- currency: "USD",
318
- unit: "per_million_tokens"
319
- }
320
- },
321
- // Google models (via OpenRouter)
322
- {
323
- name: "google/gemini-3-pro-preview",
324
- displayName: "Gemini 3 Pro",
325
- maxInputTokens: 1048576,
326
- supportedFileTypes: ["pdf", "image", "audio", "video", "document"]
327
- },
328
- {
329
- name: "google/gemini-3-flash-preview",
330
- displayName: "Gemini 3 Flash",
331
- maxInputTokens: 1048576,
332
- supportedFileTypes: ["pdf", "image", "audio", "video", "document"]
333
- },
334
- // Free models (via OpenRouter)
335
- {
336
- name: "qwen/qwen3-coder:free",
337
- displayName: "Qwen3 Coder (Free)",
338
- maxInputTokens: 262e3,
339
- supportedFileTypes: []
340
- },
341
- {
342
- name: "deepseek/deepseek-r1-0528:free",
343
- displayName: "DeepSeek R1 (Free)",
344
- maxInputTokens: 163840,
345
- supportedFileTypes: []
346
- },
347
- // Other models (via OpenRouter)
348
- {
349
- name: "z-ai/glm-4.7",
350
- displayName: "GLM 4.7",
351
- maxInputTokens: 202752,
352
- supportedFileTypes: [],
353
- pricing: {
354
- inputPerM: 0.27,
355
- outputPerM: 1.1,
356
- currency: "USD",
357
- unit: "per_million_tokens"
358
- }
359
- },
360
- {
361
- name: "minimax/minimax-m2.5",
362
- displayName: "MiniMax M2.5",
363
- maxInputTokens: 204800,
364
- supportedFileTypes: [],
365
- pricing: {
366
- inputPerM: 0.3,
367
- outputPerM: 1.2,
368
- currency: "USD",
369
- unit: "per_million_tokens"
370
- }
371
- },
372
- {
373
- name: "moonshotai/kimi-k2.5",
374
- displayName: "Kimi K2.5",
375
- maxInputTokens: 262144,
376
- supportedFileTypes: ["image"],
377
- pricing: {
378
- inputPerM: 0.5,
379
- outputPerM: 2.5,
380
- currency: "USD",
381
- unit: "per_million_tokens"
382
- }
25
+ function cloneModel(model) {
26
+ return {
27
+ ...model,
28
+ supportedFileTypes: [...model.supportedFileTypes],
29
+ ...model.modalities ? {
30
+ modalities: {
31
+ input: [...model.modalities.input],
32
+ output: [...model.modalities.output]
383
33
  }
384
- ],
385
- baseURLSupport: "optional",
386
- supportedFileTypes: GENERIC_UPLOAD_FILE_TYPES,
387
- supportsCustomModels: true,
388
- supportsAllRegistryModels: true
389
- }
390
- };
391
- function stripBedrockRegionPrefix(model) {
392
- if (model.startsWith("eu.") || model.startsWith("us.")) {
393
- return model.slice(3);
394
- }
395
- if (model.startsWith("global.")) {
396
- return model.slice(7);
397
- }
398
- return model;
399
- }
400
- function getDefaultModelForProvider(provider) {
401
- const providerInfo = LLM_REGISTRY[provider];
402
- const explicit = providerInfo.models.find((m) => m.default)?.name;
403
- if (explicit) return explicit;
404
- if (providerInfo.models.length === 0) return null;
405
- const sorted = [...providerInfo.models].sort((a, b) => a.name.localeCompare(b.name));
406
- return sorted[0]?.name ?? null;
407
- }
408
- function getSupportedProviders() {
409
- return [...LLM_PROVIDERS];
410
- }
411
- function getSupportedModels(provider) {
412
- const providerInfo = LLM_REGISTRY[provider];
413
- return providerInfo.models.map((m) => m.name);
414
- }
415
- function getMaxInputTokensForModel(provider, model, logger) {
416
- const modelInfo = findModelInfo(provider, model);
417
- if (!modelInfo) {
418
- if ((provider === "openrouter" || provider === "dexto-nova") && model.includes("/")) {
419
- const contextLength = getOpenRouterModelContextLength(model);
420
- if (typeof contextLength === "number") {
421
- logger?.debug(
422
- `Using max tokens from OpenRouter cache for ${provider}/${model}: ${contextLength}`
423
- );
424
- return contextLength;
34
+ } : {},
35
+ ...model.pricing ? {
36
+ pricing: {
37
+ ...model.pricing,
38
+ ...model.pricing.contextOver200kPerM ? { contextOver200kPerM: { ...model.pricing.contextOver200kPerM } } : {}
425
39
  }
426
- }
427
- const supportedModels = getSupportedModels(provider).join(", ");
428
- logger?.error(
429
- `Model '${model}' not found for provider '${provider}' in LLM registry. Supported models: ${supportedModels}`
430
- );
431
- throw LLMError.unknownModel(provider, model);
432
- }
433
- logger?.debug(`Found max tokens for ${provider}/${model}: ${modelInfo.maxInputTokens}`);
434
- return modelInfo.maxInputTokens;
435
- }
436
- function isValidProviderModel(provider, model) {
437
- const providerInfo = LLM_REGISTRY[provider];
438
- const normalizedModel = getNormalizedModelIdForLookup(provider, model);
439
- return providerInfo.models.some((m) => m.name.toLowerCase() === normalizedModel);
440
- }
441
- function getProviderFromModel(model) {
442
- if (model.includes("/")) {
443
- throw LLMError.modelProviderUnknown(model);
444
- }
445
- for (const provider of LLM_PROVIDERS) {
446
- const info = LLM_REGISTRY[provider];
447
- const normalizedModel = getNormalizedModelIdForLookup(provider, model);
448
- if (info.models.some((m) => m.name.toLowerCase() === normalizedModel)) {
449
- return provider;
450
- }
451
- }
452
- throw LLMError.modelProviderUnknown(model);
453
- }
454
- function getAllSupportedModels() {
455
- return Object.values(LLM_REGISTRY).flatMap((info) => info.models.map((m) => m.name));
456
- }
457
- function supportsBaseURL(provider) {
458
- const providerInfo = LLM_REGISTRY[provider];
459
- return providerInfo.baseURLSupport !== "none";
460
- }
461
- function requiresBaseURL(provider) {
462
- const providerInfo = LLM_REGISTRY[provider];
463
- return providerInfo.baseURLSupport === "required";
464
- }
465
- function acceptsAnyModel(provider) {
466
- const providerInfo = LLM_REGISTRY[provider];
467
- return providerInfo.models.length === 0;
468
- }
469
- function supportsCustomModels(provider) {
470
- const providerInfo = LLM_REGISTRY[provider];
471
- return providerInfo.supportsCustomModels === true;
472
- }
473
- function hasAllRegistryModelsSupport(provider) {
474
- const providerInfo = LLM_REGISTRY[provider];
475
- return providerInfo.supportsAllRegistryModels === true;
476
- }
477
- const OPENROUTER_PREFIX_BY_PROVIDER = {
478
- openai: "openai",
479
- anthropic: "anthropic",
480
- google: "google",
481
- xai: "x-ai",
482
- cohere: "cohere",
483
- minimax: "minimax",
484
- glm: "z-ai"
485
- };
486
- function getOpenRouterModelIdSet() {
487
- return new Set(LLM_REGISTRY.openrouter.models.map((m) => m.name.toLowerCase()));
488
- }
489
- function getOpenRouterCandidateModelIds(model, originalProvider) {
490
- if (model.includes("/")) return [model];
491
- const prefix = OPENROUTER_PREFIX_BY_PROVIDER[originalProvider];
492
- if (!prefix) return [];
493
- if (originalProvider === "anthropic") {
494
- const noDate = model.replace(/-\d{8}.*$/i, "");
495
- const dotted = noDate.replace(/-(\d)-(\d)\b/g, "-$1.$2");
496
- return [`${prefix}/${dotted}`, `${prefix}/${noDate}`, `${prefix}/${model}`];
497
- }
498
- if (originalProvider === "google") {
499
- if (!/^gemini-/i.test(model)) {
500
- return [`${prefix}/${model}`];
501
- }
502
- return [`${prefix}/${model}`, `${prefix}/${model}-001`];
503
- }
504
- return [`${prefix}/${model}`];
505
- }
506
- function pickExistingOpenRouterModelId(candidates) {
507
- const openrouterSet = getOpenRouterModelIdSet();
508
- for (const candidate of candidates) {
509
- if (openrouterSet.has(candidate.toLowerCase())) {
510
- return candidate;
511
- }
512
- }
513
- return null;
514
- }
515
- function findModelInfo(provider, model) {
516
- if (provider === "openrouter" && model.includes("/")) {
517
- const dynamicOpenRouterModel = getOpenRouterGatewayModelById(model);
518
- if (dynamicOpenRouterModel) return dynamicOpenRouterModel;
519
- }
520
- const providerInfo = LLM_REGISTRY[provider];
521
- const normalizedModel = getNormalizedModelIdForLookup(provider, model);
522
- const direct = providerInfo.models.find((m) => m.name.toLowerCase() === normalizedModel);
523
- if (direct) return direct;
524
- if (provider !== "openrouter" && hasAllRegistryModelsSupport(provider) && model.includes("/")) {
525
- const openrouterModel = getOpenRouterGatewayModelById(model);
526
- if (openrouterModel) return openrouterModel;
527
- }
528
- return null;
529
- }
530
- function ensureOpenRouterCatalogRefreshScheduled() {
531
- const cacheInfo = getOpenRouterModelCacheInfo();
532
- if (cacheInfo.modelCount === 0) {
533
- scheduleOpenRouterModelRefresh({ force: true });
534
- } else if (!cacheInfo.isFresh) {
535
- scheduleOpenRouterModelRefresh();
536
- }
40
+ } : {},
41
+ ...model.providerMetadata ? { providerMetadata: { ...model.providerMetadata } } : {},
42
+ ...model.interleaved && model.interleaved !== true ? { interleaved: { ...model.interleaved } } : {}
43
+ };
537
44
  }
538
45
  function findOpenRouterSnapshotModelById(modelId) {
539
46
  const normalized = modelId.toLowerCase();
540
47
  return LLM_REGISTRY.openrouter.models.find((m) => m.name.toLowerCase() === normalized) ?? null;
541
48
  }
542
49
  function buildOpenRouterGatewayModelInfo(cachedModel, snapshot) {
543
- const providerDefaults = LLM_REGISTRY.openrouter.supportedFileTypes;
544
50
  const displayName = snapshot?.displayName ?? cachedModel.displayName;
545
- const supportedFileTypes = snapshot?.supportedFileTypes ?? providerDefaults;
546
- const maxInputTokens = typeof cachedModel.contextLength === "number" && cachedModel.contextLength > 0 ? cachedModel.contextLength : snapshot?.maxInputTokens ?? DEFAULT_MAX_INPUT_TOKENS;
547
- const inferredReasoning = cachedModel.supportedParameters?.includes("reasoning") === true ? true : void 0;
548
- const inferredSupportsTemperature = cachedModel.supportedParameters?.includes("temperature") === true ? true : void 0;
549
- return {
51
+ const supportedFileTypes = snapshot?.supportedFileTypes ?? LLM_REGISTRY.openrouter.supportedFileTypes;
52
+ const maxInputTokens = cachedModel.contextLength > 0 ? cachedModel.contextLength : snapshot?.maxInputTokens ?? DEFAULT_MAX_INPUT_TOKENS;
53
+ const inferredReasoning = cachedModel.supportedParameters?.includes("reasoning");
54
+ const inferredSupportsTemperature = cachedModel.supportedParameters?.includes("temperature");
55
+ return cloneModel({
550
56
  name: snapshot?.name ?? cachedModel.id,
551
57
  maxInputTokens,
552
58
  supportedFileTypes,
553
59
  ...snapshot?.default ? { default: true } : {},
554
60
  ...displayName ? { displayName } : {},
555
- ...typeof snapshot?.reasoning === "boolean" ? { reasoning: snapshot.reasoning } : typeof inferredReasoning === "boolean" ? { reasoning: inferredReasoning } : {},
556
- ...typeof snapshot?.supportsTemperature === "boolean" ? { supportsTemperature: snapshot.supportsTemperature } : typeof inferredSupportsTemperature === "boolean" ? { supportsTemperature: inferredSupportsTemperature } : {},
61
+ ...typeof snapshot?.reasoning === "boolean" ? { reasoning: snapshot.reasoning } : inferredReasoning === true ? { reasoning: true } : {},
62
+ ...typeof snapshot?.supportsTemperature === "boolean" ? { supportsTemperature: snapshot.supportsTemperature } : inferredSupportsTemperature === true ? { supportsTemperature: true } : {},
557
63
  ...typeof snapshot?.supportsInterleaved === "boolean" ? { supportsInterleaved: snapshot.supportsInterleaved } : {},
558
64
  ...snapshot?.releaseDate ? { releaseDate: snapshot.releaseDate } : {},
559
65
  ...typeof snapshot?.supportsToolCall === "boolean" ? { supportsToolCall: snapshot.supportsToolCall } : {},
@@ -562,155 +68,89 @@ function buildOpenRouterGatewayModelInfo(cachedModel, snapshot) {
562
68
  ...snapshot?.providerMetadata ? { providerMetadata: snapshot.providerMetadata } : {},
563
69
  ...snapshot?.interleaved ? { interleaved: snapshot.interleaved } : {},
564
70
  ...snapshot?.pricing ? { pricing: snapshot.pricing } : {}
565
- };
566
- }
567
- function getOpenRouterGatewayModelById(modelId) {
568
- ensureOpenRouterCatalogRefreshScheduled();
569
- const snapshot = findOpenRouterSnapshotModelById(modelId);
570
- const cached = getCachedOpenRouterModelsWithInfo();
571
- if (!cached || cached.length === 0) {
572
- return snapshot ? { ...snapshot } : null;
573
- }
574
- const normalized = modelId.toLowerCase();
575
- const cachedModel = cached.find((m) => m.id.toLowerCase() === normalized);
576
- if (!cachedModel) return snapshot ? { ...snapshot } : null;
577
- return buildOpenRouterGatewayModelInfo(cachedModel, snapshot);
71
+ });
578
72
  }
579
73
  function getOpenRouterGatewayCatalogModels() {
580
- ensureOpenRouterCatalogRefreshScheduled();
581
74
  const cached = getCachedOpenRouterModelsWithInfo();
582
75
  if (!cached || cached.length === 0) {
583
- return LLM_REGISTRY.openrouter.models.map((m) => ({ ...m }));
76
+ return LLM_REGISTRY.openrouter.models.map(cloneModel);
584
77
  }
585
- const models = cached.map(
78
+ return cached.map(
586
79
  (cachedModel) => buildOpenRouterGatewayModelInfo(
587
80
  cachedModel,
588
81
  findOpenRouterSnapshotModelById(cachedModel.id)
589
82
  )
590
83
  ).sort((a, b) => a.name.localeCompare(b.name));
591
- return models;
592
84
  }
593
85
  function getAllModelsForProvider(provider) {
594
- const providerInfo = LLM_REGISTRY[provider];
595
86
  if (provider === "openrouter") {
596
- return getOpenRouterGatewayCatalogModels().map((m) => ({
597
- ...m,
87
+ return getOpenRouterGatewayCatalogModels().map((model) => ({
88
+ ...model,
598
89
  originalProvider: "openrouter"
599
90
  }));
600
91
  }
601
- if (!providerInfo.supportsAllRegistryModels) {
602
- return providerInfo.models.map((m) => ({ ...m }));
92
+ if (!hasAllRegistryModelsSupport(provider)) {
93
+ return getSharedAllModelsForProvider(provider);
603
94
  }
604
95
  const allModels = [];
605
96
  const seen = /* @__PURE__ */ new Set();
606
- for (const model of providerInfo.models) {
97
+ for (const model of LLM_REGISTRY[provider].models) {
607
98
  const key = model.name.toLowerCase();
608
99
  if (seen.has(key)) continue;
609
100
  seen.add(key);
610
- allModels.push({ ...model, originalProvider: provider });
101
+ allModels.push({ ...cloneModel(model), originalProvider: provider });
611
102
  }
612
103
  for (const model of getOpenRouterGatewayCatalogModels()) {
613
104
  const key = model.name.toLowerCase();
614
105
  if (seen.has(key)) continue;
615
106
  seen.add(key);
616
- allModels.push({ ...model, originalProvider: "openrouter" });
107
+ allModels.push({ ...cloneModel(model), originalProvider: "openrouter" });
617
108
  }
618
109
  return allModels;
619
110
  }
620
- function transformModelNameForProvider(model, originalProvider, targetProvider) {
621
- if (!hasAllRegistryModelsSupport(targetProvider)) {
622
- return model;
623
- }
624
- if (hasAllRegistryModelsSupport(originalProvider)) {
625
- return model;
626
- }
627
- if (model.includes("/")) {
628
- return model;
629
- }
630
- const candidates = getOpenRouterCandidateModelIds(model, originalProvider);
631
- if (candidates.length === 0) return model;
632
- return pickExistingOpenRouterModelId(candidates) ?? candidates[0];
633
- }
634
- function isModelValidForProvider(provider, model) {
635
- const providerInfo = LLM_REGISTRY[provider];
636
- const normalizedModel = getNormalizedModelIdForLookup(provider, model);
637
- if (providerInfo.models.some((m) => m.name.toLowerCase() === normalizedModel)) {
638
- return true;
639
- }
640
- if (providerInfo.supportsAllRegistryModels && !model.includes("/")) {
641
- return false;
642
- }
643
- if (providerInfo.supportsCustomModels) {
644
- return true;
645
- }
646
- if (providerInfo.supportsAllRegistryModels) {
647
- return findModelInfo(provider, model) !== null;
111
+ function getProviderFromModel(model) {
112
+ try {
113
+ return getSharedProviderFromModel(model);
114
+ } catch (error) {
115
+ if (isUnknownCatalogModelError(error)) {
116
+ throw LLMError.modelProviderUnknown(model);
117
+ }
118
+ throw error;
648
119
  }
649
- return false;
650
- }
651
- const API_KEY_OPTIONAL_PROVIDERS = /* @__PURE__ */ new Set([
652
- "local",
653
- // Native node-llama-cpp execution - no auth needed
654
- "ollama",
655
- // Ollama server - no auth needed by default
656
- "openai-compatible",
657
- // vLLM, LocalAI - often no auth needed
658
- "litellm",
659
- // Self-hosted proxy - handles auth internally
660
- "vertex",
661
- // Uses Google Cloud ADC (Application Default Credentials)
662
- "bedrock"
663
- // Uses AWS credentials (access key + secret or IAM role)
664
- ]);
665
- function requiresApiKey(provider) {
666
- return !API_KEY_OPTIONAL_PROVIDERS.has(provider);
667
120
  }
668
121
  function getSupportedFileTypesForModel(provider, model) {
669
- const providerInfo = LLM_REGISTRY[provider];
670
- if (acceptsAnyModel(provider)) {
671
- return providerInfo.supportedFileTypes;
672
- }
673
- const modelInfo = findModelInfo(provider, model);
674
- if (modelInfo) {
675
- return modelInfo.supportedFileTypes;
676
- }
677
- if (supportsCustomModels(provider)) {
678
- return providerInfo.supportedFileTypes;
122
+ try {
123
+ return getSharedSupportedFileTypesForModel(provider, model);
124
+ } catch (error) {
125
+ if (isUnknownCatalogModelError(error)) {
126
+ throw LLMError.unknownModel(provider, model);
127
+ }
128
+ throw error;
679
129
  }
680
- throw LLMError.unknownModel(provider, model);
681
130
  }
682
131
  function modelSupportsFileType(provider, model, fileType) {
683
- const supportedTypes = getSupportedFileTypesForModel(provider, model);
684
- return supportedTypes.includes(fileType);
132
+ return getSupportedFileTypesForModel(provider, model).includes(fileType);
685
133
  }
686
- function validateModelFileSupport(provider, model, mimeType) {
687
- const baseMimeType = mimeType.toLowerCase().split(";")[0]?.trim() || mimeType.toLowerCase();
688
- const fileType = MIME_TYPE_TO_FILE_TYPE[baseMimeType];
689
- if (!fileType) {
690
- return {
691
- isSupported: false,
692
- error: `Unsupported file type: ${mimeType}`
693
- };
694
- }
695
- try {
696
- if (!modelSupportsFileType(provider, model, fileType)) {
697
- return {
698
- isSupported: false,
699
- fileType,
700
- error: `Model '${model}' (${provider}) does not support ${fileType} files`
701
- };
134
+ function getMaxInputTokensForModel(provider, model, logger) {
135
+ const modelInfo = getModel(provider, model);
136
+ if (modelInfo !== null) {
137
+ logger?.debug(`Found max tokens for ${provider}/${model}: ${modelInfo.maxInputTokens}`);
138
+ return modelInfo.maxInputTokens;
139
+ }
140
+ if ((provider === "openrouter" || provider === "dexto-nova") && model.includes("/")) {
141
+ const contextLength = getOpenRouterModelContextLength(model);
142
+ if (typeof contextLength === "number") {
143
+ logger?.debug(
144
+ `Using max tokens from OpenRouter cache for ${provider}/${model}: ${contextLength}`
145
+ );
146
+ return contextLength;
702
147
  }
703
- return {
704
- isSupported: true,
705
- fileType
706
- };
707
- } catch (error) {
708
- return {
709
- isSupported: false,
710
- fileType,
711
- error: error instanceof Error ? error.message : "Unknown error validating model file support"
712
- };
713
148
  }
149
+ const supportedModels = getSupportedModels(provider).join(", ");
150
+ logger?.error(
151
+ `Model '${model}' not found for provider '${provider}' in LLM registry. Supported models: ${supportedModels}`
152
+ );
153
+ throw LLMError.unknownModel(provider, model);
714
154
  }
715
155
  function getEffectiveMaxInputTokens(config, logger) {
716
156
  const configuredMaxInputTokens = config.maxInputTokens;
@@ -732,25 +172,23 @@ function getEffectiveMaxInputTokens(config, logger) {
732
172
  `Provided maxInputTokens (${configuredMaxInputTokens}) for ${config.provider}/${config.model} exceeds the known limit (${registryMaxInputTokens}) for model ${config.model}. Capping to registry limit.`
733
173
  );
734
174
  return registryMaxInputTokens;
735
- } else {
736
- logger.debug(
737
- `Using valid maxInputTokens override from configuration: ${configuredMaxInputTokens} (Registry limit: ${registryMaxInputTokens})`
738
- );
739
- return configuredMaxInputTokens;
740
175
  }
176
+ logger.debug(
177
+ `Using valid maxInputTokens override from configuration: ${configuredMaxInputTokens} (Registry limit: ${registryMaxInputTokens})`
178
+ );
179
+ return configuredMaxInputTokens;
741
180
  } catch (error) {
742
181
  if (error instanceof DextoRuntimeError && error.code === LLMErrorCode.MODEL_UNKNOWN) {
743
182
  logger.warn(
744
183
  `Registry lookup failed during maxInputTokens override check for ${config.provider}/${config.model}: ${error.message}. Proceeding with the provided maxInputTokens value (${configuredMaxInputTokens}), but it might be invalid.`
745
184
  );
746
185
  return configuredMaxInputTokens;
747
- } else {
748
- const errorMessage = error instanceof Error ? error.message : String(error);
749
- logger.error(
750
- `getEffectiveMaxInputTokens: unexpected error during maxInputTokens override check: ${errorMessage}`
751
- );
752
- throw error;
753
186
  }
187
+ const errorMessage = error instanceof Error ? error.message : String(error);
188
+ logger.error(
189
+ `getEffectiveMaxInputTokens: unexpected error during maxInputTokens override check: ${errorMessage}`
190
+ );
191
+ throw error;
754
192
  }
755
193
  }
756
194
  if (config.baseURL) {
@@ -787,120 +225,19 @@ function getEffectiveMaxInputTokens(config, logger) {
787
225
  `Registry lookup failed for ${config.provider}/${config.model}: ${error.message}. Effective maxInputTokens cannot be determined.`
788
226
  );
789
227
  throw LLMError.unknownModel(config.provider, config.model);
790
- } else {
791
- const errorMessage = error instanceof Error ? error.message : String(error);
792
- logger.error(
793
- `getEffectiveMaxInputTokens: unexpected error during registry lookup for maxInputTokens: ${errorMessage}`
794
- );
795
- throw error;
796
- }
797
- }
798
- }
799
- function getModelPricing(provider, model) {
800
- if (acceptsAnyModel(provider)) {
801
- return void 0;
802
- }
803
- const modelInfo = findModelInfo(provider, model);
804
- return modelInfo?.pricing;
805
- }
806
- function getModelDisplayName(model, provider) {
807
- if (provider) {
808
- const modelInfo = findModelInfo(provider, model);
809
- return modelInfo?.displayName ?? model;
810
- }
811
- if (model.includes("/")) {
812
- const modelInfo = findModelInfo("openrouter", model);
813
- return modelInfo?.displayName ?? model;
814
- }
815
- try {
816
- const inferredProvider = getProviderFromModel(model);
817
- const modelInfo = findModelInfo(inferredProvider, model);
818
- return modelInfo?.displayName ?? model;
819
- } catch {
820
- return model;
821
- }
822
- }
823
- function isReasoningCapableModel(model, provider) {
824
- const registryProvider = (() => {
825
- if (model.includes("/")) return "openrouter";
826
- if (provider) return provider;
827
- try {
828
- return getProviderFromModel(model);
829
- } catch {
830
- return void 0;
831
228
  }
832
- })();
833
- if (registryProvider === "openrouter" && model.includes("/")) {
834
- const dynamicModel = getOpenRouterGatewayModelById(model);
835
- if (dynamicModel?.reasoning === true) return true;
836
- if (dynamicModel?.reasoning === false) return false;
837
- }
838
- if (registryProvider) {
839
- const modelInfo = findModelInfo(registryProvider, model);
840
- if (modelInfo?.reasoning === true) return true;
841
- if (modelInfo?.reasoning === false) return false;
842
- }
843
- const modelIdForHeuristics = model.includes("/") ? model.split("/").pop() ?? model : model;
844
- const modelLower = modelIdForHeuristics.toLowerCase();
845
- if (modelLower.includes("codex")) {
846
- return true;
847
- }
848
- if (modelLower.startsWith("o1") || modelLower.startsWith("o3") || modelLower.startsWith("o4")) {
849
- return true;
850
- }
851
- if (modelLower.includes("gpt-5") || modelLower.includes("gpt-5.1") || modelLower.includes("gpt-5.2")) {
852
- return true;
229
+ const errorMessage = error instanceof Error ? error.message : String(error);
230
+ logger.error(
231
+ `getEffectiveMaxInputTokens: unexpected error during registry lookup for maxInputTokens: ${errorMessage}`
232
+ );
233
+ throw error;
853
234
  }
854
- return false;
855
- }
856
- function calculateCost(usage, pricing) {
857
- return calculateCostBreakdown(usage, pricing).totalUsd;
858
- }
859
- function calculateCostBreakdown(usage, pricing) {
860
- const inputUsd = (usage.inputTokens ?? 0) * pricing.inputPerM / 1e6;
861
- const outputUsd = (usage.outputTokens ?? 0) * pricing.outputPerM / 1e6;
862
- const cacheReadUsd = (usage.cacheReadTokens ?? 0) * (pricing.cacheReadPerM ?? 0) / 1e6;
863
- const cacheWriteUsd = (usage.cacheWriteTokens ?? 0) * (pricing.cacheWritePerM ?? 0) / 1e6;
864
- const reasoningUsd = (usage.reasoningTokens ?? 0) * (pricing.reasoningPerM ?? pricing.outputPerM) / 1e6;
865
- return {
866
- inputUsd,
867
- outputUsd,
868
- reasoningUsd,
869
- cacheReadUsd,
870
- cacheWriteUsd,
871
- totalUsd: inputUsd + outputUsd + cacheReadUsd + cacheWriteUsd + reasoningUsd
872
- };
873
235
  }
874
236
  export {
875
- DEFAULT_MAX_INPUT_TOKENS,
876
- LLM_REGISTRY,
877
- MIME_TYPE_TO_FILE_TYPE,
878
- acceptsAnyModel,
879
- calculateCost,
880
- calculateCostBreakdown,
881
237
  getAllModelsForProvider,
882
- getAllSupportedModels,
883
- getAllowedMimeTypes,
884
- getDefaultModelForProvider,
885
238
  getEffectiveMaxInputTokens,
886
239
  getMaxInputTokensForModel,
887
- getModelDisplayName,
888
- getModelPricing,
889
- getOpenRouterCandidateModelIds,
890
240
  getProviderFromModel,
891
241
  getSupportedFileTypesForModel,
892
- getSupportedModels,
893
- getSupportedProviders,
894
- hasAllRegistryModelsSupport,
895
- isModelValidForProvider,
896
- isReasoningCapableModel,
897
- isValidProviderModel,
898
- modelSupportsFileType,
899
- requiresApiKey,
900
- requiresBaseURL,
901
- stripBedrockRegionPrefix,
902
- supportsBaseURL,
903
- supportsCustomModels,
904
- transformModelNameForProvider,
905
- validateModelFileSupport
242
+ modelSupportsFileType
906
243
  };