From e952ae1406ec014cfb891b6220fe82b8307b3335 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Sun, 14 Jun 2026 01:37:30 -0300 Subject: [PATCH] fix(providers): correct lmarena cookie hint to arena-auth-prod-v1 (#3810) (#3815) --- CHANGELOG.md | 1 + src/shared/providers/webSessionCredentials.ts | 11 ++- tests/unit/lmarena-provider.test.ts | 83 +++++++++---------- tests/unit/web-session-credentials.test.ts | 8 ++ 4 files changed, 56 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f73b1db743..0fe7674b23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### 🐛 Fixed - **fix(intelligence): run pricing + models.dev sync from the live startup path** — like the Arena ELO sync (v3.8.24), the external **pricing sync** (`PRICING_SYNC_ENABLED`) and the **models.dev capability sync** (Settings → AI toggle) were only initialized from `server-init.ts`, which the Next standalone runtime never executes — and models.dev had no caller at all. Their toggles were inert in production. Both are now initialized from `instrumentation-node.ts` (self-gated, opt-in preserved, non-blocking, never fatal). (thanks @diegosouzapw) +- **fix(providers): correct the lmarena cookie hint (`session` → `arena-auth-prod-v1`)** — the lmarena credential hint asked for a cookie named `session`, but lmarena.ai's real auth cookie is `arena-auth-prod-v1`, so users who pasted only `session=…` hit validation failures. The credential name, placeholder and storage keys now use the correct name (the legacy `session` key is retained for back-compat with already-saved credentials). ([#3810](https://github.com/diegosouzapw/OmniRoute/issues/3810) — thanks @xspylol) --- diff --git a/src/shared/providers/webSessionCredentials.ts b/src/shared/providers/webSessionCredentials.ts index 0914d94742..cf5e403367 100644 --- a/src/shared/providers/webSessionCredentials.ts +++ b/src/shared/providers/webSessionCredentials.ts @@ -160,7 +160,8 @@ export const WEB_SESSION_CREDENTIAL_REQUIREMENTS = { "qwen-web": { kind: "cookie", credentialName: "full Cookie header (must include cna, ssxmod_itna, token)", - placeholder: "cna=...; token=...; ssxmod_itna=...; ssxmod_itna2=... (full Cookie header from chat.qwen.ai)", + placeholder: + "cna=...; token=...; ssxmod_itna=...; ssxmod_itna2=... (full Cookie header from chat.qwen.ai)", acceptsFullCookieHeader: true, storageKeys: ["cookie", "token", "ssxmod_itna", "ssxmod_itna2", "cna", "tongyi_sso_ticket"], }, @@ -201,10 +202,12 @@ export const WEB_SESSION_CREDENTIAL_REQUIREMENTS = { }, lmarena: { kind: "cookie", - credentialName: "session", - placeholder: "session=... or full Cookie header from lmarena.ai", + // lmarena.ai's auth cookie is `arena-auth-prod-v1` (the legacy hint said `session`, + // which never matched the real cookie name and confused users). #3810 + credentialName: "arena-auth-prod-v1", + placeholder: "arena-auth-prod-v1=... or full Cookie header from lmarena.ai", acceptsFullCookieHeader: true, - storageKeys: ["cookie", "session"], + storageKeys: ["cookie", "arena-auth-prod-v1", "session"], }, } satisfies Record; diff --git a/tests/unit/lmarena-provider.test.ts b/tests/unit/lmarena-provider.test.ts index a4834e6566..96cae4d18e 100644 --- a/tests/unit/lmarena-provider.test.ts +++ b/tests/unit/lmarena-provider.test.ts @@ -44,30 +44,22 @@ describe("LMArena Credential Requirements", () => { const req = getWebSessionCredentialRequirement("lmarena"); assert.ok(req, "Should have credential requirement"); assert.equal(req.kind, "cookie"); - assert.equal(req.credentialName, "session"); + // #3810: lmarena.ai's real auth cookie is `arena-auth-prod-v1`, not `session` + assert.equal(req.credentialName, "arena-auth-prod-v1"); + assert.ok(req.placeholder.includes("arena-auth-prod-v1")); assert.ok(req.placeholder.includes("lmarena.ai")); assert.equal(req.acceptsFullCookieHeader, true); assert.ok(req.storageKeys.includes("cookie")); + assert.ok(req.storageKeys.includes("arena-auth-prod-v1")); + // legacy `session` key retained for back-compat with already-saved credentials assert.ok(req.storageKeys.includes("session")); }); it("validates usable credentials correctly", () => { - assert.equal( - hasUsableWebSessionCredential("lmarena", { cookie: "session=abc123" }), - true - ); - assert.equal( - hasUsableWebSessionCredential("lmarena", { session: "abc123" }), - true - ); - assert.equal( - hasUsableWebSessionCredential("lmarena", { cookie: "" }), - false - ); - assert.equal( - hasUsableWebSessionCredential("lmarena", {}), - false - ); + assert.equal(hasUsableWebSessionCredential("lmarena", { cookie: "session=abc123" }), true); + assert.equal(hasUsableWebSessionCredential("lmarena", { session: "abc123" }), true); + assert.equal(hasUsableWebSessionCredential("lmarena", { cookie: "" }), false); + assert.equal(hasUsableWebSessionCredential("lmarena", {}), false); }); }); @@ -135,7 +127,7 @@ describe("LMArena Executor", () => { it("parses LMArena SSE text events (a0: prefix)", () => { const textEvent = 'a0:{"text":"Hello, world!"}'; const result = parseArenaSSE(textEvent); - + assert.ok(result, "Should parse text event"); assert.equal(result.type, "text"); assert.equal(result.content, "Hello, world!"); @@ -144,7 +136,7 @@ describe("LMArena Executor", () => { it("parses LMArena SSE thinking events (ag: prefix)", () => { const thinkingEvent = 'ag:{"thinking":"Let me analyze this..."}'; const result = parseArenaSSE(thinkingEvent); - + assert.ok(result, "Should parse thinking event"); assert.equal(result.type, "thinking"); assert.equal(result.content, "Let me analyze this..."); @@ -165,37 +157,37 @@ describe("LMArena Executor", () => { }); it("parses LMArena SSE done event (ad: prefix)", () => { - const doneEvent = 'ad:{}'; + const doneEvent = "ad:{}"; const result = parseArenaSSE(doneEvent); - + assert.ok(result, "Should parse done event"); assert.equal(result.type, "done"); }); it("handles malformed SSE events gracefully", () => { - const malformedEvent = 'invalid:data'; + const malformedEvent = "invalid:data"; const result = parseArenaSSE(malformedEvent); - + assert.equal(result, null, "Should return null for malformed events"); }); it("transforms OpenAI messages to LMArena format", () => { const executor = new LMArenaExecutor(); const transformRequest = (executor as any).transformRequest.bind(executor); - + const openaiBody = { messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: "Hello!" }, { role: "assistant", content: "Hi there!" }, - { role: "user", content: "How are you?" } + { role: "user", content: "How are you?" }, ], model: "gpt-4", - stream: true + stream: true, }; - + const arenaBody = transformRequest(openaiBody, "gpt-4"); - + assert.ok(arenaBody, "Should transform request body"); assert.ok(arenaBody.messages, "Should have messages array"); assert.equal(arenaBody.model, "gpt-4", "Should preserve model"); @@ -210,7 +202,7 @@ describe("LMArena Executor", () => { body: { messages: [{ role: "user", content: "Hello" }] }, credentials: {}, signal: new AbortController().signal, - log: console + log: console, }); assert.equal(result.response.status, 401, "Should return 401 for missing cookie"); @@ -225,14 +217,15 @@ describe("LMArena Executor", () => { const mockSSE = [ 'data: a0:{"text":"Hello"}\n\n', 'data: a0:{"text":", world!"}\n\n', - 'data: ad:{}\n\n' - ].join(''); + "data: ad:{}\n\n", + ].join(""); const originalFetch = global.fetch; - global.fetch = async () => new Response(mockSSE, { - status: 200, - headers: { "Content-Type": "text/event-stream" } - }); + global.fetch = async () => + new Response(mockSSE, { + status: 200, + headers: { "Content-Type": "text/event-stream" }, + }); try { const result = await executor.execute({ @@ -240,7 +233,7 @@ describe("LMArena Executor", () => { body: { messages: [{ role: "user", content: "Hello" }], stream: true }, credentials: { cookie: "session=test" }, signal: new AbortController().signal, - log: console + log: console, }); assert.equal(result.response.status, 200, "Should return 200 for successful streaming"); @@ -254,12 +247,16 @@ describe("LMArena Executor", () => { const executor = new LMArenaExecutor(); const originalFetch = global.fetch; - global.fetch = async () => new Response(JSON.stringify({ - error: { message: "Rate limit exceeded" } - }), { - status: 429, - headers: { "Content-Type": "application/json" } - }); + global.fetch = async () => + new Response( + JSON.stringify({ + error: { message: "Rate limit exceeded" }, + }), + { + status: 429, + headers: { "Content-Type": "application/json" }, + } + ); try { const result = await executor.execute({ @@ -267,7 +264,7 @@ describe("LMArena Executor", () => { body: { messages: [{ role: "user", content: "Hello" }] }, credentials: { cookie: "session=test" }, signal: new AbortController().signal, - log: console + log: console, }); assert.equal(result.response.status, 429, "Should return 429 for rate limit"); diff --git a/tests/unit/web-session-credentials.test.ts b/tests/unit/web-session-credentials.test.ts index 7bbf2422a7..f6406ba2fb 100644 --- a/tests/unit/web-session-credentials.test.ts +++ b/tests/unit/web-session-credentials.test.ts @@ -37,6 +37,14 @@ test("web session credential metadata identifies cookie, token, and no-auth prov acceptsFullCookieHeader: false, storageKeys: ["token", "userToken"], }); + // lmarena.ai's real auth cookie is `arena-auth-prod-v1`, not `session` (#3810) + assert.deepEqual(webSessionCredentials.getWebSessionCredentialRequirement("lmarena"), { + kind: "cookie", + credentialName: "arena-auth-prod-v1", + placeholder: "arena-auth-prod-v1=... or full Cookie header from lmarena.ai", + acceptsFullCookieHeader: true, + storageKeys: ["cookie", "arena-auth-prod-v1", "session"], + }); // veoaifree-web is now a NOAUTH provider — not in WEB_SESSION_CREDENTIAL_REQUIREMENTS assert.equal(webSessionCredentials.getWebSessionCredentialRequirement("veoaifree-web"), null); assert.deepEqual(webSessionCredentials.getWebSessionCredentialRequirement("t3-web"), {