qwenproxy-cli 1.5.2 → 1.5.3
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/delete-chats.js +48 -3
- package/dist/index.js +52 -7
- package/package.json +1 -1
- package/src/core/version.ts +1 -1
- package/src/routes/chat/account.ts +10 -5
- package/src/services/qwen.ts +65 -7
package/dist/delete-chats.js
CHANGED
|
@@ -9567,9 +9567,13 @@ function parseQwenJsonError(raw, status, accountId) {
|
|
|
9567
9567
|
}
|
|
9568
9568
|
if (errorJson?.success === false) {
|
|
9569
9569
|
const code = errorJson.data?.code || errorJson.code || "UpstreamError";
|
|
9570
|
-
|
|
9570
|
+
const detailsStr = typeof details === "string" ? details : "";
|
|
9571
|
+
const codeStr = String(code).toLowerCase();
|
|
9572
|
+
const detailsLower = detailsStr.toLowerCase();
|
|
9573
|
+
const isAuthExpired = status === 401 || codeStr.includes("unauthorized") || detailsLower.includes("token has expired") || detailsLower.includes("log in") || detailsLower.includes("login") || detailsLower.includes("session") || detailsLower.includes("n\xE3o autorizado") || detailsLower.includes("unauthorized");
|
|
9574
|
+
if (isAuthExpired) {
|
|
9571
9575
|
return new QwenSessionExpiredError(
|
|
9572
|
-
`Session expired: ${
|
|
9576
|
+
`Session expired: ${detailsStr || codeStr}`,
|
|
9573
9577
|
accountId || "global"
|
|
9574
9578
|
);
|
|
9575
9579
|
}
|
|
@@ -10108,8 +10112,24 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
10108
10112
|
)
|
|
10109
10113
|
);
|
|
10110
10114
|
}
|
|
10115
|
+
const parsedJsonErr = parseQwenJsonError(errText, response.status, accountId);
|
|
10116
|
+
if (parsedJsonErr instanceof QwenSessionExpiredError && accountId && !retriedNonSseResponse) {
|
|
10117
|
+
retriedNonSseResponse = true;
|
|
10118
|
+
logger.warn(
|
|
10119
|
+
"[Qwen] Token expired on completion fetch (200 JSON); refreshing session and retrying",
|
|
10120
|
+
{ accountId, chatId: chatSessionId ?? "new" }
|
|
10121
|
+
);
|
|
10122
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
10123
|
+
const refreshed = await refreshAccountToken2(accountId);
|
|
10124
|
+
if (refreshed.success) {
|
|
10125
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
10126
|
+
activeHeaders = fresh.headers;
|
|
10127
|
+
response = await fetchCompletion(activeHeaders);
|
|
10128
|
+
continue;
|
|
10129
|
+
}
|
|
10130
|
+
}
|
|
10111
10131
|
throw withCreatedChatMetadata(
|
|
10112
|
-
|
|
10132
|
+
parsedJsonErr ?? new QwenUpstreamError(
|
|
10113
10133
|
`Qwen returned non-stream JSON response: ${errText.substring(0, 300)}`,
|
|
10114
10134
|
"NonStreamJsonResponse",
|
|
10115
10135
|
502
|
|
@@ -10160,6 +10180,31 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
10160
10180
|
response.status,
|
|
10161
10181
|
accountId
|
|
10162
10182
|
);
|
|
10183
|
+
if (parsedError instanceof QwenSessionExpiredError && accountId && !retriedNonSseResponse) {
|
|
10184
|
+
retriedNonSseResponse = true;
|
|
10185
|
+
logger.warn(
|
|
10186
|
+
"[Qwen] Token expired on completion fetch (!response.ok); refreshing session and retrying",
|
|
10187
|
+
{ accountId, chatId: chatSessionId ?? "new", status: response.status }
|
|
10188
|
+
);
|
|
10189
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
10190
|
+
const refreshed = await refreshAccountToken2(accountId);
|
|
10191
|
+
if (refreshed.success) {
|
|
10192
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
10193
|
+
activeHeaders = fresh.headers;
|
|
10194
|
+
response = await fetchCompletion(activeHeaders);
|
|
10195
|
+
if (response.ok && response.body) {
|
|
10196
|
+
return {
|
|
10197
|
+
stream: wrapUpstreamStream(response.body, controller),
|
|
10198
|
+
headers: activeHeaders,
|
|
10199
|
+
uiSessionId: chatSessionId || "",
|
|
10200
|
+
controller,
|
|
10201
|
+
accountId: accountId ?? "global",
|
|
10202
|
+
createdNewChat,
|
|
10203
|
+
tokenEstimationContext
|
|
10204
|
+
};
|
|
10205
|
+
}
|
|
10206
|
+
}
|
|
10207
|
+
}
|
|
10163
10208
|
if (parsedError) {
|
|
10164
10209
|
throw withCreatedChatMetadata(parsedError);
|
|
10165
10210
|
}
|
package/dist/index.js
CHANGED
|
@@ -12736,9 +12736,13 @@ function parseQwenJsonError(raw, status, accountId) {
|
|
|
12736
12736
|
}
|
|
12737
12737
|
if (errorJson?.success === false) {
|
|
12738
12738
|
const code = errorJson.data?.code || errorJson.code || "UpstreamError";
|
|
12739
|
-
|
|
12739
|
+
const detailsStr = typeof details === "string" ? details : "";
|
|
12740
|
+
const codeStr = String(code).toLowerCase();
|
|
12741
|
+
const detailsLower = detailsStr.toLowerCase();
|
|
12742
|
+
const isAuthExpired = status === 401 || codeStr.includes("unauthorized") || detailsLower.includes("token has expired") || detailsLower.includes("log in") || detailsLower.includes("login") || detailsLower.includes("session") || detailsLower.includes("n\xE3o autorizado") || detailsLower.includes("unauthorized");
|
|
12743
|
+
if (isAuthExpired) {
|
|
12740
12744
|
return new QwenSessionExpiredError(
|
|
12741
|
-
`Session expired: ${
|
|
12745
|
+
`Session expired: ${detailsStr || codeStr}`,
|
|
12742
12746
|
accountId || "global"
|
|
12743
12747
|
);
|
|
12744
12748
|
}
|
|
@@ -13277,8 +13281,24 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
13277
13281
|
)
|
|
13278
13282
|
);
|
|
13279
13283
|
}
|
|
13284
|
+
const parsedJsonErr = parseQwenJsonError(errText, response.status, accountId);
|
|
13285
|
+
if (parsedJsonErr instanceof QwenSessionExpiredError && accountId && !retriedNonSseResponse) {
|
|
13286
|
+
retriedNonSseResponse = true;
|
|
13287
|
+
logger.warn(
|
|
13288
|
+
"[Qwen] Token expired on completion fetch (200 JSON); refreshing session and retrying",
|
|
13289
|
+
{ accountId, chatId: chatSessionId ?? "new" }
|
|
13290
|
+
);
|
|
13291
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
13292
|
+
const refreshed = await refreshAccountToken2(accountId);
|
|
13293
|
+
if (refreshed.success) {
|
|
13294
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
13295
|
+
activeHeaders = fresh.headers;
|
|
13296
|
+
response = await fetchCompletion(activeHeaders);
|
|
13297
|
+
continue;
|
|
13298
|
+
}
|
|
13299
|
+
}
|
|
13280
13300
|
throw withCreatedChatMetadata(
|
|
13281
|
-
|
|
13301
|
+
parsedJsonErr ?? new QwenUpstreamError(
|
|
13282
13302
|
`Qwen returned non-stream JSON response: ${errText.substring(0, 300)}`,
|
|
13283
13303
|
"NonStreamJsonResponse",
|
|
13284
13304
|
502
|
|
@@ -13329,6 +13349,31 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
13329
13349
|
response.status,
|
|
13330
13350
|
accountId
|
|
13331
13351
|
);
|
|
13352
|
+
if (parsedError instanceof QwenSessionExpiredError && accountId && !retriedNonSseResponse) {
|
|
13353
|
+
retriedNonSseResponse = true;
|
|
13354
|
+
logger.warn(
|
|
13355
|
+
"[Qwen] Token expired on completion fetch (!response.ok); refreshing session and retrying",
|
|
13356
|
+
{ accountId, chatId: chatSessionId ?? "new", status: response.status }
|
|
13357
|
+
);
|
|
13358
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
13359
|
+
const refreshed = await refreshAccountToken2(accountId);
|
|
13360
|
+
if (refreshed.success) {
|
|
13361
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
13362
|
+
activeHeaders = fresh.headers;
|
|
13363
|
+
response = await fetchCompletion(activeHeaders);
|
|
13364
|
+
if (response.ok && response.body) {
|
|
13365
|
+
return {
|
|
13366
|
+
stream: wrapUpstreamStream(response.body, controller),
|
|
13367
|
+
headers: activeHeaders,
|
|
13368
|
+
uiSessionId: chatSessionId || "",
|
|
13369
|
+
controller,
|
|
13370
|
+
accountId: accountId ?? "global",
|
|
13371
|
+
createdNewChat,
|
|
13372
|
+
tokenEstimationContext
|
|
13373
|
+
};
|
|
13374
|
+
}
|
|
13375
|
+
}
|
|
13376
|
+
}
|
|
13332
13377
|
if (parsedError) {
|
|
13333
13378
|
throw withCreatedChatMetadata(parsedError);
|
|
13334
13379
|
}
|
|
@@ -17106,16 +17151,16 @@ ${loopReminder}` : truncation.prompt;
|
|
|
17106
17151
|
error: new Error("Failed to create Qwen stream")
|
|
17107
17152
|
};
|
|
17108
17153
|
}
|
|
17109
|
-
|
|
17154
|
+
const isSessionExpired = err instanceof QwenSessionExpiredError || err?.name === "QwenSessionExpiredError" || err instanceof Error && (err.message.toLowerCase().includes("token has expired") || err.message.toLowerCase().includes("session expired") || err.message.toLowerCase().includes("401 n\xE3o autorizado") || err.message.toLowerCase().includes("unauthorized"));
|
|
17155
|
+
if (isSessionExpired) {
|
|
17110
17156
|
console.warn(
|
|
17111
|
-
`\u{1F504} [Chat] Session expired for ${currentAccountEmail} (${currentAccountId}). Attempting re-login...`
|
|
17157
|
+
`\u{1F504} [Chat] Session expired for ${currentAccountEmail} (${currentAccountId}). Attempting silent token refresh/re-login...`
|
|
17112
17158
|
);
|
|
17113
17159
|
const reLoginOk = await attemptRelogin(
|
|
17114
17160
|
currentAccountId,
|
|
17115
17161
|
currentAccountEmail
|
|
17116
17162
|
);
|
|
17117
17163
|
if (reLoginOk) continue;
|
|
17118
|
-
return { success: false, error: err };
|
|
17119
17164
|
}
|
|
17120
17165
|
if (isAccountUnavailableError(err)) {
|
|
17121
17166
|
const quotaMsg = err.message || "Unknown quota error";
|
|
@@ -25891,7 +25936,7 @@ function getAppVersion() {
|
|
|
25891
25936
|
}
|
|
25892
25937
|
} catch {
|
|
25893
25938
|
}
|
|
25894
|
-
cachedVersion = "v1.5.
|
|
25939
|
+
cachedVersion = "v1.5.3";
|
|
25895
25940
|
return cachedVersion;
|
|
25896
25941
|
}
|
|
25897
25942
|
var cachedVersion;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwenproxy-cli",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.3",
|
|
4
4
|
"description": "High-performance OpenAI & Anthropic compatible API gateway for Qwen with multi-account rotation, interactive TUI, and resilient tool calling.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"bin": {
|
package/src/core/version.ts
CHANGED
|
@@ -1487,19 +1487,24 @@ async function tryCreateStreamWithRetry(
|
|
|
1487
1487
|
};
|
|
1488
1488
|
}
|
|
1489
1489
|
|
|
1490
|
-
|
|
1490
|
+
const isSessionExpired =
|
|
1491
1491
|
err instanceof QwenSessionExpiredError ||
|
|
1492
|
-
err
|
|
1493
|
-
|
|
1492
|
+
err?.name === "QwenSessionExpiredError" ||
|
|
1493
|
+
(err instanceof Error &&
|
|
1494
|
+
(err.message.toLowerCase().includes("token has expired") ||
|
|
1495
|
+
err.message.toLowerCase().includes("session expired") ||
|
|
1496
|
+
err.message.toLowerCase().includes("401 não autorizado") ||
|
|
1497
|
+
err.message.toLowerCase().includes("unauthorized")));
|
|
1498
|
+
|
|
1499
|
+
if (isSessionExpired) {
|
|
1494
1500
|
console.warn(
|
|
1495
|
-
`🔄 [Chat] Session expired for ${currentAccountEmail} (${currentAccountId}). Attempting re-login...`,
|
|
1501
|
+
`🔄 [Chat] Session expired for ${currentAccountEmail} (${currentAccountId}). Attempting silent token refresh/re-login...`,
|
|
1496
1502
|
);
|
|
1497
1503
|
const reLoginOk = await attemptRelogin(
|
|
1498
1504
|
currentAccountId,
|
|
1499
1505
|
currentAccountEmail,
|
|
1500
1506
|
);
|
|
1501
1507
|
if (reLoginOk) continue;
|
|
1502
|
-
return { success: false, error: err };
|
|
1503
1508
|
}
|
|
1504
1509
|
|
|
1505
1510
|
|
package/src/services/qwen.ts
CHANGED
|
@@ -2502,15 +2502,23 @@ function parseQwenJsonError(
|
|
|
2502
2502
|
|
|
2503
2503
|
if (errorJson?.success === false) {
|
|
2504
2504
|
const code = errorJson.data?.code || errorJson.code || "UpstreamError";
|
|
2505
|
+
const detailsStr = typeof details === "string" ? details : "";
|
|
2506
|
+
const codeStr = String(code).toLowerCase();
|
|
2507
|
+
const detailsLower = detailsStr.toLowerCase();
|
|
2505
2508
|
|
|
2506
|
-
|
|
2509
|
+
const isAuthExpired =
|
|
2507
2510
|
status === 401 ||
|
|
2508
|
-
|
|
2509
|
-
(
|
|
2510
|
-
|
|
2511
|
-
|
|
2511
|
+
codeStr.includes("unauthorized") ||
|
|
2512
|
+
detailsLower.includes("token has expired") ||
|
|
2513
|
+
detailsLower.includes("log in") ||
|
|
2514
|
+
detailsLower.includes("login") ||
|
|
2515
|
+
detailsLower.includes("session") ||
|
|
2516
|
+
detailsLower.includes("não autorizado") ||
|
|
2517
|
+
detailsLower.includes("unauthorized");
|
|
2518
|
+
|
|
2519
|
+
if (isAuthExpired) {
|
|
2512
2520
|
return new QwenSessionExpiredError(
|
|
2513
|
-
`Session expired: ${
|
|
2521
|
+
`Session expired: ${detailsStr || codeStr}`,
|
|
2514
2522
|
accountId || "global",
|
|
2515
2523
|
);
|
|
2516
2524
|
}
|
|
@@ -3301,8 +3309,29 @@ async function createQwenStreamInternal(
|
|
|
3301
3309
|
);
|
|
3302
3310
|
}
|
|
3303
3311
|
|
|
3312
|
+
const parsedJsonErr = parseQwenJsonError(errText, response.status, accountId);
|
|
3313
|
+
if (
|
|
3314
|
+
parsedJsonErr instanceof QwenSessionExpiredError &&
|
|
3315
|
+
accountId &&
|
|
3316
|
+
!retriedNonSseResponse
|
|
3317
|
+
) {
|
|
3318
|
+
retriedNonSseResponse = true;
|
|
3319
|
+
logger.warn(
|
|
3320
|
+
"[Qwen] Token expired on completion fetch (200 JSON); refreshing session and retrying",
|
|
3321
|
+
{ accountId, chatId: chatSessionId ?? "new" },
|
|
3322
|
+
);
|
|
3323
|
+
const { refreshAccountToken } = await import("./playwright.ts");
|
|
3324
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
3325
|
+
if (refreshed.success) {
|
|
3326
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
3327
|
+
activeHeaders = fresh.headers;
|
|
3328
|
+
response = await fetchCompletion(activeHeaders);
|
|
3329
|
+
continue;
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
|
|
3304
3333
|
throw withCreatedChatMetadata(
|
|
3305
|
-
|
|
3334
|
+
parsedJsonErr ??
|
|
3306
3335
|
new QwenUpstreamError(
|
|
3307
3336
|
`Qwen returned non-stream JSON response: ${errText.substring(0, 300)}`,
|
|
3308
3337
|
"NonStreamJsonResponse",
|
|
@@ -3378,6 +3407,35 @@ async function createQwenStreamInternal(
|
|
|
3378
3407
|
response.status,
|
|
3379
3408
|
accountId,
|
|
3380
3409
|
);
|
|
3410
|
+
if (
|
|
3411
|
+
parsedError instanceof QwenSessionExpiredError &&
|
|
3412
|
+
accountId &&
|
|
3413
|
+
!retriedNonSseResponse
|
|
3414
|
+
) {
|
|
3415
|
+
retriedNonSseResponse = true;
|
|
3416
|
+
logger.warn(
|
|
3417
|
+
"[Qwen] Token expired on completion fetch (!response.ok); refreshing session and retrying",
|
|
3418
|
+
{ accountId, chatId: chatSessionId ?? "new", status: response.status },
|
|
3419
|
+
);
|
|
3420
|
+
const { refreshAccountToken } = await import("./playwright.ts");
|
|
3421
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
3422
|
+
if (refreshed.success) {
|
|
3423
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
3424
|
+
activeHeaders = fresh.headers;
|
|
3425
|
+
response = await fetchCompletion(activeHeaders);
|
|
3426
|
+
if (response.ok && response.body) {
|
|
3427
|
+
return {
|
|
3428
|
+
stream: wrapUpstreamStream(response.body, controller),
|
|
3429
|
+
headers: activeHeaders,
|
|
3430
|
+
uiSessionId: chatSessionId || "",
|
|
3431
|
+
controller,
|
|
3432
|
+
accountId: accountId ?? "global",
|
|
3433
|
+
createdNewChat,
|
|
3434
|
+
tokenEstimationContext,
|
|
3435
|
+
};
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3381
3439
|
if (parsedError) {
|
|
3382
3440
|
throw withCreatedChatMetadata(parsedError);
|
|
3383
3441
|
}
|