maxpool 1.5.16 → 1.5.17
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/package.json +1 -1
- package/src/account-manager.js +120 -4
- package/src/index.js +3 -0
- package/src/oauth.js +55 -0
- package/src/prober.js +23 -6
- package/src/tui.js +39 -11
package/package.json
CHANGED
package/src/account-manager.js
CHANGED
|
@@ -42,6 +42,19 @@ function emptyQuota() {
|
|
|
42
42
|
scopedWeekly: {},
|
|
43
43
|
unifiedStatus: null, // allowed | allowed_warning | rejected
|
|
44
44
|
resetsAt: null,
|
|
45
|
+
// Provider (z.ai / Kimi) quota — kept SEPARATE from unified* so a provider
|
|
46
|
+
// reading never leaks into the OAuth quota gates (_isAvailable / _weeklyRawState
|
|
47
|
+
// / _accountScarcity read unified* only). z.ai is pollable; Kimi is not.
|
|
48
|
+
providerSes: null, // utilization 0-1 (z.ai 5h token window)
|
|
49
|
+
providerSesReset: null, // ms
|
|
50
|
+
providerWk: null, // utilization 0-1 (z.ai weekly), null if plan has none
|
|
51
|
+
providerWkReset: null, // ms
|
|
52
|
+
providerQuotaSource: null, // 'zai' (pollable) | 'console-only' (kimi) | null
|
|
53
|
+
// Freshness: last time a background usage PROBE succeeded for this account
|
|
54
|
+
// (oauth fetchUsage OR provider fetchProviderUsage). Drives the TUI staleness
|
|
55
|
+
// marker — a swallowed failing probe no longer silently freezes a stale tag.
|
|
56
|
+
// Header-driven updates do NOT stamp this (headers can't refresh scoped/provider).
|
|
57
|
+
lastProbeOkAt: null, // ms
|
|
45
58
|
};
|
|
46
59
|
}
|
|
47
60
|
|
|
@@ -589,8 +602,14 @@ export class AccountManager {
|
|
|
589
602
|
if (!fam) return null;
|
|
590
603
|
const e = account.quota?.scopedWeekly?.[fam];
|
|
591
604
|
if (!e || e.isActive === false) return null;
|
|
592
|
-
|
|
593
|
-
|
|
605
|
+
// Bench ONLY at genuine exhaustion (>= weeklyExhaustedThreshold). Anthropic
|
|
606
|
+
// labels a scoped weekly `severity:'critical'` well before it's actually
|
|
607
|
+
// capped (~90%), where the model still has headroom and is still served — a
|
|
608
|
+
// hard bench there strands the remainder and mislabels the account "maxed".
|
|
609
|
+
// A real scoped 429 writes utilization:1 (markRateLimited), so genuine
|
|
610
|
+
// exhaustion is still caught by the threshold. Same predicate drives the TUI
|
|
611
|
+
// `maxed` tag, so "maxed" renders iff the model is actually benched.
|
|
612
|
+
const exhausted = e.utilization != null && e.utilization >= this.scheduler.weeklyExhaustedThreshold;
|
|
594
613
|
return exhausted ? { resetAt: e.resetAt || null, family: fam } : null;
|
|
595
614
|
}
|
|
596
615
|
|
|
@@ -1648,6 +1667,16 @@ export class AccountManager {
|
|
|
1648
1667
|
// soft de-preference of accounts burning ahead of an even pace. Never a bench.
|
|
1649
1668
|
const paceCost = this._accountScarcity(account, now) * this.scheduler.paceCostWeight;
|
|
1650
1669
|
|
|
1670
|
+
// Per-model weekly de-preference: an account whose scoped weekly for THIS
|
|
1671
|
+
// request's model (e.g. Fable) is high-but-not-exhausted is a poor pick for
|
|
1672
|
+
// that model — shed its load toward healthier accounts BEFORE the hard bench
|
|
1673
|
+
// at weeklyExhaustedThreshold, so it's chosen only as overflow (rarely
|
|
1674
|
+
// re-429ing). Scoped weekly is otherwise absent from scoring. Soft, never a
|
|
1675
|
+
// bench; 0 below reserve and for models with no scoped cap.
|
|
1676
|
+
const scopedPace = requestInfo.model
|
|
1677
|
+
? this._scopedScarcity(account, requestInfo.model, now) * this.scheduler.paceCostWeight
|
|
1678
|
+
: 0;
|
|
1679
|
+
|
|
1651
1680
|
const fleetRecentWeight = ctx?.fleetRecentWeight ?? 0;
|
|
1652
1681
|
const recentWeight = this._loadSummary(account, this.scheduler.spreadWindowMs, now).weight;
|
|
1653
1682
|
const share = fleetRecentWeight > 0 ? recentWeight / fleetRecentWeight : 0;
|
|
@@ -1663,7 +1692,22 @@ export class AccountManager {
|
|
|
1663
1692
|
// default) learns the real number within a cycle. `probing`/requalify still
|
|
1664
1693
|
// flags a never-seen account for learning — that path is unchanged.
|
|
1665
1694
|
|
|
1666
|
-
return concurrency + capPenalty + paceCost + spread + ramp + failurePenalty;
|
|
1695
|
+
return concurrency + capPenalty + paceCost + scopedPace + spread + ramp + failurePenalty;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
/**
|
|
1699
|
+
* Per-model weekly pace-overage for `model`'s family, or 0 when the account has
|
|
1700
|
+
* no scoped cap for it, the cap is inactive, or it's below the reserve tier
|
|
1701
|
+
* (plenty of headroom → no steering). Same pace discount as _windowScarcity, so
|
|
1702
|
+
* a scoped window about to reset is cheap to spend.
|
|
1703
|
+
*/
|
|
1704
|
+
_scopedScarcity(account, model, now = Date.now()) {
|
|
1705
|
+
const fam = modelFamily(model);
|
|
1706
|
+
if (!fam) return 0;
|
|
1707
|
+
const e = account.quota?.scopedWeekly?.[fam];
|
|
1708
|
+
if (!e || e.isActive === false || e.utilization == null) return 0;
|
|
1709
|
+
if (e.utilization < this.scheduler.weeklyReserveThreshold) return 0;
|
|
1710
|
+
return this._windowScarcity(e.utilization, e.resetAt, WEEK_MS, now);
|
|
1667
1711
|
}
|
|
1668
1712
|
|
|
1669
1713
|
/**
|
|
@@ -1795,8 +1839,15 @@ export class AccountManager {
|
|
|
1795
1839
|
}
|
|
1796
1840
|
// Per-model weekly sub-limits (Fable, Opus, ...). Replace wholesale with the
|
|
1797
1841
|
// fresh probe set so a family that dropped out of the response doesn't linger
|
|
1798
|
-
// stale; expiry on reset is a backstop for the between-probe window.
|
|
1842
|
+
// stale; expiry on reset is a backstop for the between-probe window. EXCEPTION:
|
|
1843
|
+
// a `reactive` scoped-429 bench is authoritative-high — while its resetAt is
|
|
1844
|
+
// still future, a lagging probe may neither lower it nor drop it (a probe that
|
|
1845
|
+
// omits the family, or reports the pre-429 level, would otherwise un-bench it
|
|
1846
|
+
// and trigger an immediate re-429 flap). _clearExpiredQuotas self-clears it at
|
|
1847
|
+
// resetAt even if probes die.
|
|
1799
1848
|
if (usage.scopedWeekly && typeof usage.scopedWeekly === 'object') {
|
|
1849
|
+
const now = Date.now();
|
|
1850
|
+
const prev = (q.scopedWeekly && typeof q.scopedWeekly === 'object') ? q.scopedWeekly : {};
|
|
1800
1851
|
const fresh = {};
|
|
1801
1852
|
for (const [fam, e] of Object.entries(usage.scopedWeekly)) {
|
|
1802
1853
|
if (!e) continue;
|
|
@@ -1807,9 +1858,21 @@ export class AccountManager {
|
|
|
1807
1858
|
isActive: e.isActive !== false,
|
|
1808
1859
|
};
|
|
1809
1860
|
}
|
|
1861
|
+
for (const [fam, pe] of Object.entries(prev)) {
|
|
1862
|
+
if (!pe || !pe.reactive || pe.resetAt == null || pe.resetAt <= now) continue;
|
|
1863
|
+
const f = fresh[fam];
|
|
1864
|
+
// Probe absent, null, or LOWER than the reactive bench → keep the bench.
|
|
1865
|
+
// Probe CONFIRMS >= the reactive level → take the fresh reading (still >=
|
|
1866
|
+
// threshold, so still exhausted; no stickiness needed).
|
|
1867
|
+
if (!f || f.utilization == null || f.utilization < (pe.utilization ?? 0)) {
|
|
1868
|
+
fresh[fam] = { ...pe };
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1810
1871
|
q.scopedWeekly = fresh;
|
|
1811
1872
|
}
|
|
1812
1873
|
|
|
1874
|
+
q.lastProbeOkAt = Date.now();
|
|
1875
|
+
|
|
1813
1876
|
// If we just learned this account's weekly window while probing, re-evaluate
|
|
1814
1877
|
// selection (same path as learning it from a live response).
|
|
1815
1878
|
if (account.probing && q.unified7dReset != null) {
|
|
@@ -1818,6 +1881,55 @@ export class AccountManager {
|
|
|
1818
1881
|
}
|
|
1819
1882
|
}
|
|
1820
1883
|
|
|
1884
|
+
/**
|
|
1885
|
+
* Update a PROVIDER account's quota from a provider usage probe
|
|
1886
|
+
* (fetchProviderUsage). z.ai maps to Ses/Wk token windows; Kimi has no pollable
|
|
1887
|
+
* source and only sets a `console-only` marker. Writes ONLY the provider* fields
|
|
1888
|
+
* (never the unified or scopedWeekly fields) so a provider reading can't reach
|
|
1889
|
+
* the OAuth quota gates.
|
|
1890
|
+
*/
|
|
1891
|
+
applyProviderUsage(accountIndex, usage) {
|
|
1892
|
+
const account = this.accounts[accountIndex];
|
|
1893
|
+
if (!account || !usage) return;
|
|
1894
|
+
const q = account.quota;
|
|
1895
|
+
if (usage.error) {
|
|
1896
|
+
// Distinguish "no pollable quota" (Kimi) from a transient probe failure.
|
|
1897
|
+
// Never clear existing values on a transient error — let them age into the
|
|
1898
|
+
// staleness marker instead of blanking the bars.
|
|
1899
|
+
if (usage.source === 'console-only') q.providerQuotaSource = 'console-only';
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
q.providerQuotaSource = usage.source || 'zai';
|
|
1903
|
+
if (usage.ses) {
|
|
1904
|
+
if (usage.ses.utilization != null) q.providerSes = clamp01(usage.ses.utilization);
|
|
1905
|
+
if (usage.ses.resetAt != null) q.providerSesReset = usage.ses.resetAt;
|
|
1906
|
+
}
|
|
1907
|
+
if (usage.wk) {
|
|
1908
|
+
if (usage.wk.utilization != null) q.providerWk = clamp01(usage.wk.utilization);
|
|
1909
|
+
if (usage.wk.resetAt != null) q.providerWkReset = usage.wk.resetAt;
|
|
1910
|
+
} else {
|
|
1911
|
+
// Weekly window absent from this plan/response — clear so a stale weekly
|
|
1912
|
+
// reading doesn't linger after a plan/window change.
|
|
1913
|
+
q.providerWk = null;
|
|
1914
|
+
q.providerWkReset = null;
|
|
1915
|
+
}
|
|
1916
|
+
q.lastProbeOkAt = Date.now();
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
/**
|
|
1920
|
+
* True when the background quota probe hasn't succeeded in > 2× its interval —
|
|
1921
|
+
* the last-known scoped/provider values are aging with no confirmation. Returns
|
|
1922
|
+
* false when the probe is off (nothing to be stale against) or has never yet
|
|
1923
|
+
* succeeded (startup — shown as "no data", not "stale").
|
|
1924
|
+
*/
|
|
1925
|
+
_quotaProbeStale(account, now = Date.now()) {
|
|
1926
|
+
const interval = this.quotaProbeIntervalMs;
|
|
1927
|
+
if (!interval || interval <= 0) return false;
|
|
1928
|
+
const last = account?.quota?.lastProbeOkAt;
|
|
1929
|
+
if (last == null) return false;
|
|
1930
|
+
return (now - last) > Math.max(2 * interval, 120_000);
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1821
1933
|
/**
|
|
1822
1934
|
* Update an account's quota tracking from upstream response headers.
|
|
1823
1935
|
*/
|
|
@@ -1956,6 +2068,10 @@ export class AccountManager {
|
|
|
1956
2068
|
resetAt: Date.now() + (retryAfter * 1000),
|
|
1957
2069
|
severity: 'critical',
|
|
1958
2070
|
isActive: true,
|
|
2071
|
+
// Authoritative-high: a real reject. A lagging 60s probe reporting the
|
|
2072
|
+
// pre-429 level (e.g. 0.96) must NOT lower/drop this before resetAt, else
|
|
2073
|
+
// the account un-benches and immediately re-429s — a per-probe flap.
|
|
2074
|
+
reactive: true,
|
|
1959
2075
|
};
|
|
1960
2076
|
account.lastStatus = options.status || 429;
|
|
1961
2077
|
account.lastErrorAt = Date.now();
|
package/src/index.js
CHANGED
|
@@ -564,6 +564,9 @@ async function serverWorkerCommand() {
|
|
|
564
564
|
// assertions (mirrors MAXPOOL_DISABLE_SLEEP_GUARD).
|
|
565
565
|
const probeSeconds = process.env.MAXPOOL_DISABLE_QUOTA_PROBE === '1' ? 0 : (config.quotaProbeSeconds || 0);
|
|
566
566
|
const prober = new Prober(accountManager, { intervalMs: probeSeconds * 1000 });
|
|
567
|
+
// Tell the AM the probe cadence so the TUI can flag a scoped/provider tag whose
|
|
568
|
+
// background probe has gone stale (> 2× interval since last success).
|
|
569
|
+
accountManager.quotaProbeIntervalMs = probeSeconds * 1000;
|
|
567
570
|
|
|
568
571
|
// Persist refreshed tokens back to config. Defense-in-depth: the updater reads
|
|
569
572
|
// the on-disk refresh token and SKIPS the rotation if a fresher writer already
|
package/src/oauth.js
CHANGED
|
@@ -245,6 +245,61 @@ export async function fetchUsage(accessToken) {
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
// z.ai quota monitor — a DIFFERENT host/path than the message upstream
|
|
249
|
+
// (account.upstream is the Anthropic-compat endpoint). Zero-spend read.
|
|
250
|
+
const ZAI_QUOTA_URL = 'https://api.z.ai/api/monitor/usage/quota/limit';
|
|
251
|
+
|
|
252
|
+
/** Classify one z.ai `limits[]` entry into a Ses (5h) or Wk (weekly) TOKEN window.
|
|
253
|
+
* Only `TOKENS_LIMIT` maps to the quota bars; `TIME_LIMIT` is a tool-call cap
|
|
254
|
+
* (web-search/reader counts) and is intentionally ignored. `unit` is z.ai's
|
|
255
|
+
* window enum (3 = 5-hour session, 6 = weekly); we fall back to reset-distance
|
|
256
|
+
* when the code is unfamiliar so a new plan tier still classifies sanely. */
|
|
257
|
+
export function classifyZaiLimit(l, now = Date.now()) {
|
|
258
|
+
if (!l || l.type !== 'TOKENS_LIMIT') return null;
|
|
259
|
+
const reset = Number(l.nextResetTime);
|
|
260
|
+
const resetAt = Number.isFinite(reset) && reset > 0 ? reset : null;
|
|
261
|
+
const pct = typeof l.percentage === 'number' ? l.percentage : parseFloat(l.percentage);
|
|
262
|
+
const utilization = Number.isFinite(pct) ? Math.max(0, Math.min(1, pct / 100)) : null;
|
|
263
|
+
let bucket;
|
|
264
|
+
if (l.unit === 3) bucket = 'ses';
|
|
265
|
+
else if (l.unit === 6) bucket = 'wk';
|
|
266
|
+
else if (resetAt) bucket = (resetAt - now) <= 12 * 60 * 60 * 1000 ? 'ses' : 'wk';
|
|
267
|
+
else bucket = 'ses';
|
|
268
|
+
return { bucket, utilization, resetAt };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Read a provider account's quota. z.ai has a pollable monitor endpoint mapped
|
|
272
|
+
* to Ses/Wk token windows; Kimi (Moonshot coding key) has NO pollable quota
|
|
273
|
+
* (web console only), so it returns a `console-only` marker instead of fake
|
|
274
|
+
* bars. Returns { ses, wk, level } | { error, status?, source? }. */
|
|
275
|
+
export async function fetchProviderUsage(account) {
|
|
276
|
+
const provider = account?.provider;
|
|
277
|
+
const token = account?.credential;
|
|
278
|
+
if (provider === 'kimi') return { error: 'unsupported', source: 'console-only' };
|
|
279
|
+
if (provider !== 'zai' || !token) return { error: 'unsupported', source: null };
|
|
280
|
+
try {
|
|
281
|
+
const res = await fetch(ZAI_QUOTA_URL, {
|
|
282
|
+
headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'application/json' },
|
|
283
|
+
});
|
|
284
|
+
if (!res.ok) return { error: `HTTP ${res.status}`, status: res.status };
|
|
285
|
+
const data = await res.json();
|
|
286
|
+
if (data?.code !== 200 || !data?.data) {
|
|
287
|
+
return { error: `bad_envelope${data?.code != null ? ' code=' + data.code : ''}` };
|
|
288
|
+
}
|
|
289
|
+
const now = Date.now();
|
|
290
|
+
let ses = null, wk = null;
|
|
291
|
+
for (const l of (Array.isArray(data.data.limits) ? data.data.limits : [])) {
|
|
292
|
+
const c = classifyZaiLimit(l, now);
|
|
293
|
+
if (!c) continue;
|
|
294
|
+
if (c.bucket === 'ses') ses = { utilization: c.utilization, resetAt: c.resetAt };
|
|
295
|
+
else if (c.bucket === 'wk') wk = { utilization: c.utilization, resetAt: c.resetAt };
|
|
296
|
+
}
|
|
297
|
+
return { ses, wk, level: data.data.level || null, source: 'zai' };
|
|
298
|
+
} catch (err) {
|
|
299
|
+
return { error: err.message || String(err), status: null };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
248
303
|
// OAuth config (extracted from Claude Code)
|
|
249
304
|
const OAUTH_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
|
|
250
305
|
const OAUTH_AUTHORIZE = 'https://claude.ai/oauth/authorize';
|
package/src/prober.js
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
// is blind to an account it isn't actively routing to and will pile traffic onto it.
|
|
8
8
|
// This is the one sanctioned active-upstream feature; the proxy is otherwise passive.
|
|
9
9
|
|
|
10
|
-
import { fetchUsage } from './oauth.js';
|
|
10
|
+
import { fetchUsage, fetchProviderUsage } from './oauth.js';
|
|
11
11
|
|
|
12
12
|
export class Prober {
|
|
13
|
-
constructor(accountManager, { intervalMs = 0, probeFn = fetchUsage, timeoutMs = 10_000, log = console.log } = {}) {
|
|
13
|
+
constructor(accountManager, { intervalMs = 0, probeFn = fetchUsage, providerProbeFn = fetchProviderUsage, timeoutMs = 10_000, log = console.log } = {}) {
|
|
14
14
|
this.am = accountManager;
|
|
15
15
|
this.intervalMs = intervalMs;
|
|
16
16
|
this.probeFn = probeFn;
|
|
17
|
+
this.providerProbeFn = providerProbeFn;
|
|
17
18
|
this.timeoutMs = timeoutMs;
|
|
18
19
|
this.log = log;
|
|
19
20
|
this.timer = null;
|
|
@@ -49,15 +50,21 @@ export class Prober {
|
|
|
49
50
|
if (this._inflight) { try { await this._inflight; } catch { /* swallow */ } }
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
/** Probe every OAuth account
|
|
53
|
-
*
|
|
53
|
+
/** Probe every OAuth account (usage endpoint) and every provider account with a
|
|
54
|
+
* pollable/known quota source (z.ai monitor; Kimi → console-only marker) once.
|
|
55
|
+
* Overlapping cycles are skipped. The active cycle is tracked on `_inflight` so
|
|
56
|
+
* stop() can await it. */
|
|
54
57
|
probeAll() {
|
|
55
58
|
if (this._running) return this._inflight || Promise.resolve();
|
|
56
59
|
this._running = true;
|
|
57
60
|
this._inflight = (async () => {
|
|
58
61
|
try {
|
|
59
|
-
const
|
|
60
|
-
|
|
62
|
+
const oauth = this.am.accounts.filter(a => a.type === 'oauth' && a.credential);
|
|
63
|
+
const providers = this.am.accounts.filter(a => a.type === 'provider' && a.credential);
|
|
64
|
+
await Promise.all([
|
|
65
|
+
...oauth.map(a => this.probeOne(a)),
|
|
66
|
+
...providers.map(a => this.probeProvider(a)),
|
|
67
|
+
]);
|
|
61
68
|
} finally {
|
|
62
69
|
this._running = false;
|
|
63
70
|
this._inflight = null;
|
|
@@ -66,6 +73,16 @@ export class Prober {
|
|
|
66
73
|
return this._inflight;
|
|
67
74
|
}
|
|
68
75
|
|
|
76
|
+
/** Probe one PROVIDER account. Provider tokens are static API keys (no OAuth
|
|
77
|
+
* refresh). Best-effort; never throws. */
|
|
78
|
+
async probeProvider(account) {
|
|
79
|
+
try {
|
|
80
|
+
const usage = await this._withTimeout(this.providerProbeFn(account));
|
|
81
|
+
if (!usage) return; // timed out — try again next cycle
|
|
82
|
+
this.am.applyProviderUsage(account.index, usage);
|
|
83
|
+
} catch { /* best-effort; never let a probe throw */ }
|
|
84
|
+
}
|
|
85
|
+
|
|
69
86
|
async probeOne(account) {
|
|
70
87
|
try {
|
|
71
88
|
await this.am.ensureTokenFresh(account.index);
|
package/src/tui.js
CHANGED
|
@@ -984,7 +984,7 @@ export class TUI {
|
|
|
984
984
|
status = rpad(status, 13);
|
|
985
985
|
|
|
986
986
|
if (a.type === 'provider') {
|
|
987
|
-
return this._renderProviderAcct(sel, cur, name, type, status, a);
|
|
987
|
+
return this._renderProviderAcct(sel, cur, name, type, status, a, bw, showBoth);
|
|
988
988
|
}
|
|
989
989
|
|
|
990
990
|
// Quota ratios — prefer unified (Claude Max), fall back to standard (API key)
|
|
@@ -1013,25 +1013,53 @@ export class TUI {
|
|
|
1013
1013
|
}
|
|
1014
1014
|
const weekly = weeklyPolicyText(this.am, a);
|
|
1015
1015
|
if (weekly) line += ` ${weekly}`;
|
|
1016
|
-
// Per-model weekly caps (e.g. Fable
|
|
1017
|
-
// headroom)
|
|
1018
|
-
//
|
|
1016
|
+
// Per-model weekly caps (e.g. Fable, while the unified weekly still has
|
|
1017
|
+
// headroom). Show the ACTUAL utilization — "Fable 90%" (yellow) while high but
|
|
1018
|
+
// still usable, "Fable maxed" (red) ONLY at genuine exhaustion. This is the
|
|
1019
|
+
// SAME predicate the router benches on (_scopedExhausted), so "maxed" renders
|
|
1020
|
+
// iff the model is actually benched — 90%/critical is no longer mislabelled.
|
|
1019
1021
|
const exhaustedFloor = this.am.scheduler?.weeklyExhaustedThreshold ?? 0.985;
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1022
|
+
const reserveFloor = this.am.scheduler?.weeklyReserveThreshold ?? 0.85;
|
|
1023
|
+
const scopedTags = [];
|
|
1024
|
+
for (const [fam, e] of Object.entries(q.scopedWeekly || {})) {
|
|
1025
|
+
if (!e || e.isActive === false || e.utilization == null) continue;
|
|
1026
|
+
if (e.utilization < reserveFloor) continue;
|
|
1027
|
+
const Fam = fam.charAt(0).toUpperCase() + fam.slice(1);
|
|
1028
|
+
scopedTags.push(e.utilization >= exhaustedFloor
|
|
1029
|
+
? red(`${Fam} maxed`)
|
|
1030
|
+
: yellow(`${Fam} ${Math.round(e.utilization * 100)}%`));
|
|
1031
|
+
}
|
|
1032
|
+
if (scopedTags.length) line += ` ${scopedTags.join(' ')}`;
|
|
1033
|
+
// Freshness: scoped caps are refreshed ONLY by the background probe (response
|
|
1034
|
+
// headers don't carry them). If the probe has gone stale (> 2× interval since
|
|
1035
|
+
// last success), say so rather than imply the last-known value is current.
|
|
1036
|
+
if (this.am._quotaProbeStale?.(a)) line += ` ${dim('stale')}`;
|
|
1025
1037
|
line += ` ${dim(loadText(this._accountLoad(a)))}`;
|
|
1026
1038
|
return line;
|
|
1027
1039
|
}
|
|
1028
1040
|
|
|
1029
|
-
_renderProviderAcct(sel, cur, name, type, status, a) {
|
|
1041
|
+
_renderProviderAcct(sel, cur, name, type, status, a, bw = 11, showBoth = true) {
|
|
1030
1042
|
const completed = a.completedRequests || 0;
|
|
1031
1043
|
const failed = a.failedRequests || 0;
|
|
1032
1044
|
const active = a.inFlight || 0;
|
|
1033
1045
|
const last = a.lastStatus ? `${statusColor(a.lastStatus)} ${formatMs(a.lastResponseMs)}` : '-';
|
|
1034
1046
|
const q = a.quota || {};
|
|
1047
|
+
|
|
1048
|
+
// Quota segment. z.ai has a pollable monitor endpoint → real Ses/Wk token bars,
|
|
1049
|
+
// same rendering as OAuth accounts. Kimi (Moonshot coding key) has NO pollable
|
|
1050
|
+
// quota (web console only) → an honest label, never a fake bar. Fields are the
|
|
1051
|
+
// SEPARATE provider* set, so a provider reading never leaks into an OAuth bar.
|
|
1052
|
+
let quotaSeg = '';
|
|
1053
|
+
if (q.providerSes != null || q.providerWk != null) {
|
|
1054
|
+
quotaSeg = ` Ses ${bar(q.providerSes, bw, q.providerSesReset)}`;
|
|
1055
|
+
if (showBoth && q.providerWk != null) quotaSeg += ` Wk ${bar(q.providerWk, bw, q.providerWkReset)}`;
|
|
1056
|
+
if (this.am._quotaProbeStale?.(a)) quotaSeg += ` ${dim('stale')}`;
|
|
1057
|
+
} else if (q.providerQuotaSource === 'console-only') {
|
|
1058
|
+
quotaSeg = ` ${dim('Quota console-only')}`;
|
|
1059
|
+
} else if (q.providerQuotaSource === 'zai') {
|
|
1060
|
+
quotaSeg = ` ${dim('Ses/Wk probing')}`;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1035
1063
|
let limit = '';
|
|
1036
1064
|
if (q.genericLimit != null && q.genericRemaining != null) {
|
|
1037
1065
|
const used = q.genericLimit - q.genericRemaining;
|
|
@@ -1039,7 +1067,7 @@ export class TUI {
|
|
|
1039
1067
|
limit = ` Lim ${used}/${q.genericLimit}${reset ? ` ${reset}` : ''}`;
|
|
1040
1068
|
}
|
|
1041
1069
|
const err = a.lastError ? ` Err ${String(a.lastError).slice(0, 18)}` : '';
|
|
1042
|
-
return ` ${sel}${cur} ${name} ${type} ${status} Act ${String(active).padStart(2)} OK ${String(completed).padStart(3)} Fail ${String(failed).padStart(2)} Last ${last} ${dim(loadText(this._accountLoad(a)))}${limit}${err}`;
|
|
1070
|
+
return ` ${sel}${cur} ${name} ${type} ${status} Act ${String(active).padStart(2)} OK ${String(completed).padStart(3)} Fail ${String(failed).padStart(2)} Last ${last}${quotaSeg} ${dim(loadText(this._accountLoad(a)))}${limit}${err}`;
|
|
1043
1071
|
}
|
|
1044
1072
|
|
|
1045
1073
|
_accountLoad(account) {
|