Files
diegosouzapw--omniroute/tests/unit/deepseek-web-session-persistence-2942.test.ts
2026-07-13 13:39:12 +08:00

190 lines
6.7 KiB
TypeScript

// @ts-nocheck
// #2942 — persistent session for deepseek-web. Default (no config) keeps the legacy
// fresh-session-per-request behavior. With providerSpecificData.persistSession=true the
// executor reuses one upstream chat session across requests (keyed by userToken), does
// not delete it, and on a reused-session failure falls back to a fresh session + retries
// once. historyWindow is threaded into the prompt builder.
import test from "node:test";
import assert from "node:assert/strict";
const dsMod = await import("../../open-sse/executors/deepseek-web.ts");
const { DeepSeekWebExecutor } = dsMod;
const POW_CHALLENGE = {
algorithm: "DeepSeekHashV1",
challenge: "311b26ae1e0fe7375e242958ce46db5552a6c67fea3f96880dcd846c63a74286",
salt: "1122334455667788",
signature: "sig123",
difficulty: 1,
expire_at: 1778891543095,
expire_after: 300000,
target_path: "/api/v0/chat/completion",
};
const OK_SSE = [
"event: ready\n",
'data: {"request_message_id":1,"response_message_id":2}\n',
"\n",
'data: {"v":{"response":{"message_id":2,"fragments":[{"id":1,"type":"RESPONSE","content":"Hi"}]}}}\n',
"\n",
'data: {"p":"response/status","o":"SET","v":"FINISHED"}\n',
"\n",
"event: close\n",
'data: {"click_behavior":"none"}\n',
].join("");
/**
* Mock the DeepSeek web API. `completionOutcomes` is consumed one per completion call:
* "ok" -> 200 SSE stream
* "fail" -> 500 error
* When exhausted, defaults to "ok".
*/
function installMock(completionOutcomes = []) {
const original = globalThis.fetch;
const calls = { create: 0, delete: 0, completion: 0, completionBodies: [] };
let outcomeIdx = 0;
dsMod.tokenCache?.clear();
dsMod.sessionCache?.clear();
globalThis.fetch = async (url, opts = {}) => {
const u = String(url);
if (u.includes("/users/current")) {
return new Response(
JSON.stringify({ code: 0, data: { biz_data: { token: "access-token-xyz" } } }),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
}
if (u.includes("/chat_session/create")) {
calls.create += 1;
return new Response(
JSON.stringify({
code: 0,
data: { biz_data: { chat_session: { id: `session-${calls.create}` } } },
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
}
if (u.includes("/chat_session/delete")) {
calls.delete += 1;
return new Response(JSON.stringify({ code: 0 }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
if (u.includes("/create_pow_challenge")) {
return new Response(JSON.stringify({ code: 0, data: { biz_data: { challenge: POW_CHALLENGE } } }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
if (u.includes("/chat/completion")) {
calls.completion += 1;
try {
calls.completionBodies.push(JSON.parse(opts.body));
} catch {
calls.completionBodies.push(null);
}
const outcome = completionOutcomes[outcomeIdx++] ?? "ok";
if (outcome === "fail") {
return new Response(JSON.stringify({ error: "server" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
return new Response(new TextEncoder().encode(OK_SSE), {
status: 200,
headers: { "Content-Type": "text/event-stream" },
});
}
return new Response("not found", { status: 404 });
};
return {
calls,
restore: () => {
globalThis.fetch = original;
dsMod.tokenCache?.clear();
dsMod.sessionCache?.clear();
},
};
}
async function run(executor, { persistSession, historyWindow, messages, token } = {}) {
const providerSpecificData = {};
if (persistSession !== undefined) providerSpecificData.persistSession = persistSession;
if (historyWindow !== undefined) providerSpecificData.historyWindow = historyWindow;
const result = await executor.execute({
model: "default",
body: { messages: messages ?? [{ role: "user", content: "hi" }] },
stream: false,
credentials: { apiKey: token ?? "user-token-1", providerSpecificData },
signal: AbortSignal.timeout(10000),
});
// drain so the stream-cleanup (delete) fires deterministically
await result.response.text();
return result;
}
test("default (no config): fresh session per request + deletes it", async () => {
const mock = installMock();
try {
const executor = new DeepSeekWebExecutor();
await run(executor, { token: "tkn-default" });
await run(executor, { token: "tkn-default" });
assert.equal(mock.calls.create, 2, "creates a fresh session each request");
assert.ok(mock.calls.delete >= 1, "deletes the session (no persistence)");
} finally {
mock.restore();
}
});
test("persistSession=true: reuses cached session across requests, does not delete", async () => {
const mock = installMock();
try {
const executor = new DeepSeekWebExecutor();
await run(executor, { persistSession: true, token: "tkn-persist" });
await run(executor, { persistSession: true, token: "tkn-persist" });
assert.equal(mock.calls.create, 1, "session created once and reused");
assert.equal(mock.calls.delete, 0, "persistent session is not deleted");
} finally {
mock.restore();
}
});
test("persistSession=true: reused-session failure falls back to a fresh session and retries once", async () => {
// call 1 -> create+cache (ok). call 2 -> reuse cached -> completion 500 -> create fresh -> retry ok.
const mock = installMock(["ok", "fail", "ok"]);
try {
const executor = new DeepSeekWebExecutor();
const r1 = await run(executor, { persistSession: true, token: "tkn-heal" });
assert.ok(r1.response.ok, "first call ok");
const r2 = await run(executor, { persistSession: true, token: "tkn-heal" });
assert.ok(r2.response.ok, "second call recovers via fresh-session retry");
assert.equal(mock.calls.create, 2, "one initial + one fresh-session retry");
assert.equal(mock.calls.completion, 3, "1 (call1) + 1 failed reuse + 1 retry");
} finally {
mock.restore();
}
});
test("historyWindow is threaded into the completion prompt", async () => {
const mock = installMock();
try {
const executor = new DeepSeekWebExecutor();
await run(executor, {
historyWindow: 10,
token: "tkn-hist",
messages: [
{ role: "user", content: "earlier-turn-marker" },
{ role: "assistant", content: "ack" },
{ role: "user", content: "latest-turn" },
],
});
const body = mock.calls.completionBodies[0];
assert.ok(body.prompt.includes("earlier-turn-marker"), "earlier turn carried into prompt");
assert.ok(body.prompt.includes("latest-turn"), "latest turn present");
} finally {
mock.restore();
}
});