offrouter-core 0.5.1 → 0.7.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/dist/audit.d.ts +51 -2
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +60 -3
- package/dist/audit.js.map +1 -1
- package/dist/config.d.ts +37 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +171 -1
- package/dist/config.js.map +1 -1
- package/dist/delegation.d.ts +40 -0
- package/dist/delegation.d.ts.map +1 -1
- package/dist/delegation.js +169 -8
- package/dist/delegation.js.map +1 -1
- package/dist/index.d.ts +27 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/llm-judge.d.ts +41 -0
- package/dist/llm-judge.d.ts.map +1 -0
- package/dist/llm-judge.js +159 -0
- package/dist/llm-judge.js.map +1 -0
- package/dist/policy.d.ts +77 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +81 -0
- package/dist/policy.js.map +1 -1
- package/dist/provider-health.d.ts +129 -0
- package/dist/provider-health.d.ts.map +1 -0
- package/dist/provider-health.js +423 -0
- package/dist/provider-health.js.map +1 -0
- package/dist/providers/catalog-data.d.ts +7 -0
- package/dist/providers/catalog-data.d.ts.map +1 -1
- package/dist/providers/catalog-data.js +140 -53
- package/dist/providers/catalog-data.js.map +1 -1
- package/dist/providers/catalog.d.ts +3 -3
- package/dist/providers/catalog.d.ts.map +1 -1
- package/dist/providers/catalog.js +1 -0
- package/dist/providers/catalog.js.map +1 -1
- package/dist/proxy/anthropic-mapper.d.ts +585 -0
- package/dist/proxy/anthropic-mapper.d.ts.map +1 -0
- package/dist/proxy/anthropic-mapper.js +539 -0
- package/dist/proxy/anthropic-mapper.js.map +1 -0
- package/dist/proxy/anthropic-server.d.ts +24 -0
- package/dist/proxy/anthropic-server.d.ts.map +1 -0
- package/dist/proxy/anthropic-server.js +606 -0
- package/dist/proxy/anthropic-server.js.map +1 -0
- package/dist/proxy/classify.d.ts +17 -0
- package/dist/proxy/classify.d.ts.map +1 -0
- package/dist/proxy/classify.js +65 -0
- package/dist/proxy/classify.js.map +1 -0
- package/dist/proxy/responses-mapper.d.ts +15 -0
- package/dist/proxy/responses-mapper.d.ts.map +1 -1
- package/dist/proxy/responses-mapper.js +9 -2
- package/dist/proxy/responses-mapper.js.map +1 -1
- package/dist/proxy/responses-server.d.ts.map +1 -1
- package/dist/proxy/responses-server.js +14 -1
- package/dist/proxy/responses-server.js.map +1 -1
- package/dist/router.d.ts +36 -2
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +158 -23
- package/dist/router.js.map +1 -1
- package/dist/schemas.d.ts +115 -34
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +35 -0
- package/dist/schemas.js.map +1 -1
- package/dist/secret-scan.d.ts +40 -0
- package/dist/secret-scan.d.ts.map +1 -0
- package/dist/secret-scan.js +125 -0
- package/dist/secret-scan.js.map +1 -0
- package/dist/secrets.d.ts +77 -6
- package/dist/secrets.d.ts.map +1 -1
- package/dist/secrets.js +356 -32
- package/dist/secrets.js.map +1 -1
- package/dist/spend.d.ts +122 -0
- package/dist/spend.d.ts.map +1 -0
- package/dist/spend.js +279 -0
- package/dist/spend.js.map +1 -0
- package/dist/task-classifier.d.ts +45 -0
- package/dist/task-classifier.d.ts.map +1 -0
- package/dist/task-classifier.js +153 -0
- package/dist/task-classifier.js.map +1 -0
- package/dist/types.d.ts +46 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/usage-file.d.ts +2 -6
- package/dist/usage-file.d.ts.map +1 -1
- package/dist/usage-file.js +64 -6
- package/dist/usage-file.js.map +1 -1
- package/dist/usage.d.ts +64 -10
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +79 -5
- package/dist/usage.js.map +1 -1
- package/package.json +1 -1
package/dist/spend.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Estimated paid API-key spend rollup for hard spend caps and `status --costs`.
|
|
3
|
+
*
|
|
4
|
+
* Extends the near-limit mechanism: near-limit warns on subscription quota,
|
|
5
|
+
* spend caps hard-block paid API-key candidates. Both read the same usage
|
|
6
|
+
* store; subscription and local tiers are never blocked by spend caps.
|
|
7
|
+
*
|
|
8
|
+
* Accounting window: the usage store today models a single cumulative window
|
|
9
|
+
* (per-account token totals persisted in usage.json; no time bucketing), so
|
|
10
|
+
* rollups cover everything recorded since the usage file was last reset.
|
|
11
|
+
*
|
|
12
|
+
* Spend estimation: per-account usage records (`used` = total tokens, keyed
|
|
13
|
+
* by providerId + accountId, which the delegation runtime sets to the model
|
|
14
|
+
* id) priced with the catalog PricingHint. When a per-model input/output
|
|
15
|
+
* breakdown is present, tokens are priced exactly (input rate × input +
|
|
16
|
+
* output rate × output). The unattributed remainder
|
|
17
|
+
* (`used - sum(model tokens)`) keeps the conservative max(input, output)
|
|
18
|
+
* rate treatment and flags costsIncomplete. Where pricing is unknown the
|
|
19
|
+
* contribution is not guessed: zero for cap math + costsIncomplete. Local
|
|
20
|
+
* runtimes are known-zero (no paid spend by definition).
|
|
21
|
+
*/
|
|
22
|
+
import { getBuiltinProvider, } from "./providers/catalog-data.js";
|
|
23
|
+
/** Identifier for the accounting window the usage store currently models. */
|
|
24
|
+
export const SPEND_ACCOUNTING_WINDOW = "cumulative";
|
|
25
|
+
/** Catalog pricing hint for a provider/model pair, when documented. */
|
|
26
|
+
export function pricingHintForModel(providerId, modelId) {
|
|
27
|
+
const provider = getBuiltinProvider(providerId);
|
|
28
|
+
return provider?.knownModels.find((m) => m.modelId === modelId)?.pricing;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Estimate USD for a token total under a pricing hint using the higher of
|
|
32
|
+
* the input/output rates (conservative upper bound). Used for unattributed
|
|
33
|
+
* remainder / legacy totals where the input/output split is unknown.
|
|
34
|
+
* Returns undefined when the hint carries no usable rate — unknown pricing
|
|
35
|
+
* is never guessed.
|
|
36
|
+
*/
|
|
37
|
+
export function estimateTokensCostUsd(totalTokens, hint) {
|
|
38
|
+
if (!hint)
|
|
39
|
+
return undefined;
|
|
40
|
+
const rate = Math.max(hint.inputPer1M ?? 0, hint.outputPer1M ?? 0);
|
|
41
|
+
if (rate <= 0)
|
|
42
|
+
return undefined;
|
|
43
|
+
return (totalTokens / 1_000_000) * rate;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Estimate USD from an exact input/output split. Falls back to the
|
|
47
|
+
* single documented rate when only one side is known. Returns undefined
|
|
48
|
+
* when the hint carries no usable rate.
|
|
49
|
+
*/
|
|
50
|
+
export function estimateSplitTokensCostUsd(inputTokens, outputTokens, hint) {
|
|
51
|
+
if (!hint)
|
|
52
|
+
return undefined;
|
|
53
|
+
const inputRate = hint.inputPer1M;
|
|
54
|
+
const outputRate = hint.outputPer1M;
|
|
55
|
+
if ((inputRate === undefined || inputRate <= 0) &&
|
|
56
|
+
(outputRate === undefined || outputRate <= 0)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
// When only one rate is documented, apply it to both sides rather than
|
|
60
|
+
// silently dropping the other side.
|
|
61
|
+
const inRate = inputRate !== undefined && inputRate > 0
|
|
62
|
+
? inputRate
|
|
63
|
+
: outputRate;
|
|
64
|
+
const outRate = outputRate !== undefined && outputRate > 0
|
|
65
|
+
? outputRate
|
|
66
|
+
: inputRate;
|
|
67
|
+
return (inputTokens / 1_000_000) * inRate + (outputTokens / 1_000_000) * outRate;
|
|
68
|
+
}
|
|
69
|
+
function attributedTokens(models) {
|
|
70
|
+
if (!models)
|
|
71
|
+
return 0;
|
|
72
|
+
let total = 0;
|
|
73
|
+
for (const t of Object.values(models)) {
|
|
74
|
+
total += t.inputTokens + t.outputTokens;
|
|
75
|
+
}
|
|
76
|
+
return total;
|
|
77
|
+
}
|
|
78
|
+
function pricePaidTokens(args) {
|
|
79
|
+
const { providerId, modelId, totalTokens, tier, pricing } = args;
|
|
80
|
+
const isPaidTier = tier === "api-key" || tier === undefined;
|
|
81
|
+
if (!isPaidTier) {
|
|
82
|
+
return { estimatedUsd: 0, pricingKnown: true, exactPricing: true };
|
|
83
|
+
}
|
|
84
|
+
if (getBuiltinProvider(providerId)?.defaultAuthTier === "local") {
|
|
85
|
+
return { estimatedUsd: 0, pricingKnown: true, exactPricing: true };
|
|
86
|
+
}
|
|
87
|
+
const hint = pricing(providerId, modelId);
|
|
88
|
+
const hasSplit = args.inputTokens !== undefined && args.outputTokens !== undefined;
|
|
89
|
+
let estimatedUsd;
|
|
90
|
+
let exactPricing = false;
|
|
91
|
+
if (hint !== undefined) {
|
|
92
|
+
if (hasSplit) {
|
|
93
|
+
estimatedUsd = estimateSplitTokensCostUsd(args.inputTokens, args.outputTokens, hint);
|
|
94
|
+
exactPricing = estimatedUsd !== undefined;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
estimatedUsd = estimateTokensCostUsd(totalTokens, hint);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
let pricingKnown = estimatedUsd !== undefined;
|
|
101
|
+
// Legacy records without an authTier are counted, but we cannot be sure
|
|
102
|
+
// they were truly paid API-key usage, so mark the estimate incomplete.
|
|
103
|
+
if (tier === undefined) {
|
|
104
|
+
pricingKnown = false;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
estimatedUsd: estimatedUsd ?? 0,
|
|
108
|
+
pricingKnown,
|
|
109
|
+
exactPricing: exactPricing && pricingKnown,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Build a spend rollup from per-account usage records. Pure and
|
|
114
|
+
* deterministic; providers and models are sorted by id like the usage stores.
|
|
115
|
+
*
|
|
116
|
+
* Only API-key usage counts toward paid spend. Subscription and local tiers
|
|
117
|
+
* are recorded as known-zero. Legacy records with no authTier are counted
|
|
118
|
+
* conservatively (as paid) but always mark the rollup costsIncomplete.
|
|
119
|
+
*
|
|
120
|
+
* When a per-model input/output breakdown is present, those tokens are priced
|
|
121
|
+
* exactly. Any unattributed remainder (aggregate `used` minus attributed
|
|
122
|
+
* tokens) is priced at the conservative max rate under the accountId model
|
|
123
|
+
* and flags costsIncomplete for that remainder.
|
|
124
|
+
*/
|
|
125
|
+
export function buildSpendRollup(accounts, options = {}) {
|
|
126
|
+
const pricing = options.pricing ?? pricingHintForModel;
|
|
127
|
+
const caps = options.caps ?? {};
|
|
128
|
+
const byProvider = new Map();
|
|
129
|
+
for (const account of accounts) {
|
|
130
|
+
const { providerId, accountId } = account;
|
|
131
|
+
const tier = account.authTier;
|
|
132
|
+
const models = account.models;
|
|
133
|
+
const linesForAccount = [];
|
|
134
|
+
if (models && Object.keys(models).length > 0) {
|
|
135
|
+
const modelIds = Object.keys(models).sort((a, b) => a.localeCompare(b));
|
|
136
|
+
for (const modelId of modelIds) {
|
|
137
|
+
const breakdown = models[modelId];
|
|
138
|
+
const totalTokens = breakdown.inputTokens + breakdown.outputTokens;
|
|
139
|
+
const priced = pricePaidTokens({
|
|
140
|
+
providerId,
|
|
141
|
+
modelId,
|
|
142
|
+
totalTokens,
|
|
143
|
+
inputTokens: breakdown.inputTokens,
|
|
144
|
+
outputTokens: breakdown.outputTokens,
|
|
145
|
+
tier,
|
|
146
|
+
pricing,
|
|
147
|
+
});
|
|
148
|
+
linesForAccount.push({
|
|
149
|
+
providerId,
|
|
150
|
+
modelId,
|
|
151
|
+
totalTokens,
|
|
152
|
+
inputTokens: breakdown.inputTokens,
|
|
153
|
+
outputTokens: breakdown.outputTokens,
|
|
154
|
+
estimatedUsd: priced.estimatedUsd,
|
|
155
|
+
pricingKnown: priced.pricingKnown,
|
|
156
|
+
exactPricing: priced.exactPricing,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
const remainder = Math.max(0, account.used - attributedTokens(models));
|
|
160
|
+
if (remainder > 0) {
|
|
161
|
+
// Unattributed remainder: price conservatively under the account's
|
|
162
|
+
// model id (best available catalog key) but keep a distinct line id
|
|
163
|
+
// so it never coalesces with an exact-priced attributed line.
|
|
164
|
+
const priced = pricePaidTokens({
|
|
165
|
+
providerId,
|
|
166
|
+
modelId: accountId,
|
|
167
|
+
totalTokens: remainder,
|
|
168
|
+
tier,
|
|
169
|
+
pricing,
|
|
170
|
+
});
|
|
171
|
+
linesForAccount.push({
|
|
172
|
+
providerId,
|
|
173
|
+
modelId: `${accountId}#unattributed`,
|
|
174
|
+
totalTokens: remainder,
|
|
175
|
+
estimatedUsd: priced.estimatedUsd,
|
|
176
|
+
// Remainder is definitionally incomplete: we lack the split.
|
|
177
|
+
pricingKnown: false,
|
|
178
|
+
exactPricing: false,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// Legacy / no-breakdown path: single line under accountId, conservative.
|
|
184
|
+
const priced = pricePaidTokens({
|
|
185
|
+
providerId,
|
|
186
|
+
modelId: accountId,
|
|
187
|
+
totalTokens: account.used,
|
|
188
|
+
tier,
|
|
189
|
+
pricing,
|
|
190
|
+
});
|
|
191
|
+
linesForAccount.push({
|
|
192
|
+
providerId,
|
|
193
|
+
modelId: accountId,
|
|
194
|
+
totalTokens: account.used,
|
|
195
|
+
estimatedUsd: priced.estimatedUsd,
|
|
196
|
+
pricingKnown: priced.pricingKnown,
|
|
197
|
+
exactPricing: false,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
const list = byProvider.get(providerId);
|
|
201
|
+
if (list) {
|
|
202
|
+
list.push(...linesForAccount);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
byProvider.set(providerId, linesForAccount);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const providers = [];
|
|
209
|
+
for (const [providerId, rawModels] of byProvider) {
|
|
210
|
+
// Coalesce lines that share a modelId (e.g. multiple account writes for
|
|
211
|
+
// the same model, or an exact line plus a remainder under the same key).
|
|
212
|
+
const coalesced = new Map();
|
|
213
|
+
for (const line of rawModels) {
|
|
214
|
+
const existing = coalesced.get(line.modelId);
|
|
215
|
+
if (!existing) {
|
|
216
|
+
coalesced.set(line.modelId, { ...line });
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
existing.totalTokens += line.totalTokens;
|
|
220
|
+
existing.estimatedUsd += line.estimatedUsd;
|
|
221
|
+
existing.pricingKnown = existing.pricingKnown && line.pricingKnown;
|
|
222
|
+
existing.exactPricing = existing.exactPricing && line.exactPricing;
|
|
223
|
+
if (line.inputTokens !== undefined || existing.inputTokens !== undefined) {
|
|
224
|
+
existing.inputTokens =
|
|
225
|
+
(existing.inputTokens ?? 0) + (line.inputTokens ?? 0);
|
|
226
|
+
}
|
|
227
|
+
if (line.outputTokens !== undefined ||
|
|
228
|
+
existing.outputTokens !== undefined) {
|
|
229
|
+
existing.outputTokens =
|
|
230
|
+
(existing.outputTokens ?? 0) + (line.outputTokens ?? 0);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const models = [...coalesced.values()].sort((a, b) => a.modelId.localeCompare(b.modelId));
|
|
234
|
+
const estimatedUsd = models.reduce((sum, m) => sum + m.estimatedUsd, 0);
|
|
235
|
+
const capUsd = caps.perProviderUsd?.[providerId] ?? caps.globalUsd;
|
|
236
|
+
providers.push({
|
|
237
|
+
providerId,
|
|
238
|
+
totalTokens: models.reduce((sum, m) => sum + m.totalTokens, 0),
|
|
239
|
+
estimatedUsd,
|
|
240
|
+
costsIncomplete: models.some((m) => !m.pricingKnown),
|
|
241
|
+
...(capUsd !== undefined
|
|
242
|
+
? {
|
|
243
|
+
capUsd,
|
|
244
|
+
remainingUsd: Math.max(0, capUsd - estimatedUsd),
|
|
245
|
+
capExceeded: estimatedUsd >= capUsd,
|
|
246
|
+
}
|
|
247
|
+
: { capExceeded: false }),
|
|
248
|
+
models,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
providers.sort((a, b) => a.providerId.localeCompare(b.providerId));
|
|
252
|
+
const totalUsd = providers.reduce((sum, p) => sum + p.estimatedUsd, 0);
|
|
253
|
+
const globalCap = caps.globalUsd;
|
|
254
|
+
return {
|
|
255
|
+
window: SPEND_ACCOUNTING_WINDOW,
|
|
256
|
+
totalUsd,
|
|
257
|
+
costsIncomplete: providers.some((p) => p.costsIncomplete),
|
|
258
|
+
...(globalCap !== undefined
|
|
259
|
+
? {
|
|
260
|
+
capUsd: globalCap,
|
|
261
|
+
remainingUsd: Math.max(0, globalCap - totalUsd),
|
|
262
|
+
capExceeded: totalUsd >= globalCap,
|
|
263
|
+
}
|
|
264
|
+
: { capExceeded: false }),
|
|
265
|
+
providers,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Build the `currentSpendByProviderUsd` map that PolicyConfig expects from a
|
|
270
|
+
* usage store. Non-fatal on the caller side: this helper throws when the
|
|
271
|
+
* store cannot be read so the caller can decide whether to swallow the error.
|
|
272
|
+
*/
|
|
273
|
+
export async function buildCurrentSpendByProviderUsd(store, options) {
|
|
274
|
+
const rollup = buildSpendRollup(await store.listAccountUsage(), {
|
|
275
|
+
pricing: options?.pricing,
|
|
276
|
+
});
|
|
277
|
+
return Object.fromEntries(rollup.providers.map((p) => [p.providerId, p.estimatedUsd]));
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=spend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spend.js","sourceRoot":"","sources":["../src/spend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic task classifier — routing *signal*, never authority.
|
|
3
|
+
*
|
|
4
|
+
* Policy still decides what is allowed. This module only recommends a logical
|
|
5
|
+
* model family (`fast-coder` | `frontier-coder`) from cheap, local heuristics
|
|
6
|
+
* over a prompt preview / length. No network, no LLM, no config keys.
|
|
7
|
+
*
|
|
8
|
+
* Default bias: when the input is ambiguous, prefer `frontier-coder` with
|
|
9
|
+
* `confidence: "low"`. Never under-serve a task by quietly routing complex work
|
|
10
|
+
* to a fast/cheap model. Callers must treat medium/low confidence as
|
|
11
|
+
* informational only — the router only applies a within-tier preference bump
|
|
12
|
+
* when confidence is `"high"`.
|
|
13
|
+
*/
|
|
14
|
+
/** Character threshold above which a prompt is treated as "long". */
|
|
15
|
+
export declare const LONG_PROMPT_CHARS = 2000;
|
|
16
|
+
/** Minimum distinct code fences (``` pairs counted as openings) for multi-fence. */
|
|
17
|
+
export declare const MULTI_CODE_FENCE_THRESHOLD = 2;
|
|
18
|
+
/** Minimum multi-step keyword hits required to fire the multi-step signal. */
|
|
19
|
+
export declare const MULTI_STEP_HIT_THRESHOLD = 1;
|
|
20
|
+
/** Short-prompt ceiling for the mechanical / fast path (chars). */
|
|
21
|
+
export declare const SHORT_PROMPT_CHARS = 280;
|
|
22
|
+
export type ClassifierFamily = "fast-coder" | "frontier-coder";
|
|
23
|
+
export type ClassifierConfidence = "low" | "medium" | "high";
|
|
24
|
+
export interface TaskClassification {
|
|
25
|
+
recommendedFamily: ClassifierFamily;
|
|
26
|
+
confidence: ClassifierConfidence;
|
|
27
|
+
/** Short stable rule ids that fired; safe for explain/audit (no prompt text). */
|
|
28
|
+
signals: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface ClassifyTaskInput {
|
|
31
|
+
/** Optional short preview of the prompt (may be truncated upstream). */
|
|
32
|
+
promptPreview?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Optional full prompt length in characters. Prefer this over preview length
|
|
35
|
+
* when available so truncation of the preview does not hide a long prompt.
|
|
36
|
+
*/
|
|
37
|
+
promptLengthChars?: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Classify a task from prompt preview / length using deterministic heuristics.
|
|
41
|
+
*
|
|
42
|
+
* Same inputs always produce the same output. Never throws on empty input.
|
|
43
|
+
*/
|
|
44
|
+
export declare function classifyTask(input?: ClassifyTaskInput): TaskClassification;
|
|
45
|
+
//# sourceMappingURL=task-classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-classifier.d.ts","sourceRoot":"","sources":["../src/task-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,OAAQ,CAAC;AAEvC,oFAAoF;AACpF,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,8EAA8E;AAC9E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAsB1C,mEAAmE;AACnE,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,gBAAgB,CAAC;AAE/D,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,gBAAgB,CAAC;IACpC,UAAU,EAAE,oBAAoB,CAAC;IACjC,iFAAiF;IACjF,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAsBD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,GAAE,iBAAsB,GAAG,kBAAkB,CAyF9E"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic task classifier — routing *signal*, never authority.
|
|
3
|
+
*
|
|
4
|
+
* Policy still decides what is allowed. This module only recommends a logical
|
|
5
|
+
* model family (`fast-coder` | `frontier-coder`) from cheap, local heuristics
|
|
6
|
+
* over a prompt preview / length. No network, no LLM, no config keys.
|
|
7
|
+
*
|
|
8
|
+
* Default bias: when the input is ambiguous, prefer `frontier-coder` with
|
|
9
|
+
* `confidence: "low"`. Never under-serve a task by quietly routing complex work
|
|
10
|
+
* to a fast/cheap model. Callers must treat medium/low confidence as
|
|
11
|
+
* informational only — the router only applies a within-tier preference bump
|
|
12
|
+
* when confidence is `"high"`.
|
|
13
|
+
*/
|
|
14
|
+
/** Character threshold above which a prompt is treated as "long". */
|
|
15
|
+
export const LONG_PROMPT_CHARS = 2_000;
|
|
16
|
+
/** Minimum distinct code fences (``` pairs counted as openings) for multi-fence. */
|
|
17
|
+
export const MULTI_CODE_FENCE_THRESHOLD = 2;
|
|
18
|
+
/** Minimum multi-step keyword hits required to fire the multi-step signal. */
|
|
19
|
+
export const MULTI_STEP_HIT_THRESHOLD = 1;
|
|
20
|
+
const MULTI_STEP_PATTERNS = [
|
|
21
|
+
{ id: "multi_step:refactor", re: /\brefactor(?:ing|s|ed)?\b/i },
|
|
22
|
+
{ id: "multi_step:architect", re: /\barchitect(?:ure|ing|ed|s)?\b/i },
|
|
23
|
+
{ id: "multi_step:migrate", re: /\bmigrat(?:e|ion|ing|ed|es)\b/i },
|
|
24
|
+
{ id: "multi_step:design", re: /\bdesign(?:ing|ed|s)?\b/i },
|
|
25
|
+
// "debug across" is intentionally multi-word to avoid every "debug this" hit.
|
|
26
|
+
{ id: "multi_step:debug_across", re: /\bdebug\s+across\b/i },
|
|
27
|
+
{ id: "multi_step:investigate", re: /\binvestigat(?:e|ion|ing|ed|es)\b/i },
|
|
28
|
+
];
|
|
29
|
+
const FAST_MECHANICAL_PATTERNS = [
|
|
30
|
+
{ id: "mechanical:rename", re: /\brename\b/i },
|
|
31
|
+
{ id: "mechanical:format", re: /\bformat\b/i },
|
|
32
|
+
{ id: "mechanical:typo", re: /\btypos?\b/i },
|
|
33
|
+
{ id: "mechanical:bump", re: /\bbump\b/i },
|
|
34
|
+
{ id: "mechanical:list", re: /\blist\b/i },
|
|
35
|
+
// "extract single" stays multi-word so "extract the auth module" stays open.
|
|
36
|
+
{ id: "mechanical:extract_single", re: /\bextract\s+single\b/i },
|
|
37
|
+
];
|
|
38
|
+
/** Short-prompt ceiling for the mechanical / fast path (chars). */
|
|
39
|
+
export const SHORT_PROMPT_CHARS = 280;
|
|
40
|
+
function countCodeFenceOpenings(text) {
|
|
41
|
+
// Count opening fences only; a lone ``` still counts as one fence block.
|
|
42
|
+
const matches = text.match(/```/g);
|
|
43
|
+
if (!matches)
|
|
44
|
+
return 0;
|
|
45
|
+
// Each fence token is one marker; a complete block uses two. Treat every pair
|
|
46
|
+
// of markers as one fence and a trailing orphan as another block start.
|
|
47
|
+
return Math.ceil(matches.length / 2);
|
|
48
|
+
}
|
|
49
|
+
function collectHits(text, patterns) {
|
|
50
|
+
const hits = [];
|
|
51
|
+
for (const { id, re } of patterns) {
|
|
52
|
+
if (re.test(text))
|
|
53
|
+
hits.push(id);
|
|
54
|
+
}
|
|
55
|
+
return hits;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Classify a task from prompt preview / length using deterministic heuristics.
|
|
59
|
+
*
|
|
60
|
+
* Same inputs always produce the same output. Never throws on empty input.
|
|
61
|
+
*/
|
|
62
|
+
export function classifyTask(input = {}) {
|
|
63
|
+
const preview = input.promptPreview ?? "";
|
|
64
|
+
const length = typeof input.promptLengthChars === "number" &&
|
|
65
|
+
Number.isFinite(input.promptLengthChars) &&
|
|
66
|
+
input.promptLengthChars >= 0
|
|
67
|
+
? Math.floor(input.promptLengthChars)
|
|
68
|
+
: preview.length;
|
|
69
|
+
const signals = [];
|
|
70
|
+
let frontierScore = 0;
|
|
71
|
+
let fastScore = 0;
|
|
72
|
+
// --- Frontier signals ----------------------------------------------------
|
|
73
|
+
if (length > LONG_PROMPT_CHARS) {
|
|
74
|
+
signals.push("long_prompt");
|
|
75
|
+
frontierScore += 2;
|
|
76
|
+
}
|
|
77
|
+
const multiStepHits = collectHits(preview, MULTI_STEP_PATTERNS);
|
|
78
|
+
if (multiStepHits.length >= MULTI_STEP_HIT_THRESHOLD) {
|
|
79
|
+
signals.push(...multiStepHits);
|
|
80
|
+
signals.push("multi_step");
|
|
81
|
+
frontierScore += 1 + Math.min(multiStepHits.length, 2);
|
|
82
|
+
}
|
|
83
|
+
const fenceCount = countCodeFenceOpenings(preview);
|
|
84
|
+
if (fenceCount >= MULTI_CODE_FENCE_THRESHOLD) {
|
|
85
|
+
signals.push("multi_code_fence");
|
|
86
|
+
frontierScore += 2;
|
|
87
|
+
}
|
|
88
|
+
// --- Fast / mechanical signals -------------------------------------------
|
|
89
|
+
const mechanicalHits = collectHits(preview, FAST_MECHANICAL_PATTERNS);
|
|
90
|
+
const isShort = length > 0 && length <= SHORT_PROMPT_CHARS;
|
|
91
|
+
if (isShort) {
|
|
92
|
+
signals.push("short_prompt");
|
|
93
|
+
}
|
|
94
|
+
if (mechanicalHits.length > 0 && frontierScore === 0) {
|
|
95
|
+
signals.push(...mechanicalHits);
|
|
96
|
+
signals.push("mechanical_verb");
|
|
97
|
+
fastScore += 1 + Math.min(mechanicalHits.length, 2);
|
|
98
|
+
if (isShort)
|
|
99
|
+
fastScore += 1;
|
|
100
|
+
}
|
|
101
|
+
else if (mechanicalHits.length > 0 && frontierScore > 0) {
|
|
102
|
+
// Still record mechanical hits for explainability, but do not let them
|
|
103
|
+
// cancel a frontier signal (never under-serve).
|
|
104
|
+
signals.push(...mechanicalHits);
|
|
105
|
+
}
|
|
106
|
+
// Empty / whitespace-only input → ambiguous.
|
|
107
|
+
if (preview.trim().length === 0 && length === 0) {
|
|
108
|
+
return {
|
|
109
|
+
recommendedFamily: "frontier-coder",
|
|
110
|
+
confidence: "low",
|
|
111
|
+
signals: ["ambiguous_empty"],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (frontierScore > 0 && frontierScore > fastScore) {
|
|
115
|
+
const confidence = frontierScore >= 3 ? "high" : frontierScore === 2 ? "medium" : "low";
|
|
116
|
+
return {
|
|
117
|
+
recommendedFamily: "frontier-coder",
|
|
118
|
+
confidence,
|
|
119
|
+
signals: dedupe(signals),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (fastScore > 0 && fastScore > frontierScore) {
|
|
123
|
+
// High only when short + clear mechanical verb(s) and no frontier signal.
|
|
124
|
+
const confidence = fastScore >= 2 && isShort ? "high" : "medium";
|
|
125
|
+
return {
|
|
126
|
+
recommendedFamily: "fast-coder",
|
|
127
|
+
confidence,
|
|
128
|
+
signals: dedupe(signals),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// Ambiguous: mixed, missing, or equal signal weight. Default to frontier so
|
|
132
|
+
// we never under-serve. Confidence stays low so the router does not reorder.
|
|
133
|
+
if (!signals.includes("ambiguous")) {
|
|
134
|
+
signals.push("ambiguous");
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
recommendedFamily: "frontier-coder",
|
|
138
|
+
confidence: "low",
|
|
139
|
+
signals: dedupe(signals),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function dedupe(signals) {
|
|
143
|
+
const seen = new Set();
|
|
144
|
+
const out = [];
|
|
145
|
+
for (const s of signals) {
|
|
146
|
+
if (seen.has(s))
|
|
147
|
+
continue;
|
|
148
|
+
seen.add(s);
|
|
149
|
+
out.push(s);
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=task-classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-classifier.js","sourceRoot":"","sources":["../src/task-classifier.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type FallbackReason = "primary" | "subscription_exhausted" | "subscriptio
|
|
|
10
10
|
export type HarnessKind = "claude" | "codex" | "gemini" | "grok" | "cursor" | "pi" | "other";
|
|
11
11
|
export type TaskKind = "explain" | "code" | "review" | "plan" | "research" | "image" | "tools" | "other";
|
|
12
12
|
export type RiskLevel = "low" | "medium" | "high";
|
|
13
|
-
export type PolicyDenialCode = "profile_not_allowlisted" | "work_profile_denied" | "provider_denied" | "project_untrusted" | "privacy_label_denied" | "local_only_required" | "cost_cap_exceeded" | "api_key_blocked_by_subscription_first_policy" | "subscription_scope_denied" | "capability_missing";
|
|
13
|
+
export type PolicyDenialCode = "profile_not_allowlisted" | "work_profile_denied" | "provider_denied" | "project_untrusted" | "privacy_label_denied" | "local_only_required" | "cost_cap_exceeded" | "spend_cap_exceeded" | "api_key_blocked_by_subscription_first_policy" | "subscription_scope_denied" | "capability_missing" | "model_not_allowed" | "api_spend_approval_required" | "subscription_switch_requires_ack";
|
|
14
14
|
export type PolicyDenialTarget = "profile" | "provider" | "model" | "workspace" | "candidate";
|
|
15
15
|
export interface PolicyDenial {
|
|
16
16
|
code: PolicyDenialCode;
|
|
@@ -18,6 +18,8 @@ export interface PolicyDenial {
|
|
|
18
18
|
id: string;
|
|
19
19
|
message: string;
|
|
20
20
|
}
|
|
21
|
+
/** Logical model family shared across auth tiers (mirrors catalog). */
|
|
22
|
+
export type LogicalModelFamily = "frontier-coder" | "fast-coder" | "local-coder" | "vision-helper";
|
|
21
23
|
export interface ProviderCandidate {
|
|
22
24
|
providerId: string;
|
|
23
25
|
modelId: string;
|
|
@@ -35,6 +37,11 @@ export interface ProviderCandidate {
|
|
|
35
37
|
contextWindowTokens?: number;
|
|
36
38
|
maxOutputTokens?: number;
|
|
37
39
|
estimatedCostUsd?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Optional logical family used by the heuristic classifier as a same-tier
|
|
42
|
+
* preference signal. Omitted candidates never receive a family preference bump.
|
|
43
|
+
*/
|
|
44
|
+
family?: LogicalModelFamily;
|
|
38
45
|
}
|
|
39
46
|
export interface HarnessRef {
|
|
40
47
|
kind: HarnessKind;
|
|
@@ -85,7 +92,25 @@ export interface FallbackChainEntry {
|
|
|
85
92
|
model: string;
|
|
86
93
|
authTier: AuthTier;
|
|
87
94
|
reason: FallbackReason;
|
|
95
|
+
/**
|
|
96
|
+
* Recent-outcome health score used for same-tier re-ordering when a health
|
|
97
|
+
* tracker is attached to routeRequest. Higher is healthier. Unknown /
|
|
98
|
+
* unobserved pairs use the tracker neutral score (0). Omitted when no
|
|
99
|
+
* tracker was provided.
|
|
100
|
+
*/
|
|
101
|
+
healthScore?: number;
|
|
88
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Heuristic task classification attached to a route decision for explain/audit.
|
|
105
|
+
* Contains only family / confidence / stable signal ids — never prompt text.
|
|
106
|
+
*/
|
|
107
|
+
export interface RouteClassification {
|
|
108
|
+
recommendedFamily: "fast-coder" | "frontier-coder";
|
|
109
|
+
confidence: "low" | "medium" | "high";
|
|
110
|
+
signals: string[];
|
|
111
|
+
}
|
|
112
|
+
/** Which classifier produced the routing signal recorded in audit/decision. */
|
|
113
|
+
export type ClassifierName = "heuristic" | "llm" | "llm-fallback-heuristic";
|
|
89
114
|
export interface RouteDecision {
|
|
90
115
|
protocolVersion: "offrouter.route.v1";
|
|
91
116
|
decisionId: string;
|
|
@@ -105,6 +130,26 @@ export interface RouteDecision {
|
|
|
105
130
|
needsConfiguration?: boolean;
|
|
106
131
|
/** Warning when the selected route is a near-limit subscription with no healthy alternative. */
|
|
107
132
|
nearLimitWarning?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Optional classifier signal used during scoring. Present when the caller
|
|
135
|
+
* supplied a classification (or delegation computed one). Never carries
|
|
136
|
+
* prompt text — family / confidence / signal ids only.
|
|
137
|
+
*/
|
|
138
|
+
classification?: RouteClassification;
|
|
139
|
+
/**
|
|
140
|
+
* Which classifier produced the classification signal. Present when the
|
|
141
|
+
* decision carries a classification. Never prompt text.
|
|
142
|
+
*/
|
|
143
|
+
classifierName?: ClassifierName;
|
|
144
|
+
/**
|
|
145
|
+
* When a user-defined routing rule matched, the rule index and matched keys.
|
|
146
|
+
* Absent when no rule matched (auto routing).
|
|
147
|
+
*/
|
|
148
|
+
routingRule?: {
|
|
149
|
+
index: number;
|
|
150
|
+
matchedKeys: ("role" | "family")[];
|
|
151
|
+
target: "model" | "provider" | "tier";
|
|
152
|
+
};
|
|
108
153
|
}
|
|
109
154
|
/**
|
|
110
155
|
* Outcome of evaluatePolicy: filtered candidates plus structured denials.
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,OAAO,GAAG,SAAS,CAAC;AAE5D,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,aAAa,GAAG,SAAS,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,YAAY,GACZ,WAAW,GACX,cAAc,GACd,SAAS,GACT,cAAc,GACd,SAAS,CAAC;AAEd,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAE7D,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,wBAAwB,GACxB,uBAAuB,GACvB,2BAA2B,GAC3B,2BAA2B,GAC3B,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,gBAAgB,CAAC;AAErB,MAAM,MAAM,WAAW,GACrB,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC;AAErE,MAAM,MAAM,QAAQ,GAChB,SAAS,GACT,MAAM,GACN,QAAQ,GACR,MAAM,GACN,UAAU,GACV,OAAO,GACP,OAAO,GACP,OAAO,CAAC;AAEZ,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAElD,MAAM,MAAM,gBAAgB,GACxB,yBAAyB,GACzB,qBAAqB,GACrB,iBAAiB,GACjB,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,mBAAmB,GACnB,8CAA8C,GAC9C,2BAA2B,GAC3B,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/usage-file.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { chmod, mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
2
|
-
import { type AccountUsageSnapshot, type PaidFallbackExplanation, type ProviderUsageSnapshot, type RecordUsageResult, type UsageEvent, type UsageStore } from "./usage.js";
|
|
2
|
+
import { type AccountUsageSnapshot, type PaidFallbackExplanation, type ProviderUsageSnapshot, type RecordUsageInput, type RecordUsageResult, type UsageEvent, type UsageStore } from "./usage.js";
|
|
3
3
|
export { DEFAULT_NEAR_LIMIT_THRESHOLD } from "./usage.js";
|
|
4
4
|
export { InMemoryUsageStore } from "./usage.js";
|
|
5
5
|
export type { UsageStore } from "./usage.js";
|
|
@@ -45,11 +45,7 @@ export declare class FileUsageStore implements UsageStore {
|
|
|
45
45
|
explainPaidFallback(providerId: string, options?: {
|
|
46
46
|
hasApiKeyCandidate?: boolean;
|
|
47
47
|
}): Promise<PaidFallbackExplanation>;
|
|
48
|
-
recordUsage(providerId: string, accountId: string, input:
|
|
49
|
-
used?: number;
|
|
50
|
-
limit?: number;
|
|
51
|
-
at?: Date;
|
|
52
|
-
}): Promise<AccountUsageSnapshot>;
|
|
48
|
+
recordUsage(providerId: string, accountId: string, input: RecordUsageInput): Promise<AccountUsageSnapshot>;
|
|
53
49
|
isNearLimit(providerId: string, accountId: string, threshold?: number): Promise<boolean>;
|
|
54
50
|
getNearLimitAccounts(threshold?: number): Promise<AccountUsageSnapshot[]>;
|
|
55
51
|
getAccountUsage(providerId: string, accountId: string): Promise<AccountUsageSnapshot | undefined>;
|
package/dist/usage-file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-file.d.ts","sourceRoot":"","sources":["../src/usage-file.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,EACV,MAAM,kBAAkB,CAAC;AAG1B,OAAO,
|
|
1
|
+
{"version":3,"file":"usage-file.d.ts","sourceRoot":"","sources":["../src/usage-file.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,EACV,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAKL,KAAK,oBAAoB,EAEzB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,KAAK,EAAE,OAAO,KAAK,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,kFAAkF;IAClF,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC/C,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB;AAgJD;;;GAGG;AACH,qBAAa,cAAe,YAAW,UAAU;;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBASd,OAAO,EAAE,qBAAqB;IA4J1C,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIrD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC;IAI3E,aAAa,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAIjD,oBAAoB,CAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,OAAO,YAAY,EAAE,kBAAkB,CAAC;QACjD,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,EAAE,CAAC,EAAE,IAAI,CAAC;KACX,GACA,OAAO,CAAC,qBAAqB,CAAC;IAIjC,mBAAmB,CACjB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAE,GACzC,OAAO,CAAC,uBAAuB,CAAC;IAM7B,WAAW,CACf,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,oBAAoB,CAAC;IAqB1B,WAAW,CACf,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC;IASb,oBAAoB,CACxB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAgB5B,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;IAStC,gBAAgB,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAezD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQlC"}
|