tryaii-dre 0.2.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/LICENSE +190 -0
- package/README.md +234 -0
- package/dist/banner.d.ts +24 -0
- package/dist/banner.d.ts.map +1 -0
- package/dist/banner.js +125 -0
- package/dist/banner.js.map +1 -0
- package/dist/benchmarks/index.d.ts +4 -0
- package/dist/benchmarks/index.d.ts.map +1 -0
- package/dist/benchmarks/index.js +3 -0
- package/dist/benchmarks/index.js.map +1 -0
- package/dist/benchmarks/registry.d.ts +69 -0
- package/dist/benchmarks/registry.d.ts.map +1 -0
- package/dist/benchmarks/registry.js +128 -0
- package/dist/benchmarks/registry.js.map +1 -0
- package/dist/benchmarks/standard.d.ts +6 -0
- package/dist/benchmarks/standard.d.ts.map +1 -0
- package/dist/benchmarks/standard.js +115 -0
- package/dist/benchmarks/standard.js.map +1 -0
- package/dist/budget.d.ts +65 -0
- package/dist/budget.d.ts.map +1 -0
- package/dist/budget.js +344 -0
- package/dist/budget.js.map +1 -0
- package/dist/cache/index.d.ts +27 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +63 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/centroids/data/centroids_all-MiniLM-L6-v2.json +1 -0
- package/dist/centroids/data/trainingQueries.json +246 -0
- package/dist/centroids/generator.d.ts +63 -0
- package/dist/centroids/generator.d.ts.map +1 -0
- package/dist/centroids/generator.js +120 -0
- package/dist/centroids/generator.js.map +1 -0
- package/dist/centroids/index.d.ts +3 -0
- package/dist/centroids/index.d.ts.map +1 -0
- package/dist/centroids/index.js +3 -0
- package/dist/centroids/index.js.map +1 -0
- package/dist/centroids/loader.d.ts +87 -0
- package/dist/centroids/loader.d.ts.map +1 -0
- package/dist/centroids/loader.js +236 -0
- package/dist/centroids/loader.js.map +1 -0
- package/dist/classifiers/base.d.ts +56 -0
- package/dist/classifiers/base.d.ts.map +1 -0
- package/dist/classifiers/base.js +42 -0
- package/dist/classifiers/base.js.map +1 -0
- package/dist/classifiers/embedding.d.ts +68 -0
- package/dist/classifiers/embedding.d.ts.map +1 -0
- package/dist/classifiers/embedding.js +0 -0
- package/dist/classifiers/embedding.js.map +1 -0
- package/dist/classifiers/hybrid.d.ts +31 -0
- package/dist/classifiers/hybrid.d.ts.map +1 -0
- package/dist/classifiers/hybrid.js +61 -0
- package/dist/classifiers/hybrid.js.map +1 -0
- package/dist/classifiers/index.d.ts +4 -0
- package/dist/classifiers/index.d.ts.map +1 -0
- package/dist/classifiers/index.js +3 -0
- package/dist/classifiers/index.js.map +1 -0
- package/dist/classifiers/keyword.d.ts +29 -0
- package/dist/classifiers/keyword.d.ts.map +1 -0
- package/dist/classifiers/keyword.js +264 -0
- package/dist/classifiers/keyword.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +597 -0
- package/dist/cli.js.map +1 -0
- package/dist/client-types.d.ts +101 -0
- package/dist/client-types.d.ts.map +1 -0
- package/dist/client-types.js +5 -0
- package/dist/client-types.js.map +1 -0
- package/dist/client.d.ts +50 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +279 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +45 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +37 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard/index.d.ts +48 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +166 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/embeddings/base.d.ts +66 -0
- package/dist/embeddings/base.d.ts.map +1 -0
- package/dist/embeddings/base.js +77 -0
- package/dist/embeddings/base.js.map +1 -0
- package/dist/embeddings/index.d.ts +3 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +3 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/embeddings/local.d.ts +42 -0
- package/dist/embeddings/local.d.ts.map +1 -0
- package/dist/embeddings/local.js +89 -0
- package/dist/embeddings/local.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/index.d.ts +3 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +2 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/openrouter.d.ts +84 -0
- package/dist/integrations/openrouter.d.ts.map +1 -0
- package/dist/integrations/openrouter.js +253 -0
- package/dist/integrations/openrouter.js.map +1 -0
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +2 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/models.d.ts +76 -0
- package/dist/registry/models.d.ts.map +1 -0
- package/dist/registry/models.js +170 -0
- package/dist/registry/models.js.map +1 -0
- package/dist/registry/presets/defaultModels.json +435 -0
- package/dist/router.d.ts +178 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +259 -0
- package/dist/router.js.map +1 -0
- package/dist/scoring/benchmarks.d.ts +35 -0
- package/dist/scoring/benchmarks.d.ts.map +1 -0
- package/dist/scoring/benchmarks.js +68 -0
- package/dist/scoring/benchmarks.js.map +1 -0
- package/dist/scoring/engine.d.ts +43 -0
- package/dist/scoring/engine.d.ts.map +1 -0
- package/dist/scoring/engine.js +267 -0
- package/dist/scoring/engine.js.map +1 -0
- package/dist/scoring/index.d.ts +6 -0
- package/dist/scoring/index.d.ts.map +1 -0
- package/dist/scoring/index.js +4 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/scoring/priorities.d.ts +41 -0
- package/dist/scoring/priorities.d.ts.map +1 -0
- package/dist/scoring/priorities.js +49 -0
- package/dist/scoring/priorities.js.map +1 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/cosine.d.ts +10 -0
- package/dist/utils/cosine.d.ts.map +1 -0
- package/dist/utils/cosine.js +18 -0
- package/dist/utils/cosine.js.map +1 -0
- package/dist/utils/math.d.ts +18 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +54 -0
- package/dist/utils/math.js.map +1 -0
- package/package.json +65 -0
package/dist/budget.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Budget-aware dataset routing utilities.
|
|
3
|
+
*
|
|
4
|
+
* This solves the routing budget problem as a multiple-choice knapsack:
|
|
5
|
+
* for each prompt, choose one model candidate; maximize total utility while
|
|
6
|
+
* keeping estimated generation cost under one shared budget.
|
|
7
|
+
*/
|
|
8
|
+
import { Priorities } from './scoring/priorities.js';
|
|
9
|
+
/** Approximate token count with a deterministic 4 chars ~= 1 token rule. */
|
|
10
|
+
export function estimateTokens(text) {
|
|
11
|
+
return Math.max(1, Math.ceil(text.length / 4));
|
|
12
|
+
}
|
|
13
|
+
/** Estimate USD generation cost for a model, or null when pricing is missing. */
|
|
14
|
+
export function estimateGenerationCost(model, inputTokens, outputTokens) {
|
|
15
|
+
if (!model?.pricing)
|
|
16
|
+
return null;
|
|
17
|
+
// Guard against non-finite pricing fields: returning NaN here would poison
|
|
18
|
+
// every downstream comparison/sort, so surface "no estimate" instead.
|
|
19
|
+
if (!Number.isFinite(model.pricing.inputPer1k) || !Number.isFinite(model.pricing.outputPer1k)) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return ((inputTokens / 1000) * model.pricing.inputPer1k
|
|
23
|
+
+ (outputTokens / 1000) * model.pricing.outputPer1k);
|
|
24
|
+
}
|
|
25
|
+
export function costUnitForBudget(maxPrice) {
|
|
26
|
+
// Scale the unit to the budget so budgetUnits stays ~constant (~10k) for any
|
|
27
|
+
// budget size. This gives fine *relative* resolution without an absolute
|
|
28
|
+
// floor (the old 1e-5 floor collapsed resolution for sub-cent budgets) while
|
|
29
|
+
// keeping the DP state space bounded -- a fixed maxPrice/1e6 made budgetUnits
|
|
30
|
+
// ~1e6 for a $4 budget and exhausted the heap. Correctness comes from the
|
|
31
|
+
// float feasibility gate + cheapest fallback, so this only affects
|
|
32
|
+
// optimization granularity. Guard maxPrice <= 0 against a zero/negative unit.
|
|
33
|
+
if (maxPrice <= 0)
|
|
34
|
+
return 1e-9;
|
|
35
|
+
return maxPrice / 10000;
|
|
36
|
+
}
|
|
37
|
+
/** Deterministic Unicode code-point compare (NOT locale-aware) for modelIds. */
|
|
38
|
+
function compareModelId(a, b) {
|
|
39
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
40
|
+
}
|
|
41
|
+
function candidateSortKey(a, b) {
|
|
42
|
+
if (a.estimatedCost !== b.estimatedCost)
|
|
43
|
+
return a.estimatedCost - b.estimatedCost;
|
|
44
|
+
if (a.utility !== b.utility)
|
|
45
|
+
return b.utility - a.utility;
|
|
46
|
+
return compareModelId(a.modelId, b.modelId);
|
|
47
|
+
}
|
|
48
|
+
export function paretoPrune(candidates) {
|
|
49
|
+
const ordered = [...candidates].sort(candidateSortKey);
|
|
50
|
+
const kept = [];
|
|
51
|
+
let bestUtility = Number.NEGATIVE_INFINITY;
|
|
52
|
+
for (const candidate of ordered) {
|
|
53
|
+
if (candidate.utility > bestUtility + 1e-12) {
|
|
54
|
+
kept.push(candidate);
|
|
55
|
+
bestUtility = candidate.utility;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return kept;
|
|
59
|
+
}
|
|
60
|
+
export function optimizeBudgetCandidates(candidateGroups, maxPrice, costUnit = costUnitForBudget(maxPrice)) {
|
|
61
|
+
if (maxPrice < 0)
|
|
62
|
+
throw new Error('maxPrice must be non-negative');
|
|
63
|
+
if (candidateGroups.length === 0) {
|
|
64
|
+
return {
|
|
65
|
+
status: 'optimal',
|
|
66
|
+
selected: [],
|
|
67
|
+
totalEstimatedCost: 0,
|
|
68
|
+
minimumRequiredBudget: 0,
|
|
69
|
+
budget: maxPrice,
|
|
70
|
+
costUnit,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const budgetUnits = Math.floor(maxPrice / costUnit);
|
|
74
|
+
const groups = candidateGroups.map((group) => paretoPrune(group));
|
|
75
|
+
if (groups.some((group) => group.length === 0)) {
|
|
76
|
+
return {
|
|
77
|
+
status: 'infeasible',
|
|
78
|
+
selected: [],
|
|
79
|
+
totalEstimatedCost: 0,
|
|
80
|
+
minimumRequiredBudget: Number.POSITIVE_INFINITY,
|
|
81
|
+
budget: maxPrice,
|
|
82
|
+
costUnit,
|
|
83
|
+
message: 'At least one prompt has no priced model candidates.',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const cheapest = groups.map((group) => [...group].sort(candidateSortKey)[0]);
|
|
87
|
+
const minimumRequiredBudget = cheapest.reduce((sum, candidate) => sum + candidate.estimatedCost, 0);
|
|
88
|
+
// Float feasibility is the source of truth: if the cheapest float assignment
|
|
89
|
+
// fits, the workload IS feasible. The integer DP below only *optimizes* the
|
|
90
|
+
// assignment; it must never declare infeasibility on its own. When the DP
|
|
91
|
+
// frontier collapses (quantization / pruning artefacts), fall back to the
|
|
92
|
+
// proven-feasible cheapest assignment as an optimal selection.
|
|
93
|
+
const cheapestResult = () => ({
|
|
94
|
+
status: 'optimal',
|
|
95
|
+
selected: cheapest,
|
|
96
|
+
totalEstimatedCost: minimumRequiredBudget,
|
|
97
|
+
minimumRequiredBudget,
|
|
98
|
+
budget: maxPrice,
|
|
99
|
+
costUnit,
|
|
100
|
+
});
|
|
101
|
+
if (minimumRequiredBudget > maxPrice) {
|
|
102
|
+
return {
|
|
103
|
+
status: 'infeasible',
|
|
104
|
+
selected: cheapest,
|
|
105
|
+
totalEstimatedCost: minimumRequiredBudget,
|
|
106
|
+
minimumRequiredBudget,
|
|
107
|
+
budget: maxPrice,
|
|
108
|
+
costUnit,
|
|
109
|
+
message: 'Budget is below the minimum cost required to route every prompt.',
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
let states = new Map([[0, { utility: 0, previousCost: null, candidateIndex: null }]]);
|
|
113
|
+
const layers = [];
|
|
114
|
+
for (const group of groups) {
|
|
115
|
+
const nextStates = new Map();
|
|
116
|
+
for (const [previousCost, previousState] of states.entries()) {
|
|
117
|
+
for (let idx = 0; idx < group.length; idx++) {
|
|
118
|
+
const candidate = group[idx];
|
|
119
|
+
const newCost = previousCost + candidate.costUnits;
|
|
120
|
+
if (newCost > budgetUnits)
|
|
121
|
+
continue;
|
|
122
|
+
const newUtility = previousState.utility + candidate.utility;
|
|
123
|
+
const existing = nextStates.get(newCost);
|
|
124
|
+
if (!existing || newUtility > existing.utility + 1e-12) {
|
|
125
|
+
nextStates.set(newCost, { utility: newUtility, previousCost, candidateIndex: idx });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (nextStates.size === 0) {
|
|
130
|
+
// Float feasibility already proven above -> return the cheapest assignment
|
|
131
|
+
// rather than falsely reporting infeasible.
|
|
132
|
+
return cheapestResult();
|
|
133
|
+
}
|
|
134
|
+
const pruned = new Map();
|
|
135
|
+
let bestSeen = Number.NEGATIVE_INFINITY;
|
|
136
|
+
for (const cost of [...nextStates.keys()].sort((a, b) => a - b)) {
|
|
137
|
+
const state = nextStates.get(cost);
|
|
138
|
+
if (state.utility > bestSeen + 1e-12) {
|
|
139
|
+
pruned.set(cost, state);
|
|
140
|
+
bestSeen = state.utility;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
states = pruned;
|
|
144
|
+
layers.push(states);
|
|
145
|
+
}
|
|
146
|
+
if (states.size === 0) {
|
|
147
|
+
// No surviving DP state, but float feasibility holds -> cheapest fallback.
|
|
148
|
+
return cheapestResult();
|
|
149
|
+
}
|
|
150
|
+
const [bestCost] = [...states.entries()].sort((a, b) => {
|
|
151
|
+
if (b[1].utility !== a[1].utility)
|
|
152
|
+
return b[1].utility - a[1].utility;
|
|
153
|
+
return a[0] - b[0];
|
|
154
|
+
})[0];
|
|
155
|
+
const selected = new Array(groups.length);
|
|
156
|
+
let currentCost = bestCost;
|
|
157
|
+
for (let promptIndex = groups.length - 1; promptIndex >= 0; promptIndex--) {
|
|
158
|
+
const state = layers[promptIndex].get(currentCost);
|
|
159
|
+
if (!state || state.previousCost == null || state.candidateIndex == null) {
|
|
160
|
+
throw new Error('invalid optimizer backpointer');
|
|
161
|
+
}
|
|
162
|
+
selected[promptIndex] = groups[promptIndex][state.candidateIndex];
|
|
163
|
+
currentCost = state.previousCost;
|
|
164
|
+
}
|
|
165
|
+
const totalEstimatedCost = selected.reduce((sum, candidate) => sum + candidate.estimatedCost, 0);
|
|
166
|
+
return {
|
|
167
|
+
status: 'optimal',
|
|
168
|
+
selected,
|
|
169
|
+
totalEstimatedCost,
|
|
170
|
+
minimumRequiredBudget,
|
|
171
|
+
budget: maxPrice,
|
|
172
|
+
costUnit,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function repriceCandidate(router, candidate, outputTokens, costUnit) {
|
|
176
|
+
const model = router.models.getModel(candidate.modelId);
|
|
177
|
+
const estimatedCost = estimateGenerationCost(model, candidate.inputTokens, outputTokens);
|
|
178
|
+
// Reject null AND non-finite (NaN/Infinity); the `=== null` arm also narrows
|
|
179
|
+
// the type for the assignment below.
|
|
180
|
+
if (estimatedCost === null || !Number.isFinite(estimatedCost))
|
|
181
|
+
return null;
|
|
182
|
+
return {
|
|
183
|
+
...candidate,
|
|
184
|
+
estimatedCost,
|
|
185
|
+
// Zero-cost candidates must consume zero budget units; only clamp negatives.
|
|
186
|
+
costUnits: Math.max(0, Math.ceil(estimatedCost / costUnit)),
|
|
187
|
+
outputTokens,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function repriceCandidateGroups(router, candidateGroups, outputTokens, costUnit) {
|
|
191
|
+
return candidateGroups.map((group) => group
|
|
192
|
+
.map((candidate) => repriceCandidate(router, candidate, outputTokens, costUnit))
|
|
193
|
+
.filter((candidate) => candidate != null));
|
|
194
|
+
}
|
|
195
|
+
function minimumRequiredUnits(candidateGroups) {
|
|
196
|
+
if (candidateGroups.some((group) => group.length === 0))
|
|
197
|
+
return Number.POSITIVE_INFINITY;
|
|
198
|
+
return candidateGroups.reduce((sum, group) => sum + Math.min(...group.map((candidate) => candidate.costUnits)), 0);
|
|
199
|
+
}
|
|
200
|
+
function fitOutputTokens(router, candidateGroups, requestedOutputTokens, maxPrice, costUnit) {
|
|
201
|
+
const budgetUnits = Math.floor(maxPrice / costUnit);
|
|
202
|
+
// Require a positive output-token floor: an answer of 0 tokens is degenerate
|
|
203
|
+
// and must not be reported as a feasible "optimal" fit. If nothing >= 1 fits,
|
|
204
|
+
// bestTokens stays -1 and we return null (caller treats that as infeasible).
|
|
205
|
+
let low = 1;
|
|
206
|
+
let high = requestedOutputTokens;
|
|
207
|
+
let bestTokens = -1;
|
|
208
|
+
let bestGroups = [];
|
|
209
|
+
while (low <= high) {
|
|
210
|
+
const mid = Math.floor((low + high) / 2);
|
|
211
|
+
const repriced = repriceCandidateGroups(router, candidateGroups, mid, costUnit);
|
|
212
|
+
if (minimumRequiredUnits(repriced) <= budgetUnits) {
|
|
213
|
+
bestTokens = mid;
|
|
214
|
+
bestGroups = repriced;
|
|
215
|
+
low = mid + 1;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
high = mid - 1;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return bestTokens >= 1 ? { outputTokens: bestTokens, candidateGroups: bestGroups } : null;
|
|
222
|
+
}
|
|
223
|
+
async function buildBudgetCandidates(router, prompt, promptIndex, priorities, outputTokens, costUnit) {
|
|
224
|
+
const started = Date.now();
|
|
225
|
+
const routeResult = await router.route(prompt, {
|
|
226
|
+
topK: router.models.allModels.length,
|
|
227
|
+
priorities,
|
|
228
|
+
});
|
|
229
|
+
const routeMs = Date.now() - started;
|
|
230
|
+
const confidence = routeResult.classification?.confidence ?? 0;
|
|
231
|
+
const confidenceFactor = 0.75 + 0.25 * Math.max(0, Math.min(1, confidence));
|
|
232
|
+
const inputTokens = estimateTokens(prompt);
|
|
233
|
+
const candidateInputs = [];
|
|
234
|
+
for (const score of routeResult.scores) {
|
|
235
|
+
const model = router.models.getModel(score.modelId);
|
|
236
|
+
const estimatedCost = estimateGenerationCost(model, inputTokens, outputTokens);
|
|
237
|
+
// Reject null AND non-finite (NaN/Infinity); the `=== null` arm also narrows
|
|
238
|
+
// the type for the push below.
|
|
239
|
+
if (estimatedCost === null || !Number.isFinite(estimatedCost))
|
|
240
|
+
continue;
|
|
241
|
+
candidateInputs.push({
|
|
242
|
+
score,
|
|
243
|
+
estimatedCost,
|
|
244
|
+
utility: score.qualityScore * confidenceFactor,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
const qualityBestModel = [...candidateInputs].sort((a, b) => {
|
|
248
|
+
if (b.utility !== a.utility)
|
|
249
|
+
return b.utility - a.utility;
|
|
250
|
+
if (a.estimatedCost !== b.estimatedCost)
|
|
251
|
+
return a.estimatedCost - b.estimatedCost;
|
|
252
|
+
return compareModelId(a.score.modelId, b.score.modelId);
|
|
253
|
+
})[0]?.score.modelId ?? routeResult.bestModel;
|
|
254
|
+
const candidates = [];
|
|
255
|
+
for (const { score, estimatedCost, utility } of candidateInputs) {
|
|
256
|
+
candidates.push({
|
|
257
|
+
promptIndex,
|
|
258
|
+
modelId: score.modelId,
|
|
259
|
+
utility,
|
|
260
|
+
estimatedCost,
|
|
261
|
+
// Zero-cost candidates must consume zero budget units; only clamp negatives.
|
|
262
|
+
costUnits: Math.max(0, Math.ceil(estimatedCost / costUnit)),
|
|
263
|
+
inputTokens,
|
|
264
|
+
outputTokens,
|
|
265
|
+
finalScore: score.finalScore,
|
|
266
|
+
reasoning: score.reasoning,
|
|
267
|
+
normalBestModel: qualityBestModel,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
return { routeResult, candidates, routeMs };
|
|
271
|
+
}
|
|
272
|
+
export async function routeDatasetWithBudget(options) {
|
|
273
|
+
const budgetMode = options.budgetMode ?? 'strict';
|
|
274
|
+
if (budgetMode !== 'strict' && budgetMode !== 'fit-output') {
|
|
275
|
+
throw new Error("budgetMode must be 'strict' or 'fit-output'");
|
|
276
|
+
}
|
|
277
|
+
if (options.outputTokens < 0)
|
|
278
|
+
throw new Error('outputTokens must be non-negative');
|
|
279
|
+
const costUnit = costUnitForBudget(options.maxPrice);
|
|
280
|
+
const routeResults = [];
|
|
281
|
+
const routeTimes = [];
|
|
282
|
+
const candidateGroups = [];
|
|
283
|
+
const qualityPriorities = Priorities.performance();
|
|
284
|
+
for (let idx = 0; idx < options.prompts.length; idx++) {
|
|
285
|
+
const prepared = await buildBudgetCandidates(options.router, options.prompts[idx], idx, qualityPriorities, options.outputTokens, costUnit);
|
|
286
|
+
routeResults.push(prepared.routeResult);
|
|
287
|
+
routeTimes.push(prepared.routeMs);
|
|
288
|
+
candidateGroups.push(prepared.candidates);
|
|
289
|
+
options.progressCallback?.(idx + 1, options.prompts.length);
|
|
290
|
+
}
|
|
291
|
+
const requestedOutputTokens = options.outputTokens;
|
|
292
|
+
let optimization = optimizeBudgetCandidates(candidateGroups, options.maxPrice, costUnit);
|
|
293
|
+
const requestedMinimumRequiredBudget = optimization.minimumRequiredBudget;
|
|
294
|
+
const budgetShortfall = Number.isFinite(requestedMinimumRequiredBudget)
|
|
295
|
+
? Math.max(0, requestedMinimumRequiredBudget - options.maxPrice)
|
|
296
|
+
: Number.POSITIVE_INFINITY;
|
|
297
|
+
optimization = {
|
|
298
|
+
...optimization,
|
|
299
|
+
budgetMode,
|
|
300
|
+
requestedOutputTokens,
|
|
301
|
+
effectiveOutputTokens: options.outputTokens,
|
|
302
|
+
requestedMinimumRequiredBudget,
|
|
303
|
+
budgetShortfall,
|
|
304
|
+
};
|
|
305
|
+
if (budgetMode === 'fit-output' &&
|
|
306
|
+
optimization.status === 'infeasible' &&
|
|
307
|
+
options.outputTokens > 0 &&
|
|
308
|
+
Number.isFinite(optimization.minimumRequiredBudget)) {
|
|
309
|
+
const fitted = fitOutputTokens(options.router, candidateGroups, requestedOutputTokens, options.maxPrice, costUnit);
|
|
310
|
+
if (fitted) {
|
|
311
|
+
const fittedOptimization = optimizeBudgetCandidates(fitted.candidateGroups, options.maxPrice, costUnit);
|
|
312
|
+
if (fittedOptimization.status === 'optimal') {
|
|
313
|
+
optimization = {
|
|
314
|
+
...fittedOptimization,
|
|
315
|
+
budgetMode,
|
|
316
|
+
requestedOutputTokens,
|
|
317
|
+
effectiveOutputTokens: fitted.outputTokens,
|
|
318
|
+
requestedMinimumRequiredBudget,
|
|
319
|
+
budgetShortfall,
|
|
320
|
+
message: 'Requested output tokens did not fit the budget; ' +
|
|
321
|
+
`optimized with ${fitted.outputTokens} output tokens per prompt.`,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const selectedByIndex = new Map(optimization.selected.map((candidate) => [candidate.promptIndex, candidate]));
|
|
327
|
+
const results = [];
|
|
328
|
+
let cumulativeCost = 0;
|
|
329
|
+
for (let idx = 0; idx < routeResults.length; idx++) {
|
|
330
|
+
const selected = selectedByIndex.get(idx);
|
|
331
|
+
if (!selected)
|
|
332
|
+
continue;
|
|
333
|
+
cumulativeCost += selected.estimatedCost;
|
|
334
|
+
results.push({
|
|
335
|
+
routeResult: routeResults[idx],
|
|
336
|
+
selected,
|
|
337
|
+
cumulativeCost,
|
|
338
|
+
remainingBudget: options.maxPrice - cumulativeCost,
|
|
339
|
+
routeMs: routeTimes[idx],
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
return { results, optimization };
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.js","sourceRoot":"","sources":["../src/budget.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAwDrD,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,sBAAsB,CACpC,KAA4B,EAC5B,WAAmB,EACnB,YAAoB;IAEpB,IAAI,CAAC,KAAK,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,2EAA2E;IAC3E,sEAAsE;IACtE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9F,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CACL,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU;UAC7C,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CACpD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,6EAA6E;IAC7E,yEAAyE;IACzE,6EAA6E;IAC7E,8EAA8E;IAC9E,0EAA0E;IAC1E,mEAAmE;IACnE,8EAA8E;IAC9E,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,QAAQ,GAAG,KAAM,CAAC;AAC3B,CAAC;AAED,gFAAgF;AAChF,SAAS,cAAc,CAAC,CAAS,EAAE,CAAS;IAC1C,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAkB,EAAE,CAAkB;IAC9D,IAAI,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,aAAa;QAAE,OAAO,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,CAAC;IAClF,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO;QAAE,OAAO,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;IAC1D,OAAO,cAAc,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,UAA6B;IACvD,MAAM,OAAO,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACvD,MAAM,IAAI,GAAsB,EAAE,CAAC;IACnC,IAAI,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAC3C,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,CAAC;QAChC,IAAI,SAAS,CAAC,OAAO,GAAG,WAAW,GAAG,KAAK,EAAE,CAAC;YAC5C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACrB,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,eAAoC,EACpC,QAAgB,EAChB,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC;IAEtC,IAAI,QAAQ,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnE,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,EAAE;YACZ,kBAAkB,EAAE,CAAC;YACrB,qBAAqB,EAAE,CAAC;YACxB,MAAM,EAAE,QAAQ;YAChB,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAClE,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,QAAQ,EAAE,EAAE;YACZ,kBAAkB,EAAE,CAAC;YACrB,qBAAqB,EAAE,MAAM,CAAC,iBAAiB;YAC/C,MAAM,EAAE,QAAQ;YAChB,QAAQ;YACR,OAAO,EAAE,qDAAqD;SAC/D,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,qBAAqB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAEpG,6EAA6E;IAC7E,4EAA4E;IAC5E,0EAA0E;IAC1E,0EAA0E;IAC1E,+DAA+D;IAC/D,MAAM,cAAc,GAAG,GAA6B,EAAE,CAAC,CAAC;QACtD,MAAM,EAAE,SAAS;QACjB,QAAQ,EAAE,QAAQ;QAClB,kBAAkB,EAAE,qBAAqB;QACzC,qBAAqB;QACrB,MAAM,EAAE,QAAQ;QAChB,QAAQ;KACT,CAAC,CAAC;IAEH,IAAI,qBAAqB,GAAG,QAAQ,EAAE,CAAC;QACrC,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,QAAQ,EAAE,QAAQ;YAClB,kBAAkB,EAAE,qBAAqB;YACzC,qBAAqB;YACrB,MAAM,EAAE,QAAQ;YAChB,QAAQ;YACR,OAAO,EAAE,kEAAkE;SAC5E,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,GAAG,IAAI,GAAG,CAAgB,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACrG,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAiB,CAAC;QAC5C,KAAK,MAAM,CAAC,YAAY,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7D,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC7B,MAAM,OAAO,GAAG,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC;gBACnD,IAAI,OAAO,GAAG,WAAW;oBAAE,SAAS;gBACpC,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC;gBAC7D,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACzC,IAAI,CAAC,QAAQ,IAAI,UAAU,GAAG,QAAQ,CAAC,OAAO,GAAG,KAAK,EAAE,CAAC;oBACvD,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;gBACtF,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC1B,2EAA2E;YAC3E,4CAA4C;YAC5C,OAAO,cAAc,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;QACxC,IAAI,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC;QACxC,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAChE,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAU,CAAC;YAC5C,IAAI,KAAK,CAAC,OAAO,GAAG,QAAQ,GAAG,KAAK,EAAE,CAAC;gBACrC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBACxB,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,MAAM,GAAG,MAAM,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACtB,2EAA2E;QAC3E,OAAO,cAAc,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACrD,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACtE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEN,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAkB,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,WAAW,GAAG,QAAQ,CAAC;IAC3B,KAAK,IAAI,WAAW,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,WAAW,IAAI,CAAC,EAAE,WAAW,EAAE,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,YAAY,IAAI,IAAI,IAAI,KAAK,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnD,CAAC;QACD,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAClE,WAAW,GAAG,KAAK,CAAC,YAAY,CAAC;IACnC,CAAC;IAED,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IACjG,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,QAAQ;QACR,kBAAkB;QAClB,qBAAqB;QACrB,MAAM,EAAE,QAAQ;QAChB,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,MAAc,EACd,SAA0B,EAC1B,YAAoB,EACpB,QAAgB;IAEhB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,aAAa,GAAG,sBAAsB,CAAC,KAAK,EAAE,SAAS,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACzF,6EAA6E;IAC7E,qCAAqC;IACrC,IAAI,aAAa,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3E,OAAO;QACL,GAAG,SAAS;QACZ,aAAa;QACb,6EAA6E;QAC7E,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,CAAC;QAC3D,YAAY;KACb,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAC7B,MAAc,EACd,eAAoC,EACpC,YAAoB,EACpB,QAAgB;IAEhB,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACnC,KAAK;SACF,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;SAC/E,MAAM,CAAC,CAAC,SAAS,EAAgC,EAAE,CAAC,SAAS,IAAI,IAAI,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,eAAoC;IAChE,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,iBAAiB,CAAC;IACzF,OAAO,eAAe,CAAC,MAAM,CAC3B,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAChF,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CACtB,MAAc,EACd,eAAoC,EACpC,qBAA6B,EAC7B,QAAgB,EAChB,QAAgB;IAEhB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACpD,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,IAAI,GAAG,qBAAqB,CAAC;IACjC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC;IACpB,IAAI,UAAU,GAAwB,EAAE,CAAC;IAEzC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAChF,IAAI,oBAAoB,CAAC,QAAQ,CAAC,IAAI,WAAW,EAAE,CAAC;YAClD,UAAU,GAAG,GAAG,CAAC;YACjB,UAAU,GAAG,QAAQ,CAAC;YACtB,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5F,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,MAAc,EACd,MAAc,EACd,WAAmB,EACnB,UAAsB,EACtB,YAAoB,EACpB,QAAgB;IAEhB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE;QAC7C,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM;QACpC,UAAU;KACX,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;IACrC,MAAM,UAAU,GAAG,WAAW,CAAC,cAAc,EAAE,UAAU,IAAI,CAAC,CAAC;IAC/D,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;IAC5E,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,eAAe,GAIhB,EAAE,CAAC;IAER,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,aAAa,GAAG,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;QAC/E,6EAA6E;QAC7E,+BAA+B;QAC/B,IAAI,aAAa,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;YAAE,SAAS;QACxE,eAAe,CAAC,IAAI,CAAC;YACnB,KAAK;YACL,aAAa;YACb,OAAO,EAAE,KAAK,CAAC,YAAY,GAAG,gBAAgB;SAC/C,CAAC,CAAC;IACL,CAAC;IAED,MAAM,gBAAgB,GACpB,CAAC,GAAG,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjC,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;QAC1D,IAAI,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,aAAa;YAAE,OAAO,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,CAAC;QAClF,OAAO,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,IAAI,WAAW,CAAC,SAAS,CAAC;IAEhD,MAAM,UAAU,GAAsB,EAAE,CAAC;IACzC,KAAK,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,eAAe,EAAE,CAAC;QAChE,UAAU,CAAC,IAAI,CAAC;YACd,WAAW;YACX,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO;YACP,aAAa;YACb,6EAA6E;YAC7E,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,CAAC;YAC3D,WAAW;YACX,YAAY;YACZ,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,eAAe,EAAE,gBAAgB;SAClC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAsC;IAEtC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC;IAClD,IAAI,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,YAAY,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,OAAO,CAAC,YAAY,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAEnF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,MAAM,YAAY,GAAkB,EAAE,CAAC;IACvC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,eAAe,GAAwB,EAAE,CAAC;IAChD,MAAM,iBAAiB,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAEnD,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAC1C,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EACpB,GAAG,EACH,iBAAiB,EACjB,OAAO,CAAC,YAAY,EACpB,QAAQ,CACT,CAAC;QACF,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACxC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1C,OAAO,CAAC,gBAAgB,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;IACnD,IAAI,YAAY,GAAG,wBAAwB,CAAC,eAAe,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACzF,MAAM,8BAA8B,GAAG,YAAY,CAAC,qBAAqB,CAAC;IAC1E,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QACrE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,8BAA8B,GAAG,OAAO,CAAC,QAAQ,CAAC;QAChE,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;IAE7B,YAAY,GAAG;QACb,GAAG,YAAY;QACf,UAAU;QACV,qBAAqB;QACrB,qBAAqB,EAAE,OAAO,CAAC,YAAY;QAC3C,8BAA8B;QAC9B,eAAe;KAChB,CAAC;IAEF,IACE,UAAU,KAAK,YAAY;QAC3B,YAAY,CAAC,MAAM,KAAK,YAAY;QACpC,OAAO,CAAC,YAAY,GAAG,CAAC;QACxB,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,qBAAqB,CAAC,EACnD,CAAC;QACD,MAAM,MAAM,GAAG,eAAe,CAC5B,OAAO,CAAC,MAAM,EACd,eAAe,EACf,qBAAqB,EACrB,OAAO,CAAC,QAAQ,EAChB,QAAQ,CACT,CAAC;QACF,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,kBAAkB,GAAG,wBAAwB,CACjD,MAAM,CAAC,eAAe,EACtB,OAAO,CAAC,QAAQ,EAChB,QAAQ,CACT,CAAC;YACF,IAAI,kBAAkB,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC5C,YAAY,GAAG;oBACb,GAAG,kBAAkB;oBACrB,UAAU;oBACV,qBAAqB;oBACrB,qBAAqB,EAAE,MAAM,CAAC,YAAY;oBAC1C,8BAA8B;oBAC9B,eAAe;oBACf,OAAO,EACL,kDAAkD;wBAClD,kBAAkB,MAAM,CAAC,YAAY,4BAA4B;iBACpE,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAC7E,CAAC;IACF,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ;YAAE,SAAS;QACxB,cAAc,IAAI,QAAQ,CAAC,aAAa,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC;YACX,WAAW,EAAE,YAAY,CAAC,GAAG,CAAC;YAC9B,QAAQ;YACR,cAAc;YACd,eAAe,EAAE,OAAO,CAAC,QAAQ,GAAG,cAAc;YAClD,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC;SACzB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LRU Cache with TTL support.
|
|
3
|
+
*
|
|
4
|
+
* Generic cache used for embedding vectors and classification results.
|
|
5
|
+
* No threading lock needed in JS (single-threaded).
|
|
6
|
+
*/
|
|
7
|
+
export declare class LRUCache<T> {
|
|
8
|
+
private readonly _maxSize;
|
|
9
|
+
private readonly _ttlMs;
|
|
10
|
+
private readonly _cache;
|
|
11
|
+
/**
|
|
12
|
+
* @param maxSize Maximum number of items to store.
|
|
13
|
+
* @param ttlSeconds Time-to-live for each entry in seconds.
|
|
14
|
+
*/
|
|
15
|
+
constructor(maxSize?: number, ttlSeconds?: number);
|
|
16
|
+
/** Get a value from cache. Returns undefined if missing or expired. */
|
|
17
|
+
get(key: string): T | undefined;
|
|
18
|
+
/** Set a value in cache. */
|
|
19
|
+
set(key: string, value: T): void;
|
|
20
|
+
/** Clear all cached entries. */
|
|
21
|
+
clear(): void;
|
|
22
|
+
/** Current number of items in cache. */
|
|
23
|
+
get size(): number;
|
|
24
|
+
/** Check if a key exists and is not expired. */
|
|
25
|
+
has(key: string): boolean;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IAEpD;;;OAGG;gBACS,OAAO,SAAM,EAAE,UAAU,SAAQ;IAM7C,uEAAuE;IACvE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAgB/B,4BAA4B;IAC5B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAmBhC,gCAAgC;IAChC,KAAK,IAAI,IAAI;IAIb,wCAAwC;IACxC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,gDAAgD;IAChD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG1B"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LRU Cache with TTL support.
|
|
3
|
+
*
|
|
4
|
+
* Generic cache used for embedding vectors and classification results.
|
|
5
|
+
* No threading lock needed in JS (single-threaded).
|
|
6
|
+
*/
|
|
7
|
+
export class LRUCache {
|
|
8
|
+
/**
|
|
9
|
+
* @param maxSize Maximum number of items to store.
|
|
10
|
+
* @param ttlSeconds Time-to-live for each entry in seconds.
|
|
11
|
+
*/
|
|
12
|
+
constructor(maxSize = 300, ttlSeconds = 300.0) {
|
|
13
|
+
this._maxSize = maxSize;
|
|
14
|
+
this._ttlMs = ttlSeconds * 1000;
|
|
15
|
+
this._cache = new Map();
|
|
16
|
+
}
|
|
17
|
+
/** Get a value from cache. Returns undefined if missing or expired. */
|
|
18
|
+
get(key) {
|
|
19
|
+
const entry = this._cache.get(key);
|
|
20
|
+
if (!entry)
|
|
21
|
+
return undefined;
|
|
22
|
+
// Check TTL
|
|
23
|
+
if (Date.now() - entry.timestamp > this._ttlMs) {
|
|
24
|
+
this._cache.delete(key);
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
// Move to end (mark as recently used) by re-inserting
|
|
28
|
+
this._cache.delete(key);
|
|
29
|
+
this._cache.set(key, entry);
|
|
30
|
+
return entry.value;
|
|
31
|
+
}
|
|
32
|
+
/** Set a value in cache. */
|
|
33
|
+
set(key, value) {
|
|
34
|
+
// Remove if exists (to update position)
|
|
35
|
+
if (this._cache.has(key)) {
|
|
36
|
+
this._cache.delete(key);
|
|
37
|
+
}
|
|
38
|
+
// Evict oldest if at capacity
|
|
39
|
+
while (this._cache.size >= this._maxSize) {
|
|
40
|
+
const firstKey = this._cache.keys().next().value;
|
|
41
|
+
if (firstKey !== undefined) {
|
|
42
|
+
this._cache.delete(firstKey);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
this._cache.set(key, { value, timestamp: Date.now() });
|
|
49
|
+
}
|
|
50
|
+
/** Clear all cached entries. */
|
|
51
|
+
clear() {
|
|
52
|
+
this._cache.clear();
|
|
53
|
+
}
|
|
54
|
+
/** Current number of items in cache. */
|
|
55
|
+
get size() {
|
|
56
|
+
return this._cache.size;
|
|
57
|
+
}
|
|
58
|
+
/** Check if a key exists and is not expired. */
|
|
59
|
+
has(key) {
|
|
60
|
+
return this.get(key) !== undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,OAAO,QAAQ;IAKnB;;;OAGG;IACH,YAAY,OAAO,GAAG,GAAG,EAAE,UAAU,GAAG,KAAK;QAC3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,uEAAuE;IACvE,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAE7B,YAAY;QACZ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC/C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACxB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,sDAAsD;QACtD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,4BAA4B;IAC5B,GAAG,CAAC,GAAW,EAAE,KAAQ;QACvB,wCAAwC;QACxC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;QAED,8BAA8B;QAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACjD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,gCAAgC;IAChC,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,wCAAwC;IACxC,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED,gDAAgD;IAChD,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IACrC,CAAC;CACF"}
|