@x12i/ai-tools 2.0.0 → 2.0.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/{AiModelsCatalogClient-B5FMI9gj.d.cts → AiModelsCatalogClient-C9ZJHhv3.d.ts} +4 -1
- package/dist/{AiModelsCatalogClient-CPPNI6Ry.d.ts → AiModelsCatalogClient-DgBdVFk-.d.cts} +4 -1
- package/dist/aliases/index.d.cts +3 -3
- package/dist/aliases/index.d.ts +3 -3
- package/dist/catalog/index.cjs +6 -5
- package/dist/catalog/index.cjs.map +1 -1
- package/dist/catalog/index.d.cts +4 -4
- package/dist/catalog/index.d.ts +4 -4
- package/dist/catalog/index.js +5 -4
- package/dist/{chunk-EYHMQVAL.js → chunk-54GKLIDW.js} +22 -10
- package/dist/chunk-54GKLIDW.js.map +1 -0
- package/dist/chunk-5IZ7PLY2.cjs +51 -0
- package/dist/chunk-5IZ7PLY2.cjs.map +1 -0
- package/dist/{chunk-XAWBTX3N.cjs → chunk-75ZVXZAV.cjs} +7 -7
- package/dist/{chunk-XAWBTX3N.cjs.map → chunk-75ZVXZAV.cjs.map} +1 -1
- package/dist/{chunk-YQDSN6R6.cjs → chunk-76FHWQH3.cjs} +3 -3
- package/dist/{chunk-YQDSN6R6.cjs.map → chunk-76FHWQH3.cjs.map} +1 -1
- package/dist/{chunk-EDMCKHO6.cjs → chunk-BCX5CLJJ.cjs} +15 -2
- package/dist/chunk-BCX5CLJJ.cjs.map +1 -0
- package/dist/{chunk-OPN6BGNH.js → chunk-D6OIUYNC.js} +117 -5
- package/dist/{chunk-OPN6BGNH.js.map → chunk-D6OIUYNC.js.map} +1 -1
- package/dist/{chunk-NF2SKQR7.cjs → chunk-DDRWORUU.cjs} +30 -298
- package/dist/chunk-DDRWORUU.cjs.map +1 -0
- package/dist/{chunk-5XAAMBDO.cjs → chunk-HBNYVRLZ.cjs} +123 -11
- package/dist/chunk-HBNYVRLZ.cjs.map +1 -0
- package/dist/chunk-HEB73GKJ.js +263 -0
- package/dist/chunk-HEB73GKJ.js.map +1 -0
- package/dist/{chunk-VJHLO2R3.js → chunk-KSJSLKYI.js} +2 -2
- package/dist/{chunk-SIH4GPV4.js → chunk-MOLWV5LV.js} +2 -2
- package/dist/{chunk-U2YDDUVP.js → chunk-PN4FF6YF.js} +10 -275
- package/dist/chunk-PN4FF6YF.js.map +1 -0
- package/dist/{chunk-DXZOL3VN.cjs → chunk-RSHI4OOY.cjs} +46 -34
- package/dist/chunk-RSHI4OOY.cjs.map +1 -0
- package/dist/{chunk-B3V2EHRY.js → chunk-SLSKQRMI.js} +15 -2
- package/dist/{chunk-B3V2EHRY.js.map → chunk-SLSKQRMI.js.map} +1 -1
- package/dist/{chunk-XOKUDUUI.cjs → chunk-TMA6QSNH.cjs} +3 -3
- package/dist/{chunk-XOKUDUUI.cjs.map → chunk-TMA6QSNH.cjs.map} +1 -1
- package/dist/{chunk-6BQBKROR.js → chunk-VBROBIVI.js} +3 -3
- package/dist/{chunk-6BQBKROR.js.map → chunk-VBROBIVI.js.map} +1 -1
- package/dist/chunk-WSUFQR3D.cjs +266 -0
- package/dist/chunk-WSUFQR3D.cjs.map +1 -0
- package/dist/{chunk-PRCICORG.cjs → chunk-X42KFOUO.cjs} +6 -6
- package/dist/{chunk-PRCICORG.cjs.map → chunk-X42KFOUO.cjs.map} +1 -1
- package/dist/chunk-YQVY7CWT.js +51 -0
- package/dist/chunk-YQVY7CWT.js.map +1 -0
- package/dist/{chunk-AB5GNXJ4.js → chunk-ZPUZ7DBO.js} +2 -2
- package/dist/cli/index.cjs +16 -15
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +7 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cost/index.cjs +4 -3
- package/dist/cost/index.cjs.map +1 -1
- package/dist/cost/index.d.cts +4 -4
- package/dist/cost/index.d.ts +4 -4
- package/dist/cost/index.js +3 -2
- package/dist/index.cjs +28 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/index.js +33 -16
- package/dist/{modelCache-CJftI-Ko.d.cts → modelCache-sL3dBfRM.d.cts} +1 -1
- package/dist/{modelCache-BzRn6t_C.d.ts → modelCache-xzoTUue2.d.ts} +1 -1
- package/dist/{modelNameResolver-5XkBMctP.d.ts → modelNameResolver-2WroQlqt.d.ts} +2 -1
- package/dist/{modelNameResolver-C5CSTGFF.d.cts → modelNameResolver-Bxlehrbp.d.cts} +2 -1
- package/dist/models/index.cjs +7 -6
- package/dist/models/index.cjs.map +1 -1
- package/dist/models/index.d.cts +3 -3
- package/dist/models/index.d.ts +3 -3
- package/dist/models/index.js +9 -8
- package/dist/profiles/index.cjs +18 -0
- package/dist/profiles/index.cjs.map +1 -0
- package/dist/profiles/index.d.cts +40 -0
- package/dist/profiles/index.d.ts +40 -0
- package/dist/profiles/index.js +17 -0
- package/dist/profiles/index.js.map +1 -0
- package/dist/{resolveUsageModel-BFwf80Hz.d.ts → resolveUsageModel-DrFuiuIW.d.ts} +2 -2
- package/dist/{resolveUsageModel-C_YmGR1M.d.cts → resolveUsageModel-xKZ2QpHy.d.cts} +2 -2
- package/dist/sync/index.cjs +7 -5
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +3 -3
- package/dist/sync/index.d.ts +3 -3
- package/dist/sync/index.js +6 -4
- package/dist/{types-BrzJWsTU.d.ts → types-BZYGjN2O.d.cts} +21 -2
- package/dist/{types-BrzJWsTU.d.cts → types-BZYGjN2O.d.ts} +21 -2
- package/package.json +7 -2
- package/dist/chunk-5XAAMBDO.cjs.map +0 -1
- package/dist/chunk-DXZOL3VN.cjs.map +0 -1
- package/dist/chunk-EDMCKHO6.cjs.map +0 -1
- package/dist/chunk-EYHMQVAL.js.map +0 -1
- package/dist/chunk-NF2SKQR7.cjs.map +0 -1
- package/dist/chunk-U2YDDUVP.js.map +0 -1
- /package/dist/{chunk-VJHLO2R3.js.map → chunk-KSJSLKYI.js.map} +0 -0
- /package/dist/{chunk-SIH4GPV4.js.map → chunk-MOLWV5LV.js.map} +0 -0
- /package/dist/{chunk-AB5GNXJ4.js.map → chunk-ZPUZ7DBO.js.map} +0 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LOCAL_PROVIDERS,
|
|
3
|
+
loadOpenRouterRoutingEnv,
|
|
4
|
+
normalizeProvider,
|
|
5
|
+
normalizeString,
|
|
6
|
+
shouldDefaultRouteViaOpenRouter,
|
|
7
|
+
stripModelVersionSuffix
|
|
8
|
+
} from "./chunk-SLSKQRMI.js";
|
|
9
|
+
|
|
10
|
+
// src/cost/costModelResolution.ts
|
|
11
|
+
function isOpenRouterProvider(provider) {
|
|
12
|
+
return normalizeProvider(provider) === "openrouter";
|
|
13
|
+
}
|
|
14
|
+
function isLocalProvider(provider) {
|
|
15
|
+
const p = normalizeProvider(provider) ?? normalizeString(provider ?? "");
|
|
16
|
+
return LOCAL_PROVIDERS.has(p);
|
|
17
|
+
}
|
|
18
|
+
function isLocalProviderResolution(resolved, inputProvider) {
|
|
19
|
+
if (!resolved?.found || resolved.record) return false;
|
|
20
|
+
if (resolved.resolvedVia.includes("local-provider-passthrough")) return true;
|
|
21
|
+
return isLocalProvider(inputProvider);
|
|
22
|
+
}
|
|
23
|
+
function underlyingProviderFromModel(model, providerHint) {
|
|
24
|
+
const normalized = normalizeString(model);
|
|
25
|
+
if (normalized.includes("/")) {
|
|
26
|
+
const prefix = normalized.split("/")[0];
|
|
27
|
+
if (!isOpenRouterProvider(prefix)) return prefix;
|
|
28
|
+
}
|
|
29
|
+
if (providerHint && !isOpenRouterProvider(providerHint)) {
|
|
30
|
+
return normalizeProvider(providerHint);
|
|
31
|
+
}
|
|
32
|
+
return void 0;
|
|
33
|
+
}
|
|
34
|
+
function providerHintForProfiles(model, provider) {
|
|
35
|
+
if (isOpenRouterProvider(provider)) {
|
|
36
|
+
return underlyingProviderFromModel(model, provider);
|
|
37
|
+
}
|
|
38
|
+
return normalizeProvider(provider);
|
|
39
|
+
}
|
|
40
|
+
function buildCatalogResolveAttempts(model, provider) {
|
|
41
|
+
const attempts = [];
|
|
42
|
+
const seen = /* @__PURE__ */ new Set();
|
|
43
|
+
const add = (m, p) => {
|
|
44
|
+
const key = `${p ?? ""}\0${normalizeString(m)}`;
|
|
45
|
+
if (seen.has(key)) return;
|
|
46
|
+
seen.add(key);
|
|
47
|
+
attempts.push({ model: m, provider: p });
|
|
48
|
+
};
|
|
49
|
+
add(model, provider);
|
|
50
|
+
const underlying = underlyingProviderFromModel(model, provider);
|
|
51
|
+
if (provider) add(model, void 0);
|
|
52
|
+
if (underlying) add(model, underlying);
|
|
53
|
+
if (!isOpenRouterProvider(provider)) {
|
|
54
|
+
add(model, "openrouter");
|
|
55
|
+
}
|
|
56
|
+
return attempts;
|
|
57
|
+
}
|
|
58
|
+
async function resolveFromCatalogAttempts(catalog, attempts, options) {
|
|
59
|
+
let last = null;
|
|
60
|
+
let localPassthrough = null;
|
|
61
|
+
for (const attempt of attempts) {
|
|
62
|
+
const result = await catalog.resolveModel(attempt, options);
|
|
63
|
+
last = result;
|
|
64
|
+
if (result.found && result.record) return result;
|
|
65
|
+
if (result.found && !result.record && isLocalProviderResolution(result, attempt.provider)) {
|
|
66
|
+
localPassthrough = result;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return localPassthrough ?? last;
|
|
70
|
+
}
|
|
71
|
+
function resolveRoutedViaOpenRouter(inputProvider, resolved, modelId, routingEnv) {
|
|
72
|
+
const env = routingEnv ?? loadOpenRouterRoutingEnv();
|
|
73
|
+
if (isOpenRouterProvider(inputProvider)) return true;
|
|
74
|
+
if (resolved?.found) {
|
|
75
|
+
return resolved.routedViaOpenRouter;
|
|
76
|
+
}
|
|
77
|
+
const vendor = underlyingProviderFromModel(
|
|
78
|
+
modelId ?? (resolved?.found ? resolved.modelId : "") ?? "",
|
|
79
|
+
inputProvider
|
|
80
|
+
);
|
|
81
|
+
if (vendor && shouldDefaultRouteViaOpenRouter(vendor, env)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/cost/aiProfilesMatch.ts
|
|
88
|
+
import { createRequire } from "module";
|
|
89
|
+
import { dirname, join } from "path";
|
|
90
|
+
import { AIProfilesError, resolveAIProfile } from "@x12i/ai-profiles";
|
|
91
|
+
var require2 = createRequire(import.meta.url);
|
|
92
|
+
function loadProfilesRegistry() {
|
|
93
|
+
const entry = dirname(require2.resolve("@x12i/ai-profiles"));
|
|
94
|
+
const loader = require2(join(entry, "loader/loadAIProfilesRegistry.js"));
|
|
95
|
+
return loader.loadAIProfilesRegistry({ source: "auto" });
|
|
96
|
+
}
|
|
97
|
+
function profileKey(value) {
|
|
98
|
+
return value.trim().toLowerCase();
|
|
99
|
+
}
|
|
100
|
+
function canonicalModelId(provider, modelId) {
|
|
101
|
+
const normalized = normalizeString(modelId);
|
|
102
|
+
if (normalized.includes("/")) return normalized;
|
|
103
|
+
const p = normalizeProvider(provider) ?? normalizeString(provider);
|
|
104
|
+
return `${p}/${normalized}`;
|
|
105
|
+
}
|
|
106
|
+
var cachedIndex = null;
|
|
107
|
+
function indexRegistry(registry) {
|
|
108
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
109
|
+
const add = (key, entry) => {
|
|
110
|
+
const k = profileKey(key);
|
|
111
|
+
if (!k) return;
|
|
112
|
+
const list = byKey.get(k) ?? [];
|
|
113
|
+
if (list.some(
|
|
114
|
+
(e) => e.canonicalModelId === entry.canonicalModelId && e.choice === entry.choice && e.profile === entry.profile
|
|
115
|
+
)) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
list.push(entry);
|
|
119
|
+
byKey.set(k, list);
|
|
120
|
+
};
|
|
121
|
+
for (const profile of Object.values(registry.profiles)) {
|
|
122
|
+
for (const [choiceKey, choice] of Object.entries(profile.choices)) {
|
|
123
|
+
const entry = choiceEntry(choice, profile.profile, choiceKey);
|
|
124
|
+
add(choice.modelId, entry);
|
|
125
|
+
add(canonicalModelId(choice.provider, choice.modelId), entry);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return byKey;
|
|
129
|
+
}
|
|
130
|
+
function choiceEntry(choice, profile, choiceKey) {
|
|
131
|
+
const canonical = canonicalModelId(choice.provider, choice.modelId);
|
|
132
|
+
return {
|
|
133
|
+
provider: normalizeProvider(choice.provider) ?? choice.provider,
|
|
134
|
+
modelId: normalizeString(choice.modelId),
|
|
135
|
+
canonicalModelId: canonical,
|
|
136
|
+
pricing: choice.pricing,
|
|
137
|
+
profile,
|
|
138
|
+
choice: choiceKey
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async function getProfileIndex() {
|
|
142
|
+
const registry = await loadProfilesRegistry();
|
|
143
|
+
const cacheKey = `${registry.version}:${registry.generatedAt ?? ""}:${registry.source}`;
|
|
144
|
+
if (cachedIndex?.cacheKey === cacheKey) {
|
|
145
|
+
return cachedIndex.byKey;
|
|
146
|
+
}
|
|
147
|
+
const byKey = indexRegistry(registry);
|
|
148
|
+
cachedIndex = { cacheKey, byKey };
|
|
149
|
+
return byKey;
|
|
150
|
+
}
|
|
151
|
+
function scoreCandidate(entry, model, providerHint) {
|
|
152
|
+
const normalized = normalizeString(model);
|
|
153
|
+
let score = 0;
|
|
154
|
+
if (normalized === entry.canonicalModelId) score += 100;
|
|
155
|
+
if (normalized === entry.modelId) score += 80;
|
|
156
|
+
if (providerHint && entry.provider === providerHint) score += 50;
|
|
157
|
+
if (entry.pricing) score += 2;
|
|
158
|
+
return score;
|
|
159
|
+
}
|
|
160
|
+
function pickBest(candidates, model, providerHint) {
|
|
161
|
+
if (candidates.length === 0) return null;
|
|
162
|
+
if (candidates.length === 1) return candidates[0];
|
|
163
|
+
let best = candidates[0];
|
|
164
|
+
let bestScore = scoreCandidate(best, model, providerHint);
|
|
165
|
+
for (let i = 1; i < candidates.length; i++) {
|
|
166
|
+
const c = candidates[i];
|
|
167
|
+
const s = scoreCandidate(c, model, providerHint);
|
|
168
|
+
if (s > bestScore) {
|
|
169
|
+
best = c;
|
|
170
|
+
bestScore = s;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return best;
|
|
174
|
+
}
|
|
175
|
+
function resolvedToMatch(resolved) {
|
|
176
|
+
return {
|
|
177
|
+
provider: normalizeProvider(resolved.provider) ?? resolved.provider,
|
|
178
|
+
modelId: normalizeString(resolved.modelId),
|
|
179
|
+
canonicalModelId: canonicalModelId(resolved.provider, resolved.modelId),
|
|
180
|
+
pricing: resolved.pricing,
|
|
181
|
+
instructionTier: resolved.instructionTier,
|
|
182
|
+
backend: resolved.backend,
|
|
183
|
+
matchedVia: resolved.shortcut ? "shortcut" : "profile",
|
|
184
|
+
profile: resolved.profile,
|
|
185
|
+
choice: resolved.choice
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
async function fromIndexed(entry) {
|
|
189
|
+
const resolved = await resolveAIProfile(entry.profile, { choice: entry.choice });
|
|
190
|
+
return {
|
|
191
|
+
provider: normalizeProvider(resolved.provider) ?? resolved.provider,
|
|
192
|
+
modelId: normalizeString(resolved.modelId),
|
|
193
|
+
canonicalModelId: canonicalModelId(resolved.provider, resolved.modelId),
|
|
194
|
+
pricing: resolved.pricing ?? entry.pricing,
|
|
195
|
+
instructionTier: resolved.instructionTier,
|
|
196
|
+
backend: resolved.backend,
|
|
197
|
+
matchedVia: "model-id",
|
|
198
|
+
profile: resolved.profile,
|
|
199
|
+
choice: resolved.choice
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
async function lookupInIndex(index, model, provider) {
|
|
203
|
+
const providerHint = provider ? normalizeProvider(provider) : void 0;
|
|
204
|
+
const keys = [
|
|
205
|
+
profileKey(model),
|
|
206
|
+
profileKey(normalizeString(model))
|
|
207
|
+
];
|
|
208
|
+
if (providerHint) {
|
|
209
|
+
keys.push(profileKey(canonicalModelId(providerHint, model)));
|
|
210
|
+
}
|
|
211
|
+
const pooled = [];
|
|
212
|
+
for (const key of keys) {
|
|
213
|
+
const hits = index.get(key);
|
|
214
|
+
if (hits) pooled.push(...hits);
|
|
215
|
+
}
|
|
216
|
+
const bare = normalizeString(model);
|
|
217
|
+
if (!bare.includes("/")) {
|
|
218
|
+
for (const list of index.values()) {
|
|
219
|
+
for (const entry of list) {
|
|
220
|
+
if (entry.modelId === bare) pooled.push(entry);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const unique = /* @__PURE__ */ new Map();
|
|
225
|
+
for (const e of pooled) {
|
|
226
|
+
unique.set(`${e.profile}:${e.choice}:${e.canonicalModelId}`, e);
|
|
227
|
+
}
|
|
228
|
+
const best = pickBest([...unique.values()], model, providerHint);
|
|
229
|
+
return best ? fromIndexed(best) : null;
|
|
230
|
+
}
|
|
231
|
+
async function matchModelInAiProfiles(model, provider) {
|
|
232
|
+
try {
|
|
233
|
+
const resolved = await resolveAIProfile(model);
|
|
234
|
+
return resolvedToMatch(resolved);
|
|
235
|
+
} catch (err) {
|
|
236
|
+
if (!(err instanceof AIProfilesError) || err.code !== "UNKNOWN_PROFILE") {
|
|
237
|
+
throw err;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const index = await getProfileIndex();
|
|
241
|
+
const hint = providerHintForProfiles(model, provider);
|
|
242
|
+
const direct = await lookupInIndex(index, model, hint);
|
|
243
|
+
if (direct) return direct;
|
|
244
|
+
const stripped = stripModelVersionSuffix(model);
|
|
245
|
+
if (stripped && stripped !== normalizeString(model)) {
|
|
246
|
+
return lookupInIndex(
|
|
247
|
+
index,
|
|
248
|
+
stripped,
|
|
249
|
+
providerHintForProfiles(stripped, provider)
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export {
|
|
256
|
+
isLocalProvider,
|
|
257
|
+
isLocalProviderResolution,
|
|
258
|
+
buildCatalogResolveAttempts,
|
|
259
|
+
resolveFromCatalogAttempts,
|
|
260
|
+
resolveRoutedViaOpenRouter,
|
|
261
|
+
matchModelInAiProfiles
|
|
262
|
+
};
|
|
263
|
+
//# sourceMappingURL=chunk-HEB73GKJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cost/costModelResolution.ts","../src/cost/aiProfilesMatch.ts"],"sourcesContent":["import type { AiModelsCatalogClient } from \"../catalog/AiModelsCatalogClient.js\";\nimport { LOCAL_PROVIDERS } from \"../sync/modelNameResolver/constants.js\";\nimport {\n loadOpenRouterRoutingEnv,\n shouldDefaultRouteViaOpenRouter,\n} from \"../sync/openRouterRoutingEnv.js\";\nimport { normalizeProvider, normalizeString } from \"../sync/modelNameResolver/normalize.js\";\nimport type {\n ModelResolutionInput,\n ModelResolutionResult,\n ModelResolverOptions,\n} from \"../sync/modelNameResolver/types.js\";\nimport type { OpenRouterRoutingConfig } from \"../sync/openRouterRoutingEnv.js\";\n\nexport function isOpenRouterProvider(provider?: string): boolean {\n return normalizeProvider(provider) === \"openrouter\";\n}\n\nexport function isLocalProvider(provider?: string): boolean {\n const p = normalizeProvider(provider) ?? normalizeString(provider ?? \"\");\n return LOCAL_PROVIDERS.has(p);\n}\n\n/** Catalog resolver returned success without a priced record (Ollama, LM Studio, …). */\nexport function isLocalProviderResolution(\n resolved: ModelResolutionResult | null,\n inputProvider?: string,\n): boolean {\n if (!resolved?.found || resolved.record) return false;\n if (resolved.resolvedVia.includes(\"local-provider-passthrough\")) return true;\n return isLocalProvider(inputProvider);\n}\n\n/**\n * Vendor id for a model slug (`openai/gpt-4o` → `openai`).\n * Ignores `openrouter` as a provider hint — it is a routing layer, not the model owner.\n */\nexport function underlyingProviderFromModel(\n model: string,\n providerHint?: string,\n): string | undefined {\n const normalized = normalizeString(model);\n if (normalized.includes(\"/\")) {\n const prefix = normalized.split(\"/\")[0]!;\n if (!isOpenRouterProvider(prefix)) return prefix;\n }\n if (providerHint && !isOpenRouterProvider(providerHint)) {\n return normalizeProvider(providerHint);\n }\n return undefined;\n}\n\n/** Provider hint for ai-profiles index lookup (openrouter → underlying vendor). */\nexport function providerHintForProfiles(\n model: string,\n provider?: string,\n): string | undefined {\n if (isOpenRouterProvider(provider)) {\n return underlyingProviderFromModel(model, provider);\n }\n return normalizeProvider(provider);\n}\n\n/**\n * Catalog resolve attempts for direct API and OpenRouter usage.\n * Tries the caller hint, inferred vendor, no hint, and openrouter routing.\n */\nexport function buildCatalogResolveAttempts(\n model: string,\n provider?: string,\n): ModelResolutionInput[] {\n const attempts: ModelResolutionInput[] = [];\n const seen = new Set<string>();\n const add = (m: string, p?: string) => {\n const key = `${p ?? \"\"}\\0${normalizeString(m)}`;\n if (seen.has(key)) return;\n seen.add(key);\n attempts.push({ model: m, provider: p });\n };\n\n add(model, provider);\n\n const underlying = underlyingProviderFromModel(model, provider);\n if (provider) add(model, undefined);\n if (underlying) add(model, underlying);\n if (!isOpenRouterProvider(provider)) {\n add(model, \"openrouter\");\n }\n\n return attempts;\n}\n\nexport async function resolveFromCatalogAttempts(\n catalog: AiModelsCatalogClient,\n attempts: ModelResolutionInput[],\n options?: ModelResolverOptions,\n): Promise<ModelResolutionResult | null> {\n let last: ModelResolutionResult | null = null;\n let localPassthrough: ModelResolutionResult | null = null;\n\n for (const attempt of attempts) {\n const result = await catalog.resolveModel(attempt, options);\n last = result;\n if (result.found && result.record) return result;\n if (\n result.found &&\n !result.record &&\n isLocalProviderResolution(result, attempt.provider)\n ) {\n localPassthrough = result;\n }\n }\n\n return localPassthrough ?? last;\n}\n\nexport function resolveRoutedViaOpenRouter(\n inputProvider: string | undefined,\n resolved: ModelResolutionResult | null,\n modelId?: string,\n routingEnv?: OpenRouterRoutingConfig,\n): boolean {\n const env = routingEnv ?? loadOpenRouterRoutingEnv();\n\n if (isOpenRouterProvider(inputProvider)) return true;\n\n if (resolved?.found) {\n return resolved.routedViaOpenRouter;\n }\n\n const vendor = underlyingProviderFromModel(\n modelId ?? (resolved?.found ? resolved.modelId : \"\") ?? \"\",\n inputProvider,\n );\n if (vendor && shouldDefaultRouteViaOpenRouter(vendor, env)) {\n return true;\n }\n\n return false;\n}\n","import { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { AIProfilesError, resolveAIProfile } from \"@x12i/ai-profiles\";\nimport type {\n AIProfileBackend,\n AIProfileChoice,\n AIModelPricing,\n AIProfilesRegistry,\n InstructionTier,\n ResolvedAIProfile,\n} from \"@x12i/ai-profiles\";\nimport { providerHintForProfiles } from \"./costModelResolution.js\";\nimport { normalizeProvider, normalizeString } from \"../sync/modelNameResolver/normalize.js\";\nimport { stripModelVersionSuffix } from \"../sync/modelNameResolver/stripVersionSuffix.js\";\n\nconst require = createRequire(import.meta.url);\n\ntype LoadRegistryFn = (options?: {\n source?: \"auto\" | \"remote\" | \"bundled\";\n refresh?: boolean;\n}) => Promise<AIProfilesRegistry>;\n\nfunction loadProfilesRegistry(): Promise<AIProfilesRegistry> {\n const entry = dirname(require.resolve(\"@x12i/ai-profiles\"));\n const loader = require(join(entry, \"loader/loadAIProfilesRegistry.js\")) as {\n loadAIProfilesRegistry: LoadRegistryFn;\n };\n return loader.loadAIProfilesRegistry({ source: \"auto\" });\n}\n\nexport type AiProfilesModelMatch = {\n provider: string;\n modelId: string;\n canonicalModelId: string;\n pricing?: AIModelPricing;\n instructionTier: InstructionTier;\n backend: AIProfileBackend;\n matchedVia: \"profile\" | \"shortcut\" | \"profile-alias\" | \"model-id\";\n profile?: string;\n choice?: string;\n};\n\nfunction profileKey(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction canonicalModelId(provider: string, modelId: string): string {\n const normalized = normalizeString(modelId);\n if (normalized.includes(\"/\")) return normalized;\n const p = normalizeProvider(provider) ?? normalizeString(provider);\n return `${p}/${normalized}`;\n}\n\ntype IndexedChoice = {\n provider: string;\n modelId: string;\n canonicalModelId: string;\n pricing?: AIModelPricing;\n profile: string;\n choice: string;\n};\n\nlet cachedIndex: {\n cacheKey: string;\n byKey: Map<string, IndexedChoice[]>;\n} | null = null;\n\n/** Index bare model ids only — profile/shortcut names resolve via {@link resolveAIProfile}. */\nfunction indexRegistry(registry: AIProfilesRegistry): Map<string, IndexedChoice[]> {\n const byKey = new Map<string, IndexedChoice[]>();\n\n const add = (key: string, entry: IndexedChoice) => {\n const k = profileKey(key);\n if (!k) return;\n const list = byKey.get(k) ?? [];\n if (\n list.some(\n (e) =>\n e.canonicalModelId === entry.canonicalModelId &&\n e.choice === entry.choice &&\n e.profile === entry.profile,\n )\n ) {\n return;\n }\n list.push(entry);\n byKey.set(k, list);\n };\n\n for (const profile of Object.values(registry.profiles)) {\n for (const [choiceKey, choice] of Object.entries(profile.choices)) {\n const entry = choiceEntry(choice, profile.profile, choiceKey);\n add(choice.modelId, entry);\n add(canonicalModelId(choice.provider, choice.modelId), entry);\n }\n }\n\n return byKey;\n}\n\nfunction choiceEntry(\n choice: AIProfileChoice,\n profile: string,\n choiceKey: string,\n): IndexedChoice {\n const canonical = canonicalModelId(choice.provider, choice.modelId);\n return {\n provider: normalizeProvider(choice.provider) ?? choice.provider,\n modelId: normalizeString(choice.modelId),\n canonicalModelId: canonical,\n pricing: choice.pricing,\n profile,\n choice: choiceKey,\n };\n}\n\nasync function getProfileIndex(): Promise<Map<string, IndexedChoice[]>> {\n const registry = await loadProfilesRegistry();\n const cacheKey = `${registry.version}:${registry.generatedAt ?? \"\"}:${registry.source}`;\n if (cachedIndex?.cacheKey === cacheKey) {\n return cachedIndex.byKey;\n }\n const byKey = indexRegistry(registry);\n cachedIndex = { cacheKey, byKey };\n return byKey;\n}\n\nfunction scoreCandidate(\n entry: IndexedChoice,\n model: string,\n providerHint?: string,\n): number {\n const normalized = normalizeString(model);\n let score = 0;\n\n if (normalized === entry.canonicalModelId) score += 100;\n if (normalized === entry.modelId) score += 80;\n if (providerHint && entry.provider === providerHint) score += 50;\n if (entry.pricing) score += 2;\n\n return score;\n}\n\nfunction pickBest(\n candidates: IndexedChoice[],\n model: string,\n providerHint?: string,\n): IndexedChoice | null {\n if (candidates.length === 0) return null;\n if (candidates.length === 1) return candidates[0]!;\n\n let best = candidates[0]!;\n let bestScore = scoreCandidate(best, model, providerHint);\n for (let i = 1; i < candidates.length; i++) {\n const c = candidates[i]!;\n const s = scoreCandidate(c, model, providerHint);\n if (s > bestScore) {\n best = c;\n bestScore = s;\n }\n }\n return best;\n}\n\nfunction resolvedToMatch(resolved: ResolvedAIProfile): AiProfilesModelMatch {\n return {\n provider: normalizeProvider(resolved.provider) ?? resolved.provider,\n modelId: normalizeString(resolved.modelId),\n canonicalModelId: canonicalModelId(resolved.provider, resolved.modelId),\n pricing: resolved.pricing,\n instructionTier: resolved.instructionTier,\n backend: resolved.backend,\n matchedVia: resolved.shortcut ? \"shortcut\" : \"profile\",\n profile: resolved.profile,\n choice: resolved.choice,\n };\n}\n\nasync function fromIndexed(entry: IndexedChoice): Promise<AiProfilesModelMatch> {\n const resolved = await resolveAIProfile(entry.profile, { choice: entry.choice });\n return {\n provider: normalizeProvider(resolved.provider) ?? resolved.provider,\n modelId: normalizeString(resolved.modelId),\n canonicalModelId: canonicalModelId(resolved.provider, resolved.modelId),\n pricing: resolved.pricing ?? entry.pricing,\n instructionTier: resolved.instructionTier,\n backend: resolved.backend,\n matchedVia: \"model-id\",\n profile: resolved.profile,\n choice: resolved.choice,\n };\n}\n\nasync function lookupInIndex(\n index: Map<string, IndexedChoice[]>,\n model: string,\n provider?: string,\n): Promise<AiProfilesModelMatch | null> {\n const providerHint = provider ? normalizeProvider(provider) : undefined;\n const keys = [\n profileKey(model),\n profileKey(normalizeString(model)),\n ];\n if (providerHint) {\n keys.push(profileKey(canonicalModelId(providerHint, model)));\n }\n\n const pooled: IndexedChoice[] = [];\n for (const key of keys) {\n const hits = index.get(key);\n if (hits) pooled.push(...hits);\n }\n\n const bare = normalizeString(model);\n if (!bare.includes(\"/\")) {\n for (const list of index.values()) {\n for (const entry of list) {\n if (entry.modelId === bare) pooled.push(entry);\n }\n }\n }\n\n const unique = new Map<string, IndexedChoice>();\n for (const e of pooled) {\n unique.set(`${e.profile}:${e.choice}:${e.canonicalModelId}`, e);\n }\n\n const best = pickBest([...unique.values()], model, providerHint);\n return best ? fromIndexed(best) : null;\n}\n\n/**\n * Resolve a model string via @x12i/ai-profiles — profile/shortcut names, aliases,\n * or a concrete model id that appears on a profile choice.\n */\nexport async function matchModelInAiProfiles(\n model: string,\n provider?: string,\n): Promise<AiProfilesModelMatch | null> {\n try {\n const resolved = await resolveAIProfile(model);\n return resolvedToMatch(resolved);\n } catch (err) {\n if (!(err instanceof AIProfilesError) || err.code !== \"UNKNOWN_PROFILE\") {\n throw err;\n }\n }\n\n const index = await getProfileIndex();\n const hint = providerHintForProfiles(model, provider);\n const direct = await lookupInIndex(index, model, hint);\n if (direct) return direct;\n\n const stripped = stripModelVersionSuffix(model);\n if (stripped && stripped !== normalizeString(model)) {\n return lookupInIndex(\n index,\n stripped,\n providerHintForProfiles(stripped, provider),\n );\n }\n\n return null;\n}\n\n/** @internal Test-only — reset module cache between tests. */\nexport function resetAiProfilesMatchCacheForTests(): void {\n cachedIndex = null;\n}\n"],"mappings":"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","names":["require"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AiModelsCatalogClient
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-D6OIUYNC.js";
|
|
4
4
|
|
|
5
5
|
// src/models/filterModels.ts
|
|
6
6
|
function matchesSearch(record, search) {
|
|
@@ -83,4 +83,4 @@ export {
|
|
|
83
83
|
AiModelsService,
|
|
84
84
|
getModelInfo
|
|
85
85
|
};
|
|
86
|
-
//# sourceMappingURL=chunk-
|
|
86
|
+
//# sourceMappingURL=chunk-KSJSLKYI.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
computeSupportsReasoning
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-54GKLIDW.js";
|
|
4
4
|
|
|
5
5
|
// src/models/normalizeOpenRouterModel.ts
|
|
6
6
|
function parsePrice(value) {
|
|
@@ -99,4 +99,4 @@ export {
|
|
|
99
99
|
extractProviderId,
|
|
100
100
|
normalizeOpenRouterModel
|
|
101
101
|
};
|
|
102
|
-
//# sourceMappingURL=chunk-
|
|
102
|
+
//# sourceMappingURL=chunk-MOLWV5LV.js.map
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
buildCatalogResolveAttempts,
|
|
3
|
+
isLocalProvider,
|
|
4
|
+
isLocalProviderResolution,
|
|
5
|
+
matchModelInAiProfiles,
|
|
6
|
+
resolveFromCatalogAttempts,
|
|
7
|
+
resolveRoutedViaOpenRouter
|
|
8
|
+
} from "./chunk-HEB73GKJ.js";
|
|
9
|
+
import {
|
|
5
10
|
normalizeString,
|
|
6
|
-
shouldDefaultRouteViaOpenRouter,
|
|
7
11
|
stripModelVersionSuffix
|
|
8
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SLSKQRMI.js";
|
|
9
13
|
import {
|
|
10
14
|
UnknownModelCostError
|
|
11
15
|
} from "./chunk-2PTCWPHV.js";
|
|
@@ -359,275 +363,6 @@ function resolveUsageModel(input) {
|
|
|
359
363
|
return value.trim();
|
|
360
364
|
}
|
|
361
365
|
|
|
362
|
-
// src/cost/aiProfilesMatch.ts
|
|
363
|
-
import { createRequire } from "module";
|
|
364
|
-
import { dirname, join } from "path";
|
|
365
|
-
import { AIProfilesError, resolveAIProfile } from "@x12i/ai-profiles";
|
|
366
|
-
|
|
367
|
-
// src/cost/costModelResolution.ts
|
|
368
|
-
function isOpenRouterProvider(provider) {
|
|
369
|
-
return normalizeProvider(provider) === "openrouter";
|
|
370
|
-
}
|
|
371
|
-
function isLocalProvider(provider) {
|
|
372
|
-
const p = normalizeProvider(provider) ?? normalizeString(provider ?? "");
|
|
373
|
-
return LOCAL_PROVIDERS.has(p);
|
|
374
|
-
}
|
|
375
|
-
function isLocalProviderResolution(resolved, inputProvider) {
|
|
376
|
-
if (!resolved?.found || resolved.record) return false;
|
|
377
|
-
if (resolved.resolvedVia.includes("local-provider-passthrough")) return true;
|
|
378
|
-
return isLocalProvider(inputProvider);
|
|
379
|
-
}
|
|
380
|
-
function underlyingProviderFromModel(model, providerHint) {
|
|
381
|
-
const normalized = normalizeString(model);
|
|
382
|
-
if (normalized.includes("/")) {
|
|
383
|
-
const prefix = normalized.split("/")[0];
|
|
384
|
-
if (!isOpenRouterProvider(prefix)) return prefix;
|
|
385
|
-
}
|
|
386
|
-
if (providerHint && !isOpenRouterProvider(providerHint)) {
|
|
387
|
-
return normalizeProvider(providerHint);
|
|
388
|
-
}
|
|
389
|
-
return void 0;
|
|
390
|
-
}
|
|
391
|
-
function providerHintForProfiles(model, provider) {
|
|
392
|
-
if (isOpenRouterProvider(provider)) {
|
|
393
|
-
return underlyingProviderFromModel(model, provider);
|
|
394
|
-
}
|
|
395
|
-
return normalizeProvider(provider);
|
|
396
|
-
}
|
|
397
|
-
function buildCatalogResolveAttempts(model, provider) {
|
|
398
|
-
const attempts = [];
|
|
399
|
-
const seen = /* @__PURE__ */ new Set();
|
|
400
|
-
const add = (m, p) => {
|
|
401
|
-
const key = `${p ?? ""}\0${normalizeString(m)}`;
|
|
402
|
-
if (seen.has(key)) return;
|
|
403
|
-
seen.add(key);
|
|
404
|
-
attempts.push({ model: m, provider: p });
|
|
405
|
-
};
|
|
406
|
-
add(model, provider);
|
|
407
|
-
const underlying = underlyingProviderFromModel(model, provider);
|
|
408
|
-
if (provider) add(model, void 0);
|
|
409
|
-
if (underlying) add(model, underlying);
|
|
410
|
-
if (!isOpenRouterProvider(provider)) {
|
|
411
|
-
add(model, "openrouter");
|
|
412
|
-
}
|
|
413
|
-
return attempts;
|
|
414
|
-
}
|
|
415
|
-
async function resolveFromCatalogAttempts(catalog, attempts, options) {
|
|
416
|
-
let last = null;
|
|
417
|
-
let localPassthrough = null;
|
|
418
|
-
for (const attempt of attempts) {
|
|
419
|
-
const result = await catalog.resolveModel(attempt, options);
|
|
420
|
-
last = result;
|
|
421
|
-
if (result.found && result.record) return result;
|
|
422
|
-
if (result.found && !result.record && isLocalProviderResolution(result, attempt.provider)) {
|
|
423
|
-
localPassthrough = result;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
return localPassthrough ?? last;
|
|
427
|
-
}
|
|
428
|
-
function resolveRoutedViaOpenRouter(inputProvider, resolved, modelId, routingEnv) {
|
|
429
|
-
const env = routingEnv ?? loadOpenRouterRoutingEnv();
|
|
430
|
-
if (isOpenRouterProvider(inputProvider)) return true;
|
|
431
|
-
if (resolved?.found) {
|
|
432
|
-
return resolved.routedViaOpenRouter;
|
|
433
|
-
}
|
|
434
|
-
const vendor = underlyingProviderFromModel(
|
|
435
|
-
modelId ?? (resolved?.found ? resolved.modelId : "") ?? "",
|
|
436
|
-
inputProvider
|
|
437
|
-
);
|
|
438
|
-
if (vendor && shouldDefaultRouteViaOpenRouter(vendor, env)) {
|
|
439
|
-
return true;
|
|
440
|
-
}
|
|
441
|
-
return false;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// src/cost/aiProfilesMatch.ts
|
|
445
|
-
var require2 = createRequire(import.meta.url);
|
|
446
|
-
function loadProfilesRegistry() {
|
|
447
|
-
const entry = dirname(require2.resolve("@x12i/ai-profiles"));
|
|
448
|
-
const loader = require2(join(entry, "loader/loadAIProfilesRegistry.js"));
|
|
449
|
-
return loader.loadAIProfilesRegistry({ source: "auto" });
|
|
450
|
-
}
|
|
451
|
-
function profileKey(value) {
|
|
452
|
-
return value.trim().toLowerCase();
|
|
453
|
-
}
|
|
454
|
-
function canonicalModelId(provider, modelId) {
|
|
455
|
-
const normalized = normalizeString(modelId);
|
|
456
|
-
if (normalized.includes("/")) return normalized;
|
|
457
|
-
const p = normalizeProvider(provider) ?? normalizeString(provider);
|
|
458
|
-
return `${p}/${normalized}`;
|
|
459
|
-
}
|
|
460
|
-
var cachedIndex = null;
|
|
461
|
-
function indexRegistry(registry) {
|
|
462
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
463
|
-
const add = (key, entry) => {
|
|
464
|
-
const k = profileKey(key);
|
|
465
|
-
if (!k) return;
|
|
466
|
-
const list = byKey.get(k) ?? [];
|
|
467
|
-
if (list.some(
|
|
468
|
-
(e) => e.canonicalModelId === entry.canonicalModelId && e.choice === entry.choice && e.profile === entry.profile
|
|
469
|
-
)) {
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
list.push(entry);
|
|
473
|
-
byKey.set(k, list);
|
|
474
|
-
};
|
|
475
|
-
for (const shortcutKey of Object.keys(registry.shortcuts)) {
|
|
476
|
-
const shortcut = registry.shortcuts[shortcutKey];
|
|
477
|
-
const profile = registry.profiles[shortcut.profile];
|
|
478
|
-
if (!profile) continue;
|
|
479
|
-
const choiceKey = shortcut.choice ?? profile.defaultChoice;
|
|
480
|
-
const choice = profile.choices[choiceKey];
|
|
481
|
-
if (!choice) continue;
|
|
482
|
-
const entry = choiceEntry(choice, profile.profile, choiceKey, "shortcut");
|
|
483
|
-
add(shortcutKey, entry);
|
|
484
|
-
}
|
|
485
|
-
for (const profile of Object.values(registry.profiles)) {
|
|
486
|
-
for (const [choiceKey, choice] of Object.entries(profile.choices)) {
|
|
487
|
-
const entry = choiceEntry(choice, profile.profile, choiceKey, "model-id");
|
|
488
|
-
add(choice.modelId, entry);
|
|
489
|
-
add(canonicalModelId(choice.provider, choice.modelId), entry);
|
|
490
|
-
}
|
|
491
|
-
const defaultChoice = profile.choices[profile.defaultChoice];
|
|
492
|
-
if (defaultChoice) {
|
|
493
|
-
add(
|
|
494
|
-
profile.profile,
|
|
495
|
-
choiceEntry(defaultChoice, profile.profile, profile.defaultChoice, "profile")
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
for (const alias of profile.aliases ?? []) {
|
|
499
|
-
if (defaultChoice) {
|
|
500
|
-
add(
|
|
501
|
-
alias,
|
|
502
|
-
choiceEntry(
|
|
503
|
-
defaultChoice,
|
|
504
|
-
profile.profile,
|
|
505
|
-
profile.defaultChoice,
|
|
506
|
-
"profile-alias"
|
|
507
|
-
)
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
return byKey;
|
|
513
|
-
}
|
|
514
|
-
function choiceEntry(choice, profile, choiceKey, matchedVia) {
|
|
515
|
-
const canonical = canonicalModelId(choice.provider, choice.modelId);
|
|
516
|
-
return {
|
|
517
|
-
provider: normalizeProvider(choice.provider) ?? choice.provider,
|
|
518
|
-
modelId: normalizeString(choice.modelId),
|
|
519
|
-
canonicalModelId: canonical,
|
|
520
|
-
pricing: choice.pricing,
|
|
521
|
-
matchedVia,
|
|
522
|
-
profile,
|
|
523
|
-
choice: choiceKey
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
async function getProfileIndex() {
|
|
527
|
-
const registry = await loadProfilesRegistry();
|
|
528
|
-
const cacheKey = `${registry.version}:${registry.generatedAt ?? ""}:${registry.source}`;
|
|
529
|
-
if (cachedIndex?.cacheKey === cacheKey) {
|
|
530
|
-
return cachedIndex.byKey;
|
|
531
|
-
}
|
|
532
|
-
const byKey = indexRegistry(registry);
|
|
533
|
-
cachedIndex = { cacheKey, byKey };
|
|
534
|
-
return byKey;
|
|
535
|
-
}
|
|
536
|
-
function scoreCandidate(entry, model, providerHint) {
|
|
537
|
-
const normalized = normalizeString(model);
|
|
538
|
-
let score = 0;
|
|
539
|
-
if (normalized === entry.canonicalModelId) score += 100;
|
|
540
|
-
if (normalized === entry.modelId) score += 80;
|
|
541
|
-
if (providerHint && entry.provider === providerHint) score += 50;
|
|
542
|
-
if (entry.matchedVia === "model-id") score += 10;
|
|
543
|
-
if (entry.matchedVia === "shortcut") score += 5;
|
|
544
|
-
if (entry.matchedVia === "profile") score += 3;
|
|
545
|
-
if (entry.pricing) score += 2;
|
|
546
|
-
return score;
|
|
547
|
-
}
|
|
548
|
-
function pickBest(candidates, model, providerHint) {
|
|
549
|
-
if (candidates.length === 0) return null;
|
|
550
|
-
if (candidates.length === 1) return candidates[0];
|
|
551
|
-
let best = candidates[0];
|
|
552
|
-
let bestScore = scoreCandidate(best, model, providerHint);
|
|
553
|
-
for (let i = 1; i < candidates.length; i++) {
|
|
554
|
-
const c = candidates[i];
|
|
555
|
-
const s = scoreCandidate(c, model, providerHint);
|
|
556
|
-
if (s > bestScore) {
|
|
557
|
-
best = c;
|
|
558
|
-
bestScore = s;
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
return best;
|
|
562
|
-
}
|
|
563
|
-
function fromIndexed(entry) {
|
|
564
|
-
return {
|
|
565
|
-
provider: entry.provider,
|
|
566
|
-
modelId: entry.modelId,
|
|
567
|
-
canonicalModelId: entry.canonicalModelId,
|
|
568
|
-
pricing: entry.pricing,
|
|
569
|
-
matchedVia: entry.matchedVia,
|
|
570
|
-
profile: entry.profile,
|
|
571
|
-
choice: entry.choice
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
function lookupInIndex(index, model, provider) {
|
|
575
|
-
const providerHint = provider ? normalizeProvider(provider) : void 0;
|
|
576
|
-
const keys = [
|
|
577
|
-
profileKey(model),
|
|
578
|
-
profileKey(normalizeString(model))
|
|
579
|
-
];
|
|
580
|
-
if (providerHint) {
|
|
581
|
-
keys.push(profileKey(canonicalModelId(providerHint, model)));
|
|
582
|
-
}
|
|
583
|
-
const pooled = [];
|
|
584
|
-
for (const key of keys) {
|
|
585
|
-
const hits = index.get(key);
|
|
586
|
-
if (hits) pooled.push(...hits);
|
|
587
|
-
}
|
|
588
|
-
const bare = normalizeString(model);
|
|
589
|
-
if (!bare.includes("/")) {
|
|
590
|
-
for (const list of index.values()) {
|
|
591
|
-
for (const entry of list) {
|
|
592
|
-
if (entry.modelId === bare) pooled.push(entry);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
const unique = /* @__PURE__ */ new Map();
|
|
597
|
-
for (const e of pooled) {
|
|
598
|
-
unique.set(`${e.profile}:${e.choice}:${e.canonicalModelId}`, e);
|
|
599
|
-
}
|
|
600
|
-
const best = pickBest([...unique.values()], model, providerHint);
|
|
601
|
-
return best ? fromIndexed(best) : null;
|
|
602
|
-
}
|
|
603
|
-
async function matchModelInAiProfiles(model, provider) {
|
|
604
|
-
try {
|
|
605
|
-
const resolved = await resolveAIProfile(model);
|
|
606
|
-
return {
|
|
607
|
-
provider: normalizeProvider(resolved.provider) ?? resolved.provider,
|
|
608
|
-
modelId: normalizeString(resolved.modelId),
|
|
609
|
-
canonicalModelId: canonicalModelId(resolved.provider, resolved.modelId),
|
|
610
|
-
pricing: resolved.pricing,
|
|
611
|
-
matchedVia: resolved.shortcut ? "shortcut" : "profile",
|
|
612
|
-
profile: resolved.profile,
|
|
613
|
-
choice: resolved.choice
|
|
614
|
-
};
|
|
615
|
-
} catch (err) {
|
|
616
|
-
if (!(err instanceof AIProfilesError) || err.code !== "UNKNOWN_PROFILE") {
|
|
617
|
-
throw err;
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
const index = await getProfileIndex();
|
|
621
|
-
const hint = providerHintForProfiles(model, provider);
|
|
622
|
-
const direct = lookupInIndex(index, model, hint);
|
|
623
|
-
if (direct) return direct;
|
|
624
|
-
const stripped = stripModelVersionSuffix(model);
|
|
625
|
-
if (stripped && stripped !== normalizeString(model)) {
|
|
626
|
-
return lookupInIndex(index, stripped, providerHintForProfiles(stripped, provider));
|
|
627
|
-
}
|
|
628
|
-
return null;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
366
|
// src/cost/profilePricing.ts
|
|
632
367
|
var TOKENS_PER_UNIT = 1e6;
|
|
633
368
|
function usdPerToken(perMillion) {
|
|
@@ -967,4 +702,4 @@ export {
|
|
|
967
702
|
resolveUsageModel,
|
|
968
703
|
CostCalculator
|
|
969
704
|
};
|
|
970
|
-
//# sourceMappingURL=chunk-
|
|
705
|
+
//# sourceMappingURL=chunk-PN4FF6YF.js.map
|