@qadanm/opencode-smart-router 0.4.0 → 0.6.1

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.
@@ -64,6 +64,13 @@ export interface InitInput {
64
64
  }
65
65
 
66
66
  const KEY = Symbol.for("opencode-smart-router.shared-core.v1")
67
+ /**
68
+ * The API surface a bridge depends on. Bump this when the shape of SharedCore
69
+ * changes incompatibly: a core with a different stamp is refused rather than
70
+ * adopted, so a new bundle never inherits an older version's object.
71
+ * 2 = plan-model pool ledger.
72
+ */
73
+ const SHARED_CORE_API = 2
67
74
  const BRIDGE_GRACE_MS = 10_000
68
75
  const MODEL_TTL_MS = 5 * 60_000
69
76
  const UNOWNED_TTL_MS = 30_000
@@ -81,6 +88,12 @@ class SharedCore {
81
88
  readonly coreID = Math.random().toString(36).slice(2, 10)
82
89
  readonly pid = process.pid
83
90
  readonly createdAt = Date.now()
91
+ /**
92
+ * Stamped so a later plugin version can tell whether the object it found in
93
+ * globalThis was built by a compatible release. A plain object without this
94
+ * field predates the stamp and must not be adopted.
95
+ */
96
+ readonly apiVersion = SHARED_CORE_API
84
97
  ledger = new LedgerStore()
85
98
  runtime: RuntimeOverrides = {}
86
99
  quota?: QuotaService
@@ -130,6 +143,11 @@ class SharedCore {
130
143
  async init(input: InitInput): Promise<void> {
131
144
  this.setups += 1
132
145
  if (this.disposing) await this.disposing
146
+ // The ledger this core holds must answer the API this bundle was built
147
+ // against. `resetForTests` and a version skew can both leave a ledger that
148
+ // predates a method; replacing it here means the rest of the code can call
149
+ // what it imports without defending every call site.
150
+ if (!(this.ledger instanceof LedgerStore)) this.ledger = new LedgerStore()
133
151
  if (this.ready && this.ownerCtx && this.started) return this.ready
134
152
  // Several locations can initialize in the same tick when a server restores
135
153
  // its session list. Share one load; a second load would replace the ledger
@@ -666,6 +684,18 @@ class SharedCore {
666
684
  }
667
685
  }
668
686
 
687
+ /**
688
+ * Adopt the process-wide core only when this bundle built it. A core left by a
689
+ * different version is a different class with different methods; adopting it
690
+ * produced `this.ledger.planPoolSpent is not a function` on every prompt in
691
+ * 0.6.0. Replacing it is safe because each bridge re-reads persisted state in
692
+ * `init()`, and it is the only choice that keeps the process working.
693
+ */
694
+ const existing = (globalThis as any)[KEY] as SharedCore | undefined
669
695
  export const sharedCore: SharedCore =
670
- ((globalThis as any)[KEY] as SharedCore | undefined) ??
671
- (((globalThis as any)[KEY] = new SharedCore()) as SharedCore)
696
+ existing && existing.apiVersion === SHARED_CORE_API
697
+ ? existing
698
+ : (((globalThis as any)[KEY] = new SharedCore()) as SharedCore)
699
+
700
+ /** True when this process already held a core built by another version. */
701
+ export const inheritedForeignCore = existing !== undefined && existing !== sharedCore
package/dist/allowance.js DELETED
@@ -1,487 +0,0 @@
1
- // src/core/plans/catalog.ts
2
- var OPENDESIGN_DESIGN_PLAN_MODELS = /* @__PURE__ */ new Set([
3
- "deepseek-v4.1-flash",
4
- "mimo-v2.6-flash",
5
- "mimo-v2.6-pro",
6
- "hy4-preview",
7
- "deepseek-v4-flash",
8
- "deepseek-v4-flash-vision-exp",
9
- "deepseek-v4-pro",
10
- "glm-5.3-flash",
11
- "kimi-k2.7-code",
12
- "claude-haiku-5.5",
13
- "glm-5.3-flashx",
14
- "gpt-6-luna"
15
- ]);
16
- var OPENDESIGN_DESIGN_PLAN_POOL = "design-plan";
17
- var OPENDESIGN_PLAN_MODEL_POOL = "plan-models";
18
- var opendesign = (planID, label, monthlyPriceUsd, designPlanMonthlyUsd, planModelMonthlyUsd, weeklyUsd, fiveHourUsd, concurrency, extraNotes = []) => {
19
- const pools = [];
20
- if (designPlanMonthlyUsd > 0) {
21
- pools.push({
22
- id: OPENDESIGN_DESIGN_PLAN_POOL,
23
- label: "Design Plan credits",
24
- monthlyUsd: designPlanMonthlyUsd,
25
- ...weeklyUsd !== void 0 ? { weeklyUsd } : {},
26
- ...fiveHourUsd !== void 0 ? { fiveHourUsd } : {},
27
- resetKind: "fixed-7-day",
28
- drawOrder: 1,
29
- note: fiveHourUsd === void 0 ? "Seven-day ceiling nested inside the monthly maximum. Used before plan model credits." : "Five-hour and seven-day ceilings nested inside the monthly maximum. Used before plan model credits."
30
- });
31
- }
32
- if (planModelMonthlyUsd > 0) {
33
- pools.push({
34
- id: OPENDESIGN_PLAN_MODEL_POOL,
35
- label: "Plan model credits",
36
- monthlyUsd: planModelMonthlyUsd,
37
- resetKind: "billing-cycle",
38
- drawOrder: 2,
39
- note: "No five-hour or seven-day window. Funds plan models directly, and Design Plan models once their own credits are exhausted. Design Plan multipliers do not carry over to this pool."
40
- });
41
- }
42
- return {
43
- providerID: "opendesign",
44
- planID,
45
- label,
46
- monthlyPriceUsd,
47
- pools,
48
- ...concurrency > 0 ? { concurrency } : {},
49
- notes: [
50
- "Credits are not cash and are not a fixed request count.",
51
- "Design Plan credits and plan model credits are separate pools, but they do spill: on Plus, Pro and Max, Design Plan usage draws from plan model credits once the Design Plan allowance is spent. Go has no plan model credits, so a spent window means waiting for the reset.",
52
- "The seven-day Design Plan window starts when the subscription starts and repeats every seven days. It is not a rolling window and does not align to Monday or the first of the month.",
53
- "Plan model credits have no five-hour or seven-day window; they are granted and reset per billing cycle.",
54
- "Unused subscription credits do not roll over.",
55
- ...extraNotes
56
- ]
57
- };
58
- };
59
- var OPENDESIGN_PLANS = [
60
- opendesign("go", "OpenDesign Go", 10, 120, 0, 30, 10, 10, [
61
- "Go includes Design Plan credits only and no plan model credits."
62
- ]),
63
- // The seven-day Design Plan ceiling for Plus is $40, not "no cap". It was
64
- // undefined here, which made Plus look like it could spend the whole $160 in
65
- // one week — understating the real limit by 4x for anyone on that tier.
66
- opendesign("plus", "OpenDesign Plus", 20, 160, 20, 40, void 0, 20, [
67
- "Plus has a seven-day Design Plan window and no five-hour window."
68
- ]),
69
- opendesign("pro", "OpenDesign Pro", 100, 360, 120, 90, void 0, 30, [
70
- "Pro has a seven-day Design Plan window and no five-hour window.",
71
- "The $120 plan model pool currently carries a limited-time promotional bonus and resets per billing cycle."
72
- ]),
73
- opendesign("max", "OpenDesign Max", 200, 600, 300, 150, void 0, 30, [
74
- "Max has a seven-day Design Plan window and no five-hour window."
75
- ])
76
- ];
77
- var GO_MODEL_ALLOWANCES = {
78
- "deepseek-v4.1-flash": 80,
79
- "deepseek-v4-pro": 15,
80
- "glm-5.3-flash": 60,
81
- "glm-5.3": 15,
82
- "glm-5.2": 60,
83
- "minimax-m3.1-flash": 20,
84
- "mimo-v2.6-flash": 60,
85
- "mimo-v2.6-pro": 15,
86
- "claude-haiku-5-5": 15,
87
- "gpt-6-luna": 15,
88
- "gpt-6-luna-high": 15,
89
- "kimi-k3": 15,
90
- "kimi-k3.1-pro": 15,
91
- "kimi-k2.7-code": 60,
92
- "grok-4.7": 15,
93
- "qwen3.8-max": 15,
94
- "qwen3.8-flash": 30,
95
- "step-5-preview": 15,
96
- "longcat-2.0": 60,
97
- hy3: 60,
98
- "hy4-preview": 30,
99
- "gemini-4-argon": 30
100
- };
101
- var GO_PLUS_MODEL_ALLOWANCES = {
102
- "deepseek-v4.1-flash": 160,
103
- "deepseek-v4-pro": 60,
104
- "glm-5.3-flash": 180,
105
- "glm-5.3": 120,
106
- "glm-5.2": 180,
107
- "minimax-m3.1-flash": 80,
108
- "mimo-v2.6-flash": 120,
109
- "mimo-v2.6-pro": 60,
110
- "claude-haiku-5-5": 60,
111
- "gpt-6-luna": 60,
112
- "kimi-k3": 60,
113
- "kimi-k3.1-pro": 60,
114
- "kimi-k2.7-code": 180,
115
- "grok-4.7": 60,
116
- "qwen3.8-max": 60,
117
- "qwen3.8-flash": 90,
118
- "step-5-preview": 60,
119
- "longcat-2.0": 240,
120
- hy3: 240,
121
- "hy4-preview": 120,
122
- "gemini-4-argon": 120
123
- };
124
- var openCodeGoPlan = (planID, label, monthlyPriceUsd, allowances) => ({
125
- providerID: "opencode-go",
126
- planID,
127
- label,
128
- monthlyPriceUsd,
129
- pools: [
130
- {
131
- id: "per-model",
132
- label: "Per-model monthly allowances",
133
- // There is no shared pool; the monthly total is the sum of the
134
- // per-model ceilings for reporting only.
135
- monthlyUsd: Object.values(allowances).reduce((sum, value) => sum + value, 0),
136
- resetKind: "billing-cycle",
137
- drawOrder: 1,
138
- note: "Each model has its own monthly dollar allowance. The five-hour and weekly ceilings are percentages of that model's allowance, not separate credit."
139
- }
140
- ],
141
- perModelMonthlyUsd: allowances,
142
- perModelWindowRule: { fiveHourPct: 20, weeklyPct: 50 },
143
- notes: [
144
- "Allowances are per model and do not pool across models.",
145
- "Token prices are identical on Go, Go Plus and Go Teams; only the allowances differ."
146
- ]
147
- });
148
- var COMMANDCODE_PLANS = [
149
- {
150
- providerID: "commandcode",
151
- planID: "goat",
152
- label: "Command Code GOAT",
153
- monthlyPriceUsd: 10,
154
- pools: [
155
- {
156
- id: "monthly",
157
- label: "GOAT monthly credits",
158
- monthlyUsd: 70,
159
- weeklyUsd: 35,
160
- fiveHourUsd: 14,
161
- resetKind: "billing-cycle",
162
- drawOrder: 1,
163
- note: "One shared pool with five-hour and weekly ceilings nested inside the monthly maximum."
164
- }
165
- ],
166
- notes: ["Read from Command Code's read-only account endpoints; the account response is authoritative."]
167
- }
168
- ];
169
- var PLAN_CATALOG = [
170
- ...OPENDESIGN_PLANS,
171
- openCodeGoPlan("go", "OpenCode Go", 10, GO_MODEL_ALLOWANCES),
172
- openCodeGoPlan("go-plus", "OpenCode Go Plus", 40, GO_PLUS_MODEL_ALLOWANCES),
173
- ...COMMANDCODE_PLANS
174
- ];
175
- var PLAN_BY_KEY = new Map(
176
- PLAN_CATALOG.map((plan) => [`${plan.providerID}/${plan.planID}`, plan])
177
- );
178
- var DEFAULT_PLAN_ID = {
179
- opendesign: "pro",
180
- "opencode-go": "go",
181
- commandcode: "goat"
182
- };
183
- var defaultPlanIdFor = (providerID) => DEFAULT_PLAN_ID[providerID];
184
- var PLAN_ALIASES = {
185
- "opendesign/go-plus": "plus",
186
- "opendesign/max-plan": "max",
187
- "opencode-go/goplus": "go-plus",
188
- "opencode-go/go+": "go-plus"
189
- };
190
- var resolvePlanWithReason = (providerID, planID) => {
191
- const requested = (planID ?? "").trim().toLowerCase();
192
- if (requested) {
193
- const aliasTarget = PLAN_ALIASES[`${providerID}/${requested}`];
194
- if (aliasTarget) {
195
- const plan = PLAN_BY_KEY.get(`${providerID}/${aliasTarget}`);
196
- if (plan) return { plan, resolution: "alias", planID: plan.planID };
197
- }
198
- const direct = PLAN_BY_KEY.get(`${providerID}/${requested}`);
199
- if (direct) return { plan: direct, resolution: "exact", planID: direct.planID };
200
- return { plan: void 0, resolution: "unknown", planID: void 0 };
201
- }
202
- const fallback = DEFAULT_PLAN_ID[providerID];
203
- return {
204
- plan: fallback ? PLAN_BY_KEY.get(`${providerID}/${fallback}`) : void 0,
205
- resolution: fallback ? "default" : "unknown",
206
- planID: fallback
207
- };
208
- };
209
- var resolvePlan = (providerID, planID) => resolvePlanWithReason(providerID, planID).plan;
210
- var planById = (providerID, planID) => PLAN_BY_KEY.get(`${providerID}/${planID}`);
211
- var fundingPoolFor = (plan, modelID) => {
212
- if (plan.providerID === "opendesign") {
213
- const designPlan = plan.pools.find((pool) => pool.id === OPENDESIGN_DESIGN_PLAN_POOL);
214
- const planModels = plan.pools.find((pool) => pool.id === OPENDESIGN_PLAN_MODEL_POOL);
215
- if (OPENDESIGN_DESIGN_PLAN_MODELS.has(modelID)) return designPlan ?? planModels;
216
- return planModels ?? designPlan;
217
- }
218
- return [...plan.pools].sort((a, b) => a.drawOrder - b.drawOrder)[0];
219
- };
220
- var isEscalationOnlyPool = (plan, modelID) => {
221
- if (plan.providerID !== "opendesign") return false;
222
- return !OPENDESIGN_DESIGN_PLAN_MODELS.has(modelID);
223
- };
224
- var poolDrawSequence = (plan, modelID) => {
225
- const primary = fundingPoolFor(plan, modelID);
226
- if (!primary) return [];
227
- const sequence = [{ pool: primary, multiplierApplies: plan.providerID !== "opendesign" || primary.id === OPENDESIGN_DESIGN_PLAN_POOL }];
228
- if (plan.providerID !== "opendesign") return sequence;
229
- const designPlan = plan.pools.find((pool) => pool.id === OPENDESIGN_DESIGN_PLAN_POOL);
230
- const planModels = plan.pools.find((pool) => pool.id === OPENDESIGN_PLAN_MODEL_POOL);
231
- if (primary.id === OPENDESIGN_DESIGN_PLAN_POOL && planModels) {
232
- sequence.push({ pool: planModels, multiplierApplies: false });
233
- } else if (primary.id === OPENDESIGN_PLAN_MODEL_POOL && designPlan && OPENDESIGN_DESIGN_PLAN_MODELS.has(modelID)) {
234
- sequence.unshift({ pool: designPlan, multiplierApplies: true });
235
- }
236
- return sequence;
237
- };
238
- var modelMonthlyAllowanceUsd = (plan, modelID) => {
239
- const table = plan.perModelMonthlyUsd;
240
- if (!table) return 0;
241
- return table[modelID] ?? 0;
242
- };
243
- var modelWindowCaps = (plan, modelID) => {
244
- const monthlyUsd = modelMonthlyAllowanceUsd(plan, modelID);
245
- const rule = plan.perModelWindowRule;
246
- if (!rule || monthlyUsd <= 0) return { monthlyUsd, weeklyUsd: 0, fiveHourUsd: 0 };
247
- return {
248
- monthlyUsd,
249
- weeklyUsd: monthlyUsd * (rule.weeklyPct / 100),
250
- fiveHourUsd: monthlyUsd * (rule.fiveHourPct / 100)
251
- };
252
- };
253
- var planSummaryLine = (plan) => {
254
- const parts = plan.pools.map((pool) => {
255
- const windows = [
256
- pool.fiveHourUsd !== void 0 ? `5h $${pool.fiveHourUsd}` : void 0,
257
- pool.weeklyUsd !== void 0 ? `7d $${pool.weeklyUsd}` : void 0
258
- ].filter((entry) => Boolean(entry));
259
- const suffix = windows.length > 0 ? ` (${windows.join(", ")} nested)` : "";
260
- return `${pool.label} $${pool.monthlyUsd}/mo${suffix}`;
261
- });
262
- return `${plan.label} ($${plan.monthlyPriceUsd}/mo): ${parts.join(" + ")}`;
263
- };
264
-
265
- // src/core/context/strategy.ts
266
- var CONTEXT_ELIGIBILITY_MARGIN_TOKENS = 2e4;
267
- var MINIMUM_REPLY_RESERVE_FRACTION = 0.125;
268
- var replyMarginFor = (windowTokens) => {
269
- if (!Number.isFinite(windowTokens) || windowTokens <= 0) return CONTEXT_ELIGIBILITY_MARGIN_TOKENS;
270
- return Math.min(CONTEXT_ELIGIBILITY_MARGIN_TOKENS, Math.floor(windowTokens * MINIMUM_REPLY_RESERVE_FRACTION));
271
- };
272
- var CONTEXT_SAFE_WINDOW_FRACTION = 0.95;
273
- var no = (reason) => ({ compact: false, reason, hardLimit: false });
274
- var decideCompaction = (input) => {
275
- const { mode, settings, contextTokens, effectiveWindow } = input;
276
- if (!settings.enabled) {
277
- return { compact: false, reason: "Context management is disabled; native context handling only.", hardLimit: false };
278
- }
279
- if (contextTokens <= 0) return no("No measured context size yet.");
280
- if (effectiveWindow <= 0) return no("The model's accepted context window is unknown; no router-driven compaction.");
281
- const required = contextTokens + replyMarginFor(effectiveWindow);
282
- const safeLimit = effectiveWindow * CONTEXT_SAFE_WINDOW_FRACTION;
283
- const overflow = required > safeLimit;
284
- if (mode === "native") {
285
- if (!overflow) return no("Native mode: the transcript fits the verified window.");
286
- if (settings.allowEmergencyCompaction === false) {
287
- return {
288
- compact: false,
289
- reason: "Native mode: transcript is at the verified limit, but emergency compaction is disabled.",
290
- triggerTokens: contextTokens,
291
- targetTokens: Math.floor(safeLimit),
292
- hardLimit: true
293
- };
294
- }
295
- return {
296
- compact: true,
297
- reason: "Native mode emergency compaction: the transcript would exceed the model's verified window.",
298
- triggerTokens: contextTokens,
299
- targetTokens: Math.floor(safeLimit),
300
- hardLimit: true
301
- };
302
- }
303
- if (mode === "conservative") {
304
- if (!overflow) return no("Conservative mode: the transcript fits the verified window; history preserved.");
305
- return {
306
- compact: true,
307
- reason: "Conservative mode: compacting only because the transcript would exceed the verified window.",
308
- triggerTokens: contextTokens,
309
- targetTokens: Math.floor(safeLimit),
310
- hardLimit: true
311
- };
312
- }
313
- const target = input.cheapestWindow && input.cheapestWindow > 0 ? input.cheapestWindow : effectiveWindow;
314
- const targetLimit = target * CONTEXT_SAFE_WINDOW_FRACTION;
315
- const threshold = Math.min(
316
- targetLimit,
317
- settings.compactAtTokens > 0 ? settings.compactAtTokens : Number.POSITIVE_INFINITY
318
- );
319
- if (required <= threshold) return no("Budget-optimized mode: inside the configured compact threshold.");
320
- const hardLimit = required > safeLimit;
321
- return {
322
- compact: true,
323
- reason: hardLimit ? "Budget-optimized mode: compacting to stay inside the verified window of the cheapest qualified route." : "Budget-optimized mode: compacting early to keep this session on the cheapest qualified route.",
324
- triggerTokens: contextTokens,
325
- targetTokens: Math.floor(threshold),
326
- hardLimit
327
- };
328
- };
329
- var practicalWindow = (model) => {
330
- if (model.context <= 0) return 0;
331
- return model.context;
332
- };
333
- var describeMode = (mode) => {
334
- switch (mode) {
335
- case "native":
336
- return "Native: no router-driven compaction unless the transcript would exceed the verified window.";
337
- case "conservative":
338
- return "Conservative: history preserved; compaction only to prevent a real overflow.";
339
- case "budget-optimized":
340
- return "Budget-optimized: compacts early to keep sessions on the cheapest qualified route.";
341
- default:
342
- return "Unknown mode.";
343
- }
344
- };
345
-
346
- // src/core/quota/report.ts
347
- var FIVE_HOURS_MS = 5 * 60 * 60 * 1e3;
348
- var WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
349
- var DAY_MS = 24 * 60 * 60 * 1e3;
350
- var forecast = (input) => {
351
- const windowStart = input.now - input.windowMs;
352
- const earliest = Math.max(windowStart, input.activityStart ?? windowStart);
353
- const basisMs = Math.min(
354
- input.windowMs,
355
- Math.max(60 * 60 * 1e3, input.now - earliest)
356
- );
357
- const basisHours = basisMs / (60 * 60 * 1e3);
358
- const windowHours = input.windowMs / (60 * 60 * 1e3);
359
- const perHour = input.spendInWindowUsd / Math.max(1e-3, basisHours);
360
- const projectedUsd = perHour * windowHours;
361
- const remaining = input.remainingUsd;
362
- const willExhaust = remaining !== void 0 && projectedUsd > remaining;
363
- const exhaustsAt = willExhaust && perHour > 0 ? input.now + Math.max(0, remaining ?? 0) / perHour * 60 * 60 * 1e3 : void 0;
364
- const explanation = willExhaust ? `At the current rate the ${input.label} allowance runs out about ${formatRelative(exhaustsAt ?? input.now, input.now)}.` : `At the current rate the ${input.label} allowance covers the full window.`;
365
- return {
366
- projectedUsd,
367
- basisHours,
368
- ...exhaustsAt !== void 0 ? { exhaustsAt } : {},
369
- willExhaust,
370
- explanation
371
- };
372
- };
373
- var formatRelative = (at, now) => {
374
- const delta = at - now;
375
- if (delta <= 0) return "now";
376
- const hours = delta / (60 * 60 * 1e3);
377
- if (hours < 1) return `${Math.round(delta / 6e4)} minutes from now`;
378
- if (hours < 48) return `${hours.toFixed(1)} hours from now`;
379
- return `${(hours / 24).toFixed(1)} days from now`;
380
- };
381
- var buildProviderUsageReport = (input) => {
382
- const { now, source_ } = input;
383
- const monthStart = now - 30 * DAY_MS;
384
- const fiveHour = input.hasFiveHourWindow ? source_.aggregate({ providerID: input.providerID, since: now - FIVE_HOURS_MS, until: now }) : emptyTotals(now - FIVE_HOURS_MS, now);
385
- const weekly = input.hasWeeklyWindow ? source_.aggregate({ providerID: input.providerID, since: now - WEEK_MS, until: now }) : emptyTotals(now - WEEK_MS, now);
386
- const monthly = source_.aggregate({ providerID: input.providerID, since: monthStart, until: now });
387
- const byModel = source_.usageByModel({ since: monthStart, until: now }).filter((entry) => entry.providerID === input.providerID);
388
- const totalInput = monthly.input + monthly.cacheRead + monthly.cacheWrite;
389
- const cacheSharePct = totalInput > 0 ? monthly.cacheRead / totalInput * 100 : 0;
390
- const activityStart = earliestActivity(source_.usageEvents, input.providerID);
391
- const forecasts = [
392
- ...input.hasFiveHourWindow ? [{
393
- window: "5-hour",
394
- forecast: forecast({
395
- windowMs: FIVE_HOURS_MS,
396
- now,
397
- spendInWindowUsd: fiveHour.usd,
398
- ...activityStart !== void 0 ? { activityStart } : {},
399
- label: `${input.label} five-hour`
400
- })
401
- }] : [],
402
- ...input.hasWeeklyWindow ? [{
403
- window: "7-day",
404
- forecast: forecast({
405
- windowMs: WEEK_MS,
406
- now,
407
- spendInWindowUsd: weekly.usd,
408
- ...activityStart !== void 0 ? { activityStart } : {},
409
- label: `${input.label} seven-day`
410
- })
411
- }] : [],
412
- {
413
- window: "monthly",
414
- forecast: forecast({
415
- windowMs: 30 * DAY_MS,
416
- now,
417
- spendInWindowUsd: monthly.usd,
418
- ...activityStart !== void 0 ? { activityStart } : {},
419
- ...input.remainingMonthlyUsd !== void 0 ? { remainingUsd: input.remainingMonthlyUsd } : {},
420
- label: `${input.label} monthly`
421
- })
422
- }
423
- ];
424
- return {
425
- providerID: input.providerID,
426
- label: input.label,
427
- plan: input.plan,
428
- source: input.source,
429
- ...input.quotaState ? { quotaState: input.quotaState } : {},
430
- fiveHour,
431
- weekly,
432
- monthly,
433
- cacheSharePct,
434
- byModel,
435
- forecasts,
436
- notes: [
437
- ...input.notes,
438
- input.hasFiveHourWindow ? "This plan meters a five-hour window." : "This plan has no five-hour window; that row is not a limit being ignored."
439
- ]
440
- };
441
- };
442
- var emptyTotals = (since, until) => ({
443
- since,
444
- until,
445
- requests: 0,
446
- input: 0,
447
- output: 0,
448
- cacheRead: 0,
449
- cacheWrite: 0,
450
- usd: 0,
451
- failures: 0,
452
- latencyMsTotal: 0,
453
- latencySamples: 0
454
- });
455
- var earliestActivity = (events, providerID) => {
456
- let earliest;
457
- for (const event of events) {
458
- if (event.providerID !== providerID) continue;
459
- if (earliest === void 0 || event.at < earliest) earliest = event.at;
460
- }
461
- return earliest;
462
- };
463
- export {
464
- CONTEXT_ELIGIBILITY_MARGIN_TOKENS,
465
- CONTEXT_SAFE_WINDOW_FRACTION,
466
- DEFAULT_PLAN_ID,
467
- OPENDESIGN_DESIGN_PLAN_MODELS,
468
- OPENDESIGN_DESIGN_PLAN_POOL,
469
- OPENDESIGN_PLAN_MODEL_POOL,
470
- PLAN_CATALOG,
471
- buildProviderUsageReport,
472
- decideCompaction,
473
- defaultPlanIdFor,
474
- describeMode,
475
- forecast,
476
- formatRelative,
477
- fundingPoolFor,
478
- isEscalationOnlyPool,
479
- modelMonthlyAllowanceUsd,
480
- modelWindowCaps,
481
- planById,
482
- planSummaryLine,
483
- poolDrawSequence,
484
- practicalWindow,
485
- resolvePlan,
486
- resolvePlanWithReason
487
- };