sidekick-shared 0.24.5 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/README.md +205 -52
- package/dist/accountChangeSignal.d.ts +3 -0
- package/dist/accountChangeSignal.js +19 -0
- package/dist/accountChanges.d.ts +21 -0
- package/dist/accountChanges.js +170 -0
- package/dist/accountRegistry.d.ts +25 -2
- package/dist/accountRegistry.js +41 -13
- package/dist/accountStatus.d.ts +9 -1
- package/dist/accountStatus.js +3 -3
- package/dist/accounts.d.ts +3 -1
- package/dist/accounts.js +84 -64
- package/dist/aggregation/EventAggregator.d.ts +15 -2
- package/dist/aggregation/EventAggregator.js +54 -9
- package/dist/aggregation/costProvenance.d.ts +14 -0
- package/dist/aggregation/costProvenance.js +35 -0
- package/dist/aggregation/snapshot.d.ts +13 -2
- package/dist/aggregation/snapshot.js +57 -6
- package/dist/aggregation/types.d.ts +30 -1
- package/dist/analytics/compactionLedger.js +15 -5
- package/dist/analytics/qualityScore.js +2 -1
- package/dist/browser.d.ts +19 -4
- package/dist/browser.js +43 -1
- package/dist/codexProfiles.d.ts +3 -1
- package/dist/codexProfiles.js +4 -2
- package/dist/codexQuota.d.ts +2 -0
- package/dist/codexQuota.js +11 -66
- package/dist/codexQuotaWatcher.d.ts +6 -0
- package/dist/codexQuotaWatcher.js +101 -47
- package/dist/failingTools.d.ts +37 -0
- package/dist/failingTools.js +70 -0
- package/dist/formatters/sessionDump.js +13 -7
- package/dist/formatting.d.ts +13 -0
- package/dist/formatting.js +35 -0
- package/dist/historicalStore.d.ts +47 -0
- package/dist/historicalStore.js +312 -0
- package/dist/index.d.ts +67 -23
- package/dist/index.js +138 -26
- package/dist/modelAliases.d.ts +13 -0
- package/dist/modelAliases.js +58 -0
- package/dist/modelCatalog.d.ts +32 -0
- package/dist/modelCatalog.js +145 -0
- package/dist/modelContext.d.ts +36 -3
- package/dist/modelContext.js +109 -34
- package/dist/modelInfo.d.ts +30 -1
- package/dist/modelInfo.js +116 -26
- package/dist/multiProviderQuotaService.d.ts +8 -0
- package/dist/multiProviderQuotaService.js +64 -3
- package/dist/node.d.ts +23 -4
- package/dist/node.js +50 -1
- package/dist/observedContextWindows.d.ts +7 -0
- package/dist/observedContextWindows.js +17 -2
- package/dist/observedSessionCollector.d.ts +72 -6
- package/dist/observedSessionCollector.js +440 -47
- package/dist/parsers/codexHistory.d.ts +4 -2
- package/dist/parsers/codexHistory.js +9 -2
- package/dist/parsers/sessionActivityDetector.d.ts +28 -0
- package/dist/parsers/sessionActivityDetector.js +110 -15
- package/dist/parsers/sessionPathResolver.d.ts +11 -0
- package/dist/parsers/sessionPathResolver.js +13 -10
- package/dist/peakHours.d.ts +34 -3
- package/dist/peakHours.js +92 -7
- package/dist/pricingCatalog.d.ts +7 -0
- package/dist/pricingCatalog.js +8 -5
- package/dist/providerIds.d.ts +11 -0
- package/dist/providerIds.js +9 -0
- package/dist/providerQuota.d.ts +3 -1
- package/dist/providerQuota.js +3 -0
- package/dist/providers/claudeCode.d.ts +10 -1
- package/dist/providers/claudeCode.js +211 -131
- package/dist/providers/codex.d.ts +20 -1
- package/dist/providers/codex.js +308 -244
- package/dist/providers/codexDatabase.d.ts +9 -0
- package/dist/providers/codexDatabase.js +107 -2
- package/dist/providers/detect.d.ts +2 -0
- package/dist/providers/detect.js +29 -24
- package/dist/providers/diagnostics.d.ts +13 -0
- package/dist/providers/diagnostics.js +88 -0
- package/dist/providers/factory.d.ts +20 -0
- package/dist/providers/factory.js +57 -0
- package/dist/providers/openCode.d.ts +22 -1
- package/dist/providers/openCode.js +460 -126
- package/dist/providers/openCodeDatabase.d.ts +10 -0
- package/dist/providers/openCodeDatabase.js +69 -0
- package/dist/providers/rolloutWalker.d.ts +53 -0
- package/dist/providers/rolloutWalker.js +209 -0
- package/dist/providers/types.d.ts +82 -2
- package/dist/providers/types.js +4 -0
- package/dist/quota.d.ts +34 -4
- package/dist/quota.js +37 -9
- package/dist/quotaHistory.d.ts +3 -2
- package/dist/quotaHistory.js +36 -35
- package/dist/quotaPoller.d.ts +13 -1
- package/dist/quotaPoller.js +65 -3
- package/dist/quotaResolver.d.ts +81 -0
- package/dist/quotaResolver.js +213 -0
- package/dist/quotaSnapshots.d.ts +15 -2
- package/dist/quotaSnapshots.js +25 -3
- package/dist/quotaThresholds.d.ts +60 -0
- package/dist/quotaThresholds.js +90 -0
- package/dist/report/htmlReportGenerator.js +10 -4
- package/dist/report/sessionReportInputs.d.ts +23 -0
- package/dist/report/sessionReportInputs.js +34 -0
- package/dist/schemas/accountManager.d.ts +2 -2
- package/dist/schemas/accountManager.js +2 -4
- package/dist/schemas/accountStatus.d.ts +3 -0
- package/dist/schemas/accountStatus.js +1 -0
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.js +16 -2
- package/dist/schemas/observedSessionV1.d.ts +27 -26
- package/dist/schemas/observedSessionV1.js +6 -4
- package/dist/schemas/quota.d.ts +141 -2
- package/dist/schemas/quota.js +20 -8
- package/dist/schemas/quotaHistory.d.ts +3 -2
- package/dist/schemas/quotaHistory.js +1 -1
- package/dist/schemas/sessionEvent.d.ts +6 -0
- package/dist/schemas/sessionEvent.js +1 -0
- package/dist/schemas/stateFile.d.ts +198 -0
- package/dist/schemas/stateFile.js +77 -0
- package/dist/schemas/tokenEstimation.d.ts +1 -1
- package/dist/schemas/transcript.js +2 -0
- package/dist/sessionFingerprint.d.ts +25 -0
- package/dist/sessionFingerprint.js +46 -0
- package/dist/sessionMonitor.d.ts +15 -0
- package/dist/sessionMonitor.js +142 -0
- package/dist/sessionPreviews.d.ts +33 -2
- package/dist/sessionPreviews.js +333 -6
- package/dist/sessionStats.d.ts +51 -0
- package/dist/sessionStats.js +166 -0
- package/dist/stateFile.d.ts +113 -0
- package/dist/stateFile.js +160 -0
- package/dist/statusline/claudeStatuslinePayload.d.ts +89 -0
- package/dist/statusline/claudeStatuslinePayload.js +152 -0
- package/dist/statusline/formatter.d.ts +13 -0
- package/dist/statusline/formatter.js +48 -6
- package/dist/statusline/index.d.ts +10 -2
- package/dist/statusline/index.js +19 -1
- package/dist/tokenSummary.d.ts +62 -0
- package/dist/tokenSummary.js +72 -0
- package/dist/transcript.d.ts +5 -0
- package/dist/transcript.js +2 -0
- package/dist/types/observedSessionV1.d.ts +8 -2
- package/dist/types/observedSessionV1.js +88 -25
- package/dist/types/sessionEvent.d.ts +2 -0
- package/dist/usage/billingBlocks.d.ts +85 -0
- package/dist/usage/billingBlocks.js +153 -0
- package/dist/usage/importSessionHistory.d.ts +53 -0
- package/dist/usage/importSessionHistory.js +88 -0
- package/dist/usage/usageEvents.d.ts +92 -0
- package/dist/usage/usageEvents.js +322 -0
- package/dist/usage/usageReports.d.ts +76 -0
- package/dist/usage/usageReports.js +208 -0
- package/dist/watchers/factory.d.ts +6 -0
- package/dist/watchers/factory.js +30 -25
- package/dist/zaiQuotaApi.d.ts +2 -0
- package/dist/zaiQuotaApi.js +2 -0
- package/package.json +22 -1
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveModelAlias = exports.registerModelAlias = exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = void 0;
|
|
4
|
+
exports.exportResolvedModelCatalog = exportResolvedModelCatalog;
|
|
5
|
+
exports.importResolvedModelCatalog = importResolvedModelCatalog;
|
|
6
|
+
const modelContext_1 = require("./modelContext");
|
|
7
|
+
const modelInfo_1 = require("./modelInfo");
|
|
8
|
+
const modelAliases_1 = require("./modelAliases");
|
|
9
|
+
Object.defineProperty(exports, "registerModelAlias", { enumerable: true, get: function () { return modelAliases_1.registerModelAlias; } });
|
|
10
|
+
Object.defineProperty(exports, "resolveModelAlias", { enumerable: true, get: function () { return modelAliases_1.resolveModelAlias; } });
|
|
11
|
+
exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = 1;
|
|
12
|
+
function normalizedIds(ids) {
|
|
13
|
+
if (ids) {
|
|
14
|
+
return Array.from(new Set(ids.map((id) => id.trim()).filter(Boolean)));
|
|
15
|
+
}
|
|
16
|
+
const aliases = (0, modelAliases_1._getModelAliases)();
|
|
17
|
+
return Array.from(new Set([
|
|
18
|
+
...(0, modelContext_1._getModelContextIds)(),
|
|
19
|
+
...(0, modelInfo_1._getModelPricingIds)(),
|
|
20
|
+
...Object.keys(aliases),
|
|
21
|
+
...Object.values(aliases),
|
|
22
|
+
])).sort();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Export an entirely serializable catalog suitable for IPC to another JS realm.
|
|
26
|
+
* Each entry records published, observed, and tier-effective context windows,
|
|
27
|
+
* plus pricing match provenance (including prefix inheritance).
|
|
28
|
+
*/
|
|
29
|
+
function exportResolvedModelCatalog(ids) {
|
|
30
|
+
const models = {};
|
|
31
|
+
const selectedIds = normalizedIds(ids);
|
|
32
|
+
for (const id of selectedIds) {
|
|
33
|
+
const canonicalId = (0, modelAliases_1.resolveModelAlias)(id);
|
|
34
|
+
models[id] = {
|
|
35
|
+
id,
|
|
36
|
+
canonicalId,
|
|
37
|
+
contextWindow: (0, modelContext_1.resolveModelContextWindow)(id),
|
|
38
|
+
pricing: (0, modelInfo_1.resolveModelPricing)(id),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const selectedCanonicalIds = new Set(Object.values(models).flatMap(({ id, canonicalId }) => [id, canonicalId]));
|
|
42
|
+
const aliases = Object.fromEntries(Object.entries((0, modelAliases_1._getModelAliases)()).filter(([alias, canonicalId]) => selectedCanonicalIds.has(alias) || selectedCanonicalIds.has(canonicalId)));
|
|
43
|
+
return { schemaVersion: exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION, models, aliases };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Hydrate exact model resolutions exported by another bundle realm.
|
|
47
|
+
* Invalid entries are skipped and reported; import never partially mutates an
|
|
48
|
+
* entry or throws for malformed IPC data.
|
|
49
|
+
*/
|
|
50
|
+
function importResolvedModelCatalog(snapshot) {
|
|
51
|
+
const diagnostics = [];
|
|
52
|
+
if (!isRecord(snapshot) || snapshot.schemaVersion !== exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION) {
|
|
53
|
+
return { imported: 0, diagnostics: ['unsupported resolved model catalog snapshot'] };
|
|
54
|
+
}
|
|
55
|
+
const aliases = isStringRecord(snapshot.aliases) ? snapshot.aliases : {};
|
|
56
|
+
(0, modelAliases_1._importModelAliases)(aliases);
|
|
57
|
+
const contexts = {};
|
|
58
|
+
const prices = {};
|
|
59
|
+
const models = isRecord(snapshot.models) ? snapshot.models : {};
|
|
60
|
+
let imported = 0;
|
|
61
|
+
for (const [key, rawEntry] of Object.entries(models)) {
|
|
62
|
+
if (!isResolvedEntry(rawEntry)) {
|
|
63
|
+
diagnostics.push(`ignored invalid model catalog entry: ${key}`);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const entry = rawEntry;
|
|
67
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
68
|
+
const canonicalId = entry.canonicalId.trim().toLowerCase();
|
|
69
|
+
const context = cloneContext(entry.contextWindow, entry.id, canonicalId);
|
|
70
|
+
const pricing = clonePricing(entry.pricing, entry.id, canonicalId);
|
|
71
|
+
// Unresolved facets are not importable facts: pinning a 'default' window
|
|
72
|
+
// or 'none' pricing would outrank data the importing realm can resolve
|
|
73
|
+
// (or later learn) on its own.
|
|
74
|
+
const contextResolved = context.provenance.source !== 'default';
|
|
75
|
+
const pricingResolved = pricing.provenance.source !== 'none';
|
|
76
|
+
if (!contextResolved && !pricingResolved) {
|
|
77
|
+
diagnostics.push(`skipped unresolved model catalog entry: ${key}`);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
for (const id of new Set([normalizedKey, entry.id.trim().toLowerCase(), canonicalId])) {
|
|
81
|
+
if (!id)
|
|
82
|
+
continue;
|
|
83
|
+
if (contextResolved)
|
|
84
|
+
contexts[id] = context;
|
|
85
|
+
if (pricingResolved)
|
|
86
|
+
prices[id] = pricing;
|
|
87
|
+
}
|
|
88
|
+
imported++;
|
|
89
|
+
}
|
|
90
|
+
(0, modelContext_1._setImportedResolvedContextWindows)(contexts);
|
|
91
|
+
(0, modelInfo_1._setImportedResolvedPricing)(prices);
|
|
92
|
+
return { imported, diagnostics };
|
|
93
|
+
}
|
|
94
|
+
function cloneContext(value, modelId, canonicalModelId) {
|
|
95
|
+
return {
|
|
96
|
+
...value,
|
|
97
|
+
modelId,
|
|
98
|
+
canonicalModelId,
|
|
99
|
+
provenance: { ...value.provenance },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function clonePricing(value, modelId, canonicalModelId) {
|
|
103
|
+
return {
|
|
104
|
+
...value,
|
|
105
|
+
modelId,
|
|
106
|
+
canonicalModelId,
|
|
107
|
+
pricing: value.pricing ? { ...value.pricing } : null,
|
|
108
|
+
provenance: { ...value.provenance },
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function isRecord(value) {
|
|
112
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
113
|
+
}
|
|
114
|
+
function isStringRecord(value) {
|
|
115
|
+
return isRecord(value) && Object.values(value).every((item) => typeof item === 'string');
|
|
116
|
+
}
|
|
117
|
+
function validPricing(value) {
|
|
118
|
+
if (!isRecord(value))
|
|
119
|
+
return false;
|
|
120
|
+
return [
|
|
121
|
+
value.inputCostPerMillion,
|
|
122
|
+
value.outputCostPerMillion,
|
|
123
|
+
value.cacheWriteCostPerMillion,
|
|
124
|
+
value.cacheReadCostPerMillion,
|
|
125
|
+
].every((item) => typeof item === 'number' && Number.isFinite(item) && item >= 0);
|
|
126
|
+
}
|
|
127
|
+
function isResolvedEntry(value) {
|
|
128
|
+
if (!isRecord(value) || typeof value.id !== 'string' || typeof value.canonicalId !== 'string') {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
const context = value.contextWindow;
|
|
132
|
+
const pricing = value.pricing;
|
|
133
|
+
if (!isRecord(context) || !isRecord(pricing))
|
|
134
|
+
return false;
|
|
135
|
+
if (typeof context.tierEffective !== 'number' ||
|
|
136
|
+
!Number.isFinite(context.tierEffective) ||
|
|
137
|
+
context.tierEffective <= 0 ||
|
|
138
|
+
(context.published !== null && typeof context.published !== 'number') ||
|
|
139
|
+
(context.observed !== null && typeof context.observed !== 'number') ||
|
|
140
|
+
!isRecord(context.provenance) ||
|
|
141
|
+
!isRecord(pricing.provenance)) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return pricing.pricing === null || validPricing(pricing.pricing);
|
|
145
|
+
}
|
package/dist/modelContext.d.ts
CHANGED
|
@@ -9,13 +9,19 @@
|
|
|
9
9
|
* model, persisted across runs by `observedContextWindows.ts`. Reflects the
|
|
10
10
|
* effective window for this account/tier, which can be well below the
|
|
11
11
|
* model's published maximum.
|
|
12
|
-
* 3.
|
|
12
|
+
* 3. Imported resolutions — exact entries hydrated from another realm via
|
|
13
|
+
* `importResolvedModelCatalog()`. Below local observed data (a window this
|
|
14
|
+
* realm saw first-hand is fresher than a transferred snapshot), above the
|
|
15
|
+
* catalog.
|
|
16
|
+
* 4. Catalog overrides — `max_input_tokens` from the LiteLLM catalog, hydrated
|
|
13
17
|
* by `pricingCatalog.ts`. Keeps new models correct without a code change.
|
|
14
|
-
*
|
|
18
|
+
* 5. The static table below — offline baseline of last resort.
|
|
15
19
|
*
|
|
16
20
|
* Within that order, match quality comes first: every layer is tried for an
|
|
17
21
|
* exact hit before any layer is tried for a prefix hit. See
|
|
18
|
-
* `getModelContextWindowSize`.
|
|
22
|
+
* `getModelContextWindowSize`. The raw (alias) id is tried before its
|
|
23
|
+
* canonical target at every step, so registering an alias never orphans data
|
|
24
|
+
* recorded under the alias itself.
|
|
19
25
|
*
|
|
20
26
|
* Layers 2 and 3 are pushed in by Node-only modules through the `_set*` hooks,
|
|
21
27
|
* so this file stays browser-safe (no node:fs, no fetch) and can be bundled for
|
|
@@ -23,6 +29,21 @@
|
|
|
23
29
|
*/
|
|
24
30
|
/** Default context window size when model is unknown. */
|
|
25
31
|
export declare const DEFAULT_CONTEXT_WINDOW = 200000;
|
|
32
|
+
export type ModelContextWindowSource = 'explicit-1m' | 'imported' | 'observed' | 'catalog' | 'static' | 'default';
|
|
33
|
+
export type ModelCatalogMatch = 'exact' | 'prefix' | 'default';
|
|
34
|
+
export interface ModelContextWindowProvenance {
|
|
35
|
+
source: ModelContextWindowSource;
|
|
36
|
+
match: ModelCatalogMatch;
|
|
37
|
+
matchedModelId?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface ResolvedModelContextWindow {
|
|
40
|
+
modelId: string;
|
|
41
|
+
canonicalModelId: string;
|
|
42
|
+
published: number | null;
|
|
43
|
+
observed: number | null;
|
|
44
|
+
tierEffective: number;
|
|
45
|
+
provenance: ModelContextWindowProvenance;
|
|
46
|
+
}
|
|
26
47
|
/**
|
|
27
48
|
* Internal: replace the observed-context-window map. Called by
|
|
28
49
|
* `observedContextWindows.ts` on load and on each newly observed value.
|
|
@@ -43,6 +64,18 @@ export declare function _setCatalogContextWindows(overrides: Record<string, numb
|
|
|
43
64
|
export declare function _getCatalogContextWindows(): Record<string, number>;
|
|
44
65
|
/** Internal: clear catalog overrides (used by tests and when disabling hydration). */
|
|
45
66
|
export declare function _clearCatalogContextWindows(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Internal: hydrate exact, already-resolved context data from another realm.
|
|
69
|
+
* Merges so successive partial imports accumulate (aliases already merge);
|
|
70
|
+
* use `_clearImportedResolvedContextWindows` to reset.
|
|
71
|
+
*/
|
|
72
|
+
export declare function _setImportedResolvedContextWindows(values: Record<string, ResolvedModelContextWindow>): void;
|
|
73
|
+
/** Internal test hook. */
|
|
74
|
+
export declare function _clearImportedResolvedContextWindows(): void;
|
|
75
|
+
/** Internal: list every ID known to the context resolver. */
|
|
76
|
+
export declare function _getModelContextIds(): string[];
|
|
77
|
+
/** Resolve published, observed, and tier-effective context windows with provenance. */
|
|
78
|
+
export declare function resolveModelContextWindow(modelId?: string): ResolvedModelContextWindow;
|
|
46
79
|
/**
|
|
47
80
|
* Returns the context window size for a model ID.
|
|
48
81
|
*
|
package/dist/modelContext.js
CHANGED
|
@@ -10,13 +10,19 @@
|
|
|
10
10
|
* model, persisted across runs by `observedContextWindows.ts`. Reflects the
|
|
11
11
|
* effective window for this account/tier, which can be well below the
|
|
12
12
|
* model's published maximum.
|
|
13
|
-
* 3.
|
|
13
|
+
* 3. Imported resolutions — exact entries hydrated from another realm via
|
|
14
|
+
* `importResolvedModelCatalog()`. Below local observed data (a window this
|
|
15
|
+
* realm saw first-hand is fresher than a transferred snapshot), above the
|
|
16
|
+
* catalog.
|
|
17
|
+
* 4. Catalog overrides — `max_input_tokens` from the LiteLLM catalog, hydrated
|
|
14
18
|
* by `pricingCatalog.ts`. Keeps new models correct without a code change.
|
|
15
|
-
*
|
|
19
|
+
* 5. The static table below — offline baseline of last resort.
|
|
16
20
|
*
|
|
17
21
|
* Within that order, match quality comes first: every layer is tried for an
|
|
18
22
|
* exact hit before any layer is tried for a prefix hit. See
|
|
19
|
-
* `getModelContextWindowSize`.
|
|
23
|
+
* `getModelContextWindowSize`. The raw (alias) id is tried before its
|
|
24
|
+
* canonical target at every step, so registering an alias never orphans data
|
|
25
|
+
* recorded under the alias itself.
|
|
20
26
|
*
|
|
21
27
|
* Layers 2 and 3 are pushed in by Node-only modules through the `_set*` hooks,
|
|
22
28
|
* so this file stays browser-safe (no node:fs, no fetch) and can be bundled for
|
|
@@ -30,7 +36,12 @@ exports._clearObservedContextWindows = _clearObservedContextWindows;
|
|
|
30
36
|
exports._setCatalogContextWindows = _setCatalogContextWindows;
|
|
31
37
|
exports._getCatalogContextWindows = _getCatalogContextWindows;
|
|
32
38
|
exports._clearCatalogContextWindows = _clearCatalogContextWindows;
|
|
39
|
+
exports._setImportedResolvedContextWindows = _setImportedResolvedContextWindows;
|
|
40
|
+
exports._clearImportedResolvedContextWindows = _clearImportedResolvedContextWindows;
|
|
41
|
+
exports._getModelContextIds = _getModelContextIds;
|
|
42
|
+
exports.resolveModelContextWindow = resolveModelContextWindow;
|
|
33
43
|
exports.getModelContextWindowSize = getModelContextWindowSize;
|
|
44
|
+
const modelAliases_1 = require("./modelAliases");
|
|
34
45
|
/** Known model context window sizes (in tokens). */
|
|
35
46
|
const MODEL_CONTEXT_SIZES = {
|
|
36
47
|
// Claude — native 1M context (Fable 5, Opus 4.6+, Sonnet 4.6+)
|
|
@@ -92,6 +103,7 @@ let observedTable = {};
|
|
|
92
103
|
let observedSortedKeys = [];
|
|
93
104
|
let catalogTable = {};
|
|
94
105
|
let catalogSortedKeys = [];
|
|
106
|
+
let importedTable = {};
|
|
95
107
|
function sortKeysLongestFirst(table) {
|
|
96
108
|
return Object.keys(table).sort((a, b) => b.length - a.length);
|
|
97
109
|
}
|
|
@@ -145,20 +157,109 @@ function _clearCatalogContextWindows() {
|
|
|
145
157
|
catalogTable = {};
|
|
146
158
|
catalogSortedKeys = [];
|
|
147
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Internal: hydrate exact, already-resolved context data from another realm.
|
|
162
|
+
* Merges so successive partial imports accumulate (aliases already merge);
|
|
163
|
+
* use `_clearImportedResolvedContextWindows` to reset.
|
|
164
|
+
*/
|
|
165
|
+
function _setImportedResolvedContextWindows(values) {
|
|
166
|
+
importedTable = { ...importedTable, ...values };
|
|
167
|
+
}
|
|
168
|
+
/** Internal test hook. */
|
|
169
|
+
function _clearImportedResolvedContextWindows() {
|
|
170
|
+
importedTable = {};
|
|
171
|
+
}
|
|
172
|
+
/** Internal: list every ID known to the context resolver. */
|
|
173
|
+
function _getModelContextIds() {
|
|
174
|
+
return Array.from(new Set([
|
|
175
|
+
...Object.keys(MODEL_CONTEXT_SIZES),
|
|
176
|
+
...Object.keys(catalogTable),
|
|
177
|
+
...Object.keys(observedTable),
|
|
178
|
+
...Object.keys(importedTable),
|
|
179
|
+
]));
|
|
180
|
+
}
|
|
148
181
|
// ── Lookup ──
|
|
149
182
|
/** Exact match against one table. */
|
|
150
183
|
function exactWindow(table, modelId) {
|
|
151
184
|
const hit = table[modelId];
|
|
152
185
|
return hit === undefined ? null : hit;
|
|
153
186
|
}
|
|
154
|
-
|
|
155
|
-
|
|
187
|
+
function exactWindowMatch(table, modelId) {
|
|
188
|
+
const exact = exactWindow(table, modelId);
|
|
189
|
+
return exact === null ? null : { value: exact, match: 'exact', matchedModelId: modelId };
|
|
190
|
+
}
|
|
191
|
+
function prefixWindowMatch(table, sortedKeys, modelId) {
|
|
156
192
|
for (const key of sortedKeys) {
|
|
157
|
-
if (modelId.startsWith(key))
|
|
158
|
-
return table[key];
|
|
193
|
+
if (modelId !== key && modelId.startsWith(key)) {
|
|
194
|
+
return { value: table[key], match: 'prefix', matchedModelId: key };
|
|
195
|
+
}
|
|
159
196
|
}
|
|
160
197
|
return null;
|
|
161
198
|
}
|
|
199
|
+
/** Resolve published, observed, and tier-effective context windows with provenance. */
|
|
200
|
+
function resolveModelContextWindow(modelId) {
|
|
201
|
+
const rawModelId = modelId ?? '';
|
|
202
|
+
const stripped = rawModelId
|
|
203
|
+
.replace(/\[1m\]/gi, '')
|
|
204
|
+
.trim()
|
|
205
|
+
.toLowerCase();
|
|
206
|
+
const canonicalModelId = (0, modelAliases_1.resolveModelAlias)(stripped);
|
|
207
|
+
if (/\[1m\]/i.test(rawModelId) || /\[1m\]/i.test(canonicalModelId)) {
|
|
208
|
+
return {
|
|
209
|
+
modelId: rawModelId,
|
|
210
|
+
canonicalModelId: canonicalModelId.replace(/\[1m\]/gi, ''),
|
|
211
|
+
published: 1_000_000,
|
|
212
|
+
observed: null,
|
|
213
|
+
tierEffective: 1_000_000,
|
|
214
|
+
provenance: { source: 'explicit-1m', match: 'exact', matchedModelId: canonicalModelId },
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// The raw id is tried before its alias target at every step: data recorded
|
|
218
|
+
// for the alias id itself is more specific than the canonical fallback.
|
|
219
|
+
const candidateIds = stripped === canonicalModelId ? [canonicalModelId] : [stripped, canonicalModelId];
|
|
220
|
+
const firstMatch = (lookup) => {
|
|
221
|
+
for (const id of candidateIds) {
|
|
222
|
+
const hit = lookup(id);
|
|
223
|
+
if (hit)
|
|
224
|
+
return hit;
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
};
|
|
228
|
+
const observedExact = firstMatch((id) => exactWindowMatch(observedTable, id));
|
|
229
|
+
// Imported resolutions rank below local observed data: a window this realm
|
|
230
|
+
// saw first-hand is fresher than a snapshot transferred from another realm.
|
|
231
|
+
if (!observedExact) {
|
|
232
|
+
const imported = importedTable[stripped] ?? importedTable[canonicalModelId];
|
|
233
|
+
if (imported) {
|
|
234
|
+
return { ...imported, modelId: rawModelId, canonicalModelId };
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const catalogExact = firstMatch((id) => exactWindowMatch(catalogTable, id));
|
|
238
|
+
const staticExact = firstMatch((id) => exactWindowMatch(MODEL_CONTEXT_SIZES, id));
|
|
239
|
+
const observedPrefix = firstMatch((id) => prefixWindowMatch(observedTable, observedSortedKeys, id));
|
|
240
|
+
const catalogPrefix = firstMatch((id) => prefixWindowMatch(catalogTable, catalogSortedKeys, id));
|
|
241
|
+
const staticPrefix = firstMatch((id) => prefixWindowMatch(MODEL_CONTEXT_SIZES, SORTED_KEYS, id));
|
|
242
|
+
const published = catalogExact ?? staticExact ?? catalogPrefix ?? staticPrefix;
|
|
243
|
+
const effective = observedExact ?? catalogExact ?? staticExact ?? observedPrefix ?? catalogPrefix ?? staticPrefix;
|
|
244
|
+
return {
|
|
245
|
+
modelId: rawModelId,
|
|
246
|
+
canonicalModelId,
|
|
247
|
+
published: published?.value ?? null,
|
|
248
|
+
observed: (observedExact ?? observedPrefix)?.value ?? null,
|
|
249
|
+
tierEffective: effective?.value ?? exports.DEFAULT_CONTEXT_WINDOW,
|
|
250
|
+
provenance: effective
|
|
251
|
+
? {
|
|
252
|
+
source: effective === observedExact || effective === observedPrefix
|
|
253
|
+
? 'observed'
|
|
254
|
+
: effective === catalogExact || effective === catalogPrefix
|
|
255
|
+
? 'catalog'
|
|
256
|
+
: 'static',
|
|
257
|
+
match: effective.match,
|
|
258
|
+
matchedModelId: effective.matchedModelId,
|
|
259
|
+
}
|
|
260
|
+
: { source: 'default', match: 'default' },
|
|
261
|
+
};
|
|
262
|
+
}
|
|
162
263
|
/**
|
|
163
264
|
* Returns the context window size for a model ID.
|
|
164
265
|
*
|
|
@@ -180,31 +281,5 @@ function prefixWindow(table, sortedKeys, modelId) {
|
|
|
180
281
|
* of the static table's exact 1M.
|
|
181
282
|
*/
|
|
182
283
|
function getModelContextWindowSize(modelId) {
|
|
183
|
-
|
|
184
|
-
return exports.DEFAULT_CONTEXT_WINDOW;
|
|
185
|
-
// Claude Code tags the 1M-context variant with a "[1m]" suffix on the
|
|
186
|
-
// model ID. If we see it, honor it regardless of the base family.
|
|
187
|
-
if (/\[1m\]/i.test(modelId))
|
|
188
|
-
return 1_000_000;
|
|
189
|
-
// Strip the suffix if present, so the normal lookup still succeeds when
|
|
190
|
-
// a caller passes e.g. "claude-opus-5[1m]" and we've already handled it.
|
|
191
|
-
// Trim/lowercase so padded or mixed-case IDs match the lowercase table keys.
|
|
192
|
-
const normalized = modelId
|
|
193
|
-
.replace(/\[1m\]/gi, '')
|
|
194
|
-
.trim()
|
|
195
|
-
.toLowerCase();
|
|
196
|
-
// Pass 1 — exact matches, most-trusted layer first.
|
|
197
|
-
const exact = exactWindow(observedTable, normalized) ??
|
|
198
|
-
exactWindow(catalogTable, normalized) ??
|
|
199
|
-
exactWindow(MODEL_CONTEXT_SIZES, normalized);
|
|
200
|
-
if (exact !== null)
|
|
201
|
-
return exact;
|
|
202
|
-
// Pass 2 — longest-prefix matches, same layer order. Resolves versioned IDs
|
|
203
|
-
// that no layer spells out, e.g. "claude-opus-4-6-20250414".
|
|
204
|
-
const prefix = prefixWindow(observedTable, observedSortedKeys, normalized) ??
|
|
205
|
-
prefixWindow(catalogTable, catalogSortedKeys, normalized) ??
|
|
206
|
-
prefixWindow(MODEL_CONTEXT_SIZES, SORTED_KEYS, normalized);
|
|
207
|
-
if (prefix !== null)
|
|
208
|
-
return prefix;
|
|
209
|
-
return exports.DEFAULT_CONTEXT_WINDOW;
|
|
284
|
+
return resolveModelContextWindow(modelId).tierEffective;
|
|
210
285
|
}
|
package/dist/modelInfo.d.ts
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
*
|
|
18
18
|
* @module modelInfo
|
|
19
19
|
*/
|
|
20
|
+
import type { ModelProviderId } from './providerIds';
|
|
21
|
+
export { MODEL_PROVIDER_IDS } from './providerIds';
|
|
20
22
|
/** Pricing information for a model. All costs are per million tokens in USD. */
|
|
21
23
|
export interface ModelPricing {
|
|
22
24
|
inputCostPerMillion: number;
|
|
@@ -24,6 +26,21 @@ export interface ModelPricing {
|
|
|
24
26
|
cacheWriteCostPerMillion: number;
|
|
25
27
|
cacheReadCostPerMillion: number;
|
|
26
28
|
}
|
|
29
|
+
export type ModelPricingSource = 'imported' | 'catalog' | 'static' | 'none';
|
|
30
|
+
export type ModelPricingMatch = 'exact' | 'prefix' | 'none';
|
|
31
|
+
export interface ModelPricingProvenance {
|
|
32
|
+
source: ModelPricingSource;
|
|
33
|
+
match: ModelPricingMatch;
|
|
34
|
+
matchedModelId?: string;
|
|
35
|
+
/** True when the price was inherited from a shorter model-ID prefix. */
|
|
36
|
+
inheritedByPrefix: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface ResolvedModelPricing {
|
|
39
|
+
modelId: string;
|
|
40
|
+
canonicalModelId: string;
|
|
41
|
+
pricing: ModelPricing | null;
|
|
42
|
+
provenance: ModelPricingProvenance;
|
|
43
|
+
}
|
|
27
44
|
/**
|
|
28
45
|
* Token usage for the legacy cost calculation contract.
|
|
29
46
|
* @deprecated Use NormalizedUsage and calculateNormalizedUsageCost. This shape
|
|
@@ -42,7 +59,7 @@ export interface CostTokenUsage {
|
|
|
42
59
|
reasoningTokens?: number;
|
|
43
60
|
}
|
|
44
61
|
/** Provider that hosts a model. "unknown" means we couldn't classify it. */
|
|
45
|
-
export type ModelProvider =
|
|
62
|
+
export type ModelProvider = ModelProviderId;
|
|
46
63
|
/** Structured result of parsing a raw model ID. */
|
|
47
64
|
export interface ParsedModelId {
|
|
48
65
|
provider: ModelProvider;
|
|
@@ -93,6 +110,16 @@ export declare function _setPricingOverrides(overrides: Record<string, ModelPric
|
|
|
93
110
|
export declare function _getPricingOverrides(): Record<string, ModelPricing>;
|
|
94
111
|
/** Internal: clear overrides (used by tests and when disabling hydration). */
|
|
95
112
|
export declare function _clearPricingOverrides(): void;
|
|
113
|
+
/**
|
|
114
|
+
* Internal: hydrate exact pricing resolutions exported by another realm.
|
|
115
|
+
* Merges so successive partial imports accumulate (aliases already merge);
|
|
116
|
+
* use `_clearImportedResolvedPricing` to reset.
|
|
117
|
+
*/
|
|
118
|
+
export declare function _setImportedResolvedPricing(values: Record<string, ResolvedModelPricing>): void;
|
|
119
|
+
/** Internal test hook. */
|
|
120
|
+
export declare function _clearImportedResolvedPricing(): void;
|
|
121
|
+
/** Internal: list every ID known to the pricing resolver. */
|
|
122
|
+
export declare function _getModelPricingIds(): string[];
|
|
96
123
|
/**
|
|
97
124
|
* Parses a model ID into {provider, family, version}.
|
|
98
125
|
*
|
|
@@ -103,6 +130,8 @@ export declare function _clearPricingOverrides(): void;
|
|
|
103
130
|
* Returns null for anything else — callers should treat that as "unknown model".
|
|
104
131
|
*/
|
|
105
132
|
export declare function parseModelId(modelId: string): ParsedModelId | null;
|
|
133
|
+
/** Resolve pricing and disclose whether the result was inherited by prefix. */
|
|
134
|
+
export declare function resolveModelPricing(modelId: string): ResolvedModelPricing;
|
|
106
135
|
/**
|
|
107
136
|
* Gets pricing for a model ID.
|
|
108
137
|
*
|
package/dist/modelInfo.js
CHANGED
|
@@ -19,10 +19,15 @@
|
|
|
19
19
|
* @module modelInfo
|
|
20
20
|
*/
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.MODEL_PROVIDER_IDS = void 0;
|
|
22
23
|
exports._setPricingOverrides = _setPricingOverrides;
|
|
23
24
|
exports._getPricingOverrides = _getPricingOverrides;
|
|
24
25
|
exports._clearPricingOverrides = _clearPricingOverrides;
|
|
26
|
+
exports._setImportedResolvedPricing = _setImportedResolvedPricing;
|
|
27
|
+
exports._clearImportedResolvedPricing = _clearImportedResolvedPricing;
|
|
28
|
+
exports._getModelPricingIds = _getModelPricingIds;
|
|
25
29
|
exports.parseModelId = parseModelId;
|
|
30
|
+
exports.resolveModelPricing = resolveModelPricing;
|
|
26
31
|
exports.getModelPricing = getModelPricing;
|
|
27
32
|
exports.getModelInfo = getModelInfo;
|
|
28
33
|
exports.calculateCostWithPricing = calculateCostWithPricing;
|
|
@@ -35,6 +40,9 @@ exports.compareModelIds = compareModelIds;
|
|
|
35
40
|
exports.sortModelIds = sortModelIds;
|
|
36
41
|
exports.formatCost = formatCost;
|
|
37
42
|
const modelContext_1 = require("./modelContext");
|
|
43
|
+
const modelAliases_1 = require("./modelAliases");
|
|
44
|
+
var providerIds_1 = require("./providerIds");
|
|
45
|
+
Object.defineProperty(exports, "MODEL_PROVIDER_IDS", { enumerable: true, get: function () { return providerIds_1.MODEL_PROVIDER_IDS; } });
|
|
38
46
|
// ── Static Pricing Table ──
|
|
39
47
|
/**
|
|
40
48
|
* Static baseline pricing. Keys are model-ID prefixes; lookup uses
|
|
@@ -412,6 +420,7 @@ const STATIC_SORTED_KEYS = Object.keys(PRICING_TABLE).sort((a, b) => b.length -
|
|
|
412
420
|
// ── Override Table (populated at runtime by pricingCatalog) ──
|
|
413
421
|
let overrideTable = {};
|
|
414
422
|
let overrideSortedKeys = [];
|
|
423
|
+
let importedTable = {};
|
|
415
424
|
/**
|
|
416
425
|
* Internal: replace the runtime override map. Called by `pricingCatalog.ts`
|
|
417
426
|
* after a successful LiteLLM hydration. Not part of the stable public API,
|
|
@@ -419,7 +428,7 @@ let overrideSortedKeys = [];
|
|
|
419
428
|
* creating a circular import.
|
|
420
429
|
*/
|
|
421
430
|
function _setPricingOverrides(overrides) {
|
|
422
|
-
overrideTable = { ...
|
|
431
|
+
overrideTable = Object.fromEntries(Object.entries(overrides).map(([key, value]) => [key.trim().toLowerCase(), { ...value }]));
|
|
423
432
|
overrideSortedKeys = Object.keys(overrideTable).sort((a, b) => b.length - a.length);
|
|
424
433
|
}
|
|
425
434
|
/** Internal: snapshot current overrides (test + diagnostics). */
|
|
@@ -431,6 +440,26 @@ function _clearPricingOverrides() {
|
|
|
431
440
|
overrideTable = {};
|
|
432
441
|
overrideSortedKeys = [];
|
|
433
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* Internal: hydrate exact pricing resolutions exported by another realm.
|
|
445
|
+
* Merges so successive partial imports accumulate (aliases already merge);
|
|
446
|
+
* use `_clearImportedResolvedPricing` to reset.
|
|
447
|
+
*/
|
|
448
|
+
function _setImportedResolvedPricing(values) {
|
|
449
|
+
importedTable = { ...importedTable, ...values };
|
|
450
|
+
}
|
|
451
|
+
/** Internal test hook. */
|
|
452
|
+
function _clearImportedResolvedPricing() {
|
|
453
|
+
importedTable = {};
|
|
454
|
+
}
|
|
455
|
+
/** Internal: list every ID known to the pricing resolver. */
|
|
456
|
+
function _getModelPricingIds() {
|
|
457
|
+
return Array.from(new Set([
|
|
458
|
+
...Object.keys(PRICING_TABLE),
|
|
459
|
+
...Object.keys(overrideTable),
|
|
460
|
+
...Object.keys(importedTable),
|
|
461
|
+
]));
|
|
462
|
+
}
|
|
434
463
|
// ── Model ID Parsing ──
|
|
435
464
|
// Anthropic writes the minor version with a hyphen in modern IDs
|
|
436
465
|
// (`claude-sonnet-4-6-20260321`) and a dot in older ones
|
|
@@ -454,10 +483,7 @@ const GEMINI_RE = /^gemini-([0-9][0-9.A-Za-z-]*)/i;
|
|
|
454
483
|
function parseModelId(modelId) {
|
|
455
484
|
if (!modelId)
|
|
456
485
|
return null;
|
|
457
|
-
const normalized = modelId
|
|
458
|
-
.replace(/\[1m\]/gi, '')
|
|
459
|
-
.trim()
|
|
460
|
-
.toLowerCase();
|
|
486
|
+
const normalized = (0, modelAliases_1.resolveModelAlias)(modelId.replace(/\[1m\]/gi, ''));
|
|
461
487
|
const claude = normalized.match(CLAUDE_RE);
|
|
462
488
|
if (claude) {
|
|
463
489
|
return {
|
|
@@ -490,27 +516,96 @@ function parseModelId(modelId) {
|
|
|
490
516
|
return null;
|
|
491
517
|
}
|
|
492
518
|
// ── Pricing Lookup ──
|
|
493
|
-
/** Find the longest key in `keys` that is a prefix of `modelId`, or null. */
|
|
519
|
+
/** Find the longest shorter key in `keys` that is a prefix of `modelId`, or null. */
|
|
494
520
|
function findLongestPrefix(keys, modelId) {
|
|
495
521
|
for (const key of keys) {
|
|
496
|
-
if (modelId
|
|
522
|
+
if (modelId !== key && modelId.startsWith(key))
|
|
497
523
|
return key;
|
|
498
524
|
}
|
|
499
525
|
return null;
|
|
500
526
|
}
|
|
501
|
-
/**
|
|
502
|
-
function
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const
|
|
511
|
-
if (
|
|
512
|
-
return
|
|
513
|
-
|
|
527
|
+
/** Resolve pricing and disclose whether the result was inherited by prefix. */
|
|
528
|
+
function resolveModelPricing(modelId) {
|
|
529
|
+
const stripped = modelId.replace(/\[1m\]/gi, '');
|
|
530
|
+
const rawId = stripped.trim().toLowerCase();
|
|
531
|
+
const canonicalModelId = (0, modelAliases_1.resolveModelAlias)(stripped);
|
|
532
|
+
// The raw id is tried before its alias target at every step: pricing
|
|
533
|
+
// recorded for the alias id itself is more specific than the canonical
|
|
534
|
+
// fallback, so registering an alias never orphans it.
|
|
535
|
+
const candidateIds = rawId === canonicalModelId ? [canonicalModelId] : [rawId, canonicalModelId];
|
|
536
|
+
const imported = importedTable[rawId] ?? importedTable[canonicalModelId];
|
|
537
|
+
if (imported)
|
|
538
|
+
return { ...imported, modelId, canonicalModelId };
|
|
539
|
+
for (const id of candidateIds) {
|
|
540
|
+
const exactOverride = overrideTable[id];
|
|
541
|
+
if (exactOverride) {
|
|
542
|
+
return {
|
|
543
|
+
modelId,
|
|
544
|
+
canonicalModelId,
|
|
545
|
+
pricing: exactOverride,
|
|
546
|
+
provenance: {
|
|
547
|
+
source: 'catalog',
|
|
548
|
+
match: 'exact',
|
|
549
|
+
matchedModelId: id,
|
|
550
|
+
inheritedByPrefix: false,
|
|
551
|
+
},
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
for (const id of candidateIds) {
|
|
556
|
+
const exactStatic = PRICING_TABLE[id];
|
|
557
|
+
if (exactStatic) {
|
|
558
|
+
return {
|
|
559
|
+
modelId,
|
|
560
|
+
canonicalModelId,
|
|
561
|
+
pricing: exactStatic,
|
|
562
|
+
provenance: {
|
|
563
|
+
source: 'static',
|
|
564
|
+
match: 'exact',
|
|
565
|
+
matchedModelId: id,
|
|
566
|
+
inheritedByPrefix: false,
|
|
567
|
+
},
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
for (const id of candidateIds) {
|
|
572
|
+
const overridePrefix = findLongestPrefix(overrideSortedKeys, id);
|
|
573
|
+
if (overridePrefix) {
|
|
574
|
+
return {
|
|
575
|
+
modelId,
|
|
576
|
+
canonicalModelId,
|
|
577
|
+
pricing: overrideTable[overridePrefix],
|
|
578
|
+
provenance: {
|
|
579
|
+
source: 'catalog',
|
|
580
|
+
match: 'prefix',
|
|
581
|
+
matchedModelId: overridePrefix,
|
|
582
|
+
inheritedByPrefix: true,
|
|
583
|
+
},
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
for (const id of candidateIds) {
|
|
588
|
+
const staticPrefix = findLongestPrefix(STATIC_SORTED_KEYS, id);
|
|
589
|
+
if (staticPrefix) {
|
|
590
|
+
return {
|
|
591
|
+
modelId,
|
|
592
|
+
canonicalModelId,
|
|
593
|
+
pricing: PRICING_TABLE[staticPrefix],
|
|
594
|
+
provenance: {
|
|
595
|
+
source: 'static',
|
|
596
|
+
match: 'prefix',
|
|
597
|
+
matchedModelId: staticPrefix,
|
|
598
|
+
inheritedByPrefix: true,
|
|
599
|
+
},
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
modelId,
|
|
605
|
+
canonicalModelId,
|
|
606
|
+
pricing: null,
|
|
607
|
+
provenance: { source: 'none', match: 'none', inheritedByPrefix: false },
|
|
608
|
+
};
|
|
514
609
|
}
|
|
515
610
|
/**
|
|
516
611
|
* Gets pricing for a model ID.
|
|
@@ -530,12 +625,7 @@ function lookupPricing(modelId) {
|
|
|
530
625
|
function getModelPricing(modelId) {
|
|
531
626
|
if (!modelId)
|
|
532
627
|
return null;
|
|
533
|
-
|
|
534
|
-
const direct = lookupPricing(stripped);
|
|
535
|
-
if (direct)
|
|
536
|
-
return direct;
|
|
537
|
-
const normalized = stripped.trim().toLowerCase();
|
|
538
|
-
return normalized === stripped ? null : lookupPricing(normalized);
|
|
628
|
+
return resolveModelPricing(modelId).pricing;
|
|
539
629
|
}
|
|
540
630
|
/**
|
|
541
631
|
* Returns comprehensive metadata for a model ID.
|