From 922bf91c730516b164919f7dd5cc6cfc4dcc2095 Mon Sep 17 00:00:00 2001 From: zenyxx-xd Date: Fri, 31 Jul 2026 21:30:58 +0400 Subject: [PATCH 1/3] fix: auto-reset web session on new client conversation & fallback optional cookie --- scripts/doctor.js | 2 +- server.js | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/scripts/doctor.js b/scripts/doctor.js index 87f39a8..f2fad6b 100644 --- a/scripts/doctor.js +++ b/scripts/doctor.js @@ -26,7 +26,7 @@ function checkAuthFile(file) { try { auth = JSON.parse(fs.readFileSync(file, 'utf8')); } catch (e) { return { file, ok: false, issues: [`invalid JSON: ${e.message}`], auth: null }; } if (!auth.token) issues.push('token missing'); - if (!auth.cookie) issues.push('cookie missing'); + // cookie optional if (!auth.wasmUrl) issues.push('wasmUrl missing'); if (process.platform !== 'win32') { const mode = fs.statSync(file).mode & 0o777; diff --git a/server.js b/server.js index 0bad77a..d622113 100755 --- a/server.js +++ b/server.js @@ -178,7 +178,7 @@ function buildBaseHeaders(config = DS_CONFIG) { "x-hif-leim": config.hif_leim || '', "Origin": "https://chat.deepseek.com", "Referer": "https://chat.deepseek.com/", - "Cookie": config.cookie || '', + "Cookie": config.cookie || "ds_cookie_preference=%7B%22level%22%3A%22all%22%7D;", "Content-Type": "application/json", }; } @@ -224,7 +224,7 @@ function loadDeepSeekConfig({ fatal = true } = {}) { } return false; } -function hasAuthConfig() { return accounts.some(a => a.config.token && a.config.cookie); } +function hasAuthConfig() { return accounts.some(a => a.config.token); } function accountStatus(account) { return { id: account.id, @@ -246,9 +246,9 @@ function selectAccountForSession(session) { resetRemoteSession(session); session.accountId = null; } - const ready = accounts.filter(a => a.config.token && a.config.cookie && a.cooldownUntil <= now); + const ready = accounts.filter(a => a.config.token && a.cooldownUntil <= now); if (ready.length === 0) { - const waiting = accounts.filter(a => a.config.token && a.config.cookie).sort((a, b) => a.cooldownUntil - b.cooldownUntil)[0]; + const waiting = accounts.filter(a => a.config.token).sort((a, b) => a.cooldownUntil - b.cooldownUntil)[0]; if (waiting) { const waitSec = Math.max(1, Math.ceil((waiting.cooldownUntil - now) / 1000)); // Tagged so the request handler returns 429 + Retry-After instead of a @@ -1795,7 +1795,7 @@ const server = http.createServer(async (req, res) => { // one account can serve right now, so an aggregator/LB won't route to a cold pool. if (req.method === 'GET' && url.pathname === '/readyz') { const now = Date.now(); - const ready = accounts.filter(a => a.config.token && a.config.cookie && a.cooldownUntil <= now).length; + const ready = accounts.filter(a => a.config.token && a.cooldownUntil <= now).length; res.writeHead(ready > 0 ? 200 : 503, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ready: ready > 0, ready_accounts: ready, total_accounts: accounts.length })); return; @@ -1961,6 +1961,13 @@ const server = http.createServer(async (req, res) => { const session = getOrCreateAgentSession(agentId); activeSession = session; + // Auto-reset DeepSeek web session if client starts a new conversation (no assistant turns yet) + const hasAssistantTurns = messages.some(m => m && m.role === "assistant"); + if (!hasAssistantTurns && session.id) { + console.log(`${agentTag} New conversation payload detected (no assistant turns); resetting remote session.`); + resetRemoteSession(session); + } + // Roll over TTL/depth-limited sessions before deciding whether to // inject local recovery history into the newly built prompt. const promptRollover = prepareSessionForPrompt(session); From 82ae6458879ac4c191b0656c1b263801c4b28c27 Mon Sep 17 00:00:00 2001 From: zenyxx-xd Date: Fri, 31 Jul 2026 21:49:42 +0400 Subject: [PATCH 2/3] fix: exclude title generation requests from resetting web session --- server.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index d622113..45c4377 100755 --- a/server.js +++ b/server.js @@ -1962,7 +1962,14 @@ const server = http.createServer(async (req, res) => { activeSession = session; // Auto-reset DeepSeek web session if client starts a new conversation (no assistant turns yet) - const hasAssistantTurns = messages.some(m => m && m.role === "assistant"); + const isTitleRequest = /generate\\s+(?:a\\s+)?(?:short\\s+)?title/i.test(lastUserText) || /title for this conversation/i.test(lastUserText); + if (!isTitleRequest) { + const hasAssistantTurns = messages.some(m => m && m.role === "assistant"); + if (!hasAssistantTurns && session.id) { + console.log(`${agentTag} New conversation payload detected; resetting remote session.`); + resetRemoteSession(session); + } + } if (!hasAssistantTurns && session.id) { console.log(`${agentTag} New conversation payload detected (no assistant turns); resetting remote session.`); resetRemoteSession(session); From 5211ab1335516c702989e3baa9b5865666d4137a Mon Sep 17 00:00:00 2001 From: zenyxx-xd Date: Fri, 31 Jul 2026 21:55:23 +0400 Subject: [PATCH 3/3] fix: clear local session history on new conversation reset --- server.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/server.js b/server.js index 45c4377..4aca7a5 100755 --- a/server.js +++ b/server.js @@ -244,6 +244,7 @@ function selectAccountForSession(session) { // If that account disappeared, lost credentials, or is cooling down, // never reuse its session id under a different account. resetRemoteSession(session); + session.history = []; session.accountId = null; } const ready = accounts.filter(a => a.config.token && a.cooldownUntil <= now); @@ -614,6 +615,7 @@ async function askDeepSeekStream(prompt, agentId, model = 'deepseek-default', fr if (resp.status === 400 || resp.status === 404 || resp.status === 500) { console.log(`${agentTag} Session ${session.id} expired. Creating new session...`); resetRemoteSession(session); + session.history = []; const sr2 = await dsFetch('https://chat.deepseek.com/api/v0/chat_session/create', { method: 'POST', headers: dsHeaders, body: '{}' @@ -1968,11 +1970,13 @@ const server = http.createServer(async (req, res) => { if (!hasAssistantTurns && session.id) { console.log(`${agentTag} New conversation payload detected; resetting remote session.`); resetRemoteSession(session); + session.history = []; } } if (!hasAssistantTurns && session.id) { console.log(`${agentTag} New conversation payload detected (no assistant turns); resetting remote session.`); resetRemoteSession(session); + session.history = []; } // Roll over TTL/depth-limited sessions before deciding whether to @@ -2136,6 +2140,7 @@ const server = http.createServer(async (req, res) => { const reason = contextTooLong ? 'context-too-long response' : 'empty response'; console.log(`${agentTag} ${reason} (msg#${session.messageCount}, retry ${retryAttempt}/${MAX_EMPTY_RETRIES}, prompt=${retryPrompt.length} chars). Resetting session...`); resetRemoteSession(session); + session.history = []; // Brief delay before retry to let DeepSeek breathe await new Promise(r => setTimeout(r, Math.min(500 * retryAttempt, 1500))); const { resp: retryResp } = await askDeepSeekStream(retryPrompt, agentId, requestedModel); @@ -2157,6 +2162,7 @@ const server = http.createServer(async (req, res) => { const timedOut = deadlineHit(); const failureClass = classifyRecoveryFailure(modelError, timedOut); const failure = resetRemoteSession(session); + session.history = []; const errorType = failureClass.type; const errorMessage = modelError?.content || (timedOut @@ -2211,6 +2217,7 @@ const server = http.createServer(async (req, res) => { if (!isContinuationRecoverySafe(contBeforeId, continuationCall)) { console.log(`${agentTag} continuation rotated to ${contAccount.id} ≠ ${contBeforeId} — skipping (foreign session)`); resetRemoteSession(session); + session.history = []; break; } const contResult = await readDeepSeekResponse(contResp.body); @@ -2241,6 +2248,7 @@ const server = http.createServer(async (req, res) => { if (allowedToolNames.size > 0 && !toolCall && looksLikeToolCallMarkup(fullContent) && !clientGone && !deadlineHit()) { console.log(`${agentTag} Tool-call markup detected but invalid/truncated (${fullContent.length} chars). Retrying with stricter prompt...`); resetRemoteSession(session); + session.history = []; await new Promise(r => setTimeout(r, 1000)); const strictPrompt = appendPromptInstruction( freshPromptBuild.prompt, @@ -2265,6 +2273,7 @@ const server = http.createServer(async (req, res) => { if (allowedToolNames.size > 0 && !toolCall && looksLikeToolCallMarkup(fullContent)) { const failure = resetRemoteSession(session); + session.history = []; res.writeHead(502, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: { message: 'DeepSeek returned malformed tool-call markup after one repair attempt',