qwenproxy-cli 1.4.8 → 1.5.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 +59 -44
- package/dist/delete-chats.js +88 -50
- package/dist/index.js +178 -111
- package/dist/login.js +43 -44
- package/dist/reset-cooldowns.js +46 -44
- package/package.json +3 -3
- package/src/core/account-manager.ts +9 -0
- package/src/core/server-log-buffer.ts +10 -3
- package/src/core/version.ts +1 -1
- package/src/routes/chat/account.ts +22 -10
- package/src/routes/chat/helpers.ts +29 -1
- package/src/routes/chat/retry-policy.ts +5 -5
- package/src/routes/chat/streaming.ts +13 -6
- package/src/routes/upload.ts +19 -14
- package/src/services/playwright.ts +40 -49
- package/src/services/qwen-chat-pool.ts +10 -6
- package/src/services/qwen-headers.ts +2 -1
- package/src/services/qwen.ts +22 -5
- package/src/tools/instructions.ts +38 -25
- package/src/tools/parser.ts +7 -0
package/dist/index.js
CHANGED
|
@@ -2986,7 +2986,15 @@ function defaultCooldownDurationMs() {
|
|
|
2986
2986
|
return computeQuotaCooldownMs(Date.now());
|
|
2987
2987
|
}
|
|
2988
2988
|
function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
|
|
2989
|
+
if (cooldownMs !== void 0 && cooldownMs <= 0) {
|
|
2990
|
+
clearAccountCooldown(accountId);
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2989
2993
|
const duration = cooldownMs ?? defaultCooldownDurationMs();
|
|
2994
|
+
if (duration <= 0) {
|
|
2995
|
+
clearAccountCooldown(accountId);
|
|
2996
|
+
return;
|
|
2997
|
+
}
|
|
2990
2998
|
const until = Date.now() + duration;
|
|
2991
2999
|
const cooldownReason = reason ?? "RateLimited";
|
|
2992
3000
|
cooldowns.set(accountId, {
|
|
@@ -3986,7 +3994,8 @@ function buildQwenRequestHeaders(opts) {
|
|
|
3986
3994
|
"bx-v": opts.bxV || "2.5.37",
|
|
3987
3995
|
source: "web",
|
|
3988
3996
|
version: opts.version || getQwenWebVersion(),
|
|
3989
|
-
timezone: opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
3997
|
+
timezone: opts.extra?.timezone || opts.extra?.Timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
3998
|
+
Timezone: opts.extra?.Timezone || opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
3990
3999
|
// Use the real browser client-hints when captured (anti-hardcoded); fall
|
|
3991
4000
|
// back to the static fingerprint otherwise.
|
|
3992
4001
|
"sec-ch-ua": opts.secChUa || `"Google Chrome";v="${getChromeMajor()}", "Chromium";v="${getChromeMajor()}", "Not.A/Brand";v="99"`,
|
|
@@ -4528,26 +4537,6 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
4528
4537
|
}
|
|
4529
4538
|
} catch {
|
|
4530
4539
|
}
|
|
4531
|
-
try {
|
|
4532
|
-
const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
4533
|
-
method: "GET",
|
|
4534
|
-
credentials: "include",
|
|
4535
|
-
signal: AbortSignal.timeout(3e3)
|
|
4536
|
-
});
|
|
4537
|
-
if (refreshRes.status === 200) {
|
|
4538
|
-
const refreshJson = await refreshRes.json().catch(() => null);
|
|
4539
|
-
if (refreshJson && refreshJson.success === false) {
|
|
4540
|
-
const code = refreshJson.data?.code || refreshJson.code;
|
|
4541
|
-
const details = String(refreshJson.data?.details || "");
|
|
4542
|
-
if (code === "Unauthorized" || details.includes("revogado") || details.includes("revoked")) {
|
|
4543
|
-
return false;
|
|
4544
|
-
}
|
|
4545
|
-
}
|
|
4546
|
-
} else if (refreshRes.status === 401 || refreshRes.status === 403) {
|
|
4547
|
-
return false;
|
|
4548
|
-
}
|
|
4549
|
-
} catch {
|
|
4550
|
-
}
|
|
4551
4540
|
return true;
|
|
4552
4541
|
} catch {
|
|
4553
4542
|
return false;
|
|
@@ -5675,7 +5664,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
5675
5664
|
`\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
|
|
5676
5665
|
);
|
|
5677
5666
|
}
|
|
5678
|
-
if (!options.skipHeaderCapture) {
|
|
5667
|
+
if (!options.skipHeaderCapture && !isAccountHeadersReady(account.id)) {
|
|
5679
5668
|
acctPage.__qwenChatHomeLoaded = true;
|
|
5680
5669
|
await captureQwenHeaders(account.id);
|
|
5681
5670
|
}
|
|
@@ -6005,7 +5994,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
6005
5994
|
);
|
|
6006
5995
|
markAccountRateLimited(
|
|
6007
5996
|
accountId,
|
|
6008
|
-
|
|
5997
|
+
300 * 1e3,
|
|
6009
5998
|
"AuthFailed: All login methods exhausted"
|
|
6010
5999
|
);
|
|
6011
6000
|
return false;
|
|
@@ -6282,38 +6271,49 @@ async function loginViaUi(page, email, password) {
|
|
|
6282
6271
|
try {
|
|
6283
6272
|
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
6284
6273
|
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6274
|
+
const setReactValue = (el, val) => {
|
|
6275
|
+
const proto = Object.getPrototypeOf(el);
|
|
6276
|
+
const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
|
|
6277
|
+
if (setter) {
|
|
6278
|
+
setter.call(el, val);
|
|
6279
|
+
} else {
|
|
6280
|
+
el.value = val;
|
|
6281
|
+
}
|
|
6282
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
6283
|
+
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6284
|
+
el.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
6285
|
+
};
|
|
6286
|
+
if (emailEl) setReactValue(emailEl, emailEl.value);
|
|
6287
|
+
if (passEl) setReactValue(passEl, passEl.value);
|
|
6295
6288
|
} catch {
|
|
6296
6289
|
}
|
|
6297
6290
|
}).catch(() => {
|
|
6298
6291
|
});
|
|
6292
|
+
await sleep2(500);
|
|
6299
6293
|
const submitSelector = 'button.qwenchat-auth-pc-submit-button, button[type="submit"], button:has-text("Log in"), button:has-text("Sign in"), button:has-text("Fazer login"), button:has-text("Entrar"), button:has-text("Iniciar sesi\xF3n"), button:has-text("\u767B\u5F55")';
|
|
6300
6294
|
const submitButton = page.locator(submitSelector).first();
|
|
6295
|
+
await page.evaluate((sel) => {
|
|
6296
|
+
try {
|
|
6297
|
+
const btn = document.querySelector(sel);
|
|
6298
|
+
if (btn) {
|
|
6299
|
+
btn.removeAttribute("disabled");
|
|
6300
|
+
btn.classList.remove("ant-btn-disabled");
|
|
6301
|
+
btn.click();
|
|
6302
|
+
}
|
|
6303
|
+
} catch {
|
|
6304
|
+
}
|
|
6305
|
+
}, submitSelector).catch(() => {
|
|
6306
|
+
});
|
|
6301
6307
|
try {
|
|
6302
|
-
await
|
|
6303
|
-
timeout:
|
|
6304
|
-
});
|
|
6305
|
-
await submitButton.click();
|
|
6306
|
-
} catch {
|
|
6307
|
-
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
6308
|
-
if (!isDisabled) {
|
|
6309
|
-
await submitButton.click({ force: true }).catch(() => {
|
|
6308
|
+
if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
|
|
6309
|
+
await submitButton.click({ force: true, timeout: 2e3 }).catch(() => {
|
|
6310
6310
|
});
|
|
6311
|
-
} else {
|
|
6312
|
-
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
6313
|
-
return { success: true };
|
|
6314
|
-
}
|
|
6315
6311
|
}
|
|
6312
|
+
} catch {
|
|
6316
6313
|
}
|
|
6314
|
+
const passInput = page.locator(passwordSelector).first();
|
|
6315
|
+
await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
|
|
6316
|
+
});
|
|
6317
6317
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
6318
6318
|
while (Date.now() < postSubmitDeadline) {
|
|
6319
6319
|
if (page.isClosed()) break;
|
|
@@ -9087,8 +9087,11 @@ ${thought}`);
|
|
|
9087
9087
|
}
|
|
9088
9088
|
return sections.join("\n\n");
|
|
9089
9089
|
}
|
|
9090
|
+
function isAnswerPhase(phase) {
|
|
9091
|
+
return typeof phase === "string" && ANSWER_PHASES.has(phase);
|
|
9092
|
+
}
|
|
9090
9093
|
function isThinkingPhase(phase) {
|
|
9091
|
-
return phase === "
|
|
9094
|
+
return typeof phase === "string" && THINKING_PHASES.has(phase);
|
|
9092
9095
|
}
|
|
9093
9096
|
function extractThinkingContent(delta) {
|
|
9094
9097
|
if (Array.isArray(delta?.extra?.summary_title?.content) || Array.isArray(delta?.extra?.summary_thought?.content)) {
|
|
@@ -9179,9 +9182,25 @@ function buildUsage(accumulator) {
|
|
|
9179
9182
|
}
|
|
9180
9183
|
return usage;
|
|
9181
9184
|
}
|
|
9185
|
+
var ANSWER_PHASES, THINKING_PHASES;
|
|
9182
9186
|
var init_helpers = __esm({
|
|
9183
9187
|
"src/routes/chat/helpers.ts"() {
|
|
9184
9188
|
"use strict";
|
|
9189
|
+
ANSWER_PHASES = /* @__PURE__ */ new Set([
|
|
9190
|
+
"answer",
|
|
9191
|
+
"deep_research_answer",
|
|
9192
|
+
"ReportGeneration",
|
|
9193
|
+
"PdfMdGen",
|
|
9194
|
+
"image",
|
|
9195
|
+
"image_generation",
|
|
9196
|
+
"image_gen",
|
|
9197
|
+
"t2i"
|
|
9198
|
+
]);
|
|
9199
|
+
THINKING_PHASES = /* @__PURE__ */ new Set([
|
|
9200
|
+
"think",
|
|
9201
|
+
"thinking_summary",
|
|
9202
|
+
"DeepThinking"
|
|
9203
|
+
]);
|
|
9185
9204
|
}
|
|
9186
9205
|
});
|
|
9187
9206
|
|
|
@@ -9355,7 +9374,7 @@ function classifyRetryAction(err, options) {
|
|
|
9355
9374
|
switchAccount: true,
|
|
9356
9375
|
forceNewChat: true,
|
|
9357
9376
|
retryAfterMs: baseDelayMs,
|
|
9358
|
-
accountCooldownMs:
|
|
9377
|
+
accountCooldownMs: 0,
|
|
9359
9378
|
accountCooldownReason: "PersonalizationFailed"
|
|
9360
9379
|
});
|
|
9361
9380
|
}
|
|
@@ -9365,8 +9384,8 @@ function classifyRetryAction(err, options) {
|
|
|
9365
9384
|
forceNewChat: true,
|
|
9366
9385
|
retryWithFullPrompt: true,
|
|
9367
9386
|
retryAfterMs: Math.min(baseDelayMs, 1e3),
|
|
9368
|
-
accountCooldownMs:
|
|
9369
|
-
accountCooldownReason: "
|
|
9387
|
+
accountCooldownMs: 0,
|
|
9388
|
+
accountCooldownReason: "AuthExpired"
|
|
9370
9389
|
});
|
|
9371
9390
|
}
|
|
9372
9391
|
if (isCorruptedChatHistoryError(err)) {
|
|
@@ -9783,8 +9802,8 @@ async function requestCompletionsInBrowser(params) {
|
|
|
9783
9802
|
const choice = chunk?.choices?.[0];
|
|
9784
9803
|
const delta = choice?.delta;
|
|
9785
9804
|
const phase = delta?.phase;
|
|
9786
|
-
const
|
|
9787
|
-
if (choice?.finish_reason || delta?.status === "finished" &&
|
|
9805
|
+
const isAnswerPhase2 = !phase || phase === "answer";
|
|
9806
|
+
if (choice?.finish_reason || delta?.status === "finished" && isAnswerPhase2) {
|
|
9788
9807
|
finished = true;
|
|
9789
9808
|
break;
|
|
9790
9809
|
}
|
|
@@ -10835,13 +10854,15 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
|
|
|
10835
10854
|
} catch {
|
|
10836
10855
|
}
|
|
10837
10856
|
}
|
|
10838
|
-
|
|
10857
|
+
const isUnauthorized = json?.data?.code?.toLowerCase() === "unauthorized" || json?.code?.toLowerCase() === "unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access") || rawLower.includes("token has expired") || rawLower.includes("401");
|
|
10858
|
+
if (isUnauthorized) {
|
|
10839
10859
|
if (accountId) {
|
|
10840
10860
|
try {
|
|
10841
10861
|
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
10842
10862
|
const refreshed = await refreshAccountToken2(accountId);
|
|
10843
10863
|
if (refreshed.success) {
|
|
10844
|
-
|
|
10864
|
+
const { headers: freshHeaders } = await getQwenHeaders(false, accountId);
|
|
10865
|
+
return createQwenChatSession(freshHeaders, model, accountId, chatMode);
|
|
10845
10866
|
}
|
|
10846
10867
|
} catch {
|
|
10847
10868
|
}
|
|
@@ -12835,8 +12856,18 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
12835
12856
|
);
|
|
12836
12857
|
}
|
|
12837
12858
|
};
|
|
12859
|
+
let forceRefresh = options?.forceNewChat === true;
|
|
12860
|
+
if (!forceRefresh && accountId) {
|
|
12861
|
+
try {
|
|
12862
|
+
const basic = await getBasicHeaders2(accountId);
|
|
12863
|
+
if (isTokenExpiringSoon(basic.cookie, 3)) {
|
|
12864
|
+
forceRefresh = true;
|
|
12865
|
+
}
|
|
12866
|
+
} catch {
|
|
12867
|
+
}
|
|
12868
|
+
}
|
|
12838
12869
|
const captured = await getQwenHeaders(
|
|
12839
|
-
|
|
12870
|
+
forceRefresh,
|
|
12840
12871
|
accountId
|
|
12841
12872
|
);
|
|
12842
12873
|
ensureNotAborted();
|
|
@@ -12850,7 +12881,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
12850
12881
|
if (options && "chatSessionId" in options) {
|
|
12851
12882
|
if (options.chatSessionId === null || options.chatSessionId === "") {
|
|
12852
12883
|
const acquired = await acquireNewQwenChatSession(
|
|
12853
|
-
|
|
12884
|
+
activeHeaders,
|
|
12854
12885
|
model,
|
|
12855
12886
|
accountId,
|
|
12856
12887
|
options?.chatMode ?? "thread"
|
|
@@ -12858,6 +12889,11 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
12858
12889
|
chatSessionId = acquired.chatId;
|
|
12859
12890
|
leasedWarmChat = acquired.leasedFromPool;
|
|
12860
12891
|
createdNewChat = true;
|
|
12892
|
+
try {
|
|
12893
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
12894
|
+
activeHeaders = fresh.headers;
|
|
12895
|
+
} catch {
|
|
12896
|
+
}
|
|
12861
12897
|
} else {
|
|
12862
12898
|
chatSessionId = options.chatSessionId;
|
|
12863
12899
|
}
|
|
@@ -12865,7 +12901,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
12865
12901
|
chatSessionId = captured.chatSessionId;
|
|
12866
12902
|
if (!chatSessionId) {
|
|
12867
12903
|
const acquired = await acquireNewQwenChatSession(
|
|
12868
|
-
|
|
12904
|
+
activeHeaders,
|
|
12869
12905
|
model,
|
|
12870
12906
|
accountId,
|
|
12871
12907
|
options?.chatMode ?? "thread"
|
|
@@ -12873,6 +12909,11 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
12873
12909
|
chatSessionId = acquired.chatId;
|
|
12874
12910
|
leasedWarmChat = acquired.leasedFromPool;
|
|
12875
12911
|
createdNewChat = true;
|
|
12912
|
+
try {
|
|
12913
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
12914
|
+
activeHeaders = fresh.headers;
|
|
12915
|
+
} catch {
|
|
12916
|
+
}
|
|
12876
12917
|
}
|
|
12877
12918
|
}
|
|
12878
12919
|
ensureNotAborted();
|
|
@@ -14031,10 +14072,12 @@ async function getSTSToken(filename, filesize, filetype, headers, accountId) {
|
|
|
14031
14072
|
}
|
|
14032
14073
|
data = await response.json().catch(() => null);
|
|
14033
14074
|
}
|
|
14034
|
-
const
|
|
14075
|
+
const codeLower = (data?.data?.code || data?.code || "").toLowerCase();
|
|
14076
|
+
const detailsLower = (typeof data?.data?.details === "string" ? data.data.details : typeof data?.message === "string" ? data.message : "").toLowerCase();
|
|
14077
|
+
const is401 = data?.success === false && (codeLower === "unauthorized" || detailsLower.includes("401") || detailsLower.includes("token has expired") || detailsLower.includes("unauthorized"));
|
|
14035
14078
|
if (is401) {
|
|
14036
14079
|
try {
|
|
14037
|
-
const {
|
|
14080
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
14038
14081
|
const { getBasicHeaders: getBasicHeaders3 } = await Promise.resolve().then(() => (init_auth_playwright(), auth_playwright_exports));
|
|
14039
14082
|
const { loadAccounts: loadAccounts3 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
14040
14083
|
const resolvedId2 = accountId ?? loadAccounts3()[0]?.id;
|
|
@@ -14042,16 +14085,18 @@ async function getSTSToken(filename, filesize, filetype, headers, accountId) {
|
|
|
14042
14085
|
console.warn(
|
|
14043
14086
|
`[Upload] STS token 401 \u2014 refreshing session with re-auth and retrying...`
|
|
14044
14087
|
);
|
|
14045
|
-
await
|
|
14046
|
-
|
|
14047
|
-
|
|
14048
|
-
|
|
14049
|
-
|
|
14050
|
-
|
|
14051
|
-
|
|
14052
|
-
|
|
14053
|
-
|
|
14054
|
-
|
|
14088
|
+
const refreshResult = await refreshAccountToken2(resolvedId2);
|
|
14089
|
+
if (refreshResult.success) {
|
|
14090
|
+
const fresh = await getBasicHeaders3(resolvedId2);
|
|
14091
|
+
headers.cookie = fresh.cookie;
|
|
14092
|
+
headers["user-agent"] = fresh.userAgent;
|
|
14093
|
+
headers["bx-v"] = fresh.bxV;
|
|
14094
|
+
if (fresh.bxUa) headers["bx-ua"] = fresh.bxUa;
|
|
14095
|
+
if (fresh.bxUmidtoken) headers["bx-umidtoken"] = fresh.bxUmidtoken;
|
|
14096
|
+
const retryRes = await doFetch(headers);
|
|
14097
|
+
if (retryRes.ok) {
|
|
14098
|
+
data = await retryRes.json().catch(() => null);
|
|
14099
|
+
}
|
|
14055
14100
|
}
|
|
14056
14101
|
}
|
|
14057
14102
|
} catch (refreshErr) {
|
|
@@ -14645,12 +14690,12 @@ function buildToolInstructions(toolsJson, toolChoice) {
|
|
|
14645
14690
|
const sampleToolName = typeof firstTool?.function?.name === "string" && firstTool.function.name || typeof firstTool?.name === "string" && firstTool.name || "tool_name";
|
|
14646
14691
|
const properties = firstTool?.function?.parameters?.properties || firstTool?.parameters?.properties;
|
|
14647
14692
|
const firstPropKey = properties && typeof properties === "object" ? Object.keys(properties)[0] : null;
|
|
14648
|
-
|
|
14649
|
-
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
}
|
|
14693
|
+
const sampleArgs1 = firstPropKey ? JSON.stringify({ [firstPropKey]: "value1" }) : "{}";
|
|
14694
|
+
const secondTool = toolList.length > 1 ? toolList[1] : null;
|
|
14695
|
+
const secondToolName = secondTool ? typeof secondTool?.function?.name === "string" && secondTool.function.name || typeof secondTool?.name === "string" && secondTool.name || sampleToolName : null;
|
|
14696
|
+
const secondProperties = secondTool?.function?.parameters?.properties || secondTool?.parameters?.properties;
|
|
14697
|
+
const secondPropKey = secondProperties && typeof secondProperties === "object" ? Object.keys(secondProperties)[0] : null;
|
|
14698
|
+
const sampleArgs2 = secondPropKey ? JSON.stringify({ [secondPropKey]: "value2" }) : "{}";
|
|
14654
14699
|
let forcedInstruction = "";
|
|
14655
14700
|
if (toolChoice && typeof toolChoice === "object" && toolChoice.function?.name) {
|
|
14656
14701
|
forcedInstruction = `
|
|
@@ -14661,32 +14706,30 @@ CRITICAL: You MUST call the tool "${toolChoice.function.name}" in this response.
|
|
|
14661
14706
|
CRITICAL: You MUST call at least one tool from the list above in this response.
|
|
14662
14707
|
`;
|
|
14663
14708
|
}
|
|
14709
|
+
const secondExample = secondToolName ? `
|
|
14710
|
+
${TOOL_CALL_OPEN}
|
|
14711
|
+
{"name": "${secondToolName}", "arguments": ${sampleArgs2}}
|
|
14712
|
+
${TOOL_CALL_CLOSE}` : "";
|
|
14664
14713
|
let instructions = `
|
|
14665
14714
|
|
|
14666
14715
|
# TOOLS AVAILABLE
|
|
14716
|
+
You may call one or more functions to assist with the user query.
|
|
14717
|
+
You are provided with function signatures within <tools></tools> XML tags:
|
|
14718
|
+
<tools>
|
|
14667
14719
|
${manifest}
|
|
14720
|
+
</tools>
|
|
14668
14721
|
${forcedInstruction}
|
|
14669
|
-
[TOOL CALL CONTRACT
|
|
14670
|
-
To
|
|
14671
|
-
When calling multiple independent tools, output consecutive blocks:
|
|
14672
|
-
|
|
14722
|
+
[TOOL CALL CONTRACT]
|
|
14723
|
+
To call a tool, output a JSON object wrapped EXACTLY in ${TOOL_CALL_OPEN} and ${TOOL_CALL_CLOSE} tags:
|
|
14673
14724
|
${TOOL_CALL_OPEN}
|
|
14674
14725
|
{"name": "${sampleToolName}", "arguments": ${sampleArgs1}}
|
|
14675
|
-
${TOOL_CALL_CLOSE}
|
|
14676
|
-
${TOOL_CALL_OPEN}
|
|
14677
|
-
{"name": "${sampleToolName}", "arguments": ${sampleArgs2}}
|
|
14678
|
-
${TOOL_CALL_CLOSE}
|
|
14726
|
+
${TOOL_CALL_CLOSE}${secondExample}
|
|
14679
14727
|
|
|
14680
|
-
|
|
14681
|
-
1.
|
|
14682
|
-
2.
|
|
14683
|
-
3.
|
|
14684
|
-
4.
|
|
14685
|
-
5. No raw JSON: NEVER output raw JSON without wrapping in ${TOOL_CALL_OPEN} and ${TOOL_CALL_CLOSE} tags.
|
|
14686
|
-
6. Clean blocks: Put only valid JSON inside each block \u2014 no markdown fences (\`\`\`json), comments, or explanatory text.
|
|
14687
|
-
7. Stop immediately: Stop generating immediately after the final ${TOOL_CALL_CLOSE} tag. Do not emit trailing dots, ellipsis (......), explanations, or reasoning after the tool calls.
|
|
14688
|
-
8. Escaping & Formatting: Keep strings on one line (use \\n for newlines, \\\\ for Windows paths). Do not split values across lines.
|
|
14689
|
-
9. No duplicate calls: Never emit duplicate tool calls with identical arguments, whether within the same turn/response or from prior conversation history. Every call must perform distinct work.
|
|
14728
|
+
GUIDELINES:
|
|
14729
|
+
1. Tool Selection: The "name" must match a function defined in <tools>; never approximate or invent names.
|
|
14730
|
+
2. Arguments Format: "arguments" must be a valid JSON object matching the function's parameter schema. Put only valid JSON inside each block \u2014 no markdown fences (\`\`\`json), comments, or text.
|
|
14731
|
+
3. Parallel Execution: When multiple operations are needed, emit consecutive ${TOOL_CALL_OPEN} blocks (at most 4 per turn). Each block must be complete and self-contained (never nested, interleaved, or omitted).
|
|
14732
|
+
4. Direct Invocation: Stop generation after the tool call block so the tools can be executed. Never output raw JSON without ${TOOL_CALL_OPEN} tags.
|
|
14690
14733
|
`;
|
|
14691
14734
|
if (toolInstructionsCache.size >= TOOL_CACHE_MAX_ENTRIES) {
|
|
14692
14735
|
toolInstructionsCache.clear();
|
|
@@ -17166,15 +17209,26 @@ ${loopReminder}` : truncation.prompt;
|
|
|
17166
17209
|
}
|
|
17167
17210
|
}
|
|
17168
17211
|
if (policy.reason === "account_initialization_failed") {
|
|
17169
|
-
|
|
17170
|
-
|
|
17171
|
-
|
|
17172
|
-
|
|
17173
|
-
|
|
17174
|
-
currentAccountId
|
|
17175
|
-
|
|
17176
|
-
|
|
17177
|
-
|
|
17212
|
+
const cooldownMs = policy.accountCooldownMs ?? 0;
|
|
17213
|
+
if (cooldownMs > 0) {
|
|
17214
|
+
console.warn(
|
|
17215
|
+
`\u26A0\uFE0F [Chat] Account initialization failed | ${currentAccountEmail} | cooldown=${Math.round(cooldownMs / 1e3)}s`
|
|
17216
|
+
);
|
|
17217
|
+
markAccountFailed(currentAccountId);
|
|
17218
|
+
markAccountRateLimited(
|
|
17219
|
+
currentAccountId,
|
|
17220
|
+
cooldownMs,
|
|
17221
|
+
policy.accountCooldownReason
|
|
17222
|
+
);
|
|
17223
|
+
} else {
|
|
17224
|
+
console.warn(
|
|
17225
|
+
`\u26A0\uFE0F [Chat] Account auth expired/retryable | ${currentAccountEmail} | rotating without cooldown`
|
|
17226
|
+
);
|
|
17227
|
+
if (policy.accountCooldownReason === "AuthExpired") {
|
|
17228
|
+
Promise.resolve().then(() => (init_playwright(), playwright_exports)).then(({ refreshAccountToken: refreshAccountToken2 }) => refreshAccountToken2(currentAccountId)).catch(() => {
|
|
17229
|
+
});
|
|
17230
|
+
}
|
|
17231
|
+
}
|
|
17178
17232
|
return { success: false, error: err };
|
|
17179
17233
|
}
|
|
17180
17234
|
if (policy.retryable && shouldSwitchAccount && !isSingleAccount && accountSwitches < maxAccountSwitches) {
|
|
@@ -17183,7 +17237,7 @@ ${loopReminder}` : truncation.prompt;
|
|
|
17183
17237
|
console.warn(
|
|
17184
17238
|
`\u{1F504} [Chat] Switching account after ${policy.reason} | ${currentAccountEmail} -> ${maskEmail(nextAccount.email)}`
|
|
17185
17239
|
);
|
|
17186
|
-
if (policy.accountCooldownMs
|
|
17240
|
+
if ((policy.accountCooldownMs ?? 0) > 0) {
|
|
17187
17241
|
markAccountRateLimited(
|
|
17188
17242
|
currentAccountId,
|
|
17189
17243
|
policy.accountCooldownMs,
|
|
@@ -18150,6 +18204,7 @@ var init_parser = __esm({
|
|
|
18150
18204
|
currentOpenTag = TOOL_START_LITERAL;
|
|
18151
18205
|
currentCloseTag = TOOL_END;
|
|
18152
18206
|
emittedToolCallCount = 0;
|
|
18207
|
+
successfulToolCallsCount = 0;
|
|
18153
18208
|
pendingLeadIn = "";
|
|
18154
18209
|
tools = [];
|
|
18155
18210
|
declaredToolNames = [];
|
|
@@ -18357,6 +18412,7 @@ var init_parser = __esm({
|
|
|
18357
18412
|
if (matchesIncrementalCall) {
|
|
18358
18413
|
this.flushPendingToolCallDeltas(result);
|
|
18359
18414
|
this.emittedToolCallCount++;
|
|
18415
|
+
this.successfulToolCallsCount++;
|
|
18360
18416
|
this.pendingLeadIn = "";
|
|
18361
18417
|
incremental.startEmitted = false;
|
|
18362
18418
|
incremental.disabled = true;
|
|
@@ -18365,6 +18421,7 @@ var init_parser = __esm({
|
|
|
18365
18421
|
this.flushPendingToolCallDeltas(result);
|
|
18366
18422
|
result.toolCalls.push(tc);
|
|
18367
18423
|
this.emittedToolCallCount++;
|
|
18424
|
+
this.successfulToolCallsCount++;
|
|
18368
18425
|
this.pendingLeadIn = "";
|
|
18369
18426
|
}
|
|
18370
18427
|
tryRecoverIncrementalToolCall(content) {
|
|
@@ -18824,6 +18881,9 @@ var init_parser = __esm({
|
|
|
18824
18881
|
getEmittedToolCallCount() {
|
|
18825
18882
|
return this.emittedToolCallCount;
|
|
18826
18883
|
}
|
|
18884
|
+
getSuccessfulToolCallCount() {
|
|
18885
|
+
return this.successfulToolCallsCount;
|
|
18886
|
+
}
|
|
18827
18887
|
isInsideTool() {
|
|
18828
18888
|
return this.insideTool;
|
|
18829
18889
|
}
|
|
@@ -20066,7 +20126,7 @@ async function processNonStreamingResponse(params) {
|
|
|
20066
20126
|
foundStr = true;
|
|
20067
20127
|
}
|
|
20068
20128
|
}
|
|
20069
|
-
} else if (delta.phase
|
|
20129
|
+
} else if (isAnswerPhase(delta.phase)) {
|
|
20070
20130
|
isThinkingChunk = false;
|
|
20071
20131
|
if (delta.content !== void 0) {
|
|
20072
20132
|
const newContent = delta.content || "";
|
|
@@ -20805,13 +20865,17 @@ async function processStreamingResponse(params) {
|
|
|
20805
20865
|
return false;
|
|
20806
20866
|
}
|
|
20807
20867
|
const switchAccount = policy.switchAccount && !retryInvalidInputOnSameAccount;
|
|
20808
|
-
if (switchAccount && (policy.accountCooldownMs
|
|
20868
|
+
if (switchAccount && (policy.accountCooldownMs ?? 0) > 0) {
|
|
20809
20869
|
markAccountRateLimited(
|
|
20810
20870
|
currentAccountId,
|
|
20811
20871
|
policy.accountCooldownMs,
|
|
20812
20872
|
policy.accountCooldownReason || "StreamRetry"
|
|
20813
20873
|
);
|
|
20814
20874
|
}
|
|
20875
|
+
if (policy.accountCooldownReason === "AuthExpired") {
|
|
20876
|
+
Promise.resolve().then(() => (init_playwright(), playwright_exports)).then(({ refreshAccountToken: refreshAccountToken2 }) => refreshAccountToken2(currentAccountId)).catch(() => {
|
|
20877
|
+
});
|
|
20878
|
+
}
|
|
20815
20879
|
retryContext.releaseAccountLease?.();
|
|
20816
20880
|
retryContext.releaseAccountLease = null;
|
|
20817
20881
|
await reader.cancel().catch(() => void 0);
|
|
@@ -21055,7 +21119,7 @@ async function processStreamingResponse(params) {
|
|
|
21055
21119
|
}
|
|
21056
21120
|
);
|
|
21057
21121
|
}
|
|
21058
|
-
if (delta.phase
|
|
21122
|
+
if (isAnswerPhase(delta.phase) && delta.status === "finished") {
|
|
21059
21123
|
upstreamDone = true;
|
|
21060
21124
|
if (!clientDisconnected) flushWrites();
|
|
21061
21125
|
break;
|
|
@@ -21078,7 +21142,7 @@ async function processStreamingResponse(params) {
|
|
|
21078
21142
|
foundStr = true;
|
|
21079
21143
|
}
|
|
21080
21144
|
}
|
|
21081
|
-
} else if (delta.phase
|
|
21145
|
+
} else if (isAnswerPhase(delta.phase)) {
|
|
21082
21146
|
isThinkingChunk = false;
|
|
21083
21147
|
if (delta.content !== void 0) {
|
|
21084
21148
|
const newContent = delta.content || "";
|
|
@@ -21285,7 +21349,7 @@ async function processStreamingResponse(params) {
|
|
|
21285
21349
|
let activeRetryStream = null;
|
|
21286
21350
|
while (malformedRetryCount < maxMalformedRetries) {
|
|
21287
21351
|
if (!toolParser) break;
|
|
21288
|
-
const allToolsFailed = toolParser.getMalformedToolCalls().length > 0 && toolParser.
|
|
21352
|
+
const allToolsFailed = toolParser.getMalformedToolCalls().length > 0 && toolParser.getSuccessfulToolCallCount() === 0;
|
|
21289
21353
|
if (!allToolsFailed) break;
|
|
21290
21354
|
const malformedCalls = toolParser.getMalformedToolCalls();
|
|
21291
21355
|
const malformedCount = malformedCalls.length;
|
|
@@ -21456,7 +21520,7 @@ Please retry your tool call(s) with correct JSON and valid tool names from the a
|
|
|
21456
21520
|
if (!delta) {
|
|
21457
21521
|
continue;
|
|
21458
21522
|
}
|
|
21459
|
-
if (delta.phase
|
|
21523
|
+
if (isAnswerPhase(delta.phase) && delta.status === "finished") {
|
|
21460
21524
|
upstreamDone = true;
|
|
21461
21525
|
break retryReadLoop;
|
|
21462
21526
|
}
|
|
@@ -25650,11 +25714,14 @@ function recordServerLog(level, text) {
|
|
|
25650
25714
|
}
|
|
25651
25715
|
line = line.replace(/^(?:\[?(?:INFO|WARN|WARNING|ERROR|ERR|DEBUG)\]?\s+)+/i, "").replace(/([\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}\u{2300}-\u{23FF}]\uFE0F?)\s{2,}/gu, "$1 ");
|
|
25652
25716
|
if (!line) continue;
|
|
25653
|
-
const
|
|
25717
|
+
const now = Date.now();
|
|
25718
|
+
const isDuplicate = logHistory.slice(-10).some(
|
|
25719
|
+
(entry2) => (entry2.time === time || entry2._ts && now - entry2._ts < 1500) && entry2.level === level && entry2.message === line
|
|
25720
|
+
);
|
|
25654
25721
|
if (isDuplicate) {
|
|
25655
25722
|
continue;
|
|
25656
25723
|
}
|
|
25657
|
-
const entry = { time, level, message: line };
|
|
25724
|
+
const entry = { time, level, message: line, _ts: now };
|
|
25658
25725
|
logHistory.push(entry);
|
|
25659
25726
|
if (logHistory.length > MAX_LOG_HISTORY) {
|
|
25660
25727
|
logHistory.shift();
|
|
@@ -25817,7 +25884,7 @@ function getAppVersion() {
|
|
|
25817
25884
|
}
|
|
25818
25885
|
} catch {
|
|
25819
25886
|
}
|
|
25820
|
-
cachedVersion = "v1.
|
|
25887
|
+
cachedVersion = "v1.5.1";
|
|
25821
25888
|
return cachedVersion;
|
|
25822
25889
|
}
|
|
25823
25890
|
var cachedVersion;
|