@openhoo/hoopilot 0.7.4 → 0.7.5

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/index.cjs CHANGED
@@ -399,22 +399,31 @@ function normalizeCopilotUsage(body) {
399
399
  }
400
400
  function normalizeQuotaDetail(detail) {
401
401
  const entitlement = numberOrUndefined(detail.entitlement);
402
+ const overageCount = numberOrUndefined(detail.overage_count);
402
403
  const remaining = numberOrUndefined(detail.remaining) ?? numberOrUndefined(detail.quota_remaining);
403
404
  return removeUndefinedQuota({
404
405
  entitlement,
405
- overageCount: numberOrUndefined(detail.overage_count),
406
+ hasQuota: typeof detail.has_quota === "boolean" ? detail.has_quota : void 0,
407
+ overageCount,
408
+ overageEntitlement: numberOrUndefined(detail.overage_entitlement),
406
409
  overagePermitted: typeof detail.overage_permitted === "boolean" ? detail.overage_permitted : void 0,
407
410
  percentRemaining: numberOrUndefined(detail.percent_remaining),
411
+ quotaId: stringOrUndefined(detail.quota_id),
412
+ quotaResetAt: stringOrUndefined(detail.quota_reset_at),
408
413
  remaining,
414
+ timestampUtc: stringOrUndefined(detail.timestamp_utc),
415
+ tokenBasedBilling: typeof detail.token_based_billing === "boolean" ? detail.token_based_billing : void 0,
409
416
  unlimited: typeof detail.unlimited === "boolean" ? detail.unlimited : void 0,
410
- used: usedFrom(entitlement, remaining)
417
+ used: usedFrom(entitlement, remaining, overageCount)
411
418
  });
412
419
  }
413
- function usedFrom(entitlement, remaining) {
420
+ function usedFrom(entitlement, remaining, overageCount) {
414
421
  if (entitlement === void 0 || remaining === void 0) {
415
422
  return void 0;
416
423
  }
417
- return Math.max(0, entitlement - remaining);
424
+ const base = entitlement - remaining;
425
+ const overage = remaining === 0 ? overageCount ?? 0 : 0;
426
+ return Math.max(0, base + overage);
418
427
  }
419
428
  function numberOrUndefined(value) {
420
429
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
@@ -1712,11 +1721,43 @@ var MetricsRegistry = class {
1712
1721
  gauge("remaining", "Remaining quota for the Copilot category.", (q) => q.remaining);
1713
1722
  gauge("entitlement", "Quota entitlement for the Copilot category.", (q) => q.entitlement);
1714
1723
  gauge("used", "Used quota (entitlement minus remaining) for the category.", (q) => q.used);
1724
+ gauge("overage_count", "Overage count for the Copilot category.", (q) => q.overageCount);
1725
+ gauge(
1726
+ "overage_entitlement",
1727
+ "Overage entitlement for the Copilot category.",
1728
+ (q) => q.overageEntitlement
1729
+ );
1715
1730
  gauge(
1716
1731
  "percent_remaining",
1717
1732
  "Percent of quota remaining for the Copilot category.",
1718
1733
  (q) => q.percentRemaining
1719
1734
  );
1735
+ booleanGauge(
1736
+ "unlimited",
1737
+ "Whether the Copilot quota category is unlimited.",
1738
+ (q) => q.unlimited
1739
+ );
1740
+ booleanGauge(
1741
+ "overage_permitted",
1742
+ "Whether overage is permitted for the Copilot category.",
1743
+ (q) => q.overagePermitted
1744
+ );
1745
+ booleanGauge("has_quota", "Whether the Copilot quota category has a quota.", (q) => q.hasQuota);
1746
+ booleanGauge(
1747
+ "token_based_billing",
1748
+ "Whether the Copilot quota category uses token-based billing.",
1749
+ (q) => q.tokenBasedBilling
1750
+ );
1751
+ dateGauge(
1752
+ "category_reset_timestamp_seconds",
1753
+ "Unix epoch of the Copilot category-specific quota reset.",
1754
+ (q) => q.quotaResetAt
1755
+ );
1756
+ dateGauge(
1757
+ "category_snapshot_timestamp_seconds",
1758
+ "Unix epoch of the Copilot category quota snapshot.",
1759
+ (q) => q.timestampUtc
1760
+ );
1720
1761
  const resetMs = usage.quotaResetDate ? Date.parse(usage.quotaResetDate) : Number.NaN;
1721
1762
  if (Number.isFinite(resetMs)) {
1722
1763
  lines.push(
@@ -1735,6 +1776,30 @@ var MetricsRegistry = class {
1735
1776
  })} 1`
1736
1777
  );
1737
1778
  }
1779
+ function booleanGauge(suffix, help, pick) {
1780
+ const present = categories.filter(([, quota]) => pick(quota) !== void 0);
1781
+ if (present.length === 0) {
1782
+ return;
1783
+ }
1784
+ lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);
1785
+ lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);
1786
+ for (const [category, quota] of present) {
1787
+ lines.push(
1788
+ `hoopilot_copilot_quota_${suffix}${labels({ category })} ${pick(quota) ? 1 : 0}`
1789
+ );
1790
+ }
1791
+ }
1792
+ function dateGauge(suffix, help, pick) {
1793
+ const present = categories.map(([category, quota]) => [category, Date.parse(pick(quota) ?? "")]).filter(([, timestamp]) => Number.isFinite(timestamp));
1794
+ if (present.length === 0) {
1795
+ return;
1796
+ }
1797
+ lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);
1798
+ lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);
1799
+ for (const [category, timestamp] of present) {
1800
+ lines.push(`hoopilot_copilot_quota_${suffix}${labels({ category })} ${timestamp / 1e3}`);
1801
+ }
1802
+ }
1738
1803
  }
1739
1804
  };
1740
1805
  function observeResponseUsage(response, fallbackModel, onUsage, signal) {
@@ -2432,8 +2497,8 @@ function metricsResponse(metrics) {
2432
2497
  });
2433
2498
  }
2434
2499
  async function handleUsage(metrics, readUsage, signal) {
2435
- const proxy = metrics.snapshot();
2436
2500
  const { copilot, error } = await readUsage(signal);
2501
+ const proxy = metrics.snapshot();
2437
2502
  const body = { copilot: copilot ?? null, object: "usage", proxy };
2438
2503
  if (error) {
2439
2504
  body.copilot_error = error;
@@ -2458,10 +2523,10 @@ function createUsageReader(client, metrics, now = Date.now, ttlMs = USAGE_CACHE_
2458
2523
  metrics.recordCopilotQuota(value);
2459
2524
  return { copilot: value };
2460
2525
  } catch (error) {
2461
- metrics.recordUpstream(usagePath, false);
2462
2526
  if (error instanceof CopilotAuthError) {
2463
2527
  return { error: error.message };
2464
2528
  }
2529
+ metrics.recordUpstream(usagePath, false);
2465
2530
  return { error: errorMessage(error) };
2466
2531
  }
2467
2532
  };