qwenproxy-cli 1.5.3 → 1.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.
- package/dist/clean-cache.js +252 -26
- package/dist/delete-chats.js +206 -37
- package/dist/index.js +548 -74
- package/dist/login.js +144 -28
- package/dist/reset-cooldowns.js +252 -26
- package/dist/sync-clients.js +2 -2
- package/package.json +3 -3
- package/src/api/server.ts +1 -0
- package/src/clean-cache.ts +3 -0
- package/src/core/config.ts +2 -2
- package/src/core/daily-usage.ts +276 -0
- package/src/core/database.ts +27 -1
- package/src/core/process-guard.ts +77 -0
- package/src/core/version.ts +1 -1
- package/src/delete-chats.ts +3 -0
- package/src/index.ts +3 -29
- package/src/login.ts +2 -0
- package/src/routes/chat/account.ts +33 -5
- package/src/routes/chat/index.ts +1 -1
- package/src/routes/chat/retry-policy.ts +30 -0
- package/src/routes/chat/streaming.ts +72 -4
- package/src/services/captcha-coordinator.ts +12 -7
- package/src/services/chat-cleanup.ts +5 -0
- package/src/services/playwright.ts +82 -26
- package/src/services/qwen.ts +65 -9
- package/src/tui/proxy-client.ts +11 -1
- package/src/tui/types.ts +11 -0
- package/src/tui/views/accounts-view.ts +19 -2
- package/src/tui/views/status-view.ts +37 -4
package/dist/index.js
CHANGED
|
@@ -150,6 +150,44 @@ var init_paths = __esm({
|
|
|
150
150
|
}
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
+
// src/core/process-guard.ts
|
|
154
|
+
function isPlaywrightAlreadyClosedMessage(message) {
|
|
155
|
+
if (!message) return false;
|
|
156
|
+
return message.includes("Target page, context or browser has been closed") || message.includes("Browser has been closed") || message.includes("Target closed") || message.includes("Target crashed") || message.includes("Page crashed") || message.includes("Assertion error") || message.includes("Cannot find parent object") || message.includes("Connection closed") || message.includes("session closed") || message.includes("Session closed") || message.includes("Network.setCacheDisabled") || message.includes("Protocol error") || message.includes("storageState timed out");
|
|
157
|
+
}
|
|
158
|
+
function isBenignTeardownError(error) {
|
|
159
|
+
if (!error) return false;
|
|
160
|
+
const message = error instanceof Error ? error.message : typeof error === "object" && "message" in error ? String(error.message) : String(error);
|
|
161
|
+
return isPlaywrightAlreadyClosedMessage(message);
|
|
162
|
+
}
|
|
163
|
+
function installProcessTeardownGuards(label = "Process") {
|
|
164
|
+
if (guardsInstalled) return;
|
|
165
|
+
guardsInstalled = true;
|
|
166
|
+
process.on("uncaughtException", (error) => {
|
|
167
|
+
if (isBenignTeardownError(error)) {
|
|
168
|
+
const msg = error instanceof Error ? error.message : typeof error === "object" && error !== null && "message" in error ? String(error.message) : String(error);
|
|
169
|
+
console.warn(`\u26A0\uFE0F [${label}] Handled benign driver teardown exception: ${msg}`);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
console.error(`\u274C [${label}] Uncaught Exception:`, error);
|
|
173
|
+
});
|
|
174
|
+
process.on("unhandledRejection", (reason) => {
|
|
175
|
+
if (isBenignTeardownError(reason)) {
|
|
176
|
+
const msg = reason instanceof Error ? reason.message : typeof reason === "object" && reason !== null && "message" in reason ? String(reason.message) : String(reason);
|
|
177
|
+
console.warn(`\u26A0\uFE0F [${label}] Handled benign driver teardown rejection: ${msg}`);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
console.error(`\u274C [${label}] Unhandled Rejection:`, reason);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
var guardsInstalled;
|
|
184
|
+
var init_process_guard = __esm({
|
|
185
|
+
"src/core/process-guard.ts"() {
|
|
186
|
+
"use strict";
|
|
187
|
+
guardsInstalled = false;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
153
191
|
// src/core/config.ts
|
|
154
192
|
import fs2 from "node:fs";
|
|
155
193
|
import dotenv from "dotenv";
|
|
@@ -289,11 +327,11 @@ var init_config = __esm({
|
|
|
289
327
|
// nothing in this window is dead and should fail fast, retryable).
|
|
290
328
|
QWEN_FIRST_CHUNK_TIMEOUT: z.string().default("60000"),
|
|
291
329
|
TOTAL_REQUEST_TIMEOUT: z.string().default("600000"),
|
|
292
|
-
// Mid-stream silence window for thinking models:
|
|
330
|
+
// Mid-stream silence window for thinking models: 5 min with ZERO upstream
|
|
293
331
|
// bytes is a dead stream (WAF swallow / dropped connection) — fail fast and
|
|
294
332
|
// let the retry policy rotate accounts. Flowing reasoning chunks RESET this
|
|
295
333
|
// timer, so legitimate slow thinking is never cut; only total silence is.
|
|
296
|
-
REASONING_MODEL_TIMEOUT: z.string().default("
|
|
334
|
+
REASONING_MODEL_TIMEOUT: z.string().default("300000"),
|
|
297
335
|
CACHE_TTL: z.string().default("3600"),
|
|
298
336
|
RESPONSE_TTL: z.string().default("1800"),
|
|
299
337
|
CACHE_COMPRESSION_ENABLED: z.string().default("true"),
|
|
@@ -1592,7 +1630,26 @@ function runMigrations(db2) {
|
|
|
1592
1630
|
instruction_hash TEXT NOT NULL,
|
|
1593
1631
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1594
1632
|
);
|
|
1633
|
+
|
|
1634
|
+
CREATE TABLE IF NOT EXISTS account_daily_usage (
|
|
1635
|
+
account_id TEXT NOT NULL,
|
|
1636
|
+
date_utc TEXT NOT NULL,
|
|
1637
|
+
prompt_tokens INTEGER NOT NULL DEFAULT 0,
|
|
1638
|
+
completion_tokens INTEGER NOT NULL DEFAULT 0,
|
|
1639
|
+
weighted_tokens REAL NOT NULL DEFAULT 0,
|
|
1640
|
+
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
1641
|
+
turns_count INTEGER NOT NULL DEFAULT 0,
|
|
1642
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1643
|
+
PRIMARY KEY (account_id, date_utc)
|
|
1644
|
+
);
|
|
1645
|
+
|
|
1646
|
+
CREATE INDEX IF NOT EXISTS idx_daily_usage_date ON account_daily_usage(date_utc);
|
|
1595
1647
|
`);
|
|
1648
|
+
try {
|
|
1649
|
+
db2.exec(`ALTER TABLE account_daily_usage ADD COLUMN weighted_tokens REAL DEFAULT 0;`);
|
|
1650
|
+
} catch (err) {
|
|
1651
|
+
if (!isDuplicateColumnError(err)) throw err;
|
|
1652
|
+
}
|
|
1596
1653
|
try {
|
|
1597
1654
|
db2.exec(
|
|
1598
1655
|
`ALTER TABLE accounts ADD COLUMN cooldown_until INTEGER DEFAULT 0;`
|
|
@@ -1693,7 +1750,11 @@ function saveAuthSession(accountId, session) {
|
|
|
1693
1750
|
) VALUES (
|
|
1694
1751
|
?, ?, ?, ?, ?, ?,
|
|
1695
1752
|
?, ?, ?, ?,
|
|
1696
|
-
?,
|
|
1753
|
+
COALESCE(?, (SELECT user_id FROM qwen_auth_sessions WHERE account_id = ?)),
|
|
1754
|
+
?,
|
|
1755
|
+
COALESCE(?, (SELECT refresh_token FROM qwen_auth_sessions WHERE account_id = ?)),
|
|
1756
|
+
?,
|
|
1757
|
+
datetime('now')
|
|
1697
1758
|
)
|
|
1698
1759
|
`);
|
|
1699
1760
|
stmt.run(
|
|
@@ -1708,8 +1769,10 @@ function saveAuthSession(accountId, session) {
|
|
|
1708
1769
|
session.secChUaPlatform || null,
|
|
1709
1770
|
session.version || null,
|
|
1710
1771
|
session.userId || null,
|
|
1772
|
+
accountId,
|
|
1711
1773
|
session.tokenExpiresAt || null,
|
|
1712
1774
|
session.refreshToken || null,
|
|
1775
|
+
accountId,
|
|
1713
1776
|
session.capturedAt ?? Date.now()
|
|
1714
1777
|
);
|
|
1715
1778
|
}
|
|
@@ -4235,6 +4298,8 @@ var init_clean_cache = __esm({
|
|
|
4235
4298
|
"src/clean-cache.ts"() {
|
|
4236
4299
|
"use strict";
|
|
4237
4300
|
init_playwright();
|
|
4301
|
+
init_process_guard();
|
|
4302
|
+
installProcessTeardownGuards("CleanCache");
|
|
4238
4303
|
isDirectRun = process.argv[1] && (process.argv[1].endsWith("clean-cache.ts") || process.argv[1].endsWith("clean-cache.js"));
|
|
4239
4304
|
if (isDirectRun) {
|
|
4240
4305
|
main().catch((err) => {
|
|
@@ -4459,15 +4524,18 @@ function loadStorageState(accountId) {
|
|
|
4459
4524
|
return void 0;
|
|
4460
4525
|
}
|
|
4461
4526
|
}
|
|
4462
|
-
async function saveStorageState(context, accountId, timeoutMs =
|
|
4527
|
+
async function saveStorageState(context, accountId, timeoutMs = 1e4) {
|
|
4463
4528
|
try {
|
|
4464
4529
|
const stateFile = getStorageStatePath(accountId);
|
|
4465
4530
|
const dir = path6.dirname(stateFile);
|
|
4466
4531
|
if (!fs9.existsSync(dir)) {
|
|
4467
4532
|
fs9.mkdirSync(dir, { recursive: true });
|
|
4468
4533
|
}
|
|
4534
|
+
const rawPromise = context.storageState({ path: stateFile }).catch(() => {
|
|
4535
|
+
return void 0;
|
|
4536
|
+
});
|
|
4469
4537
|
await withTimeout(
|
|
4470
|
-
|
|
4538
|
+
rawPromise,
|
|
4471
4539
|
timeoutMs,
|
|
4472
4540
|
`storageState timed out after ${timeoutMs}ms`
|
|
4473
4541
|
);
|
|
@@ -5194,6 +5262,11 @@ async function getBasicHeaders(accountId) {
|
|
|
5194
5262
|
if (!page) {
|
|
5195
5263
|
throw new Error(`Playwright not initialized for account: ${accountId}`);
|
|
5196
5264
|
}
|
|
5265
|
+
const inFlightInit = inFlightAccountInits.get(accountId);
|
|
5266
|
+
if (inFlightInit) {
|
|
5267
|
+
await inFlightInit.catch(() => {
|
|
5268
|
+
});
|
|
5269
|
+
}
|
|
5197
5270
|
const release = await acquireAccountMutex(
|
|
5198
5271
|
accountId,
|
|
5199
5272
|
`headers:${accountId.substring(0, 12)}`
|
|
@@ -6668,6 +6741,11 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
6668
6741
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
6669
6742
|
const { parseJwtExpiry: parseJwtExpiry2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
|
|
6670
6743
|
const tokenExpiry = parseJwtExpiry2(capturedHeaders.cookie);
|
|
6744
|
+
let rTok;
|
|
6745
|
+
try {
|
|
6746
|
+
rTok = (await page.evaluate(() => localStorage.getItem("refresh_token") || "")).trim() || void 0;
|
|
6747
|
+
} catch {
|
|
6748
|
+
}
|
|
6671
6749
|
saveAuthSession2(accountId, {
|
|
6672
6750
|
cookie: capturedHeaders.cookie,
|
|
6673
6751
|
userAgent: capturedHeaders["user-agent"],
|
|
@@ -6679,6 +6757,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
6679
6757
|
secChUaPlatform: capturedHeaders["sec-ch-ua-platform"],
|
|
6680
6758
|
version: capturedHeaders["version"],
|
|
6681
6759
|
tokenExpiresAt: tokenExpiry || void 0,
|
|
6760
|
+
refreshToken: rTok,
|
|
6682
6761
|
capturedAt: Date.now()
|
|
6683
6762
|
});
|
|
6684
6763
|
} catch {
|
|
@@ -6710,38 +6789,57 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
6710
6789
|
const isAuthUrl = currentUrl.includes("/auth") || currentUrl.includes("/login");
|
|
6711
6790
|
const isSuspectedGuest = isAuthUrl || attempt >= 2 && !await isPageLoggedIn(page, 5e3);
|
|
6712
6791
|
if (isSuspectedGuest) {
|
|
6713
|
-
const
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
`\u26A0\uFE0F [Playwright] Session expired or guest state detected during header capture for ${accountId}; re-authenticating...`
|
|
6792
|
+
const silentRefresh = await refreshAccountToken(accountId);
|
|
6793
|
+
if (silentRefresh.success) {
|
|
6794
|
+
console.log(
|
|
6795
|
+
`\u26A1 [Playwright] Token refreshed silently during header capture for ${accountId}`
|
|
6718
6796
|
);
|
|
6719
|
-
|
|
6720
|
-
const ok = await loginToQwen(accountId, creds.email, creds.password);
|
|
6721
|
-
if (ok) {
|
|
6797
|
+
if (isAuthUrl) {
|
|
6722
6798
|
await page.goto(qwenUrl("/"), {
|
|
6723
6799
|
waitUntil: "domcontentloaded",
|
|
6724
6800
|
timeout: Math.min(config.timeouts.navigation, timeoutMs)
|
|
6725
6801
|
});
|
|
6726
|
-
await sleep2(
|
|
6802
|
+
await sleep2(1500);
|
|
6803
|
+
}
|
|
6804
|
+
if (await isPageLoggedIn(page, 5e3)) {
|
|
6805
|
+
armOverallDeadline();
|
|
6727
6806
|
}
|
|
6728
|
-
|
|
6807
|
+
}
|
|
6808
|
+
const stillSuspected = !silentRefresh.success || !await isPageLoggedIn(page, 2e3);
|
|
6809
|
+
if (stillSuspected) {
|
|
6810
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
6811
|
+
const creds = getAccountCredentials2(accountId);
|
|
6812
|
+
if (creds && creds.email && creds.password) {
|
|
6813
|
+
console.warn(
|
|
6814
|
+
`\u26A0\uFE0F [Playwright] Session expired or guest state detected during header capture for ${accountId}; re-authenticating...`
|
|
6815
|
+
);
|
|
6816
|
+
armOverallDeadline();
|
|
6817
|
+
const ok = await loginToQwen(accountId, creds.email, creds.password);
|
|
6818
|
+
if (ok) {
|
|
6819
|
+
await page.goto(qwenUrl("/"), {
|
|
6820
|
+
waitUntil: "domcontentloaded",
|
|
6821
|
+
timeout: Math.min(config.timeouts.navigation, timeoutMs)
|
|
6822
|
+
});
|
|
6823
|
+
await sleep2(2e3);
|
|
6824
|
+
}
|
|
6825
|
+
if (!ok || !await isPageLoggedIn(page, 6e3)) {
|
|
6826
|
+
settle(
|
|
6827
|
+
new Error(
|
|
6828
|
+
`Header capture failed for ${accountId}: re-login after session expiry did not succeed`
|
|
6829
|
+
)
|
|
6830
|
+
);
|
|
6831
|
+
return;
|
|
6832
|
+
}
|
|
6833
|
+
armOverallDeadline();
|
|
6834
|
+
if (settled || page.isClosed()) return;
|
|
6835
|
+
} else {
|
|
6729
6836
|
settle(
|
|
6730
6837
|
new Error(
|
|
6731
|
-
`Header capture failed for ${accountId}: re-login
|
|
6838
|
+
`Header capture failed for ${accountId}: session expired and no credentials available for re-login (run 'qpx login')`
|
|
6732
6839
|
)
|
|
6733
6840
|
);
|
|
6734
6841
|
return;
|
|
6735
6842
|
}
|
|
6736
|
-
armOverallDeadline();
|
|
6737
|
-
if (settled || page.isClosed()) return;
|
|
6738
|
-
} else {
|
|
6739
|
-
settle(
|
|
6740
|
-
new Error(
|
|
6741
|
-
`Header capture failed for ${accountId}: session expired and no credentials available for re-login (run 'qpx login')`
|
|
6742
|
-
)
|
|
6743
|
-
);
|
|
6744
|
-
return;
|
|
6745
6843
|
}
|
|
6746
6844
|
}
|
|
6747
6845
|
if (settled || page.isClosed()) return;
|
|
@@ -7057,7 +7155,13 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
7057
7155
|
`[Playwright] Navigation check failed during refresh for ${accountId}:`,
|
|
7058
7156
|
navErr.message
|
|
7059
7157
|
);
|
|
7060
|
-
await
|
|
7158
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
7159
|
+
} else {
|
|
7160
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
7161
|
+
if (!refreshed.success) {
|
|
7162
|
+
await executeReauth();
|
|
7163
|
+
}
|
|
7164
|
+
}
|
|
7061
7165
|
}
|
|
7062
7166
|
}
|
|
7063
7167
|
if (hasRequiredQwenHeaders(cache3.headers)) {
|
|
@@ -7071,6 +7175,11 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
7071
7175
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
7072
7176
|
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
7073
7177
|
const exp = tokenCookie ? parseJwtExpiry(tokenCookie.value) : void 0;
|
|
7178
|
+
let rTok;
|
|
7179
|
+
try {
|
|
7180
|
+
rTok = (await page.evaluate(() => localStorage.getItem("refresh_token") || "")).trim() || void 0;
|
|
7181
|
+
} catch {
|
|
7182
|
+
}
|
|
7074
7183
|
saveAuthSession2(accountId, {
|
|
7075
7184
|
cookie: cookieStr,
|
|
7076
7185
|
userAgent: cache3.headers["user-agent"] || "",
|
|
@@ -7082,6 +7191,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
7082
7191
|
secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
|
|
7083
7192
|
version: cache3.headers["version"] || void 0,
|
|
7084
7193
|
tokenExpiresAt: exp || void 0,
|
|
7194
|
+
refreshToken: rTok,
|
|
7085
7195
|
capturedAt: Date.now()
|
|
7086
7196
|
});
|
|
7087
7197
|
} catch {
|
|
@@ -7468,8 +7578,10 @@ async function keepAlivePlaywrightAccount(accountId) {
|
|
|
7468
7578
|
if (!page || page.isClosed()) return false;
|
|
7469
7579
|
const now = Date.now();
|
|
7470
7580
|
const currentUrl = page.url();
|
|
7581
|
+
const lastRefreshAttempt = lastProactiveTokenRefresh.get(accountId) ?? 0;
|
|
7471
7582
|
const cookie = await getCookies(accountId);
|
|
7472
|
-
if (cookie && isTokenExpiringSoon(cookie, 5)) {
|
|
7583
|
+
if (cookie && isTokenExpiringSoon(cookie, 5) && now - lastRefreshAttempt > 6e4) {
|
|
7584
|
+
lastProactiveTokenRefresh.set(accountId, now);
|
|
7473
7585
|
console.log(
|
|
7474
7586
|
`\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
|
|
7475
7587
|
);
|
|
@@ -7513,6 +7625,7 @@ function cleanupPlaywrightAccountState(accountId) {
|
|
|
7513
7625
|
cookieCaches.delete(accountId);
|
|
7514
7626
|
lastAccountActivity.delete(accountId);
|
|
7515
7627
|
lastKeepAliveNavigation.delete(accountId);
|
|
7628
|
+
lastProactiveTokenRefresh.delete(accountId);
|
|
7516
7629
|
clearFingerprintCache(accountId);
|
|
7517
7630
|
unmarkAccountHeadersReady(accountId);
|
|
7518
7631
|
}
|
|
@@ -7696,7 +7809,7 @@ async function getTokenDiagnostics(accountId) {
|
|
|
7696
7809
|
}
|
|
7697
7810
|
};
|
|
7698
7811
|
}
|
|
7699
|
-
var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, cachedUserAgents, inFlightAccountInits, sharedBrowser, sharedBrowserPromise, headerCaches, HEADER_CACHE_TTL, HEADER_REFRESH_THRESHOLD, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, profileResetQueue, profileResetChain, closingAllPlaywright, sleep2, HEADER_CAPTURE_SETTLE_MS, PLAYWRIGHT_MUTEX_WAIT_MS, ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, SESSION_PROBE_NAVIGATION_TIMEOUT_MS, HEADER_CAPTURE_TRIGGER_GRACE_MS, FIRST_TRIGGER_GRACE_MS, HEADER_CAPTURE_TRIGGER_ATTEMPTS, CHAT_INPUT_APPEAR_TIMEOUT_MS, CHAT_INPUT_ACTION_TIMEOUT_MS, PROFILE_RESET_TIMEOUT_MS;
|
|
7812
|
+
var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, cachedUserAgents, inFlightAccountInits, sharedBrowser, sharedBrowserPromise, headerCaches, HEADER_CACHE_TTL, HEADER_REFRESH_THRESHOLD, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, lastProactiveTokenRefresh, profileResetQueue, profileResetChain, closingAllPlaywright, sleep2, HEADER_CAPTURE_SETTLE_MS, PLAYWRIGHT_MUTEX_WAIT_MS, ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, SESSION_PROBE_NAVIGATION_TIMEOUT_MS, HEADER_CAPTURE_TRIGGER_GRACE_MS, FIRST_TRIGGER_GRACE_MS, HEADER_CAPTURE_TRIGGER_ATTEMPTS, CHAT_INPUT_APPEAR_TIMEOUT_MS, CHAT_INPUT_ACTION_TIMEOUT_MS, PROFILE_RESET_TIMEOUT_MS;
|
|
7700
7813
|
var init_playwright = __esm({
|
|
7701
7814
|
"src/services/playwright.ts"() {
|
|
7702
7815
|
"use strict";
|
|
@@ -7732,6 +7845,7 @@ var init_playwright = __esm({
|
|
|
7732
7845
|
cookieCaches = /* @__PURE__ */ new Map();
|
|
7733
7846
|
lastAccountActivity = /* @__PURE__ */ new Map();
|
|
7734
7847
|
lastKeepAliveNavigation = /* @__PURE__ */ new Map();
|
|
7848
|
+
lastProactiveTokenRefresh = /* @__PURE__ */ new Map();
|
|
7735
7849
|
profileResetQueue = /* @__PURE__ */ new Map();
|
|
7736
7850
|
profileResetChain = Promise.resolve();
|
|
7737
7851
|
closingAllPlaywright = false;
|
|
@@ -8547,9 +8661,13 @@ var init_model_registry = __esm({
|
|
|
8547
8661
|
// src/services/captcha-coordinator.ts
|
|
8548
8662
|
var captcha_coordinator_exports = {};
|
|
8549
8663
|
__export(captcha_coordinator_exports, {
|
|
8664
|
+
isCaptchaRecoveryActive: () => isCaptchaRecoveryActive,
|
|
8550
8665
|
recoverBaxiaCaptcha: () => recoverBaxiaCaptcha,
|
|
8551
8666
|
solveChallengeOnPage: () => solveChallengeOnPage
|
|
8552
8667
|
});
|
|
8668
|
+
function isCaptchaRecoveryActive(accountId) {
|
|
8669
|
+
return activeCaptchaRecoveries.has(accountId);
|
|
8670
|
+
}
|
|
8553
8671
|
async function gotoBestEffort(page, url) {
|
|
8554
8672
|
await page.goto(url, {
|
|
8555
8673
|
waitUntil: "domcontentloaded",
|
|
@@ -8592,11 +8710,12 @@ async function recoverBaxiaCaptcha(accountId, label, options = {}) {
|
|
|
8592
8710
|
return false;
|
|
8593
8711
|
}
|
|
8594
8712
|
metrics.increment("captcha.challenges.detected", 1, { solver });
|
|
8595
|
-
const challengeUrl = options.challengeBody ? extractBaxiaChallengeUrl(options.challengeBody, config.qwen.baseUrl) : null;
|
|
8596
8713
|
const solverOperationTimeoutMs = Math.max(
|
|
8597
8714
|
15e3,
|
|
8598
8715
|
config.captcha.timeoutMs + config.captcha.maxAttempts * (3e3 + config.captcha.retryDelayMs + config.captcha.settleMs) + 2 * CHALLENGE_NAVIGATION_TIMEOUT_MS
|
|
8599
8716
|
);
|
|
8717
|
+
const challengeUrl = options.challengeBody ? extractBaxiaChallengeUrl(options.challengeBody, config.qwen.baseUrl) : null;
|
|
8718
|
+
activeCaptchaRecoveries.add(accountId);
|
|
8600
8719
|
try {
|
|
8601
8720
|
const solved = await withAccountPage(
|
|
8602
8721
|
accountId,
|
|
@@ -8629,9 +8748,11 @@ async function recoverBaxiaCaptcha(accountId, label, options = {}) {
|
|
|
8629
8748
|
detail
|
|
8630
8749
|
});
|
|
8631
8750
|
return false;
|
|
8751
|
+
} finally {
|
|
8752
|
+
activeCaptchaRecoveries.delete(accountId);
|
|
8632
8753
|
}
|
|
8633
8754
|
}
|
|
8634
|
-
var CHALLENGE_NAVIGATION_TIMEOUT_MS, CHALLENGE_PATH_MARKER, FAILED_RECOVERY_BACKOFF_MS, lastFailedRecoveryAt;
|
|
8755
|
+
var CHALLENGE_NAVIGATION_TIMEOUT_MS, CHALLENGE_PATH_MARKER, FAILED_RECOVERY_BACKOFF_MS, lastFailedRecoveryAt, activeCaptchaRecoveries;
|
|
8635
8756
|
var init_captcha_coordinator = __esm({
|
|
8636
8757
|
"src/services/captcha-coordinator.ts"() {
|
|
8637
8758
|
"use strict";
|
|
@@ -8644,6 +8765,7 @@ var init_captcha_coordinator = __esm({
|
|
|
8644
8765
|
CHALLENGE_PATH_MARKER = "_____tmd_____";
|
|
8645
8766
|
FAILED_RECOVERY_BACKOFF_MS = 3e4;
|
|
8646
8767
|
lastFailedRecoveryAt = /* @__PURE__ */ new Map();
|
|
8768
|
+
activeCaptchaRecoveries = /* @__PURE__ */ new Set();
|
|
8647
8769
|
}
|
|
8648
8770
|
});
|
|
8649
8771
|
|
|
@@ -9336,6 +9458,11 @@ function isCorruptedChatHistoryError(err) {
|
|
|
9336
9458
|
const message = errMessage(err).toLowerCase();
|
|
9337
9459
|
return message.includes("first message must not") || message.includes("first message must be") || message.includes("must not assistant message") || message.includes("must not be assistant");
|
|
9338
9460
|
}
|
|
9461
|
+
function isInternalServerError(err) {
|
|
9462
|
+
const code = errCode(err).toLowerCase();
|
|
9463
|
+
const message = errMessage(err).toLowerCase();
|
|
9464
|
+
return code === "internal_error" || code === "internal_server_error" || code === "server_error" || code === "server_busy" || code === "busy" || message.includes("internal_error") || message.includes("ocorreu um erro inesperado") || message.includes("unexpected error") || message.includes("internal server error");
|
|
9465
|
+
}
|
|
9339
9466
|
function makeRetryAction(reason, overrides = {}) {
|
|
9340
9467
|
return {
|
|
9341
9468
|
retryable: true,
|
|
@@ -9442,6 +9569,15 @@ function classifyRetryAction(err, options) {
|
|
|
9442
9569
|
accountCooldownReason: quota.accountCooldownReason
|
|
9443
9570
|
});
|
|
9444
9571
|
}
|
|
9572
|
+
if (isInternalServerError(err) && !(err instanceof QwenUpstreamError)) {
|
|
9573
|
+
const typed = err;
|
|
9574
|
+
return makeRetryAction("upstream_internal_error", {
|
|
9575
|
+
switchAccount: typed.switchAccount !== false,
|
|
9576
|
+
forceNewChat: true,
|
|
9577
|
+
retryWithFullPrompt: true,
|
|
9578
|
+
retryAfterMs: typed.retryAfterMs ?? Math.min(baseDelayMs * 2, 3e3)
|
|
9579
|
+
});
|
|
9580
|
+
}
|
|
9445
9581
|
if (isNetworkLikeError(err) || err instanceof QwenUpstreamUnavailableError || err instanceof QwenUpstreamError || isAbortError(err)) {
|
|
9446
9582
|
const typed = err;
|
|
9447
9583
|
return makeRetryAction(
|
|
@@ -11110,6 +11246,7 @@ __export(qwen_exports, {
|
|
|
11110
11246
|
fetchRemoteQwenChats: () => fetchRemoteQwenChats,
|
|
11111
11247
|
flushLogicalThreadState: () => flushLogicalThreadState,
|
|
11112
11248
|
getAnyCachedQwenModels: () => getAnyCachedQwenModels,
|
|
11249
|
+
getInFlightPersonalizationCount: () => getInFlightPersonalizationCount,
|
|
11113
11250
|
getLogicalThreadState: () => getLogicalThreadState,
|
|
11114
11251
|
getQwenErrorCode: () => getQwenErrorCode,
|
|
11115
11252
|
getSessionParent: () => getSessionParent,
|
|
@@ -12042,12 +12179,51 @@ async function createQwenBrowserResponse(accountId, url, method, headers, body,
|
|
|
12042
12179
|
captchaWatcher?.stop();
|
|
12043
12180
|
}
|
|
12044
12181
|
}
|
|
12182
|
+
function getInFlightPersonalizationCount() {
|
|
12183
|
+
return inFlightPersonalizationSyncs.size;
|
|
12184
|
+
}
|
|
12045
12185
|
async function syncQwenRequestPersonalization(instruction, accountId, metadata = {}) {
|
|
12046
|
-
if (isAuthMockEnabled()) {
|
|
12047
|
-
if (process.env.TEST_PERSONALIZATION_SYNC_FAIL === "true") return false;
|
|
12048
|
-
return true;
|
|
12049
|
-
}
|
|
12050
12186
|
const cacheKey = accountId || "global";
|
|
12187
|
+
const sent = textSize(instruction);
|
|
12188
|
+
const syncHash = sent.hash ? `${sent.hash}:${QWEN_SAFE_SETTINGS_HASH}` : null;
|
|
12189
|
+
const inFlightKey = `${cacheKey}:${syncHash || "empty"}`;
|
|
12190
|
+
const existingInFlight = inFlightPersonalizationSyncs.get(inFlightKey);
|
|
12191
|
+
if (existingInFlight) {
|
|
12192
|
+
logger.debug("[Qwen] Personalization sync already in flight, sharing promise", {
|
|
12193
|
+
accountId: cacheKey
|
|
12194
|
+
});
|
|
12195
|
+
return existingInFlight;
|
|
12196
|
+
}
|
|
12197
|
+
let syncPromise;
|
|
12198
|
+
syncPromise = (async () => {
|
|
12199
|
+
await Promise.resolve();
|
|
12200
|
+
try {
|
|
12201
|
+
if (isAuthMockEnabled()) {
|
|
12202
|
+
const delay = parseInt(process.env.TEST_PERSONALIZATION_DELAY_MS || "0", 10);
|
|
12203
|
+
if (delay > 0) {
|
|
12204
|
+
await sleep5(delay);
|
|
12205
|
+
}
|
|
12206
|
+
if (process.env.TEST_PERSONALIZATION_SYNC_FAIL === "true") return false;
|
|
12207
|
+
return true;
|
|
12208
|
+
}
|
|
12209
|
+
return await syncQwenRequestPersonalizationInternal(
|
|
12210
|
+
instruction,
|
|
12211
|
+
accountId,
|
|
12212
|
+
metadata,
|
|
12213
|
+
cacheKey,
|
|
12214
|
+
sent,
|
|
12215
|
+
syncHash
|
|
12216
|
+
);
|
|
12217
|
+
} finally {
|
|
12218
|
+
if (inFlightPersonalizationSyncs.get(inFlightKey) === syncPromise) {
|
|
12219
|
+
inFlightPersonalizationSyncs.delete(inFlightKey);
|
|
12220
|
+
}
|
|
12221
|
+
}
|
|
12222
|
+
})();
|
|
12223
|
+
inFlightPersonalizationSyncs.set(inFlightKey, syncPromise);
|
|
12224
|
+
return syncPromise;
|
|
12225
|
+
}
|
|
12226
|
+
async function syncQwenRequestPersonalizationInternal(instruction, accountId, metadata, cacheKey, sent, syncHash) {
|
|
12051
12227
|
let forceRefresh = false;
|
|
12052
12228
|
try {
|
|
12053
12229
|
const basic = await getBasicHeaders2(accountId);
|
|
@@ -12065,8 +12241,6 @@ async function syncQwenRequestPersonalization(instruction, accountId, metadata =
|
|
|
12065
12241
|
});
|
|
12066
12242
|
let currentSettings = null;
|
|
12067
12243
|
let payload = buildQwenSettingsUpdatePayload(currentSettings, instruction);
|
|
12068
|
-
const sent = textSize(instruction);
|
|
12069
|
-
const syncHash = sent.hash ? `${sent.hash}:${QWEN_SAFE_SETTINGS_HASH}` : null;
|
|
12070
12244
|
const bypassCache = metadata.forceSync === true;
|
|
12071
12245
|
const cachedHash = lastSyncedPersonalizationHashes.get(cacheKey);
|
|
12072
12246
|
if (!bypassCache && syncHash && cachedHash === syncHash) {
|
|
@@ -13411,7 +13585,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
13411
13585
|
clearTimeout(timeoutId);
|
|
13412
13586
|
}
|
|
13413
13587
|
}
|
|
13414
|
-
var sleep5, BROWSER_STREAM_BINDING, BROWSER_ABORTERS_KEY, BROWSER_STREAM_FLUSH_BYTES, BROWSER_STREAM_FLUSH_MS, METADATA_TIMEOUT_PER_PAYLOAD_MB_MS, POST_CAPTCHA_METADATA_GRACE_MS, browserStreamStates, browserStreamBindingPages, browserStreamBindingContexts, MODEL_CACHE_TTL_MS, modelsCache, nativeToolsDisabled, disablingNativeToolsInProgress, lastSyncedPersonalizationHashes, directSettingsFetchConsecutiveFailures, DIRECT_SETTINGS_FETCH_BLOCK_THRESHOLD, directSettingsFetchBlocked, DIRECT_SETTINGS_FETCH_TIMEOUT_MS, activePersonalizationByAccount, accountStreamMutexes, QWEN_SAFE_SETTINGS_PATCH, QWEN_SAFE_SETTINGS_HASH, DISABLE_TOOLS_MAX_RETRIES, DISABLE_TOOLS_BACKOFF_MS, UPSTREAM_RESPONSE_PREVIEW_BYTES;
|
|
13588
|
+
var sleep5, BROWSER_STREAM_BINDING, BROWSER_ABORTERS_KEY, BROWSER_STREAM_FLUSH_BYTES, BROWSER_STREAM_FLUSH_MS, METADATA_TIMEOUT_PER_PAYLOAD_MB_MS, POST_CAPTCHA_METADATA_GRACE_MS, browserStreamStates, browserStreamBindingPages, browserStreamBindingContexts, MODEL_CACHE_TTL_MS, modelsCache, nativeToolsDisabled, disablingNativeToolsInProgress, lastSyncedPersonalizationHashes, directSettingsFetchConsecutiveFailures, DIRECT_SETTINGS_FETCH_BLOCK_THRESHOLD, directSettingsFetchBlocked, DIRECT_SETTINGS_FETCH_TIMEOUT_MS, activePersonalizationByAccount, accountStreamMutexes, QWEN_SAFE_SETTINGS_PATCH, QWEN_SAFE_SETTINGS_HASH, inFlightPersonalizationSyncs, DISABLE_TOOLS_MAX_RETRIES, DISABLE_TOOLS_BACKOFF_MS, UPSTREAM_RESPONSE_PREVIEW_BYTES;
|
|
13415
13589
|
var init_qwen = __esm({
|
|
13416
13590
|
"src/services/qwen.ts"() {
|
|
13417
13591
|
"use strict";
|
|
@@ -13498,6 +13672,7 @@ var init_qwen = __esm({
|
|
|
13498
13672
|
}
|
|
13499
13673
|
};
|
|
13500
13674
|
QWEN_SAFE_SETTINGS_HASH = crypto7.createHash("sha256").update(JSON.stringify(QWEN_SAFE_SETTINGS_PATCH)).digest("hex").slice(0, 12);
|
|
13675
|
+
inFlightPersonalizationSyncs = /* @__PURE__ */ new Map();
|
|
13501
13676
|
DISABLE_TOOLS_MAX_RETRIES = 3;
|
|
13502
13677
|
DISABLE_TOOLS_BACKOFF_MS = 2e3;
|
|
13503
13678
|
UPSTREAM_RESPONSE_PREVIEW_BYTES = 8 * 1024;
|
|
@@ -15945,6 +16120,12 @@ async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false) {
|
|
|
15945
16120
|
`\u274C [DeleteChats] [${currentIdx}/${totalCount}] Falha ao apagar conversas de ${maskEmail(account.email)}:`,
|
|
15946
16121
|
error instanceof Error ? error.message : String(error)
|
|
15947
16122
|
);
|
|
16123
|
+
} finally {
|
|
16124
|
+
if (!keepBrowserOpen) {
|
|
16125
|
+
const { closePlaywrightForAccount: closePlaywrightForAccount2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
16126
|
+
await closePlaywrightForAccount2(account.id).catch(() => {
|
|
16127
|
+
});
|
|
16128
|
+
}
|
|
15948
16129
|
}
|
|
15949
16130
|
}
|
|
15950
16131
|
} finally {
|
|
@@ -16430,8 +16611,9 @@ function resolveInitialAccount(preferredAccountId, excludeAccountIds) {
|
|
|
16430
16611
|
syncCooldownsFromDb(configuredAccounts);
|
|
16431
16612
|
const excluded = new Set(excludeAccountIds ?? []);
|
|
16432
16613
|
if (typeof preferredAccountId === "string" && preferredAccountId) {
|
|
16614
|
+
const needle = preferredAccountId.toLowerCase();
|
|
16433
16615
|
const preferred = configuredAccounts.find(
|
|
16434
|
-
(candidate) => candidate.id === preferredAccountId
|
|
16616
|
+
(candidate) => candidate.id === preferredAccountId || candidate.id.toLowerCase().startsWith(needle) || candidate.email.toLowerCase() === needle || candidate.email.toLowerCase().includes(needle)
|
|
16435
16617
|
);
|
|
16436
16618
|
if (preferred && !getAccountCooldownInfo(preferred.id)) {
|
|
16437
16619
|
return { account: preferred, configuredAccounts };
|
|
@@ -16786,7 +16968,12 @@ function shouldWaitQueueForever(isThreadOwnerWaiting, heldByOtherSession, hasFre
|
|
|
16786
16968
|
}
|
|
16787
16969
|
async function tryCreateStreamWithRetry(params, accountId, accountEmail) {
|
|
16788
16970
|
const maxAttempts = Math.max(1, config.retry.maxAttempts);
|
|
16789
|
-
const
|
|
16971
|
+
const accounts = loadAccounts();
|
|
16972
|
+
const configuredAccountCount = accounts.length;
|
|
16973
|
+
const maxAccountSwitches = Math.max(
|
|
16974
|
+
config.retry.maxAccountSwitches,
|
|
16975
|
+
Math.min(configuredAccountCount - 1, 6)
|
|
16976
|
+
);
|
|
16790
16977
|
let attemptsLeft = maxAttempts;
|
|
16791
16978
|
let retryDelay = config.retry.baseDelayMs;
|
|
16792
16979
|
let attempt = 0;
|
|
@@ -16798,7 +16985,6 @@ async function tryCreateStreamWithRetry(params, accountId, accountEmail) {
|
|
|
16798
16985
|
let chatInProgressOriginAccountEmail = null;
|
|
16799
16986
|
let lastAttemptError = null;
|
|
16800
16987
|
let invalidInputSameAccountRetried = false;
|
|
16801
|
-
const accounts = loadAccounts();
|
|
16802
16988
|
const isSingleAccount = accounts.length <= 1;
|
|
16803
16989
|
let currentAccountId = accountId;
|
|
16804
16990
|
let currentAccountEmail = accountEmail;
|
|
@@ -17011,14 +17197,24 @@ ${loopReminder}` : truncation.prompt;
|
|
|
17011
17197
|
const acquireDeadlineMs = config.concurrency.acquireDeadlineMs;
|
|
17012
17198
|
let acquireDeadlineTimer;
|
|
17013
17199
|
const acquireDeadline = new Promise((_, reject) => {
|
|
17014
|
-
|
|
17200
|
+
const checkDeadline = async () => {
|
|
17201
|
+
try {
|
|
17202
|
+
const { isCaptchaRecoveryActive: isCaptchaRecoveryActive2 } = await Promise.resolve().then(() => (init_captcha_coordinator(), captcha_coordinator_exports));
|
|
17203
|
+
if (currentAccountId && isCaptchaRecoveryActive2(currentAccountId)) {
|
|
17204
|
+
acquireDeadlineTimer = setTimeout(checkDeadline, 3e4);
|
|
17205
|
+
acquireDeadlineTimer.unref?.();
|
|
17206
|
+
return;
|
|
17207
|
+
}
|
|
17208
|
+
} catch {
|
|
17209
|
+
}
|
|
17015
17210
|
acquireAbort.abort();
|
|
17016
17211
|
const err2 = new Error(
|
|
17017
17212
|
`Acquire deadline (${acquireDeadlineMs}ms) exceeded creating stream on ${currentAccountEmail}`
|
|
17018
17213
|
);
|
|
17019
17214
|
err2.code = "acquire_deadline";
|
|
17020
17215
|
reject(err2);
|
|
17021
|
-
}
|
|
17216
|
+
};
|
|
17217
|
+
acquireDeadlineTimer = setTimeout(checkDeadline, acquireDeadlineMs);
|
|
17022
17218
|
acquireDeadlineTimer.unref?.();
|
|
17023
17219
|
});
|
|
17024
17220
|
result = await Promise.race([
|
|
@@ -17300,6 +17496,10 @@ ${loopReminder}` : truncation.prompt;
|
|
|
17300
17496
|
currentAccountId = nextAccount.id;
|
|
17301
17497
|
currentAccountEmail = maskEmail(nextAccount.email);
|
|
17302
17498
|
accountSwitches++;
|
|
17499
|
+
const isRealQuotaError = policy.reason === "quota_or_rate_limit" && (policy.accountCooldownReason === "RateLimited" || policy.accountCooldownReason === "QuotaExceeded");
|
|
17500
|
+
if (isRealQuotaError) {
|
|
17501
|
+
attemptsLeft = Math.max(attemptsLeft, 1);
|
|
17502
|
+
}
|
|
17303
17503
|
if (params.useThreadNative) {
|
|
17304
17504
|
const abandonedChatId = params.existingThread?.chatSessionId;
|
|
17305
17505
|
if (abandonedChatId) {
|
|
@@ -19920,6 +20120,199 @@ var init_token_estimation_metrics = __esm({
|
|
|
19920
20120
|
}
|
|
19921
20121
|
});
|
|
19922
20122
|
|
|
20123
|
+
// src/core/daily-usage.ts
|
|
20124
|
+
var daily_usage_exports = {};
|
|
20125
|
+
__export(daily_usage_exports, {
|
|
20126
|
+
DAILY_ACCOUNT_TOKEN_BASELINE: () => DAILY_ACCOUNT_TOKEN_BASELINE,
|
|
20127
|
+
MODEL_DAILY_OUTPUT_BASELINES: () => MODEL_DAILY_OUTPUT_BASELINES,
|
|
20128
|
+
STANDARD_DAILY_TOKEN_BASELINE: () => STANDARD_DAILY_TOKEN_BASELINE,
|
|
20129
|
+
getAccountDailyUsage: () => getAccountDailyUsage,
|
|
20130
|
+
getAllAccountsDailyUsage: () => getAllAccountsDailyUsage,
|
|
20131
|
+
getModelQuotaWeight: () => getModelQuotaWeight,
|
|
20132
|
+
getPoolDailyUsageSummary: () => getPoolDailyUsageSummary,
|
|
20133
|
+
getUtcDateString: () => getUtcDateString,
|
|
20134
|
+
recordTurnUsage: () => recordTurnUsage
|
|
20135
|
+
});
|
|
20136
|
+
function getModelQuotaWeight(model) {
|
|
20137
|
+
if (!model) return 1;
|
|
20138
|
+
const resolved = mapClientModelToQwen(model).toLowerCase();
|
|
20139
|
+
if (resolved.includes("max")) {
|
|
20140
|
+
return STANDARD_DAILY_TOKEN_BASELINE / MODEL_DAILY_OUTPUT_BASELINES.max;
|
|
20141
|
+
}
|
|
20142
|
+
if (resolved.includes("omni") || resolved.includes("flash")) {
|
|
20143
|
+
return STANDARD_DAILY_TOKEN_BASELINE / MODEL_DAILY_OUTPUT_BASELINES.omni;
|
|
20144
|
+
}
|
|
20145
|
+
return 1;
|
|
20146
|
+
}
|
|
20147
|
+
function getUtcDateString(timestampMs = Date.now()) {
|
|
20148
|
+
return new Date(timestampMs).toISOString().slice(0, 10);
|
|
20149
|
+
}
|
|
20150
|
+
function recordTurnUsage(accountId, usage, modelOrDate, maybeDateUtc) {
|
|
20151
|
+
if (!accountId || accountId === "global") return;
|
|
20152
|
+
let model;
|
|
20153
|
+
let dateUtc;
|
|
20154
|
+
if (modelOrDate && /^\d{4}-\d{2}-\d{2}$/.test(modelOrDate)) {
|
|
20155
|
+
dateUtc = modelOrDate;
|
|
20156
|
+
model = void 0;
|
|
20157
|
+
} else {
|
|
20158
|
+
model = modelOrDate;
|
|
20159
|
+
dateUtc = maybeDateUtc || getUtcDateString();
|
|
20160
|
+
}
|
|
20161
|
+
const prompt = Math.max(0, Number(usage.prompt_tokens) || 0);
|
|
20162
|
+
const completion = Math.max(0, Number(usage.completion_tokens) || 0);
|
|
20163
|
+
const total = Math.max(
|
|
20164
|
+
prompt + completion,
|
|
20165
|
+
Number(usage.total_tokens) || prompt + completion
|
|
20166
|
+
);
|
|
20167
|
+
const weight = getModelQuotaWeight(model);
|
|
20168
|
+
const weighted = completion * weight;
|
|
20169
|
+
try {
|
|
20170
|
+
const db2 = getDatabase();
|
|
20171
|
+
db2.prepare(
|
|
20172
|
+
`
|
|
20173
|
+
INSERT INTO account_daily_usage (
|
|
20174
|
+
account_id, date_utc, prompt_tokens, completion_tokens, weighted_tokens, total_tokens, turns_count, updated_at
|
|
20175
|
+
) VALUES (
|
|
20176
|
+
?, ?, ?, ?, ?, ?, 1, datetime('now')
|
|
20177
|
+
)
|
|
20178
|
+
ON CONFLICT(account_id, date_utc) DO UPDATE SET
|
|
20179
|
+
prompt_tokens = prompt_tokens + excluded.prompt_tokens,
|
|
20180
|
+
completion_tokens = completion_tokens + excluded.completion_tokens,
|
|
20181
|
+
weighted_tokens = weighted_tokens + excluded.weighted_tokens,
|
|
20182
|
+
total_tokens = total_tokens + excluded.total_tokens,
|
|
20183
|
+
turns_count = turns_count + 1,
|
|
20184
|
+
updated_at = datetime('now')
|
|
20185
|
+
`
|
|
20186
|
+
).run(accountId, dateUtc, prompt, completion, weighted, total);
|
|
20187
|
+
} catch (err) {
|
|
20188
|
+
}
|
|
20189
|
+
}
|
|
20190
|
+
function getAccountDailyUsage(accountId, dateUtc = getUtcDateString()) {
|
|
20191
|
+
try {
|
|
20192
|
+
const db2 = getDatabase();
|
|
20193
|
+
const row = db2.prepare(
|
|
20194
|
+
`SELECT prompt_tokens, completion_tokens, weighted_tokens, total_tokens, turns_count
|
|
20195
|
+
FROM account_daily_usage
|
|
20196
|
+
WHERE account_id = ? AND date_utc = ?`
|
|
20197
|
+
).get(accountId, dateUtc);
|
|
20198
|
+
const promptTokens = Number(row?.prompt_tokens) || 0;
|
|
20199
|
+
const completionTokens = Number(row?.completion_tokens) || 0;
|
|
20200
|
+
const weightedTokens = Number(row?.weighted_tokens) || completionTokens;
|
|
20201
|
+
const totalTokens = Number(row?.total_tokens) || 0;
|
|
20202
|
+
const turnsCount = Number(row?.turns_count) || 0;
|
|
20203
|
+
const usagePercent = Math.min(
|
|
20204
|
+
100,
|
|
20205
|
+
Math.round(weightedTokens / STANDARD_DAILY_TOKEN_BASELINE * 100)
|
|
20206
|
+
);
|
|
20207
|
+
return {
|
|
20208
|
+
accountId,
|
|
20209
|
+
dateUtc,
|
|
20210
|
+
promptTokens,
|
|
20211
|
+
completionTokens,
|
|
20212
|
+
weightedTokens,
|
|
20213
|
+
totalTokens,
|
|
20214
|
+
turnsCount,
|
|
20215
|
+
usagePercent
|
|
20216
|
+
};
|
|
20217
|
+
} catch {
|
|
20218
|
+
return {
|
|
20219
|
+
accountId,
|
|
20220
|
+
dateUtc,
|
|
20221
|
+
promptTokens: 0,
|
|
20222
|
+
completionTokens: 0,
|
|
20223
|
+
weightedTokens: 0,
|
|
20224
|
+
totalTokens: 0,
|
|
20225
|
+
turnsCount: 0,
|
|
20226
|
+
usagePercent: 0
|
|
20227
|
+
};
|
|
20228
|
+
}
|
|
20229
|
+
}
|
|
20230
|
+
function getAllAccountsDailyUsage(dateUtc = getUtcDateString()) {
|
|
20231
|
+
const result = /* @__PURE__ */ new Map();
|
|
20232
|
+
try {
|
|
20233
|
+
const db2 = getDatabase();
|
|
20234
|
+
const rows = db2.prepare(
|
|
20235
|
+
`SELECT account_id, prompt_tokens, completion_tokens, weighted_tokens, total_tokens, turns_count
|
|
20236
|
+
FROM account_daily_usage
|
|
20237
|
+
WHERE date_utc = ?`
|
|
20238
|
+
).all(dateUtc);
|
|
20239
|
+
for (const row of rows) {
|
|
20240
|
+
const promptTokens = Number(row.prompt_tokens) || 0;
|
|
20241
|
+
const completionTokens = Number(row.completion_tokens) || 0;
|
|
20242
|
+
const weightedTokens = Number(row.weighted_tokens) || completionTokens;
|
|
20243
|
+
const totalTokens = Number(row.total_tokens) || 0;
|
|
20244
|
+
const turnsCount = Number(row.turns_count) || 0;
|
|
20245
|
+
const usagePercent = Math.min(
|
|
20246
|
+
100,
|
|
20247
|
+
Math.round(weightedTokens / STANDARD_DAILY_TOKEN_BASELINE * 100)
|
|
20248
|
+
);
|
|
20249
|
+
result.set(row.account_id, {
|
|
20250
|
+
accountId: row.account_id,
|
|
20251
|
+
dateUtc,
|
|
20252
|
+
promptTokens,
|
|
20253
|
+
completionTokens,
|
|
20254
|
+
weightedTokens,
|
|
20255
|
+
totalTokens,
|
|
20256
|
+
turnsCount,
|
|
20257
|
+
usagePercent
|
|
20258
|
+
});
|
|
20259
|
+
}
|
|
20260
|
+
} catch {
|
|
20261
|
+
}
|
|
20262
|
+
return result;
|
|
20263
|
+
}
|
|
20264
|
+
function getPoolDailyUsageSummary(targetAccountIds, dateUtc = getUtcDateString()) {
|
|
20265
|
+
const accounts = targetAccountIds && targetAccountIds.length > 0 ? targetAccountIds : loadAccounts().map((a) => a.id);
|
|
20266
|
+
const accountCount = Math.max(1, accounts.length);
|
|
20267
|
+
const poolCapacityTokens = accountCount * STANDARD_DAILY_TOKEN_BASELINE;
|
|
20268
|
+
const usageMap = getAllAccountsDailyUsage(dateUtc);
|
|
20269
|
+
let totalPromptTokens = 0;
|
|
20270
|
+
let totalCompletionTokens = 0;
|
|
20271
|
+
let totalWeightedTokens = 0;
|
|
20272
|
+
let totalTokens = 0;
|
|
20273
|
+
let totalTurns = 0;
|
|
20274
|
+
for (const id of accounts) {
|
|
20275
|
+
const usage = usageMap.get(id);
|
|
20276
|
+
if (usage) {
|
|
20277
|
+
totalPromptTokens += usage.promptTokens;
|
|
20278
|
+
totalCompletionTokens += usage.completionTokens;
|
|
20279
|
+
totalWeightedTokens += usage.weightedTokens;
|
|
20280
|
+
totalTokens += usage.totalTokens;
|
|
20281
|
+
totalTurns += usage.turnsCount;
|
|
20282
|
+
}
|
|
20283
|
+
}
|
|
20284
|
+
const poolUsagePercent = Math.min(
|
|
20285
|
+
100,
|
|
20286
|
+
Math.round(totalWeightedTokens / poolCapacityTokens * 100)
|
|
20287
|
+
);
|
|
20288
|
+
return {
|
|
20289
|
+
dateUtc,
|
|
20290
|
+
totalPromptTokens,
|
|
20291
|
+
totalCompletionTokens,
|
|
20292
|
+
totalWeightedTokens,
|
|
20293
|
+
totalTokens,
|
|
20294
|
+
totalTurns,
|
|
20295
|
+
poolCapacityTokens,
|
|
20296
|
+
poolUsagePercent
|
|
20297
|
+
};
|
|
20298
|
+
}
|
|
20299
|
+
var STANDARD_DAILY_TOKEN_BASELINE, DAILY_ACCOUNT_TOKEN_BASELINE, MODEL_DAILY_OUTPUT_BASELINES;
|
|
20300
|
+
var init_daily_usage = __esm({
|
|
20301
|
+
"src/core/daily-usage.ts"() {
|
|
20302
|
+
"use strict";
|
|
20303
|
+
init_database();
|
|
20304
|
+
init_accounts();
|
|
20305
|
+
init_model_alias();
|
|
20306
|
+
STANDARD_DAILY_TOKEN_BASELINE = 5e5;
|
|
20307
|
+
DAILY_ACCOUNT_TOKEN_BASELINE = STANDARD_DAILY_TOKEN_BASELINE;
|
|
20308
|
+
MODEL_DAILY_OUTPUT_BASELINES = {
|
|
20309
|
+
max: 28e4,
|
|
20310
|
+
plus: 5e5,
|
|
20311
|
+
omni: 62e4
|
|
20312
|
+
};
|
|
20313
|
+
}
|
|
20314
|
+
});
|
|
20315
|
+
|
|
19923
20316
|
// src/routes/chat/streaming.ts
|
|
19924
20317
|
import { stream as honoStream } from "hono/streaming";
|
|
19925
20318
|
function firstString(...values) {
|
|
@@ -20425,6 +20818,9 @@ Please retry your tool call(s) with correct JSON and valid tool names from the a
|
|
|
20425
20818
|
mode: "non-stream",
|
|
20426
20819
|
context: currentTokenEstimationContext
|
|
20427
20820
|
});
|
|
20821
|
+
if (activeAccountId && usage) {
|
|
20822
|
+
recordTurnUsage(activeAccountId, usage, body.model);
|
|
20823
|
+
}
|
|
20428
20824
|
if (pendingParentId) {
|
|
20429
20825
|
rememberParent(pendingParentId);
|
|
20430
20826
|
}
|
|
@@ -20520,6 +20916,9 @@ async function processStreamingResponse(params) {
|
|
|
20520
20916
|
let activeReader = null;
|
|
20521
20917
|
let invalidInputSameAccountRetries = 0;
|
|
20522
20918
|
let chatInProgressSameAccountRetries = 0;
|
|
20919
|
+
let antiBotSameAccountRetries = 0;
|
|
20920
|
+
const totalConfiguredAccounts = loadAccounts().length;
|
|
20921
|
+
let quotaRotationsLeft = Math.min(Math.max(1, totalConfiguredAccounts - 1), 6);
|
|
20523
20922
|
let streamCompletedOk = false;
|
|
20524
20923
|
let stoppedByToolCap = false;
|
|
20525
20924
|
const runDisconnectTeardown = () => {
|
|
@@ -20877,13 +21276,18 @@ async function processStreamingResponse(params) {
|
|
|
20877
21276
|
reason: "network"
|
|
20878
21277
|
}
|
|
20879
21278
|
) : null;
|
|
20880
|
-
if (!normalizedError || clientDisconnected && !gracePending || c.req.raw.signal.aborted ||
|
|
21279
|
+
if (!normalizedError || clientDisconnected && !gracePending || c.req.raw.signal.aborted || !midStreamRetry || emittedModelOutput) {
|
|
20881
21280
|
return false;
|
|
20882
21281
|
}
|
|
20883
21282
|
const policy = classifyRetryAction(normalizedError, {
|
|
20884
21283
|
requestAborted: c.req.raw.signal.aborted
|
|
20885
21284
|
});
|
|
20886
21285
|
if (!policy.retryable) return false;
|
|
21286
|
+
const isRealQuotaError = policy.reason === "quota_or_rate_limit" && (policy.accountCooldownReason === "RateLimited" || policy.accountCooldownReason === "QuotaExceeded");
|
|
21287
|
+
const hasBudget = isRealQuotaError ? quotaRotationsLeft > 0 : retryContext.retriesLeft > 0;
|
|
21288
|
+
if (!hasBudget) {
|
|
21289
|
+
return false;
|
|
21290
|
+
}
|
|
20887
21291
|
if (logger.isLevelEnabled("info")) {
|
|
20888
21292
|
console.log(
|
|
20889
21293
|
`\u{1F9ED} [Chat] Stream recovery policy | account=${currentAccountId} | reason=${policy.reason} | retryable=${policy.retryable} | switch=${policy.switchAccount} | newChat=${policy.forceNewChat} | fullPrompt=${policy.retryWithFullPrompt} | retryAfter=${policy.retryAfterMs}ms`
|
|
@@ -20892,9 +21296,13 @@ async function processStreamingResponse(params) {
|
|
|
20892
21296
|
if (policy.reason === "corrupted_chat_history") {
|
|
20893
21297
|
invalidateLogicalThreadParent(midStreamRetry.sessionId);
|
|
20894
21298
|
}
|
|
20895
|
-
|
|
21299
|
+
if (isRealQuotaError) {
|
|
21300
|
+
quotaRotationsLeft--;
|
|
21301
|
+
} else {
|
|
21302
|
+
retryContext.retriesLeft--;
|
|
21303
|
+
}
|
|
20896
21304
|
console.warn(
|
|
20897
|
-
`\u{1F504} [Chat] Stream recovery | account=${currentAccountId} | reason=${policy.reason} | error=${normalizedError.message.substring(0, 150)} | retries_left=${retryContext.retriesLeft}`
|
|
21305
|
+
`\u{1F504} [Chat] Stream recovery | account=${currentAccountId} | reason=${policy.reason} | error=${normalizedError.message.substring(0, 150)} | retries_left=${isRealQuotaError ? quotaRotationsLeft : retryContext.retriesLeft}`
|
|
20898
21306
|
);
|
|
20899
21307
|
const retryInvalidInputOnSameAccount = shouldRetryInvalidInputOnSameAccount(
|
|
20900
21308
|
policy.reason,
|
|
@@ -20916,7 +21324,16 @@ async function processStreamingResponse(params) {
|
|
|
20916
21324
|
);
|
|
20917
21325
|
return false;
|
|
20918
21326
|
}
|
|
20919
|
-
|
|
21327
|
+
let switchAccount = policy.switchAccount && !retryInvalidInputOnSameAccount;
|
|
21328
|
+
if (policy.reason === "anti_bot") {
|
|
21329
|
+
if (antiBotSameAccountRetries === 0) {
|
|
21330
|
+
antiBotSameAccountRetries++;
|
|
21331
|
+
switchAccount = false;
|
|
21332
|
+
} else {
|
|
21333
|
+
switchAccount = true;
|
|
21334
|
+
markAccountRateLimited(currentAccountId, 6e4, "AntiBotWafChallenge");
|
|
21335
|
+
}
|
|
21336
|
+
}
|
|
20920
21337
|
if (switchAccount && (policy.accountCooldownMs ?? 0) > 0) {
|
|
20921
21338
|
markAccountRateLimited(
|
|
20922
21339
|
currentAccountId,
|
|
@@ -20928,6 +21345,33 @@ async function processStreamingResponse(params) {
|
|
|
20928
21345
|
Promise.resolve().then(() => (init_playwright(), playwright_exports)).then(({ refreshAccountToken: refreshAccountToken2 }) => refreshAccountToken2(currentAccountId)).catch(() => {
|
|
20929
21346
|
});
|
|
20930
21347
|
}
|
|
21348
|
+
if (currentUiSessionId && targetResponseId) {
|
|
21349
|
+
const streamData = getStream(completionId);
|
|
21350
|
+
const stopHeaders = streamData?.headers;
|
|
21351
|
+
if (stopHeaders?.cookie && stopHeaders["user-agent"]) {
|
|
21352
|
+
void requestQwenTextInBrowser(
|
|
21353
|
+
currentAccountId,
|
|
21354
|
+
"POST",
|
|
21355
|
+
`/api/v2/chat/completions/stop?chat_id=${encodeURIComponent(currentUiSessionId)}`,
|
|
21356
|
+
buildQwenRequestHeaders({
|
|
21357
|
+
cookie: stopHeaders.cookie,
|
|
21358
|
+
userAgent: stopHeaders["user-agent"],
|
|
21359
|
+
bxUa: stopHeaders["bx-ua"],
|
|
21360
|
+
bxUmidtoken: stopHeaders["bx-umidtoken"],
|
|
21361
|
+
bxV: stopHeaders["bx-v"],
|
|
21362
|
+
chatSessionId: currentUiSessionId
|
|
21363
|
+
}),
|
|
21364
|
+
JSON.stringify({
|
|
21365
|
+
chat_id: currentUiSessionId,
|
|
21366
|
+
response_id: targetResponseId
|
|
21367
|
+
}),
|
|
21368
|
+
{
|
|
21369
|
+
referrer: qwenUrl(`/c/${encodeURIComponent(currentUiSessionId)}`),
|
|
21370
|
+
noMutexRecovery: true
|
|
21371
|
+
}
|
|
21372
|
+
).catch(() => void 0);
|
|
21373
|
+
}
|
|
21374
|
+
}
|
|
20931
21375
|
retryContext.releaseAccountLease?.();
|
|
20932
21376
|
retryContext.releaseAccountLease = null;
|
|
20933
21377
|
await reader.cancel().catch(() => void 0);
|
|
@@ -21775,6 +22219,9 @@ Please retry your tool call(s) with correct JSON and valid tool names from the a
|
|
|
21775
22219
|
mode: "stream",
|
|
21776
22220
|
context: currentTokenEstimationContext
|
|
21777
22221
|
});
|
|
22222
|
+
if (activeAccountId && usage) {
|
|
22223
|
+
recordTurnUsage(activeAccountId, usage, body.model);
|
|
22224
|
+
}
|
|
21778
22225
|
} else {
|
|
21779
22226
|
if (isToolcallDebugEnabled()) {
|
|
21780
22227
|
logger.debug(
|
|
@@ -21980,6 +22427,7 @@ var init_streaming = __esm({
|
|
|
21980
22427
|
init_qwen_url();
|
|
21981
22428
|
init_qwen();
|
|
21982
22429
|
init_account();
|
|
22430
|
+
init_accounts();
|
|
21983
22431
|
init_account_manager();
|
|
21984
22432
|
init_account_concurrency();
|
|
21985
22433
|
init_retry_policy();
|
|
@@ -21995,6 +22443,7 @@ var init_streaming = __esm({
|
|
|
21995
22443
|
init_errors2();
|
|
21996
22444
|
init_retry_policy();
|
|
21997
22445
|
init_token_estimation_metrics();
|
|
22446
|
+
init_daily_usage();
|
|
21998
22447
|
init_context_meter();
|
|
21999
22448
|
init_helpers();
|
|
22000
22449
|
MAX_INITIAL_PROTOCOL_BYTES = 64 * 1024;
|
|
@@ -22434,7 +22883,7 @@ async function chatCompletions(c) {
|
|
|
22434
22883
|
updateLogicalThread: parallelEscape ? false : ctx.updateLogicalThread,
|
|
22435
22884
|
allowThreadReuse: ctx.allowThreadReuse,
|
|
22436
22885
|
forceNewChat: parallelEscape,
|
|
22437
|
-
preferredAccountId: void 0,
|
|
22886
|
+
preferredAccountId: c.req.header("x-qwenproxy-account") || void 0,
|
|
22438
22887
|
messageCount: msgCount,
|
|
22439
22888
|
fullMessageCount: parsed.messageCount,
|
|
22440
22889
|
toolsCount: declaredTools.length || void 0,
|
|
@@ -25936,7 +26385,7 @@ function getAppVersion() {
|
|
|
25936
26385
|
}
|
|
25937
26386
|
} catch {
|
|
25938
26387
|
}
|
|
25939
|
-
cachedVersion = "v1.
|
|
26388
|
+
cachedVersion = "v1.6.1";
|
|
25940
26389
|
return cachedVersion;
|
|
25941
26390
|
}
|
|
25942
26391
|
var cachedVersion;
|
|
@@ -26645,7 +27094,8 @@ var init_server = __esm({
|
|
|
26645
27094
|
captchasDetected: Number(metrics.get("captcha.challenges.detected")?.value ?? 0),
|
|
26646
27095
|
captchasSolved: Number(metrics.get("captcha.solves.succeeded")?.value ?? 0),
|
|
26647
27096
|
chatsCleaned: Number(metrics.get("chats.cleaned")?.value ?? 0)
|
|
26648
|
-
}
|
|
27097
|
+
},
|
|
27098
|
+
dailyUsage: (await Promise.resolve().then(() => (init_daily_usage(), daily_usage_exports))).getPoolDailyUsageSummary()
|
|
26649
27099
|
});
|
|
26650
27100
|
});
|
|
26651
27101
|
app5.get("/diagnostics/tokens", async (c) => {
|
|
@@ -27407,12 +27857,17 @@ async function fetchProxyStatus() {
|
|
|
27407
27857
|
}
|
|
27408
27858
|
} catch {
|
|
27409
27859
|
}
|
|
27860
|
+
const dailyUsageMap = getAllAccountsDailyUsage();
|
|
27410
27861
|
const accounts = cachedAccounts.map((acc) => {
|
|
27411
27862
|
const concurrency = concurrencyMap.get(acc.id);
|
|
27863
|
+
const daily = dailyUsageMap.get(acc.id);
|
|
27412
27864
|
return {
|
|
27413
27865
|
...acc,
|
|
27414
27866
|
activeStreams: concurrency?.active ?? 0,
|
|
27415
|
-
streamLimit: concurrency?.limit ?? config.concurrency.maxStreamsPerAccount
|
|
27867
|
+
streamLimit: concurrency?.limit ?? config.concurrency.maxStreamsPerAccount,
|
|
27868
|
+
dailyTokens: daily?.completionTokens ?? 0,
|
|
27869
|
+
dailyUsagePercent: daily?.usagePercent ?? 0,
|
|
27870
|
+
dailyTurns: daily?.turnsCount ?? 0
|
|
27416
27871
|
};
|
|
27417
27872
|
});
|
|
27418
27873
|
let rssMb = 0;
|
|
@@ -27471,6 +27926,7 @@ async function fetchProxyStatus() {
|
|
|
27471
27926
|
cacheHitRatio,
|
|
27472
27927
|
cacheBytesSaved
|
|
27473
27928
|
},
|
|
27929
|
+
dailyUsage: getPoolDailyUsageSummary(cachedAccounts.map((a) => a.id)),
|
|
27474
27930
|
accounts
|
|
27475
27931
|
};
|
|
27476
27932
|
}
|
|
@@ -27611,6 +28067,7 @@ var init_proxy_client = __esm({
|
|
|
27611
28067
|
init_account_concurrency();
|
|
27612
28068
|
init_memory_usage();
|
|
27613
28069
|
init_metrics();
|
|
28070
|
+
init_daily_usage();
|
|
27614
28071
|
init_model_alias();
|
|
27615
28072
|
init_model_alias();
|
|
27616
28073
|
cachedAccounts = [];
|
|
@@ -28341,12 +28798,24 @@ var init_status_view = __esm({
|
|
|
28341
28798
|
const poolPct = accounts.length > 0 ? Math.round(availableCount / accounts.length * 100) : 0;
|
|
28342
28799
|
const poolColor = poolPct >= 70 ? theme.green : poolPct >= 40 ? theme.yellow : theme.red;
|
|
28343
28800
|
const poolBar = renderProgressBar(poolPct, 8, poolColor);
|
|
28801
|
+
const poolDailyUsage = data?.dailyUsage;
|
|
28802
|
+
const poolUsagePct = poolDailyUsage?.poolUsagePercent ?? 0;
|
|
28803
|
+
const poolUsageColor = poolUsagePct >= 80 ? theme.red : poolUsagePct >= 40 ? theme.yellow : theme.cyan;
|
|
28804
|
+
const poolUsageBar = renderProgressBar(poolUsagePct, 8, poolUsageColor);
|
|
28344
28805
|
const innerRightW = Math.max(30, rightW - 2);
|
|
28345
|
-
const
|
|
28806
|
+
const showUsageCol = innerRightW >= 52;
|
|
28807
|
+
const emailWidth = showUsageCol ? Math.max(14, Math.min(18, innerRightW - 33)) : Math.max(16, Math.min(20, innerRightW - 27));
|
|
28346
28808
|
const rightContent = [
|
|
28347
28809
|
` ${theme.bold("Disponibilidade:")} [${poolBar}] ${poolColor(`${availableCount}/${accounts.length} (${poolPct}%)`)}`,
|
|
28810
|
+
...poolDailyUsage ? [
|
|
28811
|
+
` ${theme.bold("Cota Pool Hoje:")} [${poolUsageBar}] ${poolUsageColor(
|
|
28812
|
+
`${poolUsagePct}%`
|
|
28813
|
+
)} ${theme.dim(
|
|
28814
|
+
`(~${Math.round(poolDailyUsage.totalTokens / 1e3)}k tok)`
|
|
28815
|
+
)}`
|
|
28816
|
+
] : [],
|
|
28348
28817
|
` ${theme.dim("\u2500".repeat(Math.max(32, innerRightW - 2)))}`,
|
|
28349
|
-
` ${theme.dim(`# ${pad("Conta", emailWidth)} Carga Status`)}`,
|
|
28818
|
+
` ${theme.dim(`# ${pad("Conta", emailWidth)} Carga ${showUsageCol ? "Uso% " : ""}Status`)}`,
|
|
28350
28819
|
` ${theme.dim("\u2500".repeat(Math.max(32, innerRightW - 2)))}`
|
|
28351
28820
|
];
|
|
28352
28821
|
if (accounts.length === 0) {
|
|
@@ -28358,7 +28827,17 @@ var init_status_view = __esm({
|
|
|
28358
28827
|
const name = pad(truncate(acc.emailOrName, emailWidth - 1), emailWidth);
|
|
28359
28828
|
const active = acc.activeStreams || 0;
|
|
28360
28829
|
const limit = acc.streamLimit || 1;
|
|
28361
|
-
const
|
|
28830
|
+
const usagePct = acc.dailyUsagePercent ?? 0;
|
|
28831
|
+
let loadBadge;
|
|
28832
|
+
if (active > 0) {
|
|
28833
|
+
loadBadge = theme.yellow(`[${active}/${limit}]`);
|
|
28834
|
+
} else if (!showUsageCol && usagePct > 0) {
|
|
28835
|
+
const pctColor = usagePct >= 80 ? theme.red : usagePct >= 40 ? theme.yellow : theme.cyan;
|
|
28836
|
+
loadBadge = pctColor(pad(`[${usagePct}%]`, 5));
|
|
28837
|
+
} else {
|
|
28838
|
+
loadBadge = theme.dim(`[0/${limit}]`);
|
|
28839
|
+
}
|
|
28840
|
+
const usageCol = showUsageCol ? (usagePct > 0 ? usagePct >= 80 ? theme.red(pad(`${usagePct}%`, 5)) : usagePct >= 40 ? theme.yellow(pad(`${usagePct}%`, 5)) : theme.cyan(pad(`${usagePct}%`, 5)) : theme.dim(pad("0%", 5))) + " " : "";
|
|
28362
28841
|
let status = theme.green(`${glyphs.bullet} Pronto`);
|
|
28363
28842
|
if (active > 0 && !acc.onCooldown && acc.headersReady) {
|
|
28364
28843
|
status = theme.yellow(`\u25CF Gerando `);
|
|
@@ -28375,7 +28854,7 @@ var init_status_view = __esm({
|
|
|
28375
28854
|
} else if (!acc.headersReady) {
|
|
28376
28855
|
status = acc.isInitialized ? theme.yellow(`\u25D0 Aquecendo...`) : theme.muted(`\u25CB Standby`);
|
|
28377
28856
|
}
|
|
28378
|
-
rightContent.push(` ${num}${name} ${loadBadge} ${status}`);
|
|
28857
|
+
rightContent.push(` ${num}${name} ${loadBadge} ${usageCol}${status}`);
|
|
28379
28858
|
});
|
|
28380
28859
|
}
|
|
28381
28860
|
const summaryParts = [];
|
|
@@ -32757,6 +33236,7 @@ var init_accounts_view = __esm({
|
|
|
32757
33236
|
init_accounts();
|
|
32758
33237
|
init_server_manager();
|
|
32759
33238
|
init_config();
|
|
33239
|
+
init_status_view();
|
|
32760
33240
|
AccountsView = class {
|
|
32761
33241
|
id = "accounts";
|
|
32762
33242
|
title = "Contas";
|
|
@@ -33522,9 +34002,11 @@ var init_accounts_view = __esm({
|
|
|
33522
34002
|
if (this.selectedIndex >= accounts.length && accounts.length > 0) {
|
|
33523
34003
|
this.selectedIndex = accounts.length - 1;
|
|
33524
34004
|
}
|
|
34005
|
+
const showUsageCol = leftW >= 48;
|
|
34006
|
+
const headerUsage = showUsageCol ? "Uso% " : "";
|
|
33525
34007
|
const leftContent = [
|
|
33526
34008
|
"",
|
|
33527
|
-
` ${theme.dim(
|
|
34009
|
+
` ${theme.dim(`# Conta ${headerUsage}Status`)}`,
|
|
33528
34010
|
` ${theme.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}`
|
|
33529
34011
|
];
|
|
33530
34012
|
if (accounts.length === 0) {
|
|
@@ -33569,7 +34051,9 @@ var init_accounts_view = __esm({
|
|
|
33569
34051
|
} else if (!acc.headersReady) {
|
|
33570
34052
|
status = acc.isInitialized ? theme.yellow(`\u25D0 Aquecendo...`) : theme.muted(`\u25CB Standby `);
|
|
33571
34053
|
}
|
|
33572
|
-
const
|
|
34054
|
+
const usagePct = acc.dailyUsagePercent ?? 0;
|
|
34055
|
+
const usagePctStr = showUsageCol ? (usagePct > 0 ? usagePct >= 80 ? theme.red(pad(`${usagePct}%`, 5)) : usagePct >= 40 ? theme.yellow(pad(`${usagePct}%`, 5)) : theme.cyan(pad(`${usagePct}%`, 5)) : theme.dim(pad("0%", 5))) + " " : "";
|
|
34056
|
+
const line = `${pointer}${num}${name}${usagePctStr}${status}`;
|
|
33573
34057
|
if (isHovered) {
|
|
33574
34058
|
leftContent.push(theme.bgHover(line));
|
|
33575
34059
|
} else if (isFocused) {
|
|
@@ -33610,6 +34094,12 @@ var init_accounts_view = __esm({
|
|
|
33610
34094
|
rightContent.push(` ${theme.bold("Conta:")} ${theme.cyan(email)}`);
|
|
33611
34095
|
rightContent.push(` ${theme.bold("Sistema ID:")} ${theme.muted(selected.id.slice(0, 14))}`);
|
|
33612
34096
|
rightContent.push(` ${theme.bold("N\xEDvel:")} ${selected.priority}`);
|
|
34097
|
+
const usagePct = selected.dailyUsagePercent ?? 0;
|
|
34098
|
+
const usageTokens = selected.dailyTokens ?? 0;
|
|
34099
|
+
const usageTurns = selected.dailyTurns ?? 0;
|
|
34100
|
+
const usageColor = usagePct >= 80 ? theme.red : usagePct >= 40 ? theme.yellow : theme.cyan;
|
|
34101
|
+
const usageBar = renderProgressBar(usagePct, 6, usageColor);
|
|
34102
|
+
rightContent.push(` ${theme.bold("Cota Hoje:")} [${usageBar}] ${usageColor(`${usagePct}%`)} ${theme.dim(`(~${Math.round(usageTokens / 1e3)}k / ${usageTurns} reqs)`)}`);
|
|
33613
34103
|
const cdStatus = selected.onCooldown ? theme.yellow(`[!] Cooldown ${Math.round(selected.remainingCooldownMs / 6e4)}m`) : theme.green(`${glyphs.check} Dispon\xEDvel`);
|
|
33614
34104
|
rightContent.push(` ${theme.bold("Estado:")} ${cdStatus}`);
|
|
33615
34105
|
const hStatus = selected.headersReady ? theme.green(`${glyphs.check} Capturados`) : selected.isInitialized ? theme.yellow(`\u25D0 Aquecendo...`) : theme.muted(`${glyphs.circle} Standby (Sob Demanda)`);
|
|
@@ -34418,6 +34908,7 @@ var init_app = __esm({
|
|
|
34418
34908
|
|
|
34419
34909
|
// src/index.ts
|
|
34420
34910
|
init_paths();
|
|
34911
|
+
init_process_guard();
|
|
34421
34912
|
init_server();
|
|
34422
34913
|
import dotenv2 from "dotenv";
|
|
34423
34914
|
import fs26 from "node:fs";
|
|
@@ -34433,24 +34924,7 @@ if (fs26.existsSync(envPath)) {
|
|
|
34433
34924
|
} else {
|
|
34434
34925
|
dotenv2.config({ quiet: true });
|
|
34435
34926
|
}
|
|
34436
|
-
|
|
34437
|
-
const { isPlaywrightAlreadyClosedError: isPlaywrightAlreadyClosedError2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
34438
|
-
if (isPlaywrightAlreadyClosedError2(error)) {
|
|
34439
|
-
const msg = error instanceof Error ? error.message : typeof error === "object" && error !== null && "message" in error ? String(error.message) : String(error);
|
|
34440
|
-
console.warn(`\u26A0\uFE0F [Playwright] Handled benign driver teardown exception: ${msg}`);
|
|
34441
|
-
return;
|
|
34442
|
-
}
|
|
34443
|
-
console.error("\u274C [Process] Uncaught Exception:", error);
|
|
34444
|
-
});
|
|
34445
|
-
process.on("unhandledRejection", async (reason) => {
|
|
34446
|
-
const { isPlaywrightAlreadyClosedError: isPlaywrightAlreadyClosedError2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
34447
|
-
if (isPlaywrightAlreadyClosedError2(reason)) {
|
|
34448
|
-
const msg = reason instanceof Error ? reason.message : typeof reason === "object" && reason !== null && "message" in reason ? String(reason.message) : String(reason);
|
|
34449
|
-
console.warn(`\u26A0\uFE0F [Playwright] Handled benign driver teardown rejection: ${msg}`);
|
|
34450
|
-
return;
|
|
34451
|
-
}
|
|
34452
|
-
console.error("\u274C [Process] Unhandled Rejection:", reason);
|
|
34453
|
-
});
|
|
34927
|
+
installProcessTeardownGuards("Playwright");
|
|
34454
34928
|
var isTui = process.argv.includes("--tui") || process.env.QWEN_TUI === "true";
|
|
34455
34929
|
if (isTui) {
|
|
34456
34930
|
const { TuiApp: TuiApp2 } = await Promise.resolve().then(() => (init_app(), app_exports));
|