@ipv9/tokentracker-cli 0.39.56 → 0.39.57

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.
Files changed (21) hide show
  1. package/dashboard/dist/assets/{Card-DqlTs4bX.js → Card-ci17PdAV.js} +1 -1
  2. package/dashboard/dist/assets/DashboardPage-7tVtPxb8.js +60 -0
  3. package/dashboard/dist/assets/{IpCheckPage-M13-Ws2A.js → IpCheckPage-DNA0Q23M.js} +1 -1
  4. package/dashboard/dist/assets/{LimitsPage-G2Fys5yE.js → LimitsPage-BpjYvnWF.js} +1 -1
  5. package/dashboard/dist/assets/{LocalOnlyNotice-DhRn6ocA.js → LocalOnlyNotice-B5JmBabh.js} +1 -1
  6. package/dashboard/dist/assets/{PopoverPopup-bb-KJHxL.js → PopoverPopup-CcfJZMpE.js} +1 -1
  7. package/dashboard/dist/assets/{Select-CM-mkp28.js → Select-DkdVUiwm.js} +1 -1
  8. package/dashboard/dist/assets/{SettingsPage-DKQb2n41.js → SettingsPage-B3KR1Y9S.js} +1 -1
  9. package/dashboard/dist/assets/{SkillsPage-CdNJE3jQ.js → SkillsPage-ced5E6ai.js} +1 -1
  10. package/dashboard/dist/assets/{WrappedPage-DyfHVPDk.js → WrappedPage-BMgJxQLZ.js} +1 -1
  11. package/dashboard/dist/assets/{format-5-hK-Lf9.js → format-wJPB8ygX.js} +1 -1
  12. package/dashboard/dist/assets/{limitDisplay-ypD5--So.js → limitDisplay-BWIfB8aR.js} +1 -1
  13. package/dashboard/dist/assets/{main-BhUdEGPa.js → main-DFczPkAN.js} +3 -3
  14. package/dashboard/dist/assets/{mock-data-DZbvGOJz.js → mock-data-BQNbqt40.js} +1 -1
  15. package/dashboard/dist/assets/{use-limits-display-prefs-UcKuzN2-.js → use-limits-display-prefs-fr-_DlHb.js} +1 -1
  16. package/dashboard/dist/assets/{useCurrency-SDO8fpsi.js → useCurrency-CRUry3mm.js} +1 -1
  17. package/dashboard/dist/index.html +1 -1
  18. package/package.json +1 -1
  19. package/src/lib/pricing/index.js +72 -2
  20. package/src/lib/pricing/seed-snapshot.json +1 -1
  21. package/dashboard/dist/assets/DashboardPage-CIRoAF9d.js +0 -60
@@ -49,7 +49,12 @@ const RELOAD_COOLDOWN_MS = 5 * 60 * 1000;
49
49
  // curated fuzzy rule rather than an exact id, so the price is plausible but may
50
50
  // belong to a different model. Worth surfacing — a wrong price never looks
51
51
  // wrong, unlike a $0 one.
52
- const FUZZY_SOURCES = new Set(["curated:fuzzy", "litellm:fuzzy", "litellm:prefix-strip"]);
52
+ const FUZZY_SOURCES = new Set([
53
+ "curated:fuzzy",
54
+ "litellm:fuzzy",
55
+ "litellm:prefix-strip",
56
+ "routed-estimated",
57
+ ]);
53
58
 
54
59
  // Placeholder ids that stand in for "this row has no model", so they resolve to
55
60
  // the "unattributed" tier instead of being looked up and recorded as a miss.
@@ -67,6 +72,62 @@ const UNRESOLVED_LOGICAL_ROUTE_IDS = new Set([
67
72
  ]);
68
73
  const UNPRICED_TIERS = new Set(["miss", "routed-unresolved"]);
69
74
 
