@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.
- package/dist/agent/DextoAgent.cjs +10 -16
- package/dist/agent/DextoAgent.d.ts +2 -2
- package/dist/agent/DextoAgent.d.ts.map +1 -1
- package/dist/agent/DextoAgent.js +8 -5
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/context/compaction/overflow.d.ts +1 -1
- package/dist/context/compaction/overflow.d.ts.map +1 -1
- package/dist/context/manager.cjs +8 -8
- package/dist/context/manager.d.ts +1 -1
- package/dist/context/manager.d.ts.map +1 -1
- package/dist/context/manager.js +1 -1
- package/dist/context/types.d.ts +1 -1
- package/dist/context/types.d.ts.map +1 -1
- package/dist/context/utils.cjs +3 -3
- package/dist/context/utils.d.ts +1 -1
- package/dist/context/utils.d.ts.map +1 -1
- package/dist/context/utils.js +1 -1
- package/dist/events/index.d.ts +2 -2
- package/dist/events/index.d.ts.map +1 -1
- package/dist/index.browser.cjs +9 -9
- package/dist/index.browser.d.ts +4 -4
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/llm/auth/index.cjs +16 -0
- package/dist/llm/auth/index.d.ts +2 -0
- package/dist/llm/auth/index.d.ts.map +1 -0
- package/dist/llm/auth/index.js +0 -0
- package/dist/llm/auth/types.cjs +16 -0
- package/dist/llm/auth/types.d.ts +25 -0
- package/dist/llm/auth/types.d.ts.map +1 -0
- package/dist/llm/auth/types.js +0 -0
- package/dist/llm/curation-config.cjs +3 -3
- package/dist/llm/curation-config.d.ts +1 -1
- package/dist/llm/curation-config.js +3 -3
- package/dist/llm/curation.cjs +2 -2
- package/dist/llm/curation.d.ts +2 -2
- package/dist/llm/curation.d.ts.map +1 -1
- package/dist/llm/curation.js +1 -1
- package/dist/llm/errors.cjs +3 -3
- package/dist/llm/errors.d.ts +1 -1
- package/dist/llm/errors.d.ts.map +1 -1
- package/dist/llm/errors.js +1 -1
- package/dist/llm/executor/provider-options.cjs +22 -25
- package/dist/llm/executor/provider-options.d.ts +1 -1
- package/dist/llm/executor/provider-options.d.ts.map +1 -1
- package/dist/llm/executor/provider-options.js +17 -16
- package/dist/llm/executor/stream-processor.d.ts +1 -1
- package/dist/llm/executor/stream-processor.d.ts.map +1 -1
- package/dist/llm/executor/turn-executor.d.ts +1 -1
- package/dist/llm/executor/turn-executor.d.ts.map +1 -1
- package/dist/llm/executor/types.d.ts +1 -1
- package/dist/llm/executor/types.d.ts.map +1 -1
- package/dist/llm/formatters/vercel.cjs +2 -2
- package/dist/llm/formatters/vercel.d.ts +1 -1
- package/dist/llm/formatters/vercel.d.ts.map +1 -1
- package/dist/llm/index.cjs +0 -4
- package/dist/llm/index.d.ts +1 -2
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +0 -2
- package/dist/llm/registry/auto-update.cjs +5 -5
- package/dist/llm/registry/auto-update.d.ts.map +1 -1
- package/dist/llm/registry/auto-update.js +2 -2
- package/dist/llm/registry/index.cjs +96 -789
- package/dist/llm/registry/index.d.ts +4 -323
- package/dist/llm/registry/index.d.ts.map +1 -1
- package/dist/llm/registry/index.js +99 -762
- package/dist/llm/registry/sync.d.ts +2 -2
- package/dist/llm/registry/sync.d.ts.map +1 -1
- package/dist/llm/resolver.cjs +7 -6
- package/dist/llm/resolver.d.ts +1 -1
- package/dist/llm/resolver.js +4 -4
- package/dist/llm/schemas.cjs +14 -14
- package/dist/llm/schemas.d.ts +1 -1
- package/dist/llm/schemas.d.ts.map +1 -1
- package/dist/llm/schemas.js +5 -4
- package/dist/llm/services/factory.cjs +124 -33
- package/dist/llm/services/factory.d.ts.map +1 -1
- package/dist/llm/services/factory.js +128 -35
- package/dist/llm/services/types.d.ts +8 -1
- package/dist/llm/services/types.d.ts.map +1 -1
- package/dist/llm/usage-metadata.cjs +3 -3
- package/dist/llm/usage-metadata.d.ts +2 -2
- package/dist/llm/usage-metadata.d.ts.map +1 -1
- package/dist/llm/usage-metadata.js +1 -4
- package/dist/llm/usage-summary.d.ts +1 -1
- package/dist/llm/validation.cjs +4 -4
- package/dist/llm/validation.d.ts +1 -1
- package/dist/llm/validation.js +1 -1
- package/dist/session/chat-session.cjs +2 -12
- package/dist/session/chat-session.d.ts +2 -0
- package/dist/session/chat-session.d.ts.map +1 -1
- package/dist/session/chat-session.js +2 -13
- package/dist/session/session-manager.cjs +4 -1
- package/dist/session/session-manager.d.ts +5 -1
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +4 -1
- package/dist/utils/api-key-resolver.d.ts +1 -1
- package/dist/utils/api-key-resolver.d.ts.map +1 -1
- package/dist/utils/result.cjs +1 -1
- package/dist/utils/result.js +1 -1
- package/dist/utils/service-initializer.cjs +3 -0
- package/dist/utils/service-initializer.d.ts +2 -0
- package/dist/utils/service-initializer.d.ts.map +1 -1
- package/dist/utils/service-initializer.js +3 -0
- package/package.json +3 -2
- package/dist/llm/reasoning/anthropic-betas.cjs +0 -31
- package/dist/llm/reasoning/anthropic-betas.d.ts +0 -3
- package/dist/llm/reasoning/anthropic-betas.d.ts.map +0 -1
- package/dist/llm/reasoning/anthropic-betas.js +0 -7
- package/dist/llm/reasoning/anthropic-thinking.cjs +0 -79
- package/dist/llm/reasoning/anthropic-thinking.d.ts +0 -15
- package/dist/llm/reasoning/anthropic-thinking.d.ts.map +0 -1
- package/dist/llm/reasoning/anthropic-thinking.js +0 -52
- package/dist/llm/reasoning/openai-reasoning-effort.cjs +0 -86
- package/dist/llm/reasoning/openai-reasoning-effort.d.ts +0 -5
- package/dist/llm/reasoning/openai-reasoning-effort.d.ts.map +0 -1
- package/dist/llm/reasoning/openai-reasoning-effort.js +0 -61
- package/dist/llm/reasoning/profile.cjs +0 -113
- package/dist/llm/reasoning/profile.d.ts +0 -13
- package/dist/llm/reasoning/profile.d.ts.map +0 -1
- package/dist/llm/reasoning/profile.js +0 -92
- package/dist/llm/reasoning/profiles/anthropic.cjs +0 -61
- package/dist/llm/reasoning/profiles/anthropic.d.ts +0 -8
- package/dist/llm/reasoning/profiles/anthropic.d.ts.map +0 -1
- package/dist/llm/reasoning/profiles/anthropic.js +0 -45
- package/dist/llm/reasoning/profiles/bedrock.cjs +0 -54
- package/dist/llm/reasoning/profiles/bedrock.d.ts +0 -3
- package/dist/llm/reasoning/profiles/bedrock.d.ts.map +0 -1
- package/dist/llm/reasoning/profiles/bedrock.js +0 -36
- package/dist/llm/reasoning/profiles/google.cjs +0 -45
- package/dist/llm/reasoning/profiles/google.d.ts +0 -9
- package/dist/llm/reasoning/profiles/google.d.ts.map +0 -1
- package/dist/llm/reasoning/profiles/google.js +0 -21
- package/dist/llm/reasoning/profiles/openai-compatible.cjs +0 -39
- package/dist/llm/reasoning/profiles/openai-compatible.d.ts +0 -3
- package/dist/llm/reasoning/profiles/openai-compatible.d.ts.map +0 -1
- package/dist/llm/reasoning/profiles/openai-compatible.js +0 -16
- package/dist/llm/reasoning/profiles/openai.cjs +0 -41
- package/dist/llm/reasoning/profiles/openai.d.ts +0 -3
- package/dist/llm/reasoning/profiles/openai.d.ts.map +0 -1
- package/dist/llm/reasoning/profiles/openai.js +0 -18
- package/dist/llm/reasoning/profiles/openrouter.cjs +0 -83
- package/dist/llm/reasoning/profiles/openrouter.d.ts +0 -10
- package/dist/llm/reasoning/profiles/openrouter.d.ts.map +0 -1
- package/dist/llm/reasoning/profiles/openrouter.js +0 -59
- package/dist/llm/reasoning/profiles/shared.cjs +0 -80
- package/dist/llm/reasoning/profiles/shared.d.ts +0 -25
- package/dist/llm/reasoning/profiles/shared.d.ts.map +0 -1
- package/dist/llm/reasoning/profiles/shared.js +0 -53
- package/dist/llm/reasoning/profiles/vertex.cjs +0 -46
- package/dist/llm/reasoning/profiles/vertex.d.ts +0 -3
- package/dist/llm/reasoning/profiles/vertex.d.ts.map +0 -1
- package/dist/llm/reasoning/profiles/vertex.js +0 -23
- package/dist/llm/registry/models.generated.cjs +0 -10741
- package/dist/llm/registry/models.generated.d.ts +0 -2945
- package/dist/llm/registry/models.generated.d.ts.map +0 -1
- package/dist/llm/registry/models.generated.js +0 -10717
- package/dist/llm/registry/models.manual.cjs +0 -44
- package/dist/llm/registry/models.manual.d.ts +0 -22
- package/dist/llm/registry/models.manual.d.ts.map +0 -1
- package/dist/llm/registry/models.manual.js +0 -21
- package/dist/llm/types.cjs +0 -55
- package/dist/llm/types.d.ts +0 -39
- package/dist/llm/types.d.ts.map +0 -1
- 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
|
-
|
|
11
|
-
getOpenRouterModelContextLength,
|
|
12
|
-
scheduleOpenRouterModelRefresh
|
|
20
|
+
getOpenRouterModelContextLength
|
|
13
21
|
} from "../providers/openrouter-model-registry.js";
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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 ??
|
|
546
|
-
const maxInputTokens =
|
|
547
|
-
const inferredReasoning = cachedModel.supportedParameters?.includes("reasoning")
|
|
548
|
-
const inferredSupportsTemperature = cachedModel.supportedParameters?.includes("temperature")
|
|
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 } :
|
|
556
|
-
...typeof snapshot?.supportsTemperature === "boolean" ? { supportsTemperature: snapshot.supportsTemperature } :
|
|
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(
|
|
76
|
+
return LLM_REGISTRY.openrouter.models.map(cloneModel);
|
|
584
77
|
}
|
|
585
|
-
|
|
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((
|
|
597
|
-
...
|
|
87
|
+
return getOpenRouterGatewayCatalogModels().map((model) => ({
|
|
88
|
+
...model,
|
|
598
89
|
originalProvider: "openrouter"
|
|
599
90
|
}));
|
|
600
91
|
}
|
|
601
|
-
if (!
|
|
602
|
-
return
|
|
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
|
|
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
|
|
621
|
-
|
|
622
|
-
return model;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
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
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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
|
-
|
|
684
|
-
return supportedTypes.includes(fileType);
|
|
132
|
+
return getSupportedFileTypesForModel(provider, model).includes(fileType);
|
|
685
133
|
}
|
|
686
|
-
function
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
return
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
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
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
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
|
-
|
|
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
|
};
|