75
+ // Owner-approved route mix estimates. The child-model ratios are a pricing
76
+ // policy, not routing telemetry: callers must surface `routed-estimated` as a
77
+ // non-exact price. Any configured child whose current price cannot be resolved
78
+ // makes the route unpriced rather than silently using a partial blend.
79
+ const ROUTED_ESTIMATE_POLICIES = new Map([
80
+ ["claude-auto-pilot-fable-v1-canary", [
81
+ { model: "anthropic/claude-sonnet-5", pricingModel: "claude-sonnet-5", weight: 0.6 },
82
+ { model: "anthropic/claude-opus-5", pricingModel: "claude-opus-5", weight: 0.4 },
83
+ ]],
84
+ ["gpt-5.6-auto-pilot", [
85
+ { model: "gpt-5.6-terra", weight: 0.6 },
86
+ { model: "gpt-5.6-sol", weight: 0.4 },
87
+ ]],
88
+ ["gpt-5.6-auto-pilot-045-canary", [
89
+ { model: "gpt-5.6-terra", weight: 0.6 },
90
+ { model: "gpt-5.6-sol", weight: 0.4 },
91
+ ]],
92
+ ["gpt-5.6-auto-pilot-055-v2", [
93
+ { model: "gpt-5.6-terra", weight: 0.6 },
94
+ { model: "gpt-5.6-sol", weight: 0.4 },
95
+ ]],
96
+ ["gpt-5.6-auto-pilot-056-claude-reasoning-canary", [
97
+ { model: "gpt-5.6-terra", weight: 0.6 },
98
+ { model: "gpt-5.6-sol", weight: 0.4 },
99
+ ]],
100
+ ]);
101
+ const ROUTE_CHILD_EXACT_TIERS = new Set([
102
+ "curated:exact",
103
+ "curated:exact-dot",
104
+ "litellm:exact",
105
+ "litellm:exact-dot",
106
+ ]);
107
+
108
+ function isPotentialGptAutoRoute(model) {
109
+ return /^gpt-5\.6-auto/i.test(String(model || "").trim());
110
+ }
111
+
112
+ function resolveRoutedEstimate(model, lookupSource) {
113
+ const policy = ROUTED_ESTIMATE_POLICIES.get(String(model || "").trim());
114
+ if (!policy) return null;
115
+ const mixed = { input: 0, output: 0, cache_read: 0, cache_write: 0 };
116
+ for (const child of policy) {
117
+ const result = lookupPricing(child.pricingModel || child.model, {
118
+ curated: curatedOverrides,
119
+ litellm: state.litellmPerMillionMap,
120
+ source: lookupSource,
121
+ });
122
+ if (!result.hit || !result.value || !ROUTE_CHILD_EXACT_TIERS.has(result.source)) return null;
123
+ for (const field of Object.keys(mixed)) {
124
+ if (!Number.isFinite(result.value[field])) return null;
125
+ mixed[field] += child.weight * result.value[field];
126
+ }
127
+ }
128
+ return mixed;
129
+ }
130
+
70
131
  // `last_refresh_error` is served over HTTP to the dashboard, so it is built
71
132
  // from CLOSED sets, never from an arbitrary value. A previous version accepted
72
133
  // anything symbol-shaped, which a QA pass broke immediately: a 32-character
@@ -246,7 +307,16 @@ function getModelPricingMeta(model, opts = {}) {
246
307
  const lookupSource = resolveLookupSource(opts);
247
308
  const cacheKey = lookupSource ? `${lookupSource}\0${model}` : model;
248
309
 
249
- if (UNRESOLVED_LOGICAL_ROUTE_IDS.has(String(model || "").trim())) {
310
+ const routedEstimate = resolveRoutedEstimate(model, lookupSource);
311
+ if (routedEstimate) {
312
+ state.tiers.set(cacheKey, { model, source: lookupSource, tier: "routed-estimated" });
313
+ return { pricing: routedEstimate, tier: "routed-estimated" };
314
+ }
315
+
316
+ if (
317
+ UNRESOLVED_LOGICAL_ROUTE_IDS.has(String(model || "").trim())
318
+ || isPotentialGptAutoRoute(model)
319
+ ) {
250
320
  state.tiers.set(cacheKey, { model, source: lookupSource, tier: "routed-unresolved" });
251
321
  return { pricing: ZERO_PRICING, tier: "routed-unresolved" };
252
322
  }