From 73e021b8a00e81d71ffe0f1da000d786c17437d7 Mon Sep 17 00:00:00 2001 From: X-Adam Date: Sat, 19 Sep 2026 09:51:13 +0700 Subject: [PATCH 01/41] fix(ollama): map free-plan monthly window and derive reset from signup date --- open-sse/services/usage/misc.js | 62 +++++++--- .../usage/components/ProviderLimits/utils.js | 2 +- tests/unit/ollama-usage.test.js | 115 +++++++++++++++++- 3 files changed, 163 insertions(+), 16 deletions(-) diff --git a/open-sse/services/usage/misc.js b/open-sse/services/usage/misc.js index e4b04589..eac37698 100644 --- a/open-sse/services/usage/misc.js +++ b/open-sse/services/usage/misc.js @@ -24,11 +24,43 @@ export async function getIflowUsage(accessToken) { } } +const OLLAMA_LIMIT_WINDOWS = { + session: "Session (5h)", + weekly: "Weekly (7d)", + monthly: "Monthly", +}; + +function addUtcMonths(date, months) { + const total = date.getUTCMonth() + months; + const year = date.getUTCFullYear() + Math.floor(total / 12); + const month = ((total % 12) + 12) % 12; + const lastDay = new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + return new Date(Date.UTC( + year, month, Math.min(date.getUTCDate(), lastDay), + date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), + )); +} + +// Free plan: "usage resets monthly from the date you signed up" (ollama.com/pricing). +function nextMonthlyResetFromSignup(createdAt, now = new Date()) { + const anchor = new Date(createdAt); + if (Number.isNaN(anchor.getTime())) return null; + const elapsedMonths = (now.getUTCFullYear() - anchor.getUTCFullYear()) * 12 + + (now.getUTCMonth() - anchor.getUTCMonth()); + for (let i = Math.max(0, elapsedMonths); i <= elapsedMonths + 1; i++) { + const candidate = addUtcMonths(anchor, i); + if (candidate > now) return candidate.toISOString(); + } + return null; +} + /** * Ollama Cloud Usage - * GET https://ollama.com/api/usage — session (5h) + weekly (7d) `usage` is a 0..1 - * ratio (1.0 = limit reached, e.g. weekly 100% used). No reset timestamp exposed. - * POST https://ollama.com/api/me — plan label (fail-open). + * GET https://ollama.com/api/usage — `limits..usage` is a 0..1 ratio + * (1.0 = limit reached). Paid plans report session (5h) + weekly (7d); the + * free plan reports a single monthly window. No reset timestamp exposed; + * the free monthly reset is derived from the account's signup date. + * POST https://ollama.com/api/me — plan label + CreatedAt (fail-open). * Auth: Authorization: Bearer */ export async function getOllamaUsage(apiKey, providerSpecificData, proxyOptions = null) { @@ -84,14 +116,20 @@ export async function getOllamaUsage(apiKey, providerSpecificData, proxyOptions return { used: usedPct, total: 100, remainingPercentage: 100 - usedPct, resetAt, unlimited: false }; } - const sessionRaw = limits.session?.usage; - const weeklyRaw = limits.weekly?.usage; - const sessionNum = Number(sessionRaw); - const weeklyNum = Number(weeklyRaw); - const hasSession = sessionRaw !== undefined && sessionRaw !== null && !Number.isNaN(sessionNum); - const hasWeekly = weeklyRaw !== undefined && weeklyRaw !== null && !Number.isNaN(weeklyNum); + const monthlyResetAt = planRaw.toLowerCase() === "free" && me?.CreatedAt + ? nextMonthlyResetFromSignup(me.CreatedAt) + : null; - if (!hasSession && !hasWeekly) { + const quotas = {}; + for (const [key, label] of Object.entries(OLLAMA_LIMIT_WINDOWS)) { + const raw = limits[key]?.usage; + if (raw === undefined || raw === null) continue; + const ratio = Number(raw); + if (Number.isNaN(ratio)) continue; + quotas[label] = ratioQuota(ratio, key === "monthly" ? monthlyResetAt : null); + } + + if (Object.keys(quotas).length === 0) { return { plan, message: "Ollama Cloud connected. No usage limits reported.", @@ -99,10 +137,6 @@ export async function getOllamaUsage(apiKey, providerSpecificData, proxyOptions }; } - const quotas = {}; - if (hasSession) quotas["Session (5h)"] = ratioQuota(sessionNum); - if (hasWeekly) quotas["Weekly (7d)"] = ratioQuota(weeklyNum); - return { plan, quotas }; } catch (error) { return { message: `Ollama Cloud error: ${error.message}` }; diff --git a/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js b/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js index 377bb02d..784e6e47 100644 --- a/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js +++ b/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js @@ -632,7 +632,7 @@ export function parseQuotaData(provider, data) { break; case "ollama": - // Session (5h) / Weekly (7d) usage % from ollama.com/api/usage. + // Session (5h) / Weekly (7d) / Monthly usage % from ollama.com/api/usage. // remainingPercentage only — no absolute remaining (UI treats remaining as %). if (data.quotas) { Object.entries(data.quotas).forEach(([name, quota]) => { diff --git a/tests/unit/ollama-usage.test.js b/tests/unit/ollama-usage.test.js index fd8587e3..b3a5b5c2 100644 --- a/tests/unit/ollama-usage.test.js +++ b/tests/unit/ollama-usage.test.js @@ -1,4 +1,4 @@ -import { describe, it, expect, vi, beforeEach } from "vitest"; +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; vi.mock("../../open-sse/utils/proxyFetch.js", () => ({ proxyAwareFetch: vi.fn(), @@ -44,6 +44,27 @@ const SAMPLE_USAGE = { }, }; +const SAMPLE_FREE_USAGE = { + activity: { + cost: "0.00000", + period: { + type: "last_4_weeks", + starting_at: "2026-08-24T00:00:00Z", + ending_at: "2026-09-18T15:03:00Z", + }, + models: [], + }, + limits: { + monthly: { + usage: 0.021, + models: [ + { name: "gpt-oss:120b", request_count: 6 }, + { name: "gemma4:31b", request_count: 6 }, + ], + }, + }, +}; + const SAMPLE_ME = { Plan: "max", }; @@ -103,6 +124,98 @@ describe("getUsageForProvider(ollama)", () => { expect(meOpts.headers["Content-Length"]).toBe("0"); }); + it("maps the free plan's monthly window", async () => { + proxyAwareFetch + .mockResolvedValueOnce(jsonResponse(SAMPLE_FREE_USAGE)) + .mockResolvedValueOnce(jsonResponse({ Plan: "free" })); + + const usage = await getUsageForProvider({ + provider: "ollama", + apiKey: "k", + providerSpecificData: {}, + }); + + expect(usage.message).toBeUndefined(); + expect(usage.plan).toBe("Free"); + expect(Object.keys(usage.quotas)).toEqual(["Monthly"]); + expect(usage.quotas["Monthly"]).toMatchObject({ + used: 2, + total: 100, + remainingPercentage: 98, + unlimited: false, + }); + expect(usage.quotas["Monthly"].remaining).toBeUndefined(); + expect(usage.quotas["Monthly"].resetAt).toBeNull(); + }); + + describe("free plan monthly reset from signup date", () => { + afterEach(() => { + vi.useRealTimers(); + }); + + async function monthlyResetAt(createdAt, now) { + vi.useFakeTimers(); + vi.setSystemTime(new Date(now)); + proxyAwareFetch + .mockResolvedValueOnce(jsonResponse(SAMPLE_FREE_USAGE)) + .mockResolvedValueOnce(jsonResponse({ Plan: "free", CreatedAt: createdAt })); + + const usage = await getUsageForProvider({ + provider: "ollama", + apiKey: "k", + providerSpecificData: {}, + }); + return usage.quotas["Monthly"].resetAt; + } + + it("uses the signup day of the next month", async () => { + expect(await monthlyResetAt("2025-09-06T22:15:39.871687Z", "2026-09-18T15:03:00Z")) + .toBe("2026-10-06T22:15:39.000Z"); + }); + + it("stays in the current month when the signup day is still ahead", async () => { + expect(await monthlyResetAt("2026-09-18T09:50:49.514335Z", "2026-09-18T15:33:33Z")) + .toBe("2026-10-18T09:50:49.000Z"); + expect(await monthlyResetAt("2025-09-25T10:00:00Z", "2026-09-18T15:33:33Z")) + .toBe("2026-09-25T10:00:00.000Z"); + }); + + it("clamps the signup day to shorter months", async () => { + expect(await monthlyResetAt("2026-01-31T12:00:00Z", "2026-02-10T00:00:00Z")) + .toBe("2026-02-28T12:00:00.000Z"); + }); + + it("skips the reset when the plan is not free", async () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-09-18T15:03:00Z")); + proxyAwareFetch + .mockResolvedValueOnce(jsonResponse(SAMPLE_FREE_USAGE)) + .mockResolvedValueOnce(jsonResponse({ Plan: "pro", CreatedAt: "2025-09-06T22:15:39Z" })); + + const usage = await getUsageForProvider({ + provider: "ollama", + apiKey: "k", + providerSpecificData: {}, + }); + expect(usage.quotas["Monthly"].resetAt).toBeNull(); + }); + }); + + it("reports no limits when no known window is present", async () => { + proxyAwareFetch + .mockResolvedValueOnce(jsonResponse({ activity: {}, limits: {} })) + .mockResolvedValueOnce(jsonResponse({ Plan: "free" })); + + const usage = await getUsageForProvider({ + provider: "ollama", + apiKey: "k", + providerSpecificData: {}, + }); + + expect(usage.message).toMatch(/no usage limits/i); + expect(usage.quotas).toEqual({}); + }); + it("surfaces invalid key message on 401", async () => { proxyAwareFetch.mockResolvedValueOnce( jsonResponse({ error: "unauthorized" }, 401), From 49185137b8aad5dd564800402a6c02d3fa824ed8 Mon Sep 17 00:00:00 2001 From: Alexander Radchenko Date: Sat, 19 Sep 2026 10:01:51 +0700 Subject: [PATCH 02/41] feat(opencode-zen): add OpenCode Zen (PAYG) provider with free-tier fingerprint, alias ocz Multi-endpoint provider on https://opencode.ai/zen/v1 (openai / claude / openai-responses transports mirroring opencode-go) with 71 models across paid + free tiers. Free-tier fingerprint: opencode/1.18.x UA spoof, ses_-session header, built-in tool quartet, forced stream. Usage endpoint /zen/v1/usage wired into the dashboard. --- open-sse/config/providerModels.js | 2 +- open-sse/executors/index.js | 3 + open-sse/executors/opencode-zen.js | 315 ++++++++++++++++++++ open-sse/providers/registry/index.js | 2 + open-sse/providers/registry/opencode-zen.js | 123 ++++++++ open-sse/services/usage.js | 2 + open-sse/services/usage/opencode-zen.js | 107 +++++++ tests/__baseline__/alias-baseline.json | 2 + tests/__baseline__/providers-baseline.json | 38 +++ tests/unit/opencode-zen-models.test.js | 123 ++++++++ 10 files changed, 716 insertions(+), 1 deletion(-) create mode 100644 open-sse/executors/opencode-zen.js create mode 100644 open-sse/providers/registry/opencode-zen.js create mode 100644 open-sse/services/usage/opencode-zen.js create mode 100644 tests/unit/opencode-zen-models.test.js diff --git a/open-sse/config/providerModels.js b/open-sse/config/providerModels.js index afa98fa7..f4747cd4 100644 --- a/open-sse/config/providerModels.js +++ b/open-sse/config/providerModels.js @@ -53,7 +53,7 @@ export function findModelName(aliasOrId, modelId) { } export function getModelTargetFormat(aliasOrId, modelId) { - if ((!aliasOrId || aliasOrId === "oc" || aliasOrId === "opencode" || aliasOrId === "ocg" || aliasOrId === "opencode-go") && isMuseSparkModel(modelId)) { + if ((!aliasOrId || aliasOrId === "oc" || aliasOrId === "opencode" || aliasOrId === "ocg" || aliasOrId === "opencode-go" || aliasOrId === "ocz" || aliasOrId === "opencode-zen") && isMuseSparkModel(modelId)) { return FORMATS.OPENAI_RESPONSES; } const models = PROVIDER_MODELS[aliasOrId]; diff --git a/open-sse/executors/index.js b/open-sse/executors/index.js index f48a8ecb..ed17d330 100644 --- a/open-sse/executors/index.js +++ b/open-sse/executors/index.js @@ -11,6 +11,7 @@ import { CursorExecutor } from "./cursor.js"; import { VertexExecutor } from "./vertex.js"; import { OpenCodeExecutor } from "./opencode.js"; import { OpenCodeGoExecutor } from "./opencode-go.js"; +import { OpenCodeZenExecutor } from "./opencode-zen.js"; import { GrokWebExecutor } from "./grok-web.js"; import { GrokCliExecutor } from "./grok-cli.js"; import { PerplexityWebExecutor } from "./perplexity-web.js"; @@ -43,6 +44,7 @@ const executors = { "vertex-partner": new VertexExecutor("vertex-partner"), opencode: new OpenCodeExecutor(), "opencode-go": new OpenCodeGoExecutor(), + "opencode-zen": new OpenCodeZenExecutor(), "grok-web": new GrokWebExecutor(), "grok-cli": new GrokCliExecutor(), gcli: new GrokCliExecutor(), // Alias @@ -89,6 +91,7 @@ export { VertexExecutor } from "./vertex.js"; export { DefaultExecutor } from "./default.js"; export { OpenCodeExecutor } from "./opencode.js"; export { OpenCodeGoExecutor } from "./opencode-go.js"; +export { OpenCodeZenExecutor } from "./opencode-zen.js"; export { GrokWebExecutor } from "./grok-web.js"; export { GrokCliExecutor } from "./grok-cli.js"; export { PerplexityWebExecutor } from "./perplexity-web.js"; diff --git a/open-sse/executors/opencode-zen.js b/open-sse/executors/opencode-zen.js new file mode 100644 index 00000000..8a43ff85 --- /dev/null +++ b/open-sse/executors/opencode-zen.js @@ -0,0 +1,315 @@ +import crypto from "node:crypto"; +import { DefaultExecutor } from "./default.js"; +import { resolveSessionId } from "../utils/sessionManager.js"; +import { isMuseSparkModel } from "../providers/models/helpers.js"; +import { + normalizeResponsesInput, + clampResponsesCallId, + coerceResponsesArguments, + coerceResponsesOutput, +} from "../translator/formats/responsesApi.js"; + +const SESSION_HEADER = "x-opencode-session"; +const SESSION_FIELD = "_opencodeZenSession"; +const MAX_SESSION_LENGTH = 256; + +const RESPONSES_BASE_URL = "https://opencode.ai/zen/v1/responses"; +const MAX_TOOL_NAME_LEN = 128; +const OPENCODE_UA = "opencode/1.18.31"; +export const OPENCODE_SESSION_RE = /^ses_[0-9a-f]{12}[0-9A-Za-z]{14}$/; +const BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +// Free-tier fingerprint (mirrors opencode executor, PR #4132): upstream 403s +// requests without the file-search quartet and without stream:true. +const OPENCODE_FINGERPRINT_TOOLS = ["bash", "glob", "grep", "read"]; + +function hasValidOpencodeVersion(ua) { + const m = String(ua || "").match(/opencode\/(\d+)\.(\d+)(?:\.(\d+))?/i); + if (!m) return false; + const major = parseInt(m[1], 10); + const minor = parseInt(m[2], 10); + return major > 1 || (major === 1 && minor >= 17); +} + +function unstableRandom() { + const bytes = crypto.randomBytes(14); + let randomPart = ""; + for (let i = 0; i < 14; i++) { + randomPart += BASE62_CHARS[bytes[i] % 62]; + } + return randomPart; +} + +export function generateSessionId(timestamp = Date.now()) { + const current = BigInt(timestamp) * 0x1000n + 1n; + const value = ~current; + const time = Array.from({ length: 6 }, (_, index) => + Number((value >> BigInt(40 - 8 * index)) & 0xffn) + .toString(16) + .padStart(2, "0") + ).join(""); + return `ses_${time}${unstableRandom()}`; +} + +export function generateRequestId(timestamp = Date.now()) { + const current = BigInt(timestamp) * 0x1000n + 1n; + const value = current; + const time = Array.from({ length: 6 }, (_, index) => + Number((value >> BigInt(40 - 8 * index)) & 0xffn) + .toString(16) + .padStart(2, "0") + ).join(""); + return `msg_${time}${unstableRandom()}`; +} + +export function translateSessionId(sessionId, clientTool = "") { + if (typeof sessionId === "string" && OPENCODE_SESSION_RE.test(sessionId.trim())) { + return sessionId.trim(); + } + const digest = crypto + .createHash("sha256") + .update(`opencode\0${clientTool || "generic"}\0${sessionId || ""}`) + .digest(); + const timeHex = digest.subarray(0, 6).toString("hex"); + let randomPart = ""; + for (let i = 6; i < 20; i++) { + randomPart += BASE62_CHARS[digest[i] % 62]; + } + return `ses_${timeHex}${randomPart}`; +} + +function toolNameOf(tool) { + if (!tool || typeof tool !== "object" || Array.isArray(tool)) return ""; + const fn = tool.function && typeof tool.function === "object" && !Array.isArray(tool.function) ? tool.function : null; + const raw = typeof tool.name === "string" ? tool.name : (typeof fn?.name === "string" ? fn.name : ""); + return raw.trim(); +} + +function ensureChatFingerprintTools(body) { + if (!body || typeof body !== "object") return; + const present = new Set(); + if (Array.isArray(body.tools)) { + for (const tool of body.tools) { + const name = toolNameOf(tool); + if (name) present.add(name); + } + } else { + body.tools = []; + } + for (const name of OPENCODE_FINGERPRINT_TOOLS) { + if (present.has(name)) continue; + body.tools.push({ + type: "function", + function: { + name, + description: `OpenCode built-in ${name} tool`, + parameters: { type: "object", properties: {} }, + }, + }); + present.add(name); + } +} + +function ensureResponsesFingerprintTools(body) { + if (!body || typeof body !== "object") return; + const present = new Set(); + if (Array.isArray(body.tools)) { + for (const tool of body.tools) { + const name = toolNameOf(tool); + if (name) present.add(name); + } + } else { + body.tools = []; + } + for (const name of OPENCODE_FINGERPRINT_TOOLS) { + if (present.has(name)) continue; + body.tools.push({ + type: "function", + name, + description: `OpenCode built-in ${name} tool`, + parameters: { type: "object", properties: {} }, + }); + present.add(name); + } +} + +function normalizeSession(value) { + if (typeof value !== "string") return null; + const normalized = value.trim(); + if (!normalized || normalized.length > MAX_SESSION_LENGTH) return null; + return normalized; +} + +function nativeSession(headers) { + if (!headers || typeof headers !== "object") return null; + for (const [key, value] of Object.entries(headers)) { + if (key.toLowerCase() === SESSION_HEADER) { + const normalized = normalizeSession(value); + if (normalized && OPENCODE_SESSION_RE.test(normalized)) return normalized; + } + } + return null; +} + +function translatedSession(sessionId, clientTool) { + return translateSessionId(sessionId, clientTool); +} + +// Strip the thinking suffix "model(level)" so checks hit the base id. +function baseModelId(model) { + return String(model || "").replace(/\([^()]+\)\s*$/, "").trim(); +} + +function isResponsesModel(model) { + return isMuseSparkModel(baseModelId(model)); +} + +// Flatten Chat Completions tool declarations into the Responses flat shape and +// drop hosted/nameless tools the /responses endpoint rejects. +function normalizeResponsesTools(body) { + if (!Array.isArray(body.tools)) return; + const validNames = new Set(); + body.tools = body.tools.filter((tool) => { + if (!tool || typeof tool !== "object" || Array.isArray(tool)) return false; + const fn = tool.function && typeof tool.function === "object" && !Array.isArray(tool.function) ? tool.function : null; + const rawName = typeof tool.name === "string" ? tool.name : (typeof fn?.name === "string" ? fn.name : ""); + const name = rawName.trim(); + if (!name) return false; + const description = typeof tool.description === "string" ? tool.description : (typeof fn?.description === "string" ? fn.description : ""); + let parameters = (tool.parameters && typeof tool.parameters === "object" && !Array.isArray(tool.parameters)) + ? tool.parameters + : (fn?.parameters && typeof fn.parameters === "object" && !Array.isArray(fn.parameters) ? fn.parameters : { type: "object", properties: {} }); + // Mirror the request translator: {type:"object"} without properties is rejected + // by strict Responses backends, so fill in the empty properties map. + if (parameters.type === "object" && !parameters.properties) parameters = { ...parameters, properties: {} }; + for (const k of Object.keys(tool)) delete tool[k]; + tool.type = "function"; + tool.name = name.slice(0, MAX_TOOL_NAME_LEN); + if (description) tool.description = description; + tool.parameters = parameters; + validNames.add(tool.name); + return true; + }); + if (body.tool_choice && typeof body.tool_choice === "object" && !Array.isArray(body.tool_choice)) { + if (body.tool_choice.type === "function") { + const n = typeof body.tool_choice.name === "string" ? body.tool_choice.name.trim() : ""; + if (!n || !validNames.has(n)) delete body.tool_choice; + } + } +} + +// Last line of defense for native Responses clients (sourceFormat === targetFormat +// skips translation): coerce items in place so malformed tool payloads 400 here +// with a clear shape instead of upstream as InputValidationError. +function sanitizeResponsesItems(body) { + if (!Array.isArray(body.input)) return; + body.input = body.input.filter((item) => { + if (!item || typeof item !== "object" || Array.isArray(item)) return true; + // Strip prior-turn reasoning items: Muse Spark contributor models route to + // an upstream Console backend where encrypted_content cannot be validated across + // rotated accounts or sessions, causing 400 "reasoning encrypted_content was not issued to this caller". + if (item.type === "reasoning") return false; + delete item.encrypted_content; + delete item.reasoning_encrypted_content; + if (item.type === "function_call") { + if (!item.name || typeof item.name !== "string" || item.name.trim() === "") return false; + item.name = item.name.trim().slice(0, MAX_TOOL_NAME_LEN); + item.call_id = clampResponsesCallId(item.call_id); + item.arguments = coerceResponsesArguments(item.arguments); + return true; + } + if (item.type === "function_call_output") { + item.call_id = clampResponsesCallId(item.call_id); + item.output = coerceResponsesOutput(item.output); + return true; + } + return true; + }); +} + +export class OpenCodeZenExecutor extends DefaultExecutor { + constructor() { + super("opencode-zen"); + } + + buildUrl(model, stream, urlIndex = 0, credentials = null) { + // Muse Spark lives on /responses even when a stale runtimeTransport leaks in. + if (isResponsesModel(model)) return RESPONSES_BASE_URL; + return super.buildUrl(model, stream, urlIndex, credentials); + } + + prepareRequestCredentials({ body, credentials, providerSessionId, clientTool } = {}) { + const sourceCredentials = credentials || {}; + const native = nativeSession(sourceCredentials.rawHeaders); + const resolved = normalizeSession(providerSessionId) || resolveSessionId({ + headers: sourceCredentials.rawHeaders, + body, + connectionId: sourceCredentials.connectionId, + scope: "opencode-zen", + }); + + return { + ...sourceCredentials, + [SESSION_FIELD]: native || translatedSession(resolved, clientTool), + }; + } + + async execute(args) { + const credentials = this.prepareRequestCredentials(args); + return super.execute({ ...args, credentials }); + } + + buildHeaders(credentials, stream = true, url, model) { + const headers = super.buildHeaders(credentials || {}, stream, url, model); + const raw = credentials?.rawHeaders || {}; + const lower = {}; + for (const [k, v] of Object.entries(raw)) lower[k.toLowerCase()] = v; + const downstreamUa = lower["user-agent"] || ""; + // Free-tier gate: spoof the official client UA. + headers["User-Agent"] = hasValidOpencodeVersion(downstreamUa) ? downstreamUa : OPENCODE_UA; + headers["x-opencode-client"] = lower["x-opencode-client"] || "desktop"; + const prepared = credentials?.[SESSION_FIELD]; + if (prepared) { + headers[SESSION_HEADER] = prepared; + return headers; + } + + const fallback = this.prepareRequestCredentials({ credentials }); + headers[SESSION_HEADER] = fallback[SESSION_FIELD]; + return headers; + } + + transformRequest(model, body, stream, credentials) { + const out = super.transformRequest(model, body); + // Free-tier gate: upstream 403s stream:false even when everything else is valid. + if (out && typeof out === "object") out.stream = true; + if (!isResponsesModel(model || body?.model)) { + ensureChatFingerprintTools(out); + return out; + } + const normalized = normalizeResponsesInput(out.input); + if (normalized) out.input = normalized; + if (!Array.isArray(out.input) || out.input.length === 0) { + out.input = [{ type: "message", role: "user", content: [{ type: "input_text", text: "..." }] }]; + } + // Responses names the output cap max_output_tokens, not max_tokens. + if (out.max_output_tokens === undefined) { + if (out.max_completion_tokens !== undefined) out.max_output_tokens = out.max_completion_tokens; + else if (out.max_tokens !== undefined) out.max_output_tokens = out.max_tokens; + } + delete out.max_tokens; + delete out.max_completion_tokens; + if (out.reasoning_effort !== undefined && out.reasoning === undefined) { + out.reasoning = { effort: out.reasoning_effort, summary: "auto" }; + } + if (out.reasoning && typeof out.reasoning === "object" && !Array.isArray(out.reasoning)) { + if (!out.reasoning.summary) out.reasoning.summary = "auto"; + } + delete out.reasoning_effort; + out.stream = true; + out.store = false; + ensureResponsesFingerprintTools(out); + normalizeResponsesTools(out); + sanitizeResponsesItems(out); + return out; + } +} diff --git a/open-sse/providers/registry/index.js b/open-sse/providers/registry/index.js index fb355d6d..56a8d41d 100644 --- a/open-sse/providers/registry/index.js +++ b/open-sse/providers/registry/index.js @@ -69,6 +69,7 @@ import p66 from "./ollama.js"; import p123 from "./ollama-search.js"; import p67 from "./openai.js"; import p68 from "./opencode-go.js"; +import p68z from "./opencode-zen.js"; import p69 from "./opencode.js"; import p70 from "./openrouter.js"; import p71 from "./perplexity-web.js"; @@ -194,6 +195,7 @@ export default [ p123, p67, p68, + p68z, p69, p70, p71, diff --git a/open-sse/providers/registry/opencode-zen.js b/open-sse/providers/registry/opencode-zen.js new file mode 100644 index 00000000..8ec2ff1f --- /dev/null +++ b/open-sse/providers/registry/opencode-zen.js @@ -0,0 +1,123 @@ +export default { + id: "opencode-zen", + priority: 205, + alias: "ocz", + aliases: [ + "opencode-zen", + ], + uiAlias: "ocz", + display: { + name: "OpenCode Zen", + icon: "terminal", + color: "#E87040", + textIcon: "OZ", + website: "https://opencode.ai/auth", + notice: { + text: "OpenCode Zen PAYG: pay-as-you-go, key from https://opencode.ai/auth. Same models as Zen: paid + free tiers on the fast lane.", + apiKeyUrl: "https://opencode.ai/auth", + }, + }, + category: "apikey", + transport: { + baseUrl: "https://opencode.ai/zen/v1/chat/completions", + headers: {}, + usage: { + url: "https://opencode.ai/zen/v1/usage", + }, + }, + // Multi-endpoint: pick the transport matching the client sourceFormat to skip + // translation. Mirrors opencode-go, pointed at /zen/v1 (see https://opencode.ai/docs/zen/). + transports: [ + { format: "openai", baseUrl: "https://opencode.ai/zen/v1/chat/completions", auth: { combined: true, header: "Authorization", scheme: "bearer" } }, + { format: "claude", baseUrl: "https://opencode.ai/zen/v1/messages", auth: { combined: true, header: "x-api-key", scheme: "raw", anthropicVersion: true } }, + { format: "openai-responses", baseUrl: "https://opencode.ai/zen/v1/responses", auth: { combined: true, header: "Authorization", scheme: "bearer" } }, + ], + // supportedFormats follow the endpoint table in https://opencode.ai/docs/zen/ + // (live /zen/v1/models, 2026-09-18: 71 ids). + models: [ + // Claude (messages) + { id: "claude-fable-5", name: "Claude Fable 5", supportedFormats: ["claude"] }, + { id: "claude-fable-5-1", name: "Claude Fable 5.1", supportedFormats: ["claude"] }, + { id: "claude-opus-5", name: "Claude Opus 5", supportedFormats: ["claude"] }, + { id: "claude-opus-4-8", name: "Claude Opus 4.8", supportedFormats: ["claude"] }, + { id: "claude-opus-4-7", name: "Claude Opus 4.7", supportedFormats: ["claude"] }, + { id: "claude-opus-4-6", name: "Claude Opus 4.6", supportedFormats: ["claude"] }, + { id: "claude-opus-4-5", name: "Claude Opus 4.5", supportedFormats: ["claude"] }, + { id: "claude-sonnet-5", name: "Claude Sonnet 5", supportedFormats: ["claude"] }, + { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", supportedFormats: ["claude"] }, + { id: "claude-sonnet-4-5", name: "Claude Sonnet 4.5", supportedFormats: ["claude"] }, + { id: "claude-sonnet-4", name: "Claude Sonnet 4", supportedFormats: ["claude"] }, + { id: "claude-haiku-4-5", name: "Claude Haiku 4.5", supportedFormats: ["claude"] }, + // Gemini (own path, via chat completions transport) + { id: "gemini-3.6-flash", name: "Gemini 3.6 Flash", supportedFormats: ["openai"] }, + { id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", supportedFormats: ["openai"] }, + { id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", supportedFormats: ["openai"] }, + { id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite", supportedFormats: ["openai"] }, + { id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", supportedFormats: ["openai"] }, + { id: "gemini-3.1-pro", name: "Gemini 3.1 Pro", supportedFormats: ["openai"] }, + { id: "gemini-3-flash", name: "Gemini 3 Flash", supportedFormats: ["openai"] }, + // GPT / Grok / Muse Spark paid (responses) + { id: "gpt-6-astra", name: "GPT 6 Astra", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.6-sol", name: "GPT 5.6 Sol", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.6-terra", name: "GPT 5.6 Terra", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.6-luna", name: "GPT 5.6 Luna", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.5", name: "GPT 5.5", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.5-pro", name: "GPT 5.5 Pro", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.4", name: "GPT 5.4", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.4-pro", name: "GPT 5.4 Pro", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.4-mini", name: "GPT 5.4 Mini", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.4-nano", name: "GPT 5.4 Nano", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.3-codex-spark", name: "GPT 5.3 Codex Spark", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.3-codex", name: "GPT 5.3 Codex", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.2", name: "GPT 5.2", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.2-codex", name: "GPT 5.2 Codex", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.1", name: "GPT 5.1", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.1-codex-max", name: "GPT 5.1 Codex Max", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.1-codex", name: "GPT 5.1 Codex", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5.1-codex-mini", name: "GPT 5.1 Codex Mini", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5", name: "GPT 5", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5-codex", name: "GPT 5 Codex", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "gpt-5-nano", name: "GPT 5 Nano", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "grok-build-0.1", name: "Grok Build 0.1", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "grok-4.6", name: "Grok 4.6", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "grok-4.5", name: "Grok 4.5", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "muse-spark-1.3", name: "Muse Spark 1.3", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "muse-spark-1.2", name: "Muse Spark 1.2", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + // Qwen paid (messages) + { id: "qwen3.6-plus", name: "Qwen 3.6 Plus", supportedFormats: ["claude"] }, + { id: "qwen3.5-plus", name: "Qwen 3.5 Plus", supportedFormats: ["claude"] }, + // DeepSeek / GLM / MiniMax / Kimi / Big Pickle (chat completions) + { id: "deepseek-v4-pro", name: "DeepSeek V4 Pro", supportedFormats: ["openai"] }, + { id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", supportedFormats: ["openai"] }, + { id: "deepseek-v4-flash-vision-exp", name: "DeepSeek V4 Flash Vision Exp", supportedFormats: ["openai"] }, + { id: "glm-5.3-flash", name: "GLM 5.3 Flash (Vision)", supportedFormats: ["openai"] }, + { id: "glm-5.3", name: "GLM 5.3", supportedFormats: ["openai"] }, + { id: "glm-5.2", name: "GLM 5.2", supportedFormats: ["openai"] }, + { id: "glm-5.1", name: "GLM 5.1", supportedFormats: ["openai"] }, + { id: "glm-5", name: "GLM 5", supportedFormats: ["openai"] }, + { id: "minimax-m3", name: "MiniMax M3", supportedFormats: ["openai"] }, + { id: "minimax-m2.7", name: "MiniMax M2.7", supportedFormats: ["openai"] }, + { id: "minimax-m2.5", name: "MiniMax M2.5", supportedFormats: ["openai"] }, + { id: "kimi-k3", name: "Kimi K3", supportedFormats: ["openai"] }, + { id: "kimi-k2.7-code", name: "Kimi K2.7 Code", supportedFormats: ["openai"] }, + { id: "kimi-k2.6", name: "Kimi K2.6", supportedFormats: ["openai"] }, + { id: "kimi-k2.5", name: "Kimi K2.5", supportedFormats: ["openai"] }, + { id: "big-pickle", name: "Big Pickle", supportedFormats: ["openai"] }, + { id: "union-alpha", name: "Union Alpha", supportedFormats: ["claude"] }, + // Free tier on the keyed lane (chat completions) + { id: "deepseek-v4-flash-free", name: "DeepSeek V4 Flash Free", supportedFormats: ["openai"] }, + { id: "mimo-v2.5-free", name: "MiMo V2.5 Free", supportedFormats: ["openai"] }, + { id: "ling-3.0-flash-fin-free", name: "Ling 3.0 Flash Fin Free", supportedFormats: ["openai"] }, + { id: "nemotron-3-ultra-free", name: "Nemotron 3 Ultra Free", supportedFormats: ["openai"] }, + { id: "nemotron-3.5-lightning-free", name: "Nemotron 3.5 Lightning Free", supportedFormats: ["openai"] }, + // Free tier on the keyed lane (responses) + { id: "muse-spark-1.3-contributor-free", name: "Muse Spark 1.3 Contributor Free", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + { id: "muse-spark-1.2-contributor-free", name: "Muse Spark 1.2 Contributor Free", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] }, + ], + modelsFetcher: { url: "https://opencode.ai/zen/v1/models", type: "opencode-free" }, + passthroughModels: true, + features: { + usage: true, + usageApikey: true, + }, +}; diff --git a/open-sse/services/usage.js b/open-sse/services/usage.js index cca5d861..90ecb0e9 100644 --- a/open-sse/services/usage.js +++ b/open-sse/services/usage.js @@ -15,6 +15,7 @@ import { getGrokCliUsage } from "./usage/grok-cli.js"; import { getKimiUsage } from "./usage/kimi.js"; import { getDeepseekUsage } from "./usage/deepseek.js"; import { getOpenCodeGoUsage } from "./usage/opencode-go.js"; +import { getOpenCodeZenUsage } from "./usage/opencode-zen.js"; import { getGroqUsage } from "./usage/groq.js"; import { getZedUsage } from "./usage/zed.js"; import { getXiaomiMimoUsage } from "./usage/xiaomi-mimo.js"; @@ -59,6 +60,7 @@ const USAGE_HANDLERS = { "grok-cli": (c) => getGrokCliUsage(c.accessToken, c.providerSpecificData, c.proxyOptions), kimi: (c) => getKimiUsage(c.accessToken, c.apiKey, c.proxyOptions, c.providerSpecificData), "opencode-go": (c) => getOpenCodeGoUsage(c.apiKey, c.proxyOptions), + "opencode-zen": (c) => getOpenCodeZenUsage(c.apiKey, c.proxyOptions), deepseek: (c) => getDeepseekUsage(c.apiKey, c.proxyOptions), groq: (c) => getGroqUsage(c.apiKey, c.proxyOptions), zed: (c) => getZedUsage(c.accessToken, c.providerSpecificData, c.proxyOptions), diff --git a/open-sse/services/usage/opencode-zen.js b/open-sse/services/usage/opencode-zen.js new file mode 100644 index 00000000..54dacec8 --- /dev/null +++ b/open-sse/services/usage/opencode-zen.js @@ -0,0 +1,107 @@ +/** + * OpenCode Zen usage — GET https://opencode.ai/zen/v1/usage + * Auth: Bearer + */ + +import { proxyAwareFetch } from "../../utils/proxyFetch.js"; +import { parseResetTime, toFiniteNumber, U } from "./shared.js"; + +const USAGE_URL = U("opencode-zen").url; +const QUOTA_NAMES = { + rolling: "Rolling", + weekly: "Weekly", + monthly: "Monthly", +}; + +function parsePercent(value) { + if (typeof value === "number" && Number.isFinite(value)) return value; + if (typeof value === "string" && value.trim()) { + const parsed = Number(value); + if (Number.isFinite(parsed)) return parsed; + } + return null; +} + +export async function getOpenCodeZenUsage(apiKey = null, proxyOptions = null) { + if (!apiKey || typeof apiKey !== "string" || !apiKey.trim()) { + return { + message: "OpenCode Zen API key not available. Add a key to view usage.", + }; + } + + try { + const response = await proxyAwareFetch( + USAGE_URL, + { + method: "GET", + headers: { + Authorization: `Bearer ${apiKey.trim()}`, + Accept: "application/json", + }, + }, + proxyOptions, + ); + + if (response.status === 401) { + return { + plan: "OpenCode Zen", + message: "OpenCode Zen authentication failed. Check the API key.", + }; + } + + if (response.status === 403) { + const error = await response.json().catch(() => null); + const subscriptionRequired = error?.error?.type === "EntitlementError"; + return { + plan: "OpenCode Zen", + message: subscriptionRequired + ? "OpenCode Zen billing required for this API key." + : "OpenCode Zen access forbidden for this API key.", + }; + } + + if (!response.ok) { + return { + plan: "OpenCode Zen", + message: `OpenCode Zen usage API error (${response.status}).`, + }; + } + + const data = await response.json().catch(() => null); + if (!data?.usage || typeof data.usage !== "object") { + return { + plan: "OpenCode Zen", + message: "OpenCode Zen usage response did not contain quota data.", + }; + } + + const quotas = {}; + for (const [period, name] of Object.entries(QUOTA_NAMES)) { + const quota = data.usage[period]; + if (!quota || typeof quota !== "object") continue; + const percent = parsePercent(quota.percent); + if (percent === null) continue; + const used = Math.max(0, Math.min(100, toFiniteNumber(percent, 0))); + quotas[name] = { + used, + total: 100, + remaining: 100 - used, + remainingPercentage: 100 - used, + resetAt: parseResetTime(quota.resetsAt), + unlimited: false, + }; + } + + + if (Object.keys(quotas).length === 0) { + return { + plan: "OpenCode Zen", + message: "OpenCode Zen usage response did not contain valid quota data.", + }; + } + + return { plan: "OpenCode Zen", quotas }; + } catch (error) { + return { message: `OpenCode Zen error: ${error.message}` }; + } +} diff --git a/tests/__baseline__/alias-baseline.json b/tests/__baseline__/alias-baseline.json index ae3a452f..fee2d748 100644 --- a/tests/__baseline__/alias-baseline.json +++ b/tests/__baseline__/alias-baseline.json @@ -180,6 +180,7 @@ "openai": "openai", "opencode": "oc", "opencode-go": "opencode-go", + "opencode-zen": "ocz", "openrouter": "openrouter", "perplexity": "perplexity", "perplexity-agent": "perplexity-agent", @@ -265,6 +266,7 @@ "nebius", "nvidia", "oc", + "ocz", "ollama", "openai", "openai-tts-models", diff --git a/tests/__baseline__/providers-baseline.json b/tests/__baseline__/providers-baseline.json index 89a3db64..d4de0970 100644 --- a/tests/__baseline__/providers-baseline.json +++ b/tests/__baseline__/providers-baseline.json @@ -762,6 +762,44 @@ } ] }, + "opencode-zen": { + "baseUrl": "https://opencode.ai/zen/v1/chat/completions", + "headers": {}, + "usage": { + "url": "https://opencode.ai/zen/v1/usage" + }, + "format": "openai", + "transports": [ + { + "format": "openai", + "baseUrl": "https://opencode.ai/zen/v1/chat/completions", + "auth": { + "combined": true, + "header": "Authorization", + "scheme": "bearer" + } + }, + { + "format": "claude", + "baseUrl": "https://opencode.ai/zen/v1/messages", + "auth": { + "combined": true, + "header": "x-api-key", + "scheme": "raw", + "anthropicVersion": true + } + }, + { + "format": "openai-responses", + "baseUrl": "https://opencode.ai/zen/v1/responses", + "auth": { + "combined": true, + "header": "Authorization", + "scheme": "bearer" + } + } + ] + }, "opencode": { "baseUrl": "https://opencode.ai", "headers": { diff --git a/tests/unit/opencode-zen-models.test.js b/tests/unit/opencode-zen-models.test.js new file mode 100644 index 00000000..3812d400 --- /dev/null +++ b/tests/unit/opencode-zen-models.test.js @@ -0,0 +1,123 @@ +import { describe, expect, it } from "vitest"; +import { PROVIDER_MODELS, getModelSupportedFormats } from "../../open-sse/config/providerModels.js"; +import { PROVIDERS } from "../../open-sse/config/providers.js"; +import { resolveTransport } from "../../open-sse/services/provider.js"; + +// Chat-only models (no /messages, no /responses support on opencode-zen) +const CHAT_ONLY = ["deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v4-flash-vision-exp", + "glm-5.3-flash", "glm-5.3", "glm-5.2", "glm-5.1", "glm-5", + "minimax-m3", "minimax-m2.7", "minimax-m2.5", + "kimi-k3", "kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", + "big-pickle", "deepseek-v4-flash-free", + "mimo-v2.5-free", "ling-3.0-flash-fin-free", "nemotron-3-ultra-free", "nemotron-3.5-lightning-free"]; +// Models that also expose the Anthropic /messages endpoint +const CLAUDE_CAPABLE = ["claude-fable-5", "claude-fable-5-1", "claude-opus-5", + "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-opus-4-5", + "claude-sonnet-5", "claude-sonnet-4-6", "claude-sonnet-4-5", "claude-sonnet-4", + "claude-haiku-4-5", "qwen3.6-plus", "qwen3.5-plus", "union-alpha"]; +// Models that also expose the OpenAI /responses endpoint +const RESPONSES_CAPABLE = ["gpt-6-astra", + "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", + "gpt-5.5", "gpt-5.5-pro", + "gpt-5.4", "gpt-5.4-pro", "gpt-5.4-mini", "gpt-5.4-nano", + "gpt-5.3-codex-spark", "gpt-5.3-codex", + "gpt-5.2", "gpt-5.2-codex", + "gpt-5.1", "gpt-5.1-codex-max", "gpt-5.1-codex", "gpt-5.1-codex-mini", + "gpt-5", "gpt-5-codex", "gpt-5-nano", + "grok-build-0.1", "grok-4.6", "grok-4.5", + "muse-spark-1.3", "muse-spark-1.2", + "muse-spark-1.3-contributor-free", "muse-spark-1.2-contributor-free"]; + +// Mirror of chatCore's per-model transport guard: use the sourceFormat-matched +// transport only when the model declares support for that sourceFormat. +function pickTransport(provider, sourceFormat, alias, model) { + const supported = getModelSupportedFormats(alias, model); + const rt = resolveTransport(provider, sourceFormat); + return supported?.includes(sourceFormat) ? rt : null; +} + +describe("OpenCode Zen model catalog", () => { + it("matches the documented model IDs", () => { + const ids = (PROVIDER_MODELS["ocz"] || []).map((m) => m.id); + expect(ids).toContain("muse-spark-1.3-contributor-free"); + expect(ids).toContain("gpt-5.5"); + expect(ids).toContain("claude-opus-5"); + expect(ids).toContain("kimi-k3"); + expect(ids).toContain("deepseek-v4-pro"); + expect(ids.length).toBeGreaterThan(60); + }); +}); + +describe("OpenCode Zen per-model supportedFormats", () => { + it("declares [claude] for Claude + Qwen + union-alpha models", () => { + for (const m of CLAUDE_CAPABLE) { + expect(getModelSupportedFormats("ocz", m)).toEqual(["claude"]); + } + }); + + it("declares [openai-responses] for GPT/Grok/Spark responses models", () => { + for (const m of RESPONSES_CAPABLE) { + expect(getModelSupportedFormats("ocz", m)).toEqual(["openai-responses"]); + } + }); + + it("declares [openai] only for chat-only models (GLM/Kimi/MiMo) → guards /messages routing", () => { + for (const m of CHAT_ONLY) { + expect(getModelSupportedFormats("ocz", m)).toEqual(["openai"]); + } + }); +}); + +describe("OpenCode Zen multi-endpoint transports", () => { + it("declares openai / claude / openai-responses transports", () => { + const formats = (PROVIDERS["opencode-zen"].transports || []).map((t) => t.format); + expect(formats).toEqual(["openai", "claude", "openai-responses"]); + }); + + it("resolveTransport picks the endpoint matching the client sourceFormat", () => { + expect(resolveTransport("opencode-zen", "claude").baseUrl).toBe("https://opencode.ai/zen/v1/messages"); + expect(resolveTransport("opencode-zen", "openai-responses").baseUrl).toBe("https://opencode.ai/zen/v1/responses"); + expect(resolveTransport("opencode-zen", "openai").baseUrl).toBe("https://opencode.ai/zen/v1/chat/completions"); + }); + + it("uses x-api-key + anthropicVersion on the claude transport", () => { + const t = resolveTransport("opencode-zen", "claude"); + expect(t.auth.header).toBe("x-api-key"); + expect(t.auth.anthropicVersion).toBe(true); + }); +}); + +describe("OpenCode Zen per-model transport guard (chatCore logic)", () => { + it("routes MiniMax/Qwen + claude-format client to /messages", () => { + for (const m of CLAUDE_CAPABLE) { + expect(pickTransport("opencode-zen", "claude", "ocz", m)?.baseUrl).toBe("https://opencode.ai/zen/v1/messages"); + } + }); + + it("does NOT route chat-only models to /messages on a claude-format request", () => { + for (const m of CHAT_ONLY) { + expect(pickTransport("opencode-zen", "claude", "ocz", m)).toBeNull(); + } + }); + + it("routes DeepSeek + responses-format client to /responses", () => { + for (const m of RESPONSES_CAPABLE) { + expect(pickTransport("opencode-zen", "openai-responses", "ocz", m)?.baseUrl).toBe("https://opencode.ai/zen/v1/responses"); + } + }); + + it("routes Muse Spark (responses-only) to /responses, never to /messages", () => { + for (const m of ["muse-spark-1.2", "muse-spark-1.3", "muse-spark-1.2-contributor-free", "muse-spark-1.3-contributor-free", "grok-4.6", "gpt-5.6-luna"]) { + expect(getModelSupportedFormats("ocz", m)).toEqual(["openai-responses"]); + expect(pickTransport("opencode-zen", "openai-responses", "ocz", m)?.baseUrl).toBe("https://opencode.ai/zen/v1/responses"); + expect(pickTransport("opencode-zen", "claude", "ocz", m)).toBeNull(); + expect(pickTransport("opencode-zen", "openai", "ocz", m)).toBeNull(); + } + }); + + it("does NOT route MiniMax (no responses support) to /responses", () => { + for (const m of CLAUDE_CAPABLE) { + expect(pickTransport("opencode-zen", "openai-responses", "ocz", m)).toBeNull(); + } + }); +}); From 822aa958d19b535f8b02c19bb4e8aa4cf0cdd533 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 19 Sep 2026 10:10:43 +0700 Subject: [PATCH 03/41] fix(opencode): cloak Responses requests that already have tools Free-tier Zen models reject Responses requests with 403 FreeTierError when client tools are present but the fingerprint quartet is missing. Apply the fingerprint tools to every OpenCode request, canonicalise case variants of the quartet (Bash->bash) without duplication, and restore the caller's original spellings on the response side via a request-local WeakMap threaded through the existing toolNameMap. --- open-sse/executors/opencode.js | 72 +----- open-sse/handlers/chatCore.js | 7 +- .../handlers/chatCore/nonStreamingHandler.js | 3 +- .../handlers/chatCore/sseToJsonHandler.js | 9 +- open-sse/translator/index.js | 8 +- open-sse/utils/opencodeFingerprint.js | 232 ++++++++++++++++++ tests/unit/opencode-fingerprint.test.js | 191 ++++++++++++++ tests/unit/opencode-session.test.js | 87 ++++--- 8 files changed, 506 insertions(+), 103 deletions(-) create mode 100644 open-sse/utils/opencodeFingerprint.js create mode 100644 tests/unit/opencode-fingerprint.test.js diff --git a/open-sse/executors/opencode.js b/open-sse/executors/opencode.js index 507c3718..4623dcf6 100644 --- a/open-sse/executors/opencode.js +++ b/open-sse/executors/opencode.js @@ -6,6 +6,7 @@ import { getThinkingLevels } from "../providers/thinkingLevels.js"; import { injectReasoningContent } from "../utils/reasoningContentInjector.js"; import { resolveSessionId } from "../utils/sessionManager.js"; import { isMuseSparkModel } from "../providers/models/helpers.js"; +import { applyFingerprintTools } from "../utils/opencodeFingerprint.js"; import { ANTHROPIC_API_VERSION } from "../providers/shared.js"; import { normalizeResponsesInput, @@ -24,68 +25,6 @@ export const OPENCODE_SESSION_RE = /^ses_[0-9a-f]{12}[0-9A-Za-z]{14}$/; export const OPENCODE_REQUEST_RE = /^msg_[0-9a-f]{12}[0-9A-Za-z]{14}$/; const BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -// OpenCode free tier requires both 'bash' and 'read' in tools payload. -// Injected as cloaked decoy tools so external CLI tools (e.g. Claude Code's Bash/Read) -// take precedence while satisfying upstream verification. -const OPENCODE_DECOY_CHAT_TOOLS = [ - { - type: "function", - function: { - name: "bash", - description: "This tool is currently unavailable and must not be used.", - parameters: { type: "object", properties: {} }, - }, - }, - { - type: "function", - function: { - name: "read", - description: "This tool is currently unavailable and must not be used.", - parameters: { type: "object", properties: {} }, - }, - }, -]; - -const OPENCODE_DECOY_RESPONSES_TOOLS = [ - { - type: "function", - name: "bash", - description: "This tool is currently unavailable and must not be used.", - parameters: { type: "object", properties: {} }, - }, - { - type: "function", - name: "read", - description: "This tool is currently unavailable and must not be used.", - parameters: { type: "object", properties: {} }, - }, -]; - -function cloakOpencodeTools(body, isResponses) { - if (!body || typeof body !== "object") return; - if (isResponses) { - if (!Array.isArray(body.tools)) body.tools = []; - const names = new Set(body.tools.map((t) => t.name || t.function?.name)); - for (const tool of OPENCODE_DECOY_RESPONSES_TOOLS) { - if (!names.has(tool.name)) body.tools.push({ ...tool }); - } - if (!body.tool_choice) body.tool_choice = "auto"; - } else { - const hasTools = Array.isArray(body.tools) && body.tools.length > 0; - if (!hasTools) { - body.tools = OPENCODE_DECOY_CHAT_TOOLS.map((t) => ({ ...t, function: { ...t.function } })); - if (!body.tool_choice) body.tool_choice = "none"; - } else { - const names = new Set(body.tools.map((t) => t.function?.name || t.name)); - for (const tool of OPENCODE_DECOY_CHAT_TOOLS) { - if (!names.has(tool.function.name)) { - body.tools.push({ ...tool, function: { ...tool.function } }); - } - } - } - } -} - function hasValidOpencodeVersion(ua) { const m = String(ua || "").match(/opencode\/(\d+)\.(\d+)(?:\.(\d+))?/i); if (!m) return false; @@ -499,11 +438,12 @@ export class OpenCodeExecutor extends BaseExecutor { body.store = false; normalizeResponsesTools(body); sanitizeResponsesItems(body); - if (!Array.isArray(body.tools) || body.tools.length === 0) { - cloakOpencodeTools(body, true); - } + // Free-tier fingerprint tools are required even when an agent client + // already supplied tools. ZCode/Claude Code requests normally have + // non-empty tool arrays; skipping cloaking here triggers 403 FreeTierError. + applyFingerprintTools(body, true); } else if (body && typeof body === "object") { - cloakOpencodeTools(body, false); + applyFingerprintTools(body, false); } return injectReasoningContent({ provider: this.provider, model, body }); } diff --git a/open-sse/handlers/chatCore.js b/open-sse/handlers/chatCore.js index 85c6fc4a..56a9d69f 100644 --- a/open-sse/handlers/chatCore.js +++ b/open-sse/handlers/chatCore.js @@ -20,6 +20,7 @@ import { handleNonStreamingResponse } from "./chatCore/nonStreamingHandler.js"; import { handleStreamingResponse, buildOnStreamComplete } from "./chatCore/streamingHandler.js"; import { detectClientTool, isNativePassthrough } from "../utils/clientDetector.js"; import { dedupeTools } from "../utils/toolDeduper.js"; +import { takeRenamedToolNames } from "../utils/opencodeFingerprint.js"; import { injectCaveman } from "../rtk/caveman.js"; import { injectPonytail } from "../rtk/ponytail.js"; import { compressMessages, formatRtkLog } from "../rtk/index.js"; @@ -376,6 +377,10 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred providerHeaders = result.headers; finalBody = result.transformedBody; providerResponseFormat = result.responseFormat || targetFormat; + const renamedToolNames = takeRenamedToolNames(translatedBody); + if (renamedToolNames?.size) { + toolNameMap = new Map([...(toolNameMap || []), ...renamedToolNames]); + } reqLogger.logTargetRequest(providerUrl, providerHeaders, finalBody); } catch (error) { trackPendingRequest(model, provider, connectionId, false, true); @@ -480,7 +485,7 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred // Provider forced streaming but client wants JSON if (!clientRequestedStreaming && providerRequiresStreaming) { - const result = await handleForcedSSEToJson({ ...sharedCtx, providerResponse, sourceFormat, targetFormat: providerResponseFormat, customToolNames, trackDone, appendLog }); + const result = await handleForcedSSEToJson({ ...sharedCtx, providerResponse, sourceFormat, targetFormat: providerResponseFormat, customToolNames, toolNameMap, trackDone, appendLog }); if (result) { streamController.handleComplete(); return result; } } diff --git a/open-sse/handlers/chatCore/nonStreamingHandler.js b/open-sse/handlers/chatCore/nonStreamingHandler.js index d7f4f3fe..19018147 100644 --- a/open-sse/handlers/chatCore/nonStreamingHandler.js +++ b/open-sse/handlers/chatCore/nonStreamingHandler.js @@ -10,6 +10,7 @@ import { unwrapClineEnvelope } from "../../shared/clineEnvelope.js"; import { buildRequestDetail, extractRequestConfig, extractUsageFromResponse, saveUsageStats, formatDoneLine } from "./requestDetail.js"; import { appendRequestLog, saveRequestDetail } from "@/lib/usageDb.js"; import { decloakToolNames } from "../../utils/claudeCloaking.js"; +import { restoreToolNames } from "../../utils/opencodeFingerprint.js"; import { ROLE, RESPONSES_ITEM } from "../../translator/schema/index.js"; function parseToolArguments(value) { @@ -397,7 +398,7 @@ export async function handleNonStreamingResponse({ providerResponse, provider, m return { success: true, - response: new Response(JSON.stringify(translatedResponse), { + response: new Response(JSON.stringify(restoreToolNames(translatedResponse, toolNameMap)), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } }) }; diff --git a/open-sse/handlers/chatCore/sseToJsonHandler.js b/open-sse/handlers/chatCore/sseToJsonHandler.js index 6801be89..cc7c9aac 100644 --- a/open-sse/handlers/chatCore/sseToJsonHandler.js +++ b/open-sse/handlers/chatCore/sseToJsonHandler.js @@ -1,4 +1,5 @@ import { convertResponsesStreamToJson } from "../../transformer/streamToJsonConverter.js"; +import { restoreToolNames } from "../../utils/opencodeFingerprint.js"; import { createErrorResult } from "../../utils/error.js"; import { HTTP_STATUS } from "../../config/runtimeConfig.js"; import { FORMATS } from "../../translator/formats.js"; @@ -179,7 +180,7 @@ export function parseSSEToOpenAIResponse(rawSSE, fallbackModel) { * Handle case: provider forced streaming but client wants JSON. * Supports both Codex/Responses API SSE and standard Chat Completions SSE. */ -export async function handleForcedSSEToJson({ providerResponse, sourceFormat, targetFormat, provider, model, body, stream, translatedBody, finalBody, requestStartTime, connectionId, apiKey, clientRawRequest, onRequestSuccess, customToolNames, trackDone, appendLog, reqTag, log }) { +export async function handleForcedSSEToJson({ providerResponse, sourceFormat, targetFormat, provider, model, body, stream, translatedBody, finalBody, requestStartTime, connectionId, apiKey, clientRawRequest, onRequestSuccess, customToolNames, toolNameMap, trackDone, appendLog, reqTag, log }) { const contentType = providerResponse.headers.get("content-type") || ""; const isSSE = contentType.includes("text/event-stream") || (contentType === "" && isResponsesProvider(provider)); if (!isSSE) return null; // not handled here @@ -225,7 +226,7 @@ export async function handleForcedSSEToJson({ providerResponse, sourceFormat, ta // Client is Responses API → return as-is if (sourceFormat === FORMATS.OPENAI_RESPONSES) { - return { success: true, response: new Response(JSON.stringify(jsonResponse), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } }) }; + return { success: true, response: new Response(JSON.stringify(restoreToolNames(jsonResponse, toolNameMap)), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } }) }; } // Build client-format response. @@ -281,7 +282,7 @@ export async function handleForcedSSEToJson({ providerResponse, sourceFormat, ta }; } - return { success: true, response: new Response(JSON.stringify(finalResp), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } }) }; + return { success: true, response: new Response(JSON.stringify(restoreToolNames(finalResp, toolNameMap)), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } }) }; } catch (err) { console.error("[ChatCore] Responses API SSE→JSON failed:", err); return createErrorResult(HTTP_STATUS.BAD_GATEWAY, "Failed to convert streaming response to JSON"); @@ -351,7 +352,7 @@ export async function handleForcedSSEToJson({ providerResponse, sourceFormat, ta ? chatCompletionToResponses(parsed, customToolNames) : parsed; - return { success: true, response: new Response(JSON.stringify(finalBody), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } }) }; + return { success: true, response: new Response(JSON.stringify(restoreToolNames(finalBody, toolNameMap)), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } }) }; } catch (err) { console.error("[ChatCore] Chat Completions SSE→JSON failed:", err); return createErrorResult(HTTP_STATUS.BAD_GATEWAY, "Failed to convert streaming response to JSON"); diff --git a/open-sse/translator/index.js b/open-sse/translator/index.js index 2fcbcbf8..8a1add5f 100644 --- a/open-sse/translator/index.js +++ b/open-sse/translator/index.js @@ -2,6 +2,7 @@ import { FORMATS } from "./formats.js"; import { ensureToolCallIds, fixMissingToolResponses } from "./concerns/toolCall.js"; import { prepareClaudeRequest } from "./formats/claude.js"; import { cloakClaudeTools, decloakStreamChunk } from "../utils/claudeCloaking.js"; +import { restoreToolNames } from "../utils/opencodeFingerprint.js"; import { filterToOpenAIFormat } from "./formats/openai.js"; import { normalizeThinkingConfig } from "../services/provider.js"; import { applyThinking, captureThinking } from "./concerns/thinkingUnified.js"; @@ -166,7 +167,7 @@ export function translateResponse(targetFormat, sourceFormat, chunk, state) { // even when no format conversion is needed, so streamed tool_use blocks must // be decloaked here or the client sees an unknown ("_ide"-suffixed) tool. if (sourceFormat === targetFormat) { - return [decloakStreamChunk(chunk, state?.toolNameMap)]; + return [restoreToolNames(decloakStreamChunk(chunk, state?.toolNameMap), state?.toolNameMap)]; } let results = [chunk]; @@ -179,7 +180,8 @@ export function translateResponse(targetFormat, sourceFormat, chunk, state) { const directFn = responseRegistry.get(`${targetFormat}:${sourceFormat}`); if (directFn) { const converted = directFn(chunk, state); - return converted ? (Array.isArray(converted) ? converted : [converted]) : []; + const directResults = converted ? (Array.isArray(converted) ? converted : [converted]) : []; + return restoreToolNames(directResults, state?.toolNameMap); } // Step 1: target -> openai (if target is not openai) @@ -210,6 +212,8 @@ export function translateResponse(targetFormat, sourceFormat, chunk, state) { } } + results = restoreToolNames(results, state?.toolNameMap); + // Attach OpenAI intermediate results for logging if (openaiResults && sourceFormat !== FORMATS.OPENAI && targetFormat !== FORMATS.OPENAI) { results._openaiIntermediate = openaiResults; diff --git a/open-sse/utils/opencodeFingerprint.js b/open-sse/utils/opencodeFingerprint.js new file mode 100644 index 00000000..db7ba03a --- /dev/null +++ b/open-sse/utils/opencodeFingerprint.js @@ -0,0 +1,232 @@ +/** + * Helpers for the OpenCode Zen free-tier client fingerprint. + * + * Live upstream probes show that free-tier requests must include the lowercase + * file-search quartet (bash/glob/grep/read). Agent clients such as Claude Code + * may declare the same tools with different casing, so those case variants must + * be renamed instead of duplicated. The response side restores the caller's + * original spelling so downstream clients still recognise their own tool calls. + */ + +/** Canonical names required by the upstream free-tier gate. */ +export const OPENCODE_FINGERPRINT_TOOLS = ["bash", "glob", "grep", "read"]; + +// Request body -> names renamed for that request. transformRequest() mutates the +// same body object that chatCore passed into the executor, so a WeakMap keeps the +// mapping request-local without putting transport metadata on the wire. +const renamedToolNames = new WeakMap(); + +/** Canonical lowercase name when `name` is a quartet member; "" otherwise. */ +export function fingerprintToolKey(name) { + const lower = String(name ?? "").trim().toLowerCase(); + return OPENCODE_FINGERPRINT_TOOLS.includes(lower) ? lower : ""; +} + +/** Read a tool name from either flat ({name}) or chat ({function:{name}}) shape. */ +function toolNameOf(tool) { + if (!tool || typeof tool !== "object" || Array.isArray(tool)) return ""; + if (typeof tool.name === "string" && tool.name.trim()) return tool.name.trim(); + const fn = tool.function; + if (fn && typeof fn === "object" && !Array.isArray(fn) && typeof fn.name === "string") { + return fn.name.trim(); + } + return ""; +} + +/** + * Canonicalise only the fingerprint quartet and remove duplicate quartet + * variants. Non-fingerprint tools are preserved verbatim, including tools whose + * names differ only by case; they are outside OpenCode's fingerprint contract. + * + * @param {Array} tools + * @returns {{ tools: Array, map: Map }} map: sent name -> original name + */ +export function concealFingerprintToolNames(tools) { + const map = new Map(); + if (!Array.isArray(tools) || tools.length === 0) return { tools, map }; + + const seenQuartet = new Set(); + const out = []; + for (const tool of tools) { + if (!tool || typeof tool !== "object" || Array.isArray(tool)) { + out.push(tool); + continue; + } + + const current = toolNameOf(tool); + const key = fingerprintToolKey(current); + if (!key) { + out.push(tool); + continue; + } + + // `Bash` + `bash` is rejected upstream as a duplicate. Keep exactly one + // declaration for each quartet member. + if (seenQuartet.has(key)) continue; + seenQuartet.add(key); + + if (current !== key) { + map.set(key, current); + const fn = tool.function && typeof tool.function === "object" && !Array.isArray(tool.function) + ? tool.function + : null; + out.push(fn ? { ...tool, function: { ...fn, name: key } } : { ...tool, name: key }); + } else { + out.push(tool); + } + } + return { tools: out, map }; +} + +/** Append only genuinely missing quartet declarations. */ +export function appendMissingFingerprintTools(tools, flat) { + const list = Array.isArray(tools) ? tools : []; + for (const name of OPENCODE_FINGERPRINT_TOOLS) { + if (list.some((tool) => fingerprintToolKey(toolNameOf(tool)) === name)) continue; + list.push(flat ? { + type: "function", + name, + description: "This tool is currently unavailable and must not be used.", + parameters: { type: "object", properties: {} }, + } : { + type: "function", + function: { + name, + description: "This tool is currently unavailable and must not be used.", + parameters: { type: "object", properties: {} }, + }, + }); + } + return list; +} + +/** Point an explicit tool_choice at a quartet member after canonicalisation. */ +export function retargetToolChoice(body, map) { + if (!body || typeof body !== "object" || !map?.size) return; + const choice = body.tool_choice; + if (!choice || typeof choice !== "object" || Array.isArray(choice)) return; + + if (typeof choice.name === "string") { + const key = fingerprintToolKey(choice.name); + if (key && map.has(key)) body.tool_choice = { ...choice, name: key }; + return; + } + + const fn = choice.function; + if (fn && typeof fn === "object" && !Array.isArray(fn) && typeof fn.name === "string") { + const key = fingerprintToolKey(fn.name); + if (key && map.has(key)) { + body.tool_choice = { ...choice, function: { ...fn, name: key } }; + } + } +} + +/** + * Full request-side pass: canonicalise quartet case variants, remove duplicate + * quartet declarations, append missing members and preserve the legacy + * tool_choice defaults used by the OpenCode executor. + * + * @param {object} body + * @param {boolean} flat - true for Responses tools ({name}), false for chat tools + * @returns {Map} map: sent name -> original name + */ +export function applyFingerprintTools(body, flat) { + if (!body || typeof body !== "object") return new Map(); + + const hadClientTools = Array.isArray(body.tools) && body.tools.length > 0; + const { tools, map } = concealFingerprintToolNames(body.tools); + body.tools = appendMissingFingerprintTools(tools, flat); + retargetToolChoice(body, map); + + // Preserve the existing executor semantics. Responses uses auto when the + // fingerprint helper supplies tools; chat requests with no caller tools use + // none so the injected decoys cannot be selected. + if (!body.tool_choice) { + if (flat) body.tool_choice = "auto"; + else if (!hadClientTools) body.tool_choice = "none"; + } + + recordRenamedToolNames(body, map); + return map; +} + +/** Store the rename map for `body`. */ +export function recordRenamedToolNames(body, map) { + if (!body || typeof body !== "object" || !map?.size) return; + renamedToolNames.set(body, map); +} + +/** Retrieve the rename map for `body`. */ +export function takeRenamedToolNames(body) { + if (!body || typeof body !== "object") return null; + return renamedToolNames.get(body) || null; +} + +// Response side ------------------------------------------------------------- + +/** Restore caller tool spellings in supported response/event shapes. */ +export function restoreToolNames(payload, map) { + if (!map?.size || !payload) return payload; + if (Array.isArray(payload)) return payload.map((item) => restoreToolNames(item, map)); + if (typeof payload !== "object") return payload; + + let out = payload; + const put = (key, value) => { + if (out === payload) out = { ...payload }; + out[key] = value; + }; + + // Claude streaming content_block_start event. + if (payload.type === "content_block_start") { + const block = payload.content_block; + if (block?.type === "tool_use" && typeof block.name === "string" && map.has(block.name)) { + put("content_block", { ...block, name: map.get(block.name) }); + } + } + + // Claude non-streaming message body. + if (Array.isArray(payload.content)) { + put("content", payload.content.map((block) => + block?.type === "tool_use" && typeof block.name === "string" && map.has(block.name) + ? { ...block, name: map.get(block.name) } + : block)); + } + + // OpenAI Chat Completions, both streaming delta and JSON message shapes. + if (Array.isArray(payload.choices)) { + put("choices", payload.choices.map((choice) => { + let changed = false; + const next = { ...choice }; + for (const holder of ["delta", "message"]) { + const value = choice?.[holder]; + if (!value || !Array.isArray(value.tool_calls) || value.tool_calls.length === 0) continue; + const calls = value.tool_calls.map((call) => { + const name = call?.function?.name; + if (typeof name === "string" && map.has(name)) { + changed = true; + return { ...call, function: { ...call.function, name: map.get(name) } }; + } + return call; + }); + next[holder] = { ...value, tool_calls: calls }; + } + return changed ? next : choice; + })); + } + + // OpenAI Responses final JSON body. + if (Array.isArray(payload.output)) { + put("output", payload.output.map((item) => + item?.type === "function_call" && typeof item.name === "string" && map.has(item.name) + ? { ...item, name: map.get(item.name) } + : item)); + } + + // OpenAI Responses SSE events such as response.output_item.added/done. + const item = payload.item; + if (item?.type === "function_call" && typeof item.name === "string" && map.has(item.name)) { + put("item", { ...item, name: map.get(item.name) }); + } + + return out; +} diff --git a/tests/unit/opencode-fingerprint.test.js b/tests/unit/opencode-fingerprint.test.js new file mode 100644 index 00000000..35036699 --- /dev/null +++ b/tests/unit/opencode-fingerprint.test.js @@ -0,0 +1,191 @@ +import { describe, it, expect } from "vitest"; +import { + applyFingerprintTools, + concealFingerprintToolNames, + appendMissingFingerprintTools, + fingerprintToolKey, + restoreToolNames, + takeRenamedToolNames, + OPENCODE_FINGERPRINT_TOOLS, +} from "open-sse/utils/opencodeFingerprint.js"; + +const CC_TOOLS = ["Task", "Bash", "Glob", "Grep", "Read", "Edit", "Write", "WebFetch"]; +const flat = (names) => names.map((name) => ({ type: "function", name })); +const chat = (names) => names.map((name) => ({ type: "function", function: { name } })); + +describe("opencodeFingerprint — request side", () => { + it("renames capitalised quartet members to lowercase", () => { + const body = { tools: flat(CC_TOOLS) }; + const map = applyFingerprintTools(body, true); + const names = body.tools.map((tool) => tool.name); + + expect(names).toContain("bash"); + expect(names).not.toContain("Bash"); + expect(names).toContain("Edit"); + expect(map.get("bash")).toBe("Bash"); + }); + + it("removes quartet case duplicates without dropping unrelated case variants", () => { + const body = { tools: flat(["Bash", "bash", "Glob", "grep", "Read", "Foo", "foo"]) }; + applyFingerprintTools(body, true); + + const names = body.tools.map((tool) => tool.name); + expect(names.filter((name) => name === "bash")).toHaveLength(1); + expect(names).toContain("Foo"); + expect(names).toContain("foo"); + }); + + it("preserves tool count when a complete quartet is only renamed", () => { + const body = { tools: flat(CC_TOOLS) }; + applyFingerprintTools(body, true); + expect(body.tools).toHaveLength(CC_TOOLS.length); + }); + + it("handles the nested chat shape without dropping .function", () => { + const body = { tools: chat(CC_TOOLS) }; + applyFingerprintTools(body, false); + + const names = body.tools.map((tool) => tool.function.name); + expect(names).toContain("bash"); + expect(names).not.toContain("Bash"); + expect(body.tools[1].function.name).toBe("bash"); + }); + + it("injects all four fingerprint tools when the body carries no tools", () => { + const body = { tools: [] }; + applyFingerprintTools(body, true); + + expect(body.tools.map((tool) => tool.name).sort()).toEqual([...OPENCODE_FINGERPRINT_TOOLS].sort()); + expect(body.tool_choice).toBe("auto"); + }); + + it("preserves the chat no-tool default tool_choice=none", () => { + const body = {}; + applyFingerprintTools(body, false); + + expect(body.tools.map((tool) => tool.function.name)).toEqual(OPENCODE_FINGERPRINT_TOOLS); + expect(body.tool_choice).toBe("none"); + }); + + it("does not invent a chat tool_choice when the caller already supplied tools", () => { + const body = { tools: chat(["Edit"]) }; + applyFingerprintTools(body, false); + expect(body.tool_choice).toBeUndefined(); + }); + + it("appends only genuinely missing quartet members", () => { + const body = { tools: flat(["Bash", "Read", "terminal"]) }; + applyFingerprintTools(body, true); + + const names = body.tools.map((tool) => tool.name); + expect(names).toContain("glob"); + expect(names).toContain("grep"); + expect(names).toContain("terminal"); + expect(body.tools).toHaveLength(5); + }); + + it("retargets flat tool_choice that points at a renamed tool", () => { + const body = { tools: flat(CC_TOOLS), tool_choice: { type: "function", name: "Bash" } }; + applyFingerprintTools(body, true); + expect(body.tool_choice.name).toBe("bash"); + }); + + it("retargets nested tool_choice that points at a renamed tool", () => { + const body = { + tools: chat(CC_TOOLS), + tool_choice: { type: "function", function: { name: "Read" } }, + }; + applyFingerprintTools(body, false); + expect(body.tool_choice.function.name).toBe("read"); + }); + + it("records the rename map against the body for the response side", () => { + const body = { tools: flat(CC_TOOLS) }; + const map = applyFingerprintTools(body, true); + expect(takeRenamedToolNames(body)).toBe(map); + }); + + it("never throws on malformed tools", () => { + for (const tools of [null, undefined, "nope", [null, 42, []], [{}, { name: "" }]]) { + expect(() => concealFingerprintToolNames(tools)).not.toThrow(); + expect(() => appendMissingFingerprintTools(tools, true)).not.toThrow(); + } + }); +}); + +describe("opencodeFingerprint — response side", () => { + const map = new Map([["bash", "Bash"], ["grep", "Grep"], ["read", "Read"]]); + + it("restores names in Claude content_block_start chunks", () => { + const chunk = { + type: "content_block_start", + content_block: { type: "tool_use", name: "bash", id: "t1" }, + }; + const out = restoreToolNames(chunk, map); + + expect(out.content_block.name).toBe("Bash"); + expect(chunk.content_block.name).toBe("bash"); + }); + + it("recursively restores streaming chunks inside arrays", () => { + const chunks = [{ + choices: [{ delta: { tool_calls: [{ function: { name: "grep", arguments: "{}" } }] } }], + }]; + const out = restoreToolNames(chunks, map); + expect(out[0].choices[0].delta.tool_calls[0].function.name).toBe("Grep"); + }); + + it("restores names in Claude non-streaming bodies", () => { + const body = { type: "message", content: [{ type: "tool_use", name: "bash", input: {} }] }; + expect(restoreToolNames(body, map).content[0].name).toBe("Bash"); + }); + + it("restores names in Chat Completions message and delta shapes", () => { + const body = { + choices: [ + { message: { tool_calls: [{ function: { name: "grep", arguments: "{}" } }] } }, + { delta: { tool_calls: [{ function: { name: "read", arguments: "{}" } }] } }, + ], + }; + const out = restoreToolNames(body, map); + + expect(out.choices[0].message.tool_calls[0].function.name).toBe("Grep"); + expect(out.choices[1].delta.tool_calls[0].function.name).toBe("Read"); + }); + + it("restores names in Responses final output items", () => { + const body = { output: [{ type: "function_call", name: "bash", call_id: "c1" }] }; + expect(restoreToolNames(body, map).output[0].name).toBe("Bash"); + }); + + it("restores names in Responses streaming output_item events", () => { + const event = { + type: "response.output_item.added", + item: { type: "function_call", name: "read", call_id: "c1" }, + }; + expect(restoreToolNames(event, map).item.name).toBe("Read"); + }); + + it("is a no-op without a map or with an empty map", () => { + const body = { choices: [{ message: { tool_calls: [{ function: { name: "bash" } }] } }] }; + expect(restoreToolNames(body, null)).toBe(body); + expect(restoreToolNames(body, new Map())).toBe(body); + }); + + it("leaves unknown tool names untouched", () => { + const body = { output: [{ type: "function_call", name: "Edit" }] }; + expect(restoreToolNames(body, map).output[0].name).toBe("Edit"); + }); +}); + +describe("fingerprintToolKey", () => { + it("maps quartet case/whitespace variants and rejects other tools", () => { + expect(fingerprintToolKey("Bash")).toBe("bash"); + expect(fingerprintToolKey(" bash ")).toBe("bash"); + expect(fingerprintToolKey("GLOB")).toBe("glob"); + expect(fingerprintToolKey("Read")).toBe("read"); + expect(fingerprintToolKey("Edit")).toBe(""); + expect(fingerprintToolKey("terminal")).toBe(""); + expect(fingerprintToolKey(null)).toBe(""); + }); +}); diff --git a/tests/unit/opencode-session.test.js b/tests/unit/opencode-session.test.js index 3e50b9fe..e8161f7e 100644 --- a/tests/unit/opencode-session.test.js +++ b/tests/unit/opencode-session.test.js @@ -277,39 +277,68 @@ describe("OpenCode Stable Session Reuse (429 follow-up)", () => { expect(second).toBe(first); }); - it("cloaks free-tier requests with bash and read decoy tools", () => { + it("applies the full lowercase free-tier fingerprint quartet", () => { + const executor = getExecutor("opencode"); + + const chatNoTools = executor.transformRequest("nemotron-3-ultra-free", { + messages: [{ role: "user", content: "hi" }], + }); + expect(chatNoTools.stream).toBe(true); + expect(chatNoTools.tool_choice).toBe("none"); + expect(chatNoTools.tools.map((t) => t.function?.name)).toEqual([ + "bash", "glob", "grep", "read", + ]); + + const chatWithTools = executor.transformRequest("nemotron-3-ultra-free", { + messages: [{ role: "user", content: "hi" }], + tools: [ + { type: "function", function: { name: "Bash", description: "Claude Code tool" } }, + { type: "function", function: { name: "Glob", description: "Claude Code tool" } }, + { type: "function", function: { name: "Grep", description: "Claude Code tool" } }, + { type: "function", function: { name: "Read", description: "Claude Code tool" } }, + ], + tool_choice: "auto", + }); + expect(chatWithTools.tool_choice).toBe("auto"); + expect(chatWithTools.tools.map((t) => t.function?.name)).toEqual([ + "bash", "glob", "grep", "read", + ]); + + const chatPartial = executor.transformRequest("nemotron-3-ultra-free", { + messages: [{ role: "user", content: "hi" }], + tools: [ + { type: "function", function: { name: "bash", description: "existing" } }, + { type: "function", function: { name: "read", description: "existing" } }, + ], + }); + expect(chatPartial.tools.map((t) => t.function?.name)).toEqual([ + "bash", "read", "glob", "grep", + ]); + expect(chatPartial.tools[0].function.description).toBe("existing"); +}); + + it("cloaks Muse Responses requests even when the client already supplies tools", () => { const executor = getExecutor("opencode"); - - // Case 1: no tools sent by client -> injects bash + read with tool_choice none - const chatNoTools = executor.transformRequest("nemotron-3-ultra-free", { - messages: [{ role: "user", content: "hi" }], - }); - expect(chatNoTools.stream).toBe(true); - expect(chatNoTools.tool_choice).toBe("none"); - expect(chatNoTools.tools.map((t) => t.function?.name)).toEqual(["bash", "read"]); - - // Case 2: external CLI tools (e.g. Claude Code Bash) -> preserves Bash, appends read - const chatWithTools = executor.transformRequest("nemotron-3-ultra-free", { - messages: [{ role: "user", content: "hi" }], - tools: [{ type: "function", function: { name: "Bash", description: "Claude Code tool" } }], + const transformed = executor.transformRequest("muse-spark-1.3-contributor-free(xhigh)", { + input: [{ type: "message", role: "user", content: [{ type: "input_text", text: "hi" }] }], + tools: [{ + type: "function", + name: "zcode_search", + description: "client-provided tool", + parameters: { type: "object", properties: {} }, + }], tool_choice: "auto", - }); - expect(chatWithTools.tool_choice).toBe("auto"); - const names = chatWithTools.tools.map((t) => t.function?.name); - expect(names).toContain("Bash"); + reasoning_effort: "xhigh", + }, true, {}); + + expect(transformed.stream).toBe(true); + expect(transformed.reasoning?.effort).toBe("xhigh"); + const names = transformed.tools.map((tool) => tool.name); + expect(names).toContain("zcode_search"); expect(names).toContain("bash"); expect(names).toContain("read"); - - // Case 3: already has both bash and read -> do not insert anything - const chatFull = executor.transformRequest("nemotron-3-ultra-free", { - messages: [{ role: "user", content: "hi" }], - tools: [ - { type: "function", function: { name: "bash", description: "existing" } }, - { type: "function", function: { name: "read", description: "existing" } }, - ], - }); - expect(chatFull.tools.length).toBe(2); - expect(chatFull.tools[0].function.description).toBe("existing"); + expect(names.filter((name) => name === "bash")).toHaveLength(1); + expect(names.filter((name) => name === "read")).toHaveLength(1); }); it("declares forceStream on the opencode transport so chatCore serves SSE upstream", async () => { From cf663f5300035b7a45e05dd5aed15f4d39340ee6 Mon Sep 17 00:00:00 2001 From: kimono381 <62897149+kimono381@users.noreply.github.com> Date: Sat, 19 Sep 2026 10:44:13 +0700 Subject: [PATCH 04/41] fix(huggingface): complete the Inference Providers router migration Replace the retired api-inference.huggingface.co host with the Inference Providers router (router.huggingface.co): imageConfig.modelMap resolves Hub ids to provider-resolved ids, image-to-image models receive the source image in inputs with the prompt under parameters.prompt, and a new sttConfig wires the hf-inference ASR route. The image catalog grows to 23 models, dead whisper-small is replaced by whisper-large-v3-turbo, the unusable "language" param is dropped, and edit models declare the edit capability so the dashboard offers a source image. Adds unit and end-to-end coverage plus a model-id guard on custom endpoints. --- .../handlers/imageProviders/huggingface.js | 85 ++++- open-sse/providers/registry/huggingface.js | 76 +++- open-sse/providers/schema.js | 7 + .../[id]/components/GenericExampleCard.js | 6 + .../unit/huggingface-image-end-to-end.test.js | 144 ++++++++ .../unit/huggingface-router-migration.test.js | 349 ++++++++++++++++++ 6 files changed, 659 insertions(+), 8 deletions(-) create mode 100644 tests/unit/huggingface-image-end-to-end.test.js create mode 100644 tests/unit/huggingface-router-migration.test.js diff --git a/open-sse/handlers/imageProviders/huggingface.js b/open-sse/handlers/imageProviders/huggingface.js index 2093d9c3..371b18f8 100644 --- a/open-sse/handlers/imageProviders/huggingface.js +++ b/open-sse/handlers/imageProviders/huggingface.js @@ -1,18 +1,93 @@ -// HuggingFace Inference API — returns binary image -import { nowSec } from "./_base.js"; +// HuggingFace Inference Providers router — returns binary image +// +// The router is a switchboard in front of many inference providers and is +// addressed as `//`. `providerModelId` is +// the id the *provider* uses, which is not the Hub model id, so it is resolved +// through `imageConfig.modelMap` (built from the Hub API's +// inferenceProviderMapping and limited to providers the router forwards to). +// +// The legacy `api-inference.huggingface.co` host is gone (DNS ENOTFOUND) and is +// deliberately not referenced anywhere here. +import { nowSec, urlToBase64 } from "./_base.js"; import { PROVIDER_MEDIA } from "../../providers/index.js"; -const BASE_URL = PROVIDER_MEDIA["huggingface"]?.imageConfig?.baseUrl; +const imageConfig = () => PROVIDER_MEDIA["huggingface"]?.imageConfig || {}; +const BASE_URL = imageConfig().baseUrl; +const MODEL_MAP = imageConfig().modelMap || {}; + +// A plain-object lookup returns inherited truthy values for keys like "toString" or +// "constructor", which would build nonsense URLs. Resolve own keys only. +const lookup = (model) => (Object.hasOwn(MODEL_MAP, model) ? MODEL_MAP[model] : undefined); + +// modelMap values are either a bare path (text-to-image) or { path, task }. +const mappingPath = (entry) => (typeof entry === "string" ? entry : entry.path); +const mappingTask = (entry) => (typeof entry === "string" ? "text-to-image" : entry.task || "text-to-image"); + +// A connection may point at its own endpoint (self-hosted Text Generation +// Inference / TGI container). That endpoint already knows its own model ids, so +// the router mapping does not apply and the Hub id is passed through verbatim. +function customBaseUrl(creds) { + const url = creds?.providerSpecificData?.baseUrl; + return typeof url === "string" && url.trim() ? url.trim().replace(/\/+$/, "") : null; +} + +// The router's image-to-image payload wants raw base64 — not a data URL, not a URL. +// Accept every shape our own callers use (data URL, bare base64, remote URL, array). +async function sourceImage(body) { + const raw = body?.image || (Array.isArray(body?.images) ? body.images[0] : null); + if (typeof raw !== "string" || !raw.trim()) return null; + const value = raw.trim(); + if (/^https?:\/\//i.test(value)) return await urlToBase64(value); + const match = /^data:image\/[^;]+;base64,(.+)$/i.exec(value); + return match ? match[1] : value; +} export default { - buildUrl: (model) => `${BASE_URL}/${model}`, + buildUrl: (model, creds) => { + const override = customBaseUrl(creds); + if (override) { + // The model id is client-controlled; on a custom endpoint it lands in a URL + // path verbatim, so reject traversal/query injection (mirrors sttCore's guard). + if (model.includes("..") || model.includes("//") || /[?#]/.test(model)) { + throw new Error(`HuggingFace: invalid model ID "${model}"`); + } + return `${override}/${model}`; + } + + const entry = lookup(model); + if (!entry) { + throw new Error( + `HuggingFace: no HuggingFace router mapping for model "${model}". ` + + `Add it to imageConfig.modelMap in open-sse/providers/registry/huggingface.js, ` + + `or set a custom base URL on the connection.` + ); + } + return `${BASE_URL}/${mappingPath(entry)}`; + }, buildHeaders: (creds) => { const headers = { "Content-Type": "application/json" }; const key = creds?.apiKey || creds?.accessToken; if (key) headers["Authorization"] = `Bearer ${key}`; return headers; }, - buildBody: (_model, body) => ({ inputs: body.prompt }), + buildBody: async (model, body) => { + const entry = lookup(model); + const task = mappingTask(entry || ""); + + if (task === "image-to-image") { + const image = await sourceImage(body); + if (!image) { + throw new Error( + `HuggingFace: model "${model}" requires a source image. ` + + `Send it as "image" (or "images") in the request body.` + ); + } + // inputs carries the source image; the prompt moves under parameters. + return { inputs: image, parameters: { prompt: body.prompt } }; + } + + return { inputs: body.prompt }; + }, // HF returns raw image bytes — convert to b64_json async parseResponse(response) { const buf = await response.arrayBuffer(); diff --git a/open-sse/providers/registry/huggingface.js b/open-sse/providers/registry/huggingface.js index 768b0ded..7eafea1c 100644 --- a/open-sse/providers/registry/huggingface.js +++ b/open-sse/providers/registry/huggingface.js @@ -15,6 +15,7 @@ export default { website: "https://huggingface.co", notice: { apiKeyUrl: "https://huggingface.co/settings/tokens", + text: "Runs through the Inference Providers router. Image and speech models are billed by the provider selected per model.", }, }, category: "apikey", @@ -25,10 +26,79 @@ export default { transport: null, models: [ { id: "black-forest-labs/FLUX.1-schnell", name: "FLUX.1 Schnell", params: [], kind: "image" }, + { id: "black-forest-labs/FLUX.1-dev", name: "FLUX.1 Dev", params: [], kind: "image" }, + { id: "black-forest-labs/FLUX.1-Krea-dev", name: "FLUX.1 Krea", params: [], kind: "image" }, + { id: "black-forest-labs/FLUX.1-Kontext-dev", name: "FLUX.1 Kontext", params: [], kind: "image", capabilities: ["edit"] }, + { id: "black-forest-labs/FLUX.2-dev", name: "FLUX.2 Dev", params: [], kind: "image", capabilities: ["edit"] }, + { id: "black-forest-labs/FLUX.2-klein-9B", name: "FLUX.2 Klein 9B", params: [], kind: "image", capabilities: ["edit"] }, + { id: "black-forest-labs/FLUX.2-klein-4B", name: "FLUX.2 Klein 4B", params: [], kind: "image", capabilities: ["edit"] }, + { id: "black-forest-labs/FLUX.2-klein-base-9B", name: "FLUX.2 Klein Base 9B", params: [], kind: "image", capabilities: ["edit"] }, + { id: "black-forest-labs/FLUX.2-klein-base-4B", name: "FLUX.2 Klein Base 4B", params: [], kind: "image", capabilities: ["edit"] }, { id: "stabilityai/stable-diffusion-xl-base-1.0", name: "SDXL Base 1.0", params: [], kind: "image" }, - { id: "openai/whisper-large-v3", name: "Whisper Large v3 (HF)", params: ["language"], kind: "stt" }, - { id: "openai/whisper-small", name: "Whisper Small (HF)", params: ["language"], kind: "stt" }, + { id: "stabilityai/stable-diffusion-3.5-large", name: "Stable Diffusion 3.5 Large", params: [], kind: "image" }, + { id: "stabilityai/stable-diffusion-3.5-large-turbo", name: "Stable Diffusion 3.5 Large Turbo", params: [], kind: "image" }, + { id: "Qwen/Qwen-Image", name: "Qwen Image", params: [], kind: "image" }, + { id: "Qwen/Qwen-Image-2512", name: "Qwen Image 2512", params: [], kind: "image" }, + { id: "Qwen/Qwen-Image-Edit", name: "Qwen Image Edit", params: [], kind: "image", capabilities: ["edit"] }, + { id: "Qwen/Qwen-Image-Edit-2509", name: "Qwen Image Edit 2509", params: [], kind: "image", capabilities: ["edit"] }, + { id: "Qwen/Qwen-Image-Edit-2511", name: "Qwen Image Edit 2511", params: [], kind: "image", capabilities: ["edit"] }, + { id: "ideogram-ai/ideogram-4-fp8", name: "Ideogram 4", params: [], kind: "image" }, + { id: "tencent/HunyuanImage-3.0", name: "HunyuanImage 3.0", params: [], kind: "image" }, + { id: "Tongyi-MAI/Z-Image-Turbo", name: "Z-Image Turbo", params: [], kind: "image" }, + { id: "krea/Krea-2-Turbo", name: "Krea 2 Turbo", params: [], kind: "image" }, + { id: "HiDream-ai/HiDream-I1-Fast", name: "HiDream I1 Fast", params: [], kind: "image" }, + { id: "playgroundai/playground-v2.5-1024px-aesthetic", name: "Playground v2.5", params: [], kind: "image" }, + { id: "openai/whisper-large-v3", name: "Whisper Large v3 (HF)", params: [], kind: "stt" }, + { id: "openai/whisper-large-v3-turbo", name: "Whisper Large v3 Turbo (HF)", params: [], kind: "stt" }, ], serviceKinds: ["image", "stt"], - imageConfig: { baseUrl: "https://api-inference.huggingface.co/models" }, + // Inference Providers router. The router is addressed as + // `//` — see open-sse/handlers/imageProviders/huggingface.js. + // `modelMap` resolves a Hub model id to the provider-resolved id the router expects. + // A plain string value is the provider path. Image-to-image models use + // `{ path, task: "image-to-image" }`: their payload differs — the source image goes in + // `inputs` and the prompt under `parameters.prompt`. See + // https://huggingface.co/docs/inference-providers/tasks/image-to-image + // Only providers the router actually forwards to are listed: replicate, wavespeed and + // deepinfra appear in the Hub's inferenceProviderMapping but reject router traffic with + // "Model not supported by provider ". + imageConfig: { + baseUrl: "https://router.huggingface.co", + modelMap: { + "black-forest-labs/FLUX.1-schnell": "fal-ai/fal-ai/flux/schnell", + "black-forest-labs/FLUX.1-dev": "fal-ai/fal-ai/flux/dev", + "black-forest-labs/FLUX.1-Krea-dev": "fal-ai/fal-ai/flux/krea", + "black-forest-labs/FLUX.1-Kontext-dev": { path: "fal-ai/fal-ai/flux-kontext/dev", task: "image-to-image" }, + "black-forest-labs/FLUX.2-dev": { path: "fal-ai/fal-ai/flux-2/edit", task: "image-to-image" }, + "black-forest-labs/FLUX.2-klein-9B": { path: "fal-ai/fal-ai/flux-2/klein/9b/edit", task: "image-to-image" }, + "black-forest-labs/FLUX.2-klein-4B": { path: "fal-ai/fal-ai/flux-2/klein/4b/distilled/edit", task: "image-to-image" }, + "black-forest-labs/FLUX.2-klein-base-9B": { path: "fal-ai/fal-ai/flux-2/klein/9b/base/edit", task: "image-to-image" }, + "black-forest-labs/FLUX.2-klein-base-4B": { path: "fal-ai/fal-ai/flux-2/klein/4b/base/edit", task: "image-to-image" }, + "stabilityai/stable-diffusion-xl-base-1.0": "fal-ai/fal-ai/fast-sdxl", + "stabilityai/stable-diffusion-3.5-large": "fal-ai/fal-ai/stable-diffusion-v35-large", + "stabilityai/stable-diffusion-3.5-large-turbo": "fal-ai/fal-ai/stable-diffusion-v35-large/turbo", + "Qwen/Qwen-Image": "fal-ai/fal-ai/qwen-image", + "Qwen/Qwen-Image-2512": "fal-ai/fal-ai/qwen-image-2512", + "Qwen/Qwen-Image-Edit": { path: "fal-ai/fal-ai/qwen-image-edit", task: "image-to-image" }, + "Qwen/Qwen-Image-Edit-2509": { path: "fal-ai/fal-ai/qwen-image-edit-2509", task: "image-to-image" }, + "Qwen/Qwen-Image-Edit-2511": { path: "fal-ai/fal-ai/qwen-image-edit-plus", task: "image-to-image" }, + "ideogram-ai/ideogram-4-fp8": "fal-ai/ideogram/v4", + "tencent/HunyuanImage-3.0": "fal-ai/fal-ai/hunyuan-image/v3/text-to-image", + "Tongyi-MAI/Z-Image-Turbo": "fal-ai/fal-ai/z-image/turbo", + "krea/Krea-2-Turbo": "fal-ai/fal-ai/krea-2/turbo", + "HiDream-ai/HiDream-I1-Fast": "fal-ai/fal-ai/hidream-i1-fast", + "playgroundai/playground-v2.5-1024px-aesthetic": "fal-ai/fal-ai/playground-v25", + }, + }, + // Speech-to-text goes through the hf-inference provider, which keeps the Hub + // model id as its provider-resolved id (`/hf-inference/models/`). + // No `params` are declared: the router's ASR payload carries only `inputs` and + // `parameters.return_timestamps` / `parameters.generation_parameters` — it has no + // language field, so a UI-declared "language" would be silently dropped. + sttConfig: { + baseUrl: "https://router.huggingface.co/hf-inference/models", + authType: "apikey", + authHeader: "bearer", + format: "huggingface-asr", + }, }; diff --git a/open-sse/providers/schema.js b/open-sse/providers/schema.js index e8b5ddd1..eddf201b 100644 --- a/open-sse/providers/schema.js +++ b/open-sse/providers/schema.js @@ -36,6 +36,13 @@ import { DEFAULT_RETRY_CONFIG, FETCH_CONNECT_TIMEOUT_MS } from "../config/runtim * MediaConfig: { serviceKinds:[...], ttsConfig, sttConfig, embeddingConfig, imageConfig, * searchViaChat:{defaultModel,pricingUrl}, hiddenKinds } — each *Config: {baseUrl,authType,authHeader, * format,defaultModel,models:[{id,name,dimensions?}]}. + * + * imageConfig.modelMap (optional): maps a client-facing model id to a provider-resolved id when + * those differ — e.g. the HuggingFace Inference Providers router, where a Hub id like + * `black-forest-labs/FLUX.1-schnell` is addressed as `fal-ai/fal-ai/flux/schnell`. A value is + * either the provider path, or `{path, task}` when the request shape differs per task + * (HuggingFace uses task:"image-to-image" to move the prompt under `parameters.prompt`). + * Ignored by providers whose model ids are sent verbatim. */ // Shared transport defaults — provider only overrides fields that differ. diff --git a/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/components/GenericExampleCard.js b/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/components/GenericExampleCard.js index ff30dcb2..4d10ba1c 100644 --- a/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/components/GenericExampleCard.js +++ b/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/components/GenericExampleCard.js @@ -9,8 +9,14 @@ import { Row, KIND_EXAMPLE_CONFIG } from "./exampleShared"; const CLOUDFLARE_TEST_IMAGE_URL = "https://pub-1fb693cb11cc46b2b2f656f51e015a2c.r2.dev/dog.png"; const CLOUDFLARE_TEST_MASK_URL = "https://pub-1fb693cb11cc46b2b2f656f51e015a2c.r2.dev/dog-mask.png"; +// HuggingFace router edit models need a source image; reuse the public dog sample so +// the card is runnable as-is. The router derives it from inputs, not from the Hub host. +const HUGGINGFACE_TEST_IMAGE_URL = CLOUDFLARE_TEST_IMAGE_URL; function getImageEditDefaults(providerId, modelId) { + if (providerId === "huggingface") { + return { image: HUGGINGFACE_TEST_IMAGE_URL }; + } if (providerId !== "cloudflare-ai") return {}; if (modelId === "@cf/runwayml/stable-diffusion-v1-5-img2img") { return { image: CLOUDFLARE_TEST_IMAGE_URL }; diff --git a/tests/unit/huggingface-image-end-to-end.test.js b/tests/unit/huggingface-image-end-to-end.test.js new file mode 100644 index 00000000..8ce37268 --- /dev/null +++ b/tests/unit/huggingface-image-end-to-end.test.js @@ -0,0 +1,144 @@ +/** + * HuggingFace image generation — end-to-end through the real core handler. + * + * The registry/adapter tests pin the URL and payload in isolation. These tests + * drive `handleImageGenerationCore` — the same function the `/v1/images/generations` + * route calls — so the whole seam is exercised: adapter selection, buildUrl / + * buildBody / buildHeaders, the fetch call, and the binary response parse. + * + * The mocked `fetch` asserts on the exact request the router would receive, which + * is the strongest check available without burning live Inference Providers credits + * (the router bills before validating the payload, so a live probe can only prove + * the path exists, never that the body is right). + */ + +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { handleImageGenerationCore } from "../../open-sse/handlers/imageGenerationCore.js"; + +const originalFetch = global.fetch; +const CREDS = { apiKey: "hf_test_token" }; + +// A 1x1 transparent PNG — enough to prove the bytes survive the round trip. +const PNG_1X1 = Buffer.from( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==", + "base64" +); + +function mockBinaryResponse() { + return { + ok: true, + status: 200, + arrayBuffer: async () => PNG_1X1.buffer.slice(PNG_1X1.byteOffset, PNG_1X1.byteOffset + PNG_1X1.byteLength), + }; +} + +async function generate(body, model) { + return handleImageGenerationCore({ + body, + modelInfo: { provider: "huggingface", model }, + credentials: CREDS, + log: null, + }); +} + +describe("HuggingFace image generation — end to end", () => { + beforeEach(() => { + global.fetch = vi.fn().mockResolvedValue(mockBinaryResponse()); + }); + + afterEach(() => { + global.fetch = originalFetch; + }); + + it("posts a text-to-image request to the fal-ai router path", async () => { + const result = await generate({ prompt: "a lighthouse at dusk" }, "black-forest-labs/FLUX.1-schnell"); + + expect(result.success).toBe(true); + + const [url, init] = global.fetch.mock.calls[0]; + expect(url).toBe("https://router.huggingface.co/fal-ai/fal-ai/flux/schnell"); + expect(init.method).toBe("POST"); + expect(JSON.parse(init.body)).toEqual({ inputs: "a lighthouse at dusk" }); + }); + + it("authenticates with the connection's API key", async () => { + await generate({ prompt: "x" }, "black-forest-labs/FLUX.1-schnell"); + + const [, init] = global.fetch.mock.calls[0]; + expect(init.headers.Authorization).toBe("Bearer hf_test_token"); + }); + + it("never touches the dead api-inference host", async () => { + await generate({ prompt: "x" }, "black-forest-labs/FLUX.1-schnell"); + + expect(global.fetch.mock.calls[0][0]).not.toContain("api-inference.huggingface.co"); + }); + + it("posts an image-to-image request with the source image in inputs", async () => { + const result = await generate( + { prompt: "make it snow", image: "data:image/png;base64,AAAB" }, + "Qwen/Qwen-Image-Edit" + ); + + expect(result.success).toBe(true); + + const [url, init] = global.fetch.mock.calls[0]; + expect(url).toBe("https://router.huggingface.co/fal-ai/fal-ai/qwen-image-edit"); + // The router takes raw base64 in inputs and the prompt under parameters — + // the data-URL prefix must be stripped, not forwarded. + expect(JSON.parse(init.body)).toEqual({ + inputs: "AAAB", + parameters: { prompt: "make it snow" }, + }); + }); + + it("rejects an image-to-image model that was given no source image", async () => { + const result = await generate({ prompt: "make it snow" }, "Qwen/Qwen-Image-Edit"); + + expect(result.success).toBe(false); + expect(result.status).toBe(400); + expect(result.error).toMatch(/requires a source image/i); + expect(global.fetch).not.toHaveBeenCalled(); + }); + + it("rejects a model with no router mapping before calling upstream", async () => { + const result = await generate({ prompt: "x" }, "some-org/unmapped-model"); + + expect(result.success).toBe(false); + expect(result.status).toBe(400); + expect(result.error).toMatch(/no HuggingFace router mapping/i); + expect(global.fetch).not.toHaveBeenCalled(); + }); + + it("returns the generated image as base64 to the client", async () => { + const result = await generate({ prompt: "x" }, "black-forest-labs/FLUX.1-schnell"); + + const payload = await result.response.json(); + expect(payload.data[0].b64_json).toBe(PNG_1X1.toString("base64")); + }); + + it("routes a self-hosted connection to its own endpoint", async () => { + await handleImageGenerationCore({ + body: { prompt: "x" }, + modelInfo: { provider: "huggingface", model: "my-org/my-tgi-model" }, + credentials: { apiKey: "k", providerSpecificData: { baseUrl: "https://tgi.internal" } }, + log: null, + }); + + expect(global.fetch.mock.calls[0][0]).toBe("https://tgi.internal/my-org/my-tgi-model"); + }); + + it("surfaces an upstream error instead of a broken image", async () => { + global.fetch = vi.fn().mockResolvedValue({ + ok: false, + status: 402, + text: async () => JSON.stringify({ error: "You have depleted your monthly included credits." }), + json: async () => ({ error: "You have depleted your monthly included credits." }), + }); + + const result = await generate({ prompt: "x" }, "black-forest-labs/FLUX.1-schnell"); + + expect(result.success).toBe(false); + expect(result.status).toBe(402); + }); +}); diff --git a/tests/unit/huggingface-router-migration.test.js b/tests/unit/huggingface-router-migration.test.js new file mode 100644 index 00000000..cfa46e3b --- /dev/null +++ b/tests/unit/huggingface-router-migration.test.js @@ -0,0 +1,349 @@ +/** + * HuggingFace registry migration to router.huggingface.co + * + * The legacy base URL `https://api-inference.huggingface.co` no longer resolves + * (DNS ENOTFOUND), so every HuggingFace image/STT request failed at the fetch + * layer. The replacement is `https://router.huggingface.co`, which routes by + * `/` — the provider-resolved id is NOT the + * Hub model id and must be resolved from the Hub API's inferenceProviderMapping. + * + * Covers: + * - imageConfig base URL is the live router host, not the dead legacy host + * - image URL builder emits the provider-resolved id, not the Hub id + * - image URL builder throws a descriptive error for unmapped models + * - sttConfig exists and points at the live router host + * - every registered public model resolves through a provider the router serves + */ + +import { describe, it, expect } from "vitest"; +import huggingface from "../../open-sse/providers/registry/huggingface.js"; +import imageAdapter from "../../open-sse/handlers/imageProviders/huggingface.js"; + +const DEAD_HOST = "api-inference.huggingface.co"; +const LIVE_ROUTER = "router.huggingface.co"; + +// Providers the router actually forwards to. replicate/wavespeed/deepinfra appear +// in the Hub's inferenceProviderMapping but reject every router request with +// "Model not supported by provider ", so they must not be used here. +const ROUTABLE_PROVIDERS = new Set(["fal-ai", "hf-inference", "nscale", "together", "novita", "hyperbolic"]); + +const imageConfig = huggingface.imageConfig; +const modelMap = imageConfig.modelMap || {}; + +// modelMap values are either a bare path (text-to-image) or +// { path, task: "image-to-image" } for models that require a source image. +const mappingPath = (value) => (typeof value === "string" ? value : value.path); +const mappingTask = (value) => (typeof value === "string" ? "text-to-image" : value.task || "text-to-image"); + +describe("HuggingFace registry — legacy host removal", () => { + it("does not use the dead api-inference host for images", () => { + expect(imageConfig.baseUrl).not.toContain(DEAD_HOST); + }); + + it("points imageConfig at the live router host", () => { + expect(imageConfig.baseUrl).toContain(LIVE_ROUTER); + }); + + it("does not use the dead api-inference host for STT", () => { + expect(huggingface.sttConfig?.baseUrl).not.toContain(DEAD_HOST); + }); +}); + +describe("HuggingFace STT dispatch", () => { + it("declares an sttConfig so sttCore can dispatch", () => { + expect(huggingface.sttConfig).toBeDefined(); + }); + + it("uses the HuggingFace ASR wire format", () => { + expect(huggingface.sttConfig.format).toBe("huggingface-asr"); + }); + + it("authenticates with a bearer API key", () => { + expect(huggingface.sttConfig.authType).toBe("apikey"); + expect(huggingface.sttConfig.authHeader).toBe("bearer"); + }); + + it("advertises stt in serviceKinds", () => { + expect(huggingface.serviceKinds).toContain("stt"); + }); + + it("points sttConfig at the hf-inference model route", () => { + expect(huggingface.sttConfig.baseUrl).toBe("https://router.huggingface.co/hf-inference/models"); + }); +}); + +describe("HuggingFace image URL builder", () => { + it("routes FLUX.1-schnell through its fal-ai provider id", () => { + expect(imageAdapter.buildUrl("black-forest-labs/FLUX.1-schnell")).toBe( + "https://router.huggingface.co/fal-ai/fal-ai/flux/schnell" + ); + }); + + it("routes SDXL through its fal-ai provider id", () => { + expect(imageAdapter.buildUrl("stabilityai/stable-diffusion-xl-base-1.0")).toBe( + "https://router.huggingface.co/fal-ai/fal-ai/fast-sdxl" + ); + }); + + it("never leaks the dead host into a built URL", () => { + expect(imageAdapter.buildUrl("black-forest-labs/FLUX.1-schnell")).not.toContain(DEAD_HOST); + }); + + it("throws a descriptive error for a model with no provider mapping", () => { + expect(() => imageAdapter.buildUrl("some-org/not-mapped-model")).toThrow(/no HuggingFace router mapping/i); + }); + + it("lets a connection override the endpoint for a self-hosted model", () => { + const creds = { providerSpecificData: { baseUrl: "https://tgi.internal/" } }; + + expect(imageAdapter.buildUrl("my-org/my-tgi-model", creds)).toBe("https://tgi.internal/my-org/my-tgi-model"); + }); + + it("does not apply the router mapping when a custom endpoint is set", () => { + const creds = { providerSpecificData: { baseUrl: "https://tgi.internal" } }; + + // The custom endpoint knows its own model ids — the Hub id passes through verbatim. + expect(imageAdapter.buildUrl("black-forest-labs/FLUX.1-schnell", creds)).toBe( + "https://tgi.internal/black-forest-labs/FLUX.1-schnell" + ); + }); + + it("ignores a blank custom endpoint", () => { + expect(imageAdapter.buildUrl("black-forest-labs/FLUX.1-schnell", { providerSpecificData: { baseUrl: " " } })).toBe( + "https://router.huggingface.co/fal-ai/fal-ai/flux/schnell" + ); + }); + + it("rejects traversal or query injection in the model id on a custom endpoint", () => { + const creds = { providerSpecificData: { baseUrl: "https://tgi.internal" } }; + + for (const model of ["x/../../admin", "org//model", "model?x=1", "model#f"]) { + expect(() => imageAdapter.buildUrl(model, creds), model).toThrow(/invalid model ID/i); + } + }); +}); + +describe("HuggingFace registry model table", () => { + const modelsById = Object.fromEntries(huggingface.models.map((m) => [m.id, m])); + const imageModels = huggingface.models.filter((m) => m.kind === "image"); + const sttModels = huggingface.models.filter((m) => m.kind === "stt"); + + it("every image model is present in imageConfig.modelMap", () => { + for (const model of imageModels) { + expect(modelMap[model.id], `model ${model.id} is missing from imageConfig.modelMap`).toBeTruthy(); + } + }); + + it("every modelMap entry points at a routable provider", () => { + for (const [hubId, value] of Object.entries(modelMap)) { + const provider = String(mappingPath(value)).split("/")[0]; + expect(ROUTABLE_PROVIDERS.has(provider), `${hubId} -> unsupported provider ${provider}`).toBe(true); + } + }); + + it("every modelMap entry has a provider/model path shape", () => { + for (const [hubId, value] of Object.entries(modelMap)) { + expect(String(mappingPath(value)), `${hubId} has a malformed target`).toMatch(/^[a-z0-9-]+\/[A-Za-z0-9._/-]+$/); + } + }); + + it("does not advertise whisper-small, which has no live provider", () => { + expect(modelsById["openai/whisper-small"]).toBeUndefined(); + }); + + it("advertises whisper-large-v3-turbo as its STT replacement", () => { + expect(modelsById["openai/whisper-large-v3-turbo"]?.kind).toBe("stt"); + }); + + it("exposes the FLUX family image models", () => { + for (const id of [ + "black-forest-labs/FLUX.1-schnell", + "black-forest-labs/FLUX.1-dev", + "black-forest-labs/FLUX.1-Krea-dev", + "black-forest-labs/FLUX.1-Kontext-dev", + "black-forest-labs/FLUX.2-dev", + "black-forest-labs/FLUX.2-klein-9B", + "black-forest-labs/FLUX.2-klein-4B", + "black-forest-labs/FLUX.2-klein-base-9B", + "black-forest-labs/FLUX.2-klein-base-4B", + ]) { + expect(modelsById[id]?.kind, `${id} should be registered as an image model`).toBe("image"); + } + }); + + it("exposes the Qwen-Image family", () => { + for (const id of [ + "Qwen/Qwen-Image", + "Qwen/Qwen-Image-2512", + "Qwen/Qwen-Image-Edit", + "Qwen/Qwen-Image-Edit-2509", + "Qwen/Qwen-Image-Edit-2511", + ]) { + expect(modelsById[id]?.kind, `${id} should be registered as an image model`).toBe("image"); + } + }); + + it("exposes the Stable Diffusion family", () => { + for (const id of [ + "stabilityai/stable-diffusion-xl-base-1.0", + "stabilityai/stable-diffusion-3.5-large", + "stabilityai/stable-diffusion-3.5-large-turbo", + ]) { + expect(modelsById[id]?.kind, `${id} should be registered as an image model`).toBe("image"); + } + }); + + it("exposes the HuggingFace ASR models", () => { + for (const id of ["openai/whisper-large-v3", "openai/whisper-large-v3-turbo"]) { + expect(modelsById[id]?.kind, `${id} should be registered as an stt model`).toBe("stt"); + } + }); + + it("exposes the remaining third-party image models", () => { + for (const id of [ + "tencent/HunyuanImage-3.0", + "Tongyi-MAI/Z-Image-Turbo", + "krea/Krea-2-Turbo", + "HiDream-ai/HiDream-I1-Fast", + "playgroundai/playground-v2.5-1024px-aesthetic", + "ideogram-ai/ideogram-4-fp8", + ]) { + expect(modelsById[id]?.kind, `${id} should be registered as an image model`).toBe("image"); + } + }); + + it("keeps the model table free of duplicates", () => { + const ids = huggingface.models.map((m) => m.id); + expect(new Set(ids).size).toBe(ids.length); + }); + + it("keeps STT models free of image-only router mappings", () => { + for (const model of sttModels) { + expect(modelMap[model.id], `STT model ${model.id} should not be in the image model map`).toBeUndefined(); + } + }); +}); + +// The router is a switchboard in front of many providers; every Hub model that is +// `pipeline_tag: image-to-image` needs a source image, and the request shape differs +// from text-to-image: `inputs` carries the base64 source image and the prompt moves +// under `parameters.prompt`. Verified against +// https://huggingface.co/docs/inference-providers/tasks/image-to-image +describe("HuggingFace image-to-image models", () => { + const IMAGE_TO_IMAGE = [ + "black-forest-labs/FLUX.2-dev", + "black-forest-labs/FLUX.1-Kontext-dev", + "black-forest-labs/FLUX.2-klein-9B", + "black-forest-labs/FLUX.2-klein-4B", + "black-forest-labs/FLUX.2-klein-base-9B", + "black-forest-labs/FLUX.2-klein-base-4B", + "Qwen/Qwen-Image-Edit", + "Qwen/Qwen-Image-Edit-2509", + "Qwen/Qwen-Image-Edit-2511", + ]; + + it("marks every image-to-image model as such in modelMap", () => { + for (const hubId of IMAGE_TO_IMAGE) { + expect(mappingTask(modelMap[hubId]), `${hubId} must be declared image-to-image`).toBe("image-to-image"); + } + }); + + it("declares text-to-image as the default for the remaining image models", () => { + for (const [hubId, value] of Object.entries(modelMap)) { + if (IMAGE_TO_IMAGE.includes(hubId)) continue; + expect(mappingTask(value), `${hubId} should default to text-to-image`).toBe("text-to-image"); + } + }); + + it("sends the source image as inputs and the prompt under parameters", async () => { + const body = await imageAdapter.buildBody("Qwen/Qwen-Image-Edit", { + prompt: "make it snow", + image: "data:image/png;base64,AAAA", + }); + + expect(body.inputs).toBe("AAAA"); + expect(body.parameters).toEqual({ prompt: "make it snow" }); + }); + + it("accepts a source image given as a bare base64 payload", async () => { + const body = await imageAdapter.buildBody("black-forest-labs/FLUX.2-dev", { + prompt: "winter", + image: "AAAA", + }); + + expect(body.inputs).toBe("AAAA"); + }); + + it("accepts a source image given as an array", async () => { + const body = await imageAdapter.buildBody("Qwen/Qwen-Image-Edit-2509", { + prompt: "winter", + images: ["data:image/png;base64,BBBB"], + }); + + expect(body.inputs).toBe("BBBB"); + }); + + it("throws a descriptive error when an image-to-image model gets no source image", async () => { + await expect( + imageAdapter.buildBody("black-forest-labs/FLUX.1-Kontext-dev", { prompt: "winter" }) + ).rejects.toThrow(/requires a source image/i); + }); + + it("keeps the text-to-image shape prompt-only", async () => { + const body = await imageAdapter.buildBody("black-forest-labs/FLUX.1-schnell", { + prompt: "a lighthouse", + image: "data:image/png;base64,AAAA", + }); + + expect(body).toEqual({ inputs: "a lighthouse" }); + }); + + it("still throws for a model with no router mapping", () => { + expect(() => imageAdapter.buildUrl("some-org/unknown")).toThrow(/no HuggingFace router mapping/i); + }); +}); + +// The dashboard's GenericExampleCard only renders the source-image field when the +// selected model declares capabilities: ["edit"] (GenericExampleCard.js:47), and it +// then sends the value as `image`. Without the flag the edit models are unusable +// from the UI even though the adapter supports them. +describe("HuggingFace edit models reach the dashboard", () => { + const IMAGE_TO_IMAGE = ["black-forest-labs/FLUX.2-dev", "Qwen/Qwen-Image-Edit"]; + + it("declares the edit capability on image-to-image models", () => { + const modelsById = Object.fromEntries(huggingface.models.map((m) => [m.id, m])); + + for (const hubId of IMAGE_TO_IMAGE) { + expect(modelsById[hubId]?.capabilities, `${hubId} must declare the edit capability`).toContain("edit"); + } + }); + + it("keeps the capability on text-to-image models that do not take a source image", () => { + const modelsById = Object.fromEntries(huggingface.models.map((m) => [m.id, m])); + + expect(modelsById["black-forest-labs/FLUX.1-schnell"]?.capabilities || []).not.toContain("edit"); + }); +}); + +describe("HuggingFace registry prototype safety", () => { + it("does not resolve inherited object keys as models", () => { + // A plain-object map returns a truthy inherited value for these, which would + // build a URL like `/function Object() { [native code] }`. + for (const key of ["toString", "constructor", "__proto__", "hasOwnProperty"]) { + expect(() => imageAdapter.buildUrl(key)).toThrow(/no HuggingFace router mapping/i); + } + }); +}); + +describe("HuggingFace STT model parameters", () => { + const sttModels = huggingface.models.filter((m) => m.kind === "stt"); + + it("does not advertise a language parameter the ASR route cannot carry", () => { + // transcribeHuggingFace posts raw audio bytes and never reads formData, and the + // router's ASR payload has no `language` field — so a UI-declared "language" + // param is silently dropped. Declaring it lies to the dashboard. + for (const model of sttModels) { + expect(model.params, `${model.id} advertises an unusable language param`).toEqual([]); + } + }); +}); From 9f42e7ac1c7edd4690263919b596d22c957e3757 Mon Sep 17 00:00:00 2001 From: decolua Date: Mon, 21 Sep 2026 18:56:56 +0700 Subject: [PATCH 05/41] fix(sidebar): restore NEW badge for 9Remote menu Co-Authored-By: Claude Code --- src/shared/components/Sidebar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/components/Sidebar.js b/src/shared/components/Sidebar.js index 9e97f0e6..01dd1334 100644 --- a/src/shared/components/Sidebar.js +++ b/src/shared/components/Sidebar.js @@ -303,9 +303,9 @@ export default function Sidebar({ onClose }) { computer 9Remote - {/* + New - */} + {/* 9English */} From 477b2aed0b7e601956563cd6880eb8cc857ae430 Mon Sep 17 00:00:00 2001 From: chisewaguri Date: Mon, 21 Sep 2026 19:07:18 +0700 Subject: [PATCH 06/41] fix(opencode-go): send reasoning_effort for glm-5.3-flash --- open-sse/providers/capabilities.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/open-sse/providers/capabilities.js b/open-sse/providers/capabilities.js index c02f255f..b55244fb 100644 --- a/open-sse/providers/capabilities.js +++ b/open-sse/providers/capabilities.js @@ -165,6 +165,12 @@ export const PROVIDER_CAPABILITIES = { "deepseek-ai/deepseek-v4-pro": { reasoning: true, thinkingFormat: "openai", contextWindow: 1000000, maxOutput: 65536 }, "deepseek-ai/deepseek-v4-flash": { reasoning: true, thinkingFormat: "openai", contextWindow: 1000000, maxOutput: 65536 }, }, + // glm-5.3-flash on OpenCode Go is served by a backend that rejects the z.ai + // `thinking` object (400: unknown field "thinking") and wants reasoning_effort. + // Overrides the global entry, whose z.ai shape is correct for z.ai itself. + "opencode-go": { + "glm-5.3-flash": { vision: true, videoInput: true, pdf: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 131072 }, + }, "codex": { "gpt-6-astra": { vision: true, reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 272000, maxOutput: 128000 }, "gpt-5.6-sol": CODEX_GPT_56_SOL_CAPS, From 5c217d34f369a13a1362833e679d5e8aee2ef81b Mon Sep 17 00:00:00 2001 From: Minh Ha Date: Mon, 21 Sep 2026 19:37:55 +0700 Subject: [PATCH 07/41] feat(capabilities): model capability metadata on /v1/models, combo aggregation, pattern fixes - Export aggregateComboCapabilities: union for vision/audio/search/pdf, intersection for tools, primary-model for reasoning fields, min contextWindow, max maxOutput - Support nested combo resolution in aggregateComboCapabilities via comboLookup with depth guard (max 6) - Wire capability metadata to all /v1/models entries and combos - Show aggregated ctx/max metadata line and capability badges on combo chips - Pattern fixes: MiMo v2.5/omni reasoning, qwen max/plus vision, minimax m2.x vision - Sync commandcode model catalog and add openai gpt-5.5 - Add unit tests for capability patterns and combo capability aggregation --- open-sse/providers/capabilities.js | 106 +++++++------ open-sse/providers/registry/commandcode.js | 11 ++ open-sse/providers/registry/openai.js | 1 + src/app/(dashboard)/dashboard/combos/page.js | 65 +++++--- src/app/api/v1/models/route.js | 15 +- tests/unit/capabilities.test.js | 136 ++++++++++++++++ tests/unit/combo-capabilities.test.js | 155 +++++++++++++++++++ 7 files changed, 419 insertions(+), 70 deletions(-) create mode 100644 tests/unit/combo-capabilities.test.js diff --git a/open-sse/providers/capabilities.js b/open-sse/providers/capabilities.js index b55244fb..221488cf 100644 --- a/open-sse/providers/capabilities.js +++ b/open-sse/providers/capabilities.js @@ -112,6 +112,8 @@ export const MODEL_CAPABILITIES = { "glm-5.3-flash": { vision: true, videoInput: true, pdf: true, reasoning: true, thinkingFormat: "zai", contextWindow: 1000000, maxOutput: 131072 }, "glm-4.6v": { vision: true, videoInput: true, reasoning: true, thinkingFormat: "zai", contextWindow: 128000, maxOutput: 32768 }, "glm-4.5v": { vision: true, videoInput: true, reasoning: true, thinkingFormat: "zai", contextWindow: 64000, maxOutput: 16384 }, + // GLM-5.2 has 1M context — pattern *glm-5* only gives 200k, so override here + "glm-5.2": { reasoning: true, thinkingFormat: "zai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 131072 }, // DeepSeek's first V4 model with image input; text limits match V4-Flash. "deepseek-v4-flash-vision-exp": { vision: true, reasoning: true, thinkingFormat: "deepseek", contextWindow: 1000000, maxOutput: 384000 }, @@ -211,6 +213,10 @@ export const PROVIDER_CAPABILITIES = { "minimax-m3": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 512000, maxOutput: 128000 }, "kimi-k2.7": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 256000, maxOutput: 32000 }, "kimi-k2.6": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 256000, maxOutput: 32000 }, + "kimi-k2.5": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 164000, maxOutput: 32000 }, + "hy3-preview": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 192000, maxOutput: 64000 }, + "deepseek-v4-flash": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 50000 }, + "deepseek-v3-2-volc": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 96000, maxOutput: 32000 }, // Per-model values mirror the server's product-config payload (the plugin // fetches it from copilot.tencent.com; the `models[]` entries carry // maxInputTokens/maxOutputTokens/supportsImages). contextWindow = @@ -232,45 +238,6 @@ export const PROVIDER_CAPABILITIES = { // contract). maxOutput 128000 per the server's product-config payload. "deepseek-v4.1-flash": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: true, contextWindow: 1000000, maxOutput: 128000 }, }, - // CodeBuddy intl — same gateway catalog as CN, so deepseek-v4.1-flash mirrors - // the codebuddy-cn entry (the openai-style reasoning_effort format matters: - // the generic *deepseek-v4* pattern would otherwise pick the vendor-native - // "deepseek" thinking shape, which the CodeBuddy gateway does not accept). - "codebuddy-intl": { - "deepseek-v4.1-flash": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: true, contextWindow: 1000000, maxOutput: 128000 }, - }, - // Qoder — upstream exposes opaque internal ids (dfmodel, kmodel, …); the - // registry `name` is display-only and capability lookup matches on the raw - // id, so every qoder model would fall through to DEFAULT_CAPABILITIES - // (200K) without this map. contextWindow follows the real model family's - // spec: the /algo/api/v2/model/list max_input_tokens under-reports some - // windows (GLM-5.3 / Kimi-K3 / Qwen3.8-Max claim 180K but accept more). - // max_output_tokens arrives as 0 for every model, so outputs are - // best-guess from the real model family. Vision tags below follow the - // upstream is_vl flag. The executor uploads inlined images to - // /api/v2/image/upload and leaves image_urls/chat_context.imageUrls null - // (same as qodercli). reasoning:true on all of them — every model can - // reason; the upstream is_reasoning flag only drives model_config selection. - // thinkingFormat keeps the true-model family for documentation/UI, but - // thinkingCanDisable:false everywhere: the executor only forwards - // messages/tools/max_tokens, and thinking is fixed upstream via - // modelConfig.is_reasoning — client thinking intent is dropped, so "none" - // must never be offered as an option. - "qoder": { - "ultimate": { vision: true, reasoning: true, thinkingFormat: "claude-adaptive", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 }, // Claude Opus 5 - "performance": { vision: true, reasoning: true, thinkingFormat: "claude-adaptive", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 }, // Claude Sonnet 5 - "dmodel": { reasoning: true, thinkingFormat: "deepseek", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // DeepSeek-V4-Pro - "dfmodel": { reasoning: true, thinkingFormat: "deepseek", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // DeepSeek-V4-Flash - "gmodel": { reasoning: true, thinkingFormat: "zai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 }, // GLM-5.3 - "gfmodel": { vision: true, reasoning: true, thinkingFormat: "zai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 }, // GLM-5.3-Flash - "kmodel_latest": { vision: true, reasoning: true, thinkingFormat: "kimi", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Kimi-K3 - "kmodel": { vision: true, reasoning: true, thinkingFormat: "kimi", thinkingCanDisable: false, contextWindow: 256000, maxOutput: 65536 }, // Kimi-K2.7-Code - "mmodel": { reasoning: true, thinkingFormat: "minimax", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 512000 }, // MiniMax-M3 - "qmodel_latest": { vision: true, reasoning: true, thinkingFormat: "qwen", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Qwen3.7-Max - "qmodel": { vision: true, reasoning: true, thinkingFormat: "qwen", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Qwen3.7-Plus - "qfmodel": { vision: true, reasoning: true, thinkingFormat: "qwen", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Qwen3.8-Flash - "qmodel_38max": { vision: true, reasoning: true, thinkingFormat: "qwen", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Qwen3.8-Max - }, // Poolside Laguna — OpenAI-compatible, all reasoning-capable (32K max output). "poolside": { "laguna-s-2.1": { reasoning: true, thinkingFormat: "openai", contextWindow: 1000000, maxOutput: 32000 }, @@ -357,7 +324,7 @@ export const PATTERN_CAPABILITIES = [ { pattern: "*qwen*vl*", caps: { vision: true, reasoning: true, thinkingFormat: "qwen", contextWindow: 262144 } }, { pattern: "*qwen*omni*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, thinkingFormat: "qwen", contextWindow: 262144, maxOutput: 65536 } }, { pattern: "*qwen*coder*", caps: { reasoning: true, thinkingFormat: "qwen", contextWindow: 1000000 } }, - { pattern: "*qwen*max*", caps: { reasoning: true, thinkingFormat: "qwen", contextWindow: 1000000, maxOutput: 65536 } }, + { pattern: "*qwen*max*", caps: { vision: true, reasoning: true, thinkingFormat: "qwen", contextWindow: 1000000, maxOutput: 65536 } }, { pattern: "*qwen3.5*", caps: { vision: true, videoInput: true, reasoning: true, thinkingFormat: "qwen", contextWindow: 1000000, maxOutput: 65536 } }, { pattern: "*qwen3.6*", caps: { vision: true, videoInput: true, reasoning: true, thinkingFormat: "qwen", contextWindow: 1000000, maxOutput: 65536 } }, { pattern: "*qwen3.7*", caps: { vision: true, videoInput: true, reasoning: true, thinkingFormat: "qwen", contextWindow: 1000000, maxOutput: 65536 } }, @@ -396,14 +363,15 @@ export const PATTERN_CAPABILITIES = [ // ── MiniMax (M3 = adaptive; M2.x cannot disable) ───────────────── { pattern: "*minimax*image*", caps: { imageOutput: true } }, - { pattern: "*minimax-m3*", caps: { vision: true, reasoning: true, thinkingFormat: "minimax", contextWindow: 1048576, maxOutput: 512000 } }, - { pattern: "*minimax-m2.7*", caps: { reasoning: true, thinkingFormat: "minimax", thinkingCanDisable: false, contextWindow: 204800, maxOutput: 131072 } }, + { pattern: "*minimax-m3*", caps: { vision: true, reasoning: true, thinkingFormat: "minimax", contextWindow: 1000000, maxOutput: 131072 } }, + { pattern: "*minimax-m2.7*", caps: { vision: true, reasoning: true, thinkingFormat: "minimax", thinkingCanDisable: false, contextWindow: 204800, maxOutput: 131072 } }, + { pattern: "*minimax-m2.5*", caps: { vision: true, reasoning: true, thinkingFormat: "minimax", thinkingCanDisable: false, contextWindow: 204800, maxOutput: 131072 } }, { pattern: "*minimax*", caps: { reasoning: true, thinkingFormat: "minimax", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 131072 } }, - // ── Xiaomi MiMo (vision, 1M / 262K ctx) ────────────────────────── - { pattern: "*mimo*v2.5*", caps: { vision: true, audioInput: true, videoInput: true, contextWindow: 1048576, maxOutput: 131072 } }, - { pattern: "*mimo*omni*", caps: { vision: true, audioInput: true, contextWindow: 262144, maxOutput: 131072 } }, - { pattern: "*mimo*", caps: { vision: true, contextWindow: 262144, maxOutput: 131072 } }, + // ── Xiaomi MiMo (vision + -tag reasoning, always-on, can't disable) ── + { pattern: "*mimo*v2.5*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, thinkingFormat: "deepseek", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 131072 } }, + { pattern: "*mimo*omni*", caps: { vision: true, audioInput: true, reasoning: true, thinkingFormat: "deepseek", thinkingCanDisable: false, contextWindow: 262144, maxOutput: 131072 } }, + { pattern: "*mimo*", caps: { vision: true, reasoning: true, thinkingFormat: "deepseek", thinkingCanDisable: false, contextWindow: 262144, maxOutput: 131072 } }, // ── Llama (4 = vision/1M; 3.x = text-only/128K) ────────────────── { pattern: "*llama-4*", caps: { vision: true, contextWindow: 1000000 } }, @@ -441,6 +409,52 @@ export const PATTERN_CAPABILITIES = [ { pattern: "*ling-*", caps: { reasoning: true, contextWindow: 128000 } }, ]; +/** + * Aggregate capabilities for a combo from its constituent model IDs. + * Each entry in comboModels is a fully-qualified "provider/model" string. + * + * Union: vision, pdf, audioInput, videoInput, imageOutput, audioOutput, search + * Intersection: tools + * Primary: reasoning fields from the first (primary) model + * Conservative: contextWindow = min; maxOutput = max + * + * @param {string[]} comboModels + * @param {Object|null} [comboLookup] optional map of combo name → models array for nested resolution + * @param {number} [_depth] internal recursion depth guard + * @returns {object|null} full capabilities object, or null for empty input + */ +export function aggregateComboCapabilities(comboModels, comboLookup = null, _depth = 0) { + if (!comboModels?.length || _depth > 6) return null; + const allCaps = comboModels.map((fullId) => { + // Nested combo: bare name (no slash) that exists in the lookup — recurse + if (!fullId.includes("/") && comboLookup?.[fullId]) { + return aggregateComboCapabilities(comboLookup[fullId], comboLookup, _depth + 1) + ?? getCapabilitiesForModel(null, fullId); + } + const slash = fullId.indexOf("/"); + const provider = slash === -1 ? null : fullId.slice(0, slash); + const model = slash === -1 ? fullId : fullId.slice(slash + 1); + return getCapabilitiesForModel(provider, model); + }); + const first = allCaps[0]; + return { + vision: allCaps.some((c) => c.vision), + pdf: allCaps.some((c) => c.pdf), + audioInput: allCaps.some((c) => c.audioInput), + videoInput: allCaps.some((c) => c.videoInput), + imageOutput: allCaps.some((c) => c.imageOutput), + audioOutput: allCaps.some((c) => c.audioOutput), + search: allCaps.some((c) => c.search), + tools: allCaps.every((c) => c.tools), + reasoning: first.reasoning, + thinkingFormat: first.thinkingFormat, + thinkingCanDisable: first.thinkingCanDisable, + thinkingRange: first.thinkingRange, + contextWindow: Math.min(...allCaps.map((c) => c.contextWindow)), + maxOutput: Math.max(...allCaps.map((c) => c.maxOutput)), + }; +} + /** * Resolve capabilities for a model using the 4-step fallback chain, * merged over DEFAULT_CAPABILITIES so the result is always complete. diff --git a/open-sse/providers/registry/commandcode.js b/open-sse/providers/registry/commandcode.js index f59aac04..8c8c6373 100644 --- a/open-sse/providers/registry/commandcode.js +++ b/open-sse/providers/registry/commandcode.js @@ -30,15 +30,26 @@ export default { models: [ { id: "deepseek/deepseek-v4-pro", name: "DeepSeek V4 Pro" }, { id: "deepseek/deepseek-v4-flash", name: "DeepSeek V4 Flash" }, + { id: "moonshotai/Kimi-K2.7-Code", name: "Kimi K2.7 Code" }, + { id: "moonshotai/Kimi-K2.7-Code-Highspeed", name: "Kimi K2.7 Code HighSpeed" }, { id: "moonshotai/Kimi-K2.6", name: "Kimi K2.6" }, { id: "moonshotai/Kimi-K2.5", name: "Kimi K2.5" }, + { id: "zai-org/GLM-5.2", name: "GLM 5.2" }, + { id: "zai-org/GLM-5.2-Fast", name: "GLM 5.2 Fast" }, { id: "zai-org/GLM-5.1", name: "GLM 5.1" }, { id: "zai-org/GLM-5", name: "GLM 5" }, + { id: "MiniMaxAI/MiniMax-M3", name: "MiniMax M3" }, { id: "MiniMaxAI/MiniMax-M2.7", name: "MiniMax M2.7" }, { id: "MiniMaxAI/MiniMax-M2.5", name: "MiniMax M2.5" }, + { id: "xiaomi/mimo-v2.5-pro", name: "MiMo V2.5 Pro" }, + { id: "xiaomi/mimo-v2.5", name: "MiMo V2.5" }, { id: "Qwen/Qwen3.6-Max-Preview", name: "Qwen 3.6 Max Preview" }, { id: "Qwen/Qwen3.6-Plus", name: "Qwen 3.6 Plus" }, + { id: "Qwen/Qwen3.7-Max", name: "Qwen 3.7 Max" }, + { id: "Qwen/Qwen3.7-Plus", name: "Qwen 3.7 Plus" }, + { id: "stepfun/Step-3.7-Flash", name: "Step 3.7 Flash" }, { id: "stepfun/Step-3.5-Flash", name: "Step 3.5 Flash" }, + { id: "nvidia/nemotron-3-ultra-550b-a55b", name: "Nemotron 3 Ultra" }, ], features: { usage: true, diff --git a/open-sse/providers/registry/openai.js b/open-sse/providers/registry/openai.js index 4a5f0eb1..ba87329c 100644 --- a/open-sse/providers/registry/openai.js +++ b/open-sse/providers/registry/openai.js @@ -28,6 +28,7 @@ export default { forceStream: true, }, models: [ + { id: "gpt-5.5", name: "GPT-5.5" }, { id: "gpt-5.4", name: "GPT-5.4" }, { id: "gpt-5.4-mini", name: "GPT-5.4 Mini" }, { id: "gpt-5.4-nano", name: "GPT-5.4 Nano" }, diff --git a/src/app/(dashboard)/dashboard/combos/page.js b/src/app/(dashboard)/dashboard/combos/page.js index fa093bfd..52ed7459 100644 --- a/src/app/(dashboard)/dashboard/combos/page.js +++ b/src/app/(dashboard)/dashboard/combos/page.js @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect, useCallback } from "react"; +import { useState, useEffect } from "react"; import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors } from "@dnd-kit/core"; import { arrayMove, SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; @@ -8,7 +8,7 @@ import { restrictToVerticalAxis, restrictToParentElement } from "@dnd-kit/modifi import { Card, Button, Modal, Input, CardSkeleton, ModelSelectModal, ConfirmModal, CapacityBadges, Select, Toggle } from "@/shared/components"; import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard"; import { useModelCaps } from "@/shared/hooks/useModelCaps"; -import { isOpenAICompatibleProvider, isAnthropicCompatibleProvider } from "@/shared/constants/providers"; +import { aggregateComboCapabilities } from "open-sse/providers/capabilities.js"; // Validate combo name: only a-z, A-Z, 0-9, -, _ const VALID_NAME_REGEX = /^[a-zA-Z0-9_.\-]+$/; @@ -52,8 +52,8 @@ export default function CombosPage() { const [activeProviders, setActiveProviders] = useState([]); const [comboStrategies, setComboStrategies] = useState({}); const [capacityAdapter, setCapacityAdapter] = useState(EMPTY_CAPACITY_ADAPTER); - const { getCaps } = useModelCaps(); const [confirmState, setConfirmState] = useState(null); + const { getCaps } = useModelCaps(); const { copied, copy } = useCopyToClipboard(); useEffect(() => { @@ -70,7 +70,7 @@ export default function CombosPage() { const combosData = await combosRes.json(); const providersData = await providersRes.json(); const settingsData = settingsRes.ok ? await settingsRes.json() : {}; - + // Only LLM combos here - webSearch/webFetch combos belong to media-providers/web if (combosRes.ok) setCombos((combosData.combos || []).filter(c => !c.kind || c.kind === "llm")); if (providersRes.ok) { @@ -228,20 +228,24 @@ export default function CombosPage() { ) : (
- {combos.map((combo) => ( - setEditingCombo(combo)} - onDelete={() => handleDelete(combo.id)} - strategy={comboStrategies[combo.name] || {}} - onSetStrategy={(patch) => handleSetComboStrategy(combo.name, patch)} - /> - ))} + {(() => { + const comboByName = Object.fromEntries(combos.map((c) => [c.name, c.models])); + return combos.map((combo) => ( + setEditingCombo(combo)} + onDelete={() => handleDelete(combo.id)} + strategy={comboStrategies[combo.name] || {}} + onSetStrategy={(patch) => handleSetComboStrategy(combo.name, patch)} + /> + )); + })()}
)} @@ -288,17 +292,27 @@ export default function CombosPage() { ); } +const fmtK = (n) => { + if (!n) return "?"; + if (n >= 1000000) { + const m = n / 1000000; + return `${Number.isInteger(m) ? m : m.toFixed(1)}M`; + } + return `${Math.round(n / 1000)}k`; +}; + const STRATEGY_OPTIONS = [ { value: "fallback", label: "Fallback — try in order" }, { value: "round-robin", label: "Round Robin — rotate" }, { value: "fusion", label: "Fusion — panel + judge" }, ]; -function ComboCard({ combo, getCaps, activeProviders = [], copied, onCopy, onEdit, onDelete, strategy = {}, onSetStrategy }) { +function ComboCard({ combo, getCaps, comboByName = {}, activeProviders = [], copied, onCopy, onEdit, onDelete, strategy = {}, onSetStrategy }) { const [showJudgeSelect, setShowJudgeSelect] = useState(false); const current = strategy.fallbackStrategy || "fallback"; const judge = strategy.judgeModel || ""; const isFusion = current === "fusion"; + const comboCaps = aggregateComboCapabilities(combo.models, comboByName); return ( @@ -316,7 +330,11 @@ function ComboCard({ combo, getCaps, activeProviders = [], copied, onCopy, onEdi combo.models.slice(0, 3).map((model, index) => ( {model} - + )) )} @@ -324,6 +342,13 @@ function ComboCard({ combo, getCaps, activeProviders = [], copied, onCopy, onEdi +{combo.models.length - 3} more )} + {comboCaps && ( +
+ ctx {fmtK(comboCaps.contextWindow)} + · + max {fmtK(comboCaps.maxOutput)} +
+ )} {/* Fusion: judge picker (Auto = first model) */} {isFusion && (
diff --git a/src/app/api/v1/models/route.js b/src/app/api/v1/models/route.js index 9ce571b4..5413820a 100644 --- a/src/app/api/v1/models/route.js +++ b/src/app/api/v1/models/route.js @@ -17,7 +17,7 @@ import { resolveCursorModels } from "open-sse/services/cursorModels.js"; import { resolveZedModels } from "open-sse/shared/zedAuth.js"; import { updateProviderCredentials } from "@/sse/services/tokenRefresh"; import { resolveConnectionProxyConfig } from "@/lib/network/connectionProxy"; -import { capabilitiesFromServiceKind, getCapabilitiesForModel } from "open-sse/providers/capabilities.js"; +import { capabilitiesFromServiceKind, getCapabilitiesForModel, aggregateComboCapabilities } from "open-sse/providers/capabilities.js"; // Per-provider live model resolvers. Each receives a connection record and // returns { models: [{ id, name? }, ...] } | null on failure. @@ -302,6 +302,9 @@ export async function buildModelsList(kindFilter, options = {}) { const models = []; + // Lookup map so aggregateComboCapabilities can recursively resolve nested combos + const comboByName = Object.fromEntries(combos.map((c) => [c.name, c.models])); + // Combos first (filtered by kind). Web combos expose `kind` so AI knows search vs fetch. for (const combo of combos) { if (!comboMatchesKinds(combo, kindFilter)) continue; @@ -312,6 +315,9 @@ export async function buildModelsList(kindFilter, options = {}) { }; if (combo.kind === "webSearch" || combo.kind === "webFetch") { entry.kind = combo.kind; + } else { + const comboCaps = aggregateComboCapabilities(combo.models, comboByName); + if (comboCaps) entry.capabilities = comboCaps; } models.push(entry); } @@ -331,6 +337,7 @@ export async function buildModelsList(kindFilter, options = {}) { id: `${alias}/${model.id}`, object: "model", owned_by: alias, + capabilities: getCapabilitiesForModel(alias, model.id), }); } } @@ -491,9 +498,9 @@ export async function buildModelsList(kindFilter, options = {}) { // { id, name } — no per-model capability data. Fall back to the same // pattern-matched capabilities the dashboard uses (useModelCaps.js) so // dynamically-discovered LLM models still surface vision/reasoning/search/tools. - const caps = liveCapabilitiesById.get(modelId) - || capabilitiesFromServiceKind(customKind || liveKind) - || (kind === LLM_KIND ? getCapabilitiesForModel(providerId, modelId) : null); + const liveCaps = liveCapabilitiesById.get(modelId); + const serviceCaps = capabilitiesFromServiceKind(customKind || liveKind); + const caps = liveCaps || serviceCaps || (kind === LLM_KIND ? getCapabilitiesForModel(providerId, modelId) : null); if (caps) model.capabilities = caps; // Token limits under the snake_case names the OpenAI/OpenRouter // convention uses. `capabilities.contextWindow` is camelCase and nested, diff --git a/tests/unit/capabilities.test.js b/tests/unit/capabilities.test.js index 84a8643c..555c32ec 100644 --- a/tests/unit/capabilities.test.js +++ b/tests/unit/capabilities.test.js @@ -114,3 +114,139 @@ describe("getCapabilitiesForModel", () => { }); }); }); + +describe("getCapabilitiesForModel — MiMo (-tag reasoning, always-on)", () => { + it("mimo-v2.5 has vision + reasoning + deepseek format, cannot disable", () => { + const caps = getCapabilitiesForModel(null, "mimo-v2.5"); + expect(caps.vision).toBe(true); + expect(caps.reasoning).toBe(true); + expect(caps.thinkingFormat).toBe("deepseek"); + expect(caps.thinkingCanDisable).toBe(false); + }); + + it("mimo-v2.5-pro has vision (matches *mimo*v2.5* pattern)", () => { + const caps = getCapabilitiesForModel(null, "mimo-v2.5-pro"); + expect(caps.vision).toBe(true); + expect(caps.reasoning).toBe(true); + expect(caps.thinkingFormat).toBe("deepseek"); + expect(caps.thinkingCanDisable).toBe(false); + }); + + it("xiaomi/mimo-v2.5-pro (vendor-prefixed) has vision", () => { + const caps = getCapabilitiesForModel(null, "xiaomi/mimo-v2.5-pro"); + expect(caps.vision).toBe(true); + expect(caps.thinkingFormat).toBe("deepseek"); + }); + + it("mimo-omni-x has audioInput via the omni pattern", () => { + const caps = getCapabilitiesForModel(null, "mimo-omni-x"); + expect(caps.vision).toBe(true); + expect(caps.audioInput).toBe(true); + expect(caps.reasoning).toBe(true); + expect(caps.thinkingCanDisable).toBe(false); + }); + + it("generic mimo has vision + reasoning (fallback pattern)", () => { + const caps = getCapabilitiesForModel(null, "mimo"); + expect(caps.vision).toBe(true); + expect(caps.reasoning).toBe(true); + expect(caps.thinkingCanDisable).toBe(false); + }); +}); + +describe("getCapabilitiesForModel — Qwen max/plus vision", () => { + it("qwen3.7-max has vision (*qwen*max* fires before *qwen3.7*)", () => { + const caps = getCapabilitiesForModel(null, "qwen3.7-max"); + expect(caps.vision).toBe(true); + expect(caps.reasoning).toBe(true); + }); + + it("Qwen3.6-Max-Preview has vision (case-insensitive pattern match)", () => { + const caps = getCapabilitiesForModel(null, "Qwen3.6-Max-Preview"); + expect(caps.vision).toBe(true); + }); + + it("qwen3.7-plus has vision", () => { + const caps = getCapabilitiesForModel(null, "qwen3.7-plus"); + expect(caps.vision).toBe(true); + }); + + it("qwen3.7 has vision from the qwen3.7 pattern", () => { + const caps = getCapabilitiesForModel(null, "qwen3.7"); + expect(caps.vision).toBe(true); + }); + + it("qwq has no vision (thinking-only model)", () => { + const caps = getCapabilitiesForModel(null, "qwq-32b"); + expect(caps.vision).toBe(false); + expect(caps.reasoning).toBe(true); + expect(caps.thinkingCanDisable).toBe(false); + }); +}); + +describe("getCapabilitiesForModel — MiniMax M2.x vision", () => { + it("minimax-m2.7 has vision", () => { + const caps = getCapabilitiesForModel(null, "minimax-m2.7"); + expect(caps.vision).toBe(true); + expect(caps.thinkingCanDisable).toBe(false); + }); + + it("minimax-m2.5 has vision", () => { + const caps = getCapabilitiesForModel(null, "minimax-m2.5"); + expect(caps.vision).toBe(true); + expect(caps.thinkingCanDisable).toBe(false); + }); + + it("MiniMax-M2.7 has vision (vendor prefix MiniMaxAI/ stripped by route)", () => { + const caps = getCapabilitiesForModel(null, "MiniMaxAI/MiniMax-M2.7"); + expect(caps.vision).toBe(true); + }); + + it("minimax-m3 has vision (separate pattern)", () => { + const caps = getCapabilitiesForModel(null, "minimax-m3"); + expect(caps.vision).toBe(true); + }); +}); + +describe("getCapabilitiesForModel — DeepSeek V4 text-only", () => { + it("deepseek-v4-pro has no vision", () => { + const caps = getCapabilitiesForModel(null, "deepseek-v4-pro"); + expect(caps.vision).toBe(false); + expect(caps.reasoning).toBe(true); + expect(caps.thinkingFormat).toBe("deepseek"); + }); + + it("deepseek-v4-flash has no vision", () => { + const caps = getCapabilitiesForModel(null, "deepseek-v4-flash"); + expect(caps.vision).toBe(false); + expect(caps.reasoning).toBe(true); + }); + + it("deepseek/deepseek-v4-pro (vendor-prefixed) has no vision", () => { + const caps = getCapabilitiesForModel(null, "deepseek/deepseek-v4-pro"); + expect(caps.vision).toBe(false); + }); +}); + +describe("getCapabilitiesForModel — codebuddy-cn provider overrides", () => { + it("deepseek-v4-pro via codebuddy-cn uses openai thinking format", () => { + const caps = getCapabilitiesForModel("codebuddy-cn", "deepseek-v4-pro"); + expect(caps.vision).toBe(true); + expect(caps.reasoning).toBe(true); + expect(caps.thinkingFormat).toBe("openai"); + expect(caps.thinkingCanDisable).toBe(true); + }); + + it("minimax-m3 via codebuddy-cn has vision (provider override)", () => { + const caps = getCapabilitiesForModel("codebuddy-cn", "minimax-m3"); + expect(caps.vision).toBe(true); + expect(caps.thinkingFormat).toBe("openai"); + expect(caps.thinkingCanDisable).toBe(false); + }); + + it("unknown provider falls through to pattern matching", () => { + const caps = getCapabilitiesForModel("unknown-provider", "mimo-v2.5"); + expect(caps.vision).toBe(true); + expect(caps.thinkingFormat).toBe("deepseek"); + }); +}); diff --git a/tests/unit/combo-capabilities.test.js b/tests/unit/combo-capabilities.test.js new file mode 100644 index 00000000..10a3d367 --- /dev/null +++ b/tests/unit/combo-capabilities.test.js @@ -0,0 +1,155 @@ +import { describe, expect, it } from "vitest"; +import { aggregateComboCapabilities } from "../../open-sse/providers/capabilities.js"; + +describe("aggregateComboCapabilities — null / empty", () => { + it("returns null for null", () => { + expect(aggregateComboCapabilities(null)).toBeNull(); + }); + + it("returns null for empty array", () => { + expect(aggregateComboCapabilities([])).toBeNull(); + }); +}); + +describe("aggregateComboCapabilities — single model passthrough", () => { + it("single model returns its own capabilities", () => { + const caps = aggregateComboCapabilities(["opencode-go/mimo-v2.5"]); + expect(caps.vision).toBe(true); + expect(caps.reasoning).toBe(true); + expect(caps.thinkingFormat).toBe("deepseek"); + expect(caps.thinkingCanDisable).toBe(false); + expect(caps.contextWindow).toBe(1048576); + expect(caps.maxOutput).toBe(131072); + }); +}); + +describe("aggregateComboCapabilities — union fields (vision, audioInput, search)", () => { + it("vision is true if any backend has it", () => { + // deepseek-v4-pro: no vision; mimo-v2.5: vision + const caps = aggregateComboCapabilities([ + "opencode-go/deepseek-v4-pro", + "opencode-go/mimo-v2.5", + ]); + expect(caps.vision).toBe(true); + }); + + it("vision is false if no backend has it", () => { + const caps = aggregateComboCapabilities([ + "opencode-go/deepseek-v4-pro", + "opencode-go/deepseek-v4-flash", + ]); + expect(caps.vision).toBe(false); + }); + + it("audioInput is true if any backend has it", () => { + // mimo-omni has audioInput; mimo-v2.5 does not + const caps = aggregateComboCapabilities([ + "opencode-go/mimo-v2.5", + "opencode-go/mimo-omni-test", + ]); + expect(caps.audioInput).toBe(true); + }); + + it("search is true if any backend has it", () => { + // gpt-5: search; mimo-v2.5: no search + const caps = aggregateComboCapabilities([ + "openai/gpt-5", + "opencode-go/mimo-v2.5", + ]); + expect(caps.search).toBe(true); + }); +}); + +describe("aggregateComboCapabilities — intersection: tools", () => { + it("tools is false if any backend lacks it", () => { + // gpt-image-1: tools:false; gpt-5: tools:true + const caps = aggregateComboCapabilities([ + "openai/gpt-5", + "openai/gpt-image-1", + ]); + expect(caps.tools).toBe(false); + }); + + it("tools is true when all backends support it", () => { + const caps = aggregateComboCapabilities([ + "opencode-go/mimo-v2.5", + "opencode-go/kimi-k2.5", + ]); + expect(caps.tools).toBe(true); + }); +}); + +describe("aggregateComboCapabilities — primary model drives reasoning fields", () => { + it("thinkingFormat comes from the first model", () => { + // primary: mimo-v2.5 (deepseek); secondary: kimi-k2.5 (kimi) + const caps = aggregateComboCapabilities([ + "opencode-go/mimo-v2.5", + "opencode-go/kimi-k2.5", + ]); + expect(caps.thinkingFormat).toBe("deepseek"); + expect(caps.reasoning).toBe(true); + }); + + it("flipping order changes thinkingFormat to the new primary", () => { + const caps = aggregateComboCapabilities([ + "opencode-go/kimi-k2.5", + "opencode-go/mimo-v2.5", + ]); + expect(caps.thinkingFormat).toBe("kimi"); + }); +}); + +describe("aggregateComboCapabilities — context/output limits", () => { + it("contextWindow is the minimum across all models", () => { + // mimo-v2.5: 1048576; kimi-k2.5 (*kimi*k2* pattern): 262144 + const caps = aggregateComboCapabilities([ + "opencode-go/mimo-v2.5", + "opencode-go/kimi-k2.5", + ]); + expect(caps.contextWindow).toBe(262144); + }); + + it("maxOutput is the maximum across all models", () => { + // mimo-v2.5: 131072; kimi-k2.5 (*kimi*k2* pattern): 262144 + const caps = aggregateComboCapabilities([ + "opencode-go/mimo-v2.5", + "opencode-go/kimi-k2.5", + ]); + expect(caps.maxOutput).toBe(262144); + }); +}); + +describe("aggregateComboCapabilities — nested combo resolution via comboLookup", () => { + it("resolves nested combo and unions vision from its members", () => { + const lookup = { "inner-combo": ["opencode-go/deepseek-v4-pro", "opencode-go/mimo-v2.5"] }; + const caps = aggregateComboCapabilities(["inner-combo"], lookup); + expect(caps.reasoning).toBe(true); + expect(caps.vision).toBe(true); // mimo brings vision through the lookup + }); + + it("outer combo gets vision via nested combo containing mimo", () => { + const lookup = { "deepseek-v4-pro-fusion": ["opencode-go/deepseek-v4-pro", "opencode-go/mimo-v2.5"] }; + const caps = aggregateComboCapabilities(["deepseek-v4-pro-fusion", "openai/gpt-5"], lookup); + expect(caps.vision).toBe(true); + expect(caps.reasoning).toBe(true); + }); + + it("contextWindow is min across all resolved leaves", () => { + // deepseek-v4-pro (*deepseek-v4*): 1000000; mimo-v2.5: 1048576 → min = 1000000 + const lookup = { "inner": ["opencode-go/deepseek-v4-pro"] }; + const caps = aggregateComboCapabilities(["inner", "opencode-go/mimo-v2.5"], lookup); + expect(caps.contextWindow).toBe(1000000); + }); + + it("handles cycles without throwing", () => { + const lookup = { "a": ["b"], "b": ["a"] }; + expect(() => aggregateComboCapabilities(["a"], lookup)).not.toThrow(); + }); + + it("without comboLookup bare combo name falls through to pattern match", () => { + // *deepseek-v4* pattern: reasoning true, vision false + const caps = aggregateComboCapabilities(["deepseek-v4-pro-fusion"]); + expect(caps.reasoning).toBe(true); + expect(caps.vision).toBe(false); + }); +}); From c933eefc2711ab94d3bb0508973f827532c7bd07 Mon Sep 17 00:00:00 2001 From: Amir Seify Date: Wed, 16 Sep 2026 21:31:22 +0700 Subject: [PATCH 08/41] fix(cursor): stop AgentService empty turns and silent tool hangs Cursor-hosted models (cu/composer-2.5, cu/cursor-grok-*, cu/default) returned HTTP 200 with an empty turn, or hung, whenever a client sent tools. - Fold system prompts into the current user message. custom_system_prompt (RunRequest field 8) makes AgentService return an empty turn. - Send ModelDetails (field 3); thinking variants (Composer, Grok, *-thinking) return an empty turn when only requested_model (field 9) is set. - Route tool-call history and declared tool schemas through AgentService: encode OpenAI tools into mcp_tools (field 4), decode McpArgs and emit real tool_calls with finish_reason tool_calls. - Map Composer thinking / Grok thinking_delta (field 4) into visible content instead of dropping the answer with the unsigned reasoning. - Ack request_context without echoing MCP tools (double-advertise stalls the HTTP/2 stream) and ack kv_server_message so the run proceeds. - Reject IDE builtin execs instead of failing the turn, so the model can continue with MCP tools or a text answer. - Add google.protobuf.Value / MCP encoders and a FIXED64 branch to encodeField in cursorProtobuf.js. RTK now compresses the source-format body before translation for cursor only: its translator rewrites role:tool into user XML, so the post-translate pass missed those tool results. Every other provider keeps the post-translate pass unchanged. --- CHANGELOG.md | 2 + open-sse/AGENTS.md | 2 +- open-sse/executors/cursor.js | 269 +++++++++++++++---- open-sse/handlers/chatCore.js | 24 +- open-sse/rtk/index.js | 2 +- open-sse/utils/cursorProtobuf.js | 221 ++++++++++++++- tests/unit/cursor-agent-exec-request.test.js | 81 +++++- tests/unit/cursor-agent-proto.test.js | 9 + tests/unit/rtk-cursor-pretranslate.test.js | 131 +++++++++ 9 files changed, 670 insertions(+), 71 deletions(-) create mode 100644 tests/unit/rtk-cursor-pretranslate.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index f16c8f53..2bcc3390 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - **i18n**: integrate Persian (fa) translation ## Fixes +- **Cursor**: stop AgentService empty turns (`OUT 0`) and silent hangs — fold system prompts instead of `custom_system_prompt`, send `ModelDetails`, read Composer/Grok `thinking_delta`, ack request-context without echoing MCP tools, and reject IDE execs so the model can continue +- **RTK**: for Cursor, compress source-format `tool_result` / `role:tool` **before** translation — its translator rewrites those shapes, so post-translate compression missed them. Other providers keep the post-translate pass unchanged - **OpenCode / OpenCode Go**: resolve 403 `FreeTierError` and 429 rate limits with canonical session format, valid User-Agent, and stable upstream session reuse; force stream and declare `forceStream` for free-tier SSE aggregation; cloak decoy tools, normalize Muse Free tool choice, and strip prior reasoning items on Responses models; route Union Alpha via Messages API - **Kiro**: preserve underscores in tool names (`mcp__server__tool`) and restore client tool names in responses; use neutral placeholder for tool-result-only turns; forward tool-result images - **Stream**: report aborts after HTTP 200 in-band (per-format error frames) instead of closing silently diff --git a/open-sse/AGENTS.md b/open-sse/AGENTS.md index 5ea0d971..7e63c051 100644 --- a/open-sse/AGENTS.md +++ b/open-sse/AGENTS.md @@ -4,7 +4,7 @@ Provider-agnostic SSE engine: one OpenAI-style request → any provider (LLM cha ## Request lifecycle (chat) -`handlers/chatCore.js` → `services/model.js` `parseModel` (resolve `provider/model`) → **pre-translate hooks** (`rtk/` tool_result compress, `rtk/headroom.js` proxy compress, `rtk/caveman.js` system inject — all fail-open) → `executors/index.js` `getExecutor(provider)` → `translator/index.js` `translateRequest` (client format → provider format) → `executor.execute()` (streams upstream) → `translateResponse` (provider chunks → client format) → SSE out. +`handlers/chatCore.js` → `services/model.js` `parseModel` (resolve `provider/model`) → **RTK for `cursor`** (`rtk/` compresses the source-format `tool_result` / `role:tool` in-place — its translator rewrites those shapes, so this one provider must run **before** translate) → `translator/index.js` `translateRequest` (client format → provider format) → **post-translate savers** (`rtk/` compress for every other provider, `rtk/headroom.js` proxy compress, `rtk/caveman.js` / `rtk/ponytail.js` system inject — all fail-open) → `executors/index.js` `getExecutor(provider)` → `executor.execute()` (streams upstream) → `translateResponse` (provider chunks → client format) → SSE out. ## Directory map diff --git a/open-sse/executors/cursor.js b/open-sse/executors/cursor.js index 0aefc623..8f20040d 100644 --- a/open-sse/executors/cursor.js +++ b/open-sse/executors/cursor.js @@ -7,13 +7,16 @@ import { wrapConnectRPCFrame, decodeMessage, parseConnectRPCFrame, - extractTextFromResponse + extractTextFromResponse, + encodeMcpTools, + decodeMcpArgs, } from "../utils/cursorProtobuf.js"; import { buildCursorHeaders } from "../utils/cursorChecksum.js"; import { estimateUsage } from "../utils/usageTracking.js"; import { SSE_DONE, SSE_HEADERS } from "../utils/sseConstants.js"; import { chatChunkSse, sseChunk } from "../utils/sse.js"; import { FORMATS } from "../translator/formats.js"; +import { ROLE, OPENAI_BLOCK } from "../translator/schema/index.js"; import { proxyAwareFetch } from "../utils/proxyFetch.js"; import zlib from "zlib"; import crypto from "crypto"; @@ -65,55 +68,74 @@ function textFromContent(content) { if (typeof content === "string") return content; if (!Array.isArray(content)) return ""; return content - .filter((part) => part?.type === "text" && typeof part.text === "string") + .filter((part) => part?.type === OPENAI_BLOCK.TEXT && typeof part.text === "string") .map((part) => part.text) .join("\n"); } -function isAgentTextRequest(body) { - // Many compatible clients always attach their built-in tool schemas, even - // for a normal text turn. Cursor's retired ChatService rejects those - // requests; AgentService can still answer the text turn, so ignore schemas - // here. A real tool-call/result conversation is kept on the legacy path - // until its AgentService tool protocol is implemented. - return Array.isArray(body?.messages) && body.messages.every((message) => { - if (message?.tool_calls?.length || message?.role === "tool") return false; - return typeof message?.content === "string" - || Array.isArray(message?.content) && message.content.every((part) => part?.type === "text"); +function isTextPart(part) { + return !part || part.type === OPENAI_BLOCK.TEXT || typeof part === "string"; +} + +export function isAgentCapableRequest(body) { + // ChatService rejects auto/composer and most thinking variants. AgentService + // can answer text turns (including declared tool schemas) and tool-call + // history. Image parts still need the legacy protobuf path. + if (!Array.isArray(body?.messages) || body.messages.length === 0) return false; + return body.messages.every((message) => { + if (Array.isArray(message?.content)) return message.content.every(isTextPart); + return message?.content == null || typeof message.content === "string"; }); } function encodeHistoryMessage(message) { const content = textFromContent(message?.content); - if (!content) return null; + const extras = []; + if (message?.role === ROLE.ASSISTANT && message.tool_calls?.length) { + for (const tc of message.tool_calls) { + extras.push(`[tool_call id=${tc.id || ""} name=${tc.function?.name || "tool"} args=${tc.function?.arguments || "{}"}]`); + } + } + if (message?.role === ROLE.TOOL) { + extras.push(`[tool_result id=${message.tool_call_id || ""}]`); + } + const textBody = [content, ...extras].filter(Boolean).join("\n"); + if (!textBody) return null; // ConversationHistoryMessage.user / .assistant -> repeated content -> text. - const text = agentString(1, content); - if (message.role === "assistant") { + const text = agentString(1, textBody); + if (message.role === ROLE.ASSISTANT) { return agentMessage(2, agentMessage(1, agentMessage(1, text))); } return agentMessage(1, agentMessage(1, agentMessage(1, text))); } -function buildAgentRunFrame(messages, model) { +export function buildAgentRunFrame(messages, model, tools = []) { + // custom_system_prompt (RunRequest field 8) makes AgentService return an + // empty turn. Fold system text into the current user message instead. const system = messages - .filter((message) => message?.role === "system") + .filter((message) => message?.role === ROLE.SYSTEM) .map((message) => textFromContent(message.content)) .filter(Boolean) .join("\n\n"); - const chatMessages = messages.filter((message) => message?.role !== "system"); - const currentIndex = [...chatMessages].map((message) => message?.role).lastIndexOf("user"); + const chatMessages = messages.filter((message) => message?.role !== ROLE.SYSTEM); + const currentIndex = [...chatMessages].map((message) => message?.role).lastIndexOf(ROLE.USER); const current = currentIndex >= 0 ? chatMessages[currentIndex] : chatMessages.at(-1); const history = chatMessages .slice(0, currentIndex >= 0 ? currentIndex : -1) .map(encodeHistoryMessage) .filter(Boolean); - const userText = textFromContent(current?.content) || "Continue."; + const rawUser = textFromContent(current?.content) || "Continue."; + const userText = system ? `${system}\n\n${rawUser}` : rawUser; // agent.v1.UserMessageAction.user_message and its optional history. + // selected_context (3) + mode=1 (4) match cursor-agent's wire format; without + // them the server may accept the RPC and stream an empty turn. const userMessage = concatBuffers( agentString(1, userText), agentString(2, crypto.randomUUID()), + agentMessage(3, new Uint8Array()), + encodeField(4, PROTOBUF_VARINT, 1), ); const conversationHistory = history.length ? concatBuffers(...history.map((entry) => agentMessage(1, entry))) @@ -124,11 +146,20 @@ function buildAgentRunFrame(messages, model) { ); const conversationAction = agentMessage(1, userAction); const requestedModel = concatBuffers(agentString(1, model), agentBool(7, true)); + // ModelDetails (field 3): thinking variants (Composer, Grok, *-thinking) + // return an empty turn when only RequestedModel (field 9) is set. + const modelDetails = concatBuffers( + agentString(1, model), + agentString(3, model), + agentString(4, model), + ); + const mcpTools = encodeMcpTools(tools); const runRequest = concatBuffers( // An empty ConversationStateStructure starts a fresh local agent session. agentMessage(1, new Uint8Array()), agentMessage(2, conversationAction), - ...(system ? [agentString(8, system)] : []), + agentMessage(3, modelDetails), + ...(mcpTools.length ? [agentMessage(4, mcpTools)] : []), agentMessage(9, requestedModel), ); @@ -157,13 +188,51 @@ function decodeAgentFrames(buffer, onFrame) { return pending; } -function createRequestContextResponse() { - // AgentService asks every run for client context. 9router has no IDE file - // context, so acknowledge with an empty RequestContext. +function execIds(execRequest) { + const id = Number(execRequest?.get(1)?.[0]?.value || 0); + const execId = extractAgentString(execRequest, 15); + return { id, execId }; +} + +function wrapExecClientMessage(execMsgId, execId, resultField, resultPayload) { + const parts = []; + if (execMsgId) parts.push(encodeField(1, PROTOBUF_VARINT, execMsgId)); + parts.push(agentString(15, execId || "")); + parts.push(encodeField(resultField, PROTOBUF_LEN, resultPayload || new Uint8Array())); + return wrapConnectRPCFrame(agentMessage(2, concatBuffers(...parts))); +} + +function createRequestContextResponse(execRequest) { + // Tools already go out on AgentRunRequest.mcp_tools. Echoing them again on + // this ack makes AgentService stall silently (0 SSE bytes until abort). + const { id, execId } = execIds(execRequest); const requestContextSuccess = agentMessage(1, new Uint8Array()); const requestContextResult = agentMessage(1, requestContextSuccess); - const execClientMessage = agentMessage(10, requestContextResult); - return wrapConnectRPCFrame(agentMessage(2, execClientMessage)); + return wrapExecClientMessage(id, execId, 10, requestContextResult); +} + +// ExecServerMessage variant → ExecClientMessage result field (same numbers). +const EXEC_RESULT_FIELD = { + 2: 2, 3: 3, 4: 4, 5: 5, 7: 7, 8: 8, 9: 9, 16: 16, 20: 20, 23: 23, +}; + +function rejectExecRequest(execRequest) { + const { id, execId } = execIds(execRequest); + const variant = [...(execRequest?.keys?.() || [])].find((field) => field !== 1 && field !== 15); + const resultField = EXEC_RESULT_FIELD[variant]; + if (!resultField) return null; + // Diagnostics has no rejected variant — empty success unblocks the stream. + if (variant === 9) return wrapExecClientMessage(id, execId, 9, new Uint8Array()); + const rejected = agentMessage(2, agentString(2, "Tool not available in this environment. Use the MCP tools provided instead.")); + return wrapExecClientMessage(id, execId, resultField, rejected); +} + +function encodeKvClientMessage(kvId, resultField, resultPayload, metadata) { + const parts = []; + if (kvId) parts.push(encodeField(1, PROTOBUF_VARINT, kvId)); + parts.push(encodeField(resultField, PROTOBUF_LEN, resultPayload || new Uint8Array())); + if (metadata && metadata.length) parts.push(encodeField(4, PROTOBUF_LEN, metadata)); + return wrapConnectRPCFrame(agentMessage(3, concatBuffers(...parts))); } const CURSOR_STREAM_DEBUG = process.env.CURSOR_STREAM_DEBUG === "1"; @@ -479,7 +548,7 @@ export class CursorExecutor extends BaseExecutor { }; } - async executeAgent({ model, body, stream, credentials, signal }) { + async executeAgent({ model, body, stream, credentials, signal, log }) { const agentEndpoint = PROVIDER_OAUTH.cursor?.agentEndpoint; if (!agentEndpoint) throw new Error("Cursor AgentService endpoint is not configured"); @@ -491,9 +560,10 @@ export class CursorExecutor extends BaseExecutor { } let session; + const tools = body.tools || []; try { session = this.openAgentHttp2Stream(url, headers, requestController.signal); - session.write(buildAgentRunFrame(body.messages || [], model)); + session.write(buildAgentRunFrame(body.messages || [], model, tools)); } catch (error) { throw new Error(`Cursor AgentService request failed: ${error.message}`); } @@ -533,8 +603,23 @@ export class CursorExecutor extends BaseExecutor { // so strict clients such as Claude Code accept the completed stream. const responseId = `chatcmpl-msg_${Date.now()}`; const created = Math.floor(Date.now() / 1000); + const composerModel = isComposerModel(model); let pending = Buffer.alloc(0); let finished = false; + let thinkingAcc = ""; + let emittedVisible = 0; + let emittedText = false; + + const flushThinkingFallback = (onEvent) => { + if (emittedText || !thinkingAcc) return; + const fallback = composerModel + ? visibleComposerContentFromThinking(thinkingAcc) + : thinkingAcc.trim(); + if (fallback) { + emittedText = true; + onEvent({ type: "text", value: fallback }); + } + }; const consume = async (onEvent) => { try { @@ -553,32 +638,87 @@ export class CursorExecutor extends BaseExecutor { const update = decodeMessage(serverMessage.get(1)[0].value); if (update.has(1)) { const textDelta = extractAgentString(decodeMessage(update.get(1)[0].value), 1); - if (textDelta) onEvent({ type: "text", value: textDelta }); + if (textDelta) { + emittedText = true; + onEvent({ type: "text", value: textDelta }); + } } - // Cursor's AgentService emits internal reasoning without the - // cryptographic signature required by Anthropic thinking blocks. - // Forwarding it makes strict Anthropic clients (Claude Code) - // discard or wait on an otherwise complete response. Keep the - // reasoning upstream-only and emit the normal answer text. + // thinking_delta (field 4). Composer (and some Grok variants) put + // the visible answer after here and never send text_delta. + if (update.has(4)) { + const thinkingDelta = extractAgentString(decodeMessage(update.get(4)[0].value), 1); + if (thinkingDelta) { + thinkingAcc += thinkingDelta; + if (composerModel) { + const visible = visibleComposerContentFromThinking(thinkingAcc); + if (visible.length > emittedVisible) { + const deltaContent = visible.slice(emittedVisible); + emittedVisible = visible.length; + emittedText = true; + onEvent({ type: "text", value: deltaContent }); + } + } + } + } + // Keep unsigned reasoning upstream-only for Anthropic clients. if (update.has(14)) { + flushThinkingFallback(onEvent); finished = true; onEvent({ type: "done" }); } } + // KvServerMessage (field 4): get/set blob. Ack so the stream proceeds. + if (serverMessage.has(4)) { + const kv = decodeMessage(serverMessage.get(4)[0].value); + const kvId = kv.get(1)?.[0]?.value || 0; + const metadata = kv.get(4)?.[0]?.value || null; + if (kv.has(2)) { + session.write(encodeKvClientMessage(kvId, 2, agentMessage(1, new Uint8Array()), metadata)); + } else if (kv.has(3)) { + session.write(encodeKvClientMessage(kvId, 3, new Uint8Array(), metadata)); + } + } + // AgentService requests IDE context before producing a response. - // Return an empty context; 9router is not coupled to an editor. if (serverMessage.has(2)) { const execRequest = decodeMessage(serverMessage.get(2)[0].value); if (execRequest.has(10)) { - session.write(createRequestContextResponse()); + log?.info?.("CURSOR", "AgentService request_context ack"); + session.write(createRequestContextResponse(execRequest)); + } else if (execRequest.has(11)) { + const mcp = decodeMcpArgs(execRequest.get(11)[0].value); + const name = mcp.toolName || mcp.name; + if (name) { + log?.info?.("CURSOR", `AgentService MCP tool_call ${name}`); + finished = true; + onEvent({ + type: "tool_call", + value: { + id: mcp.toolCallId || `call_${crypto.randomUUID()}`, + name, + arguments: JSON.stringify(mcp.args || {}), + }, + }); + onEvent({ type: "done", finishReason: "tool_calls" }); + } else { + debugLog(`[CURSOR AGENT] Unsupported exec request fields: ${[...execRequest.keys()].join(",")}`); + finished = true; + onEvent({ type: "error", value: "Cursor AgentService requested an unsupported IDE tool" }); + } } else { - // Every other ExecServerMessage variant is an editor-backed tool - // (shell, read, write, …) that 9router cannot service. Fail the - // turn rather than narrating protocol state as assistant text. - debugLog(`[CURSOR AGENT] Unsupported exec request fields: ${[...execRequest.keys()].join(",")}`); - finished = true; - onEvent({ type: "error", value: "Cursor AgentService requested an unsupported IDE tool" }); + // Auto/Composer often probe IDE builtins (shell/read/…). Reject + // them so the model can continue with MCP tools or a text answer + // instead of stalling the h2 stream. + const rejection = rejectExecRequest(execRequest); + if (rejection) { + log?.info?.("CURSOR", `AgentService rejected IDE exec fields=${[...execRequest.keys()].join(",")}`); + session.write(rejection); + } else { + debugLog(`[CURSOR AGENT] Unsupported exec request fields: ${[...execRequest.keys()].join(",")}`); + finished = true; + onEvent({ type: "error", value: "Cursor AgentService requested an unsupported IDE tool" }); + } } } }); @@ -586,7 +726,10 @@ export class CursorExecutor extends BaseExecutor { } finally { try { session.end(); } catch {} try { session.close(); } catch {} - if (!finished) onEvent({ type: "done" }); + if (!finished) { + flushThinkingFallback(onEvent); + onEvent({ type: "done" }); + } } }; @@ -594,10 +737,21 @@ export class CursorExecutor extends BaseExecutor { let content = ""; let reasoning = ""; let agentError = null; + const toolCalls = []; + let finishReason = "stop"; await consume((event) => { if (event.type === "text") content += event.value; else if (event.type === "thinking") reasoning += event.value; + else if (event.type === "tool_call") { + toolCalls.push({ + id: event.value.id, + type: "function", + function: { name: event.value.name, arguments: event.value.arguments }, + }); + finishReason = "tool_calls"; + } else if (event.type === "error") agentError = event.value; + else if (event.type === "done" && event.finishReason) finishReason = event.finishReason; }); if (agentError) { return { @@ -611,13 +765,19 @@ export class CursorExecutor extends BaseExecutor { responseFormat: FORMATS.OPENAI, }; } + const message = { + role: "assistant", + content: content || null, + ...(reasoning ? { reasoning_content: reasoning } : {}), + ...(toolCalls.length ? { tool_calls: toolCalls } : {}), + }; return { response: new Response(JSON.stringify({ id: responseId, object: "chat.completion", created, model, - choices: [{ index: 0, message: { role: "assistant", content: content || null, ...(reasoning ? { reasoning_content: reasoning } : {}) }, finish_reason: "stop" }], + choices: [{ index: 0, message, finish_reason: finishReason }], usage: estimateUsage(body, content.length, FORMATS.OPENAI), }), { headers: { "Content-Type": "application/json" } }), url, @@ -635,6 +795,18 @@ export class CursorExecutor extends BaseExecutor { controller.enqueue(encoder.encode(chatChunkSse({ id: responseId, created, model, delta: { content: event.value } }))); } else if (event.type === "thinking") { controller.enqueue(encoder.encode(chatChunkSse({ id: responseId, created, model, delta: { reasoning_content: event.value } }))); + } else if (event.type === "tool_call") { + controller.enqueue(encoder.encode(chatChunkSse({ + id: responseId, created, model, + delta: { + tool_calls: [{ + index: 0, + id: event.value.id, + type: "function", + function: { name: event.value.name, arguments: event.value.arguments }, + }], + }, + }))); } else if (event.type === "error") { // An SSE error frame, not a content delta: a protocol failure must not // be rendered to the user as the assistant's reply, and downstream @@ -643,7 +815,10 @@ export class CursorExecutor extends BaseExecutor { controller.enqueue(encoder.encode(SSE_DONE)); controller.close(); } else if (event.type === "done") { - controller.enqueue(encoder.encode(chatChunkSse({ id: responseId, created, model, delta: {}, finishReason: "stop" }))); + controller.enqueue(encoder.encode(chatChunkSse({ + id: responseId, created, model, delta: {}, + finishReason: event.finishReason || "stop", + }))); controller.enqueue(encoder.encode(SSE_DONE)); controller.close(); } @@ -664,9 +839,9 @@ export class CursorExecutor extends BaseExecutor { } async execute({ model, body, stream, credentials, signal, log, proxyOptions = null }) { - if (isAgentTextRequest(body)) { + if (isAgentCapableRequest(body)) { try { - return await this.executeAgent({ model, body, stream, credentials, signal }); + return await this.executeAgent({ model, body, stream, credentials, signal, log }); } catch (error) { return { response: new Response(JSON.stringify({ diff --git a/open-sse/handlers/chatCore.js b/open-sse/handlers/chatCore.js index 56a9d69f..0db37ba1 100644 --- a/open-sse/handlers/chatCore.js +++ b/open-sse/handlers/chatCore.js @@ -116,6 +116,19 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred } } + // Per-request opt-out: client can bypass all token savers via header + const tokenSaverEnabled = clientRawRequest?.headers?.[TOKEN_SAVER_HEADER]?.toLowerCase() !== "off"; + + // Cursor's translator rewrites tool_result into user text, so RTK must run on + // the source body before translation. Every other pair translates the tool + // shapes 1:1 — keep the post-translate pass there so those providers are + // untouched (and a retry never re-compresses an already-compressed body). + const preTranslateRtk = provider === "cursor" + ? compressMessages(body, tokenSaverEnabled && rtkEnabled) + : null; + const preTranslateRtkLine = formatRtkLog(preTranslateRtk); + if (preTranslateRtkLine) console.log(preTranslateRtkLine); + const clientRequestedStreaming = body.stream === true || sourceFormat === FORMATS.ANTIGRAVITY || sourceFormat === FORMATS.GEMINI || sourceFormat === FORMATS.GEMINI_CLI; const providerRequiresStreaming = PROVIDERS[provider]?.forceStream === true; let stream = providerRequiresStreaming ? true : (body.stream !== false); @@ -252,13 +265,8 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred translatedBody.tools = defaultClaudeToolType(translatedBody.tools); } - // Per-request opt-out: client can bypass all token savers via header - const tokenSaverEnabled = clientRawRequest?.headers?.[TOKEN_SAVER_HEADER]?.toLowerCase() !== "off"; - - // RTK: compress tool_result content - const rtkStats = compressMessages(translatedBody, tokenSaverEnabled && rtkEnabled); - const rtkLine = formatRtkLog(rtkStats); - if (rtkLine) console.log(rtkLine); + // RTK: compress tool_result content. Skipped when already done pre-translate. + const rtkStats = preTranslateRtk || compressMessages(translatedBody, tokenSaverEnabled && rtkEnabled); // Headroom: optional external proxy compression; fail open if proxy is absent. const headroomDiagnostics = {}; @@ -275,6 +283,8 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred // Token-saver flags accumulator for the single "⚙" log line below. const xf = []; + if (rtkStats?.hits?.length) xf.push(`RTK:${rtkStats.hits.length}`); + // Caveman: inject terse-style system prompt if (tokenSaverEnabled && cavemanEnabled && cavemanLevel) { injectCaveman(translatedBody, finalFormat, cavemanLevel); diff --git a/open-sse/rtk/index.js b/open-sse/rtk/index.js index dd1e5018..b8488baa 100644 --- a/open-sse/rtk/index.js +++ b/open-sse/rtk/index.js @@ -1,5 +1,5 @@ // RTK port: compress tool_result content in LLM request bodies -// Injected at the top of translateRequest (before any format translation) +// Applied in chatCore on the source-format body, before translateRequest. import { RAW_CAP, MIN_COMPRESS_SIZE } from "./constants.js"; import { autoDetectFilter } from "./autodetect.js"; import { safeApply } from "./applyFilter.js"; diff --git a/open-sse/utils/cursorProtobuf.js b/open-sse/utils/cursorProtobuf.js index c870921b..47b3e0ba 100644 --- a/open-sse/utils/cursorProtobuf.js +++ b/open-sse/utils/cursorProtobuf.js @@ -218,6 +218,12 @@ export function encodeField(fieldNum, wireType, value) { return concatArrays(tagBytes, lengthBytes, dataBytes); } + if (wireType === WIRE_TYPE.FIXED64) { + const buf = Buffer.alloc(8); + buf.writeDoubleLE(Number(value)); + return concatArrays(tagBytes, buf); + } + return new Uint8Array(0); } @@ -887,6 +893,211 @@ export function extractTextFromResponse(payload) { } } +// ==================== AGENT SERVICE (google.protobuf.Value + MCP) ==================== + +const PB_VALUE = { NULL: 1, NUMBER: 2, STRING: 3, BOOL: 4, STRUCT: 5, LIST: 6 }; +const PB_STRUCT_FIELDS = 1; +const PB_MAP_KEY = 1; +const PB_MAP_VALUE = 2; +const PB_LIST_VALUES = 1; + +const MTD_NAME = 1; +const MTD_DESCRIPTION = 2; +const MTD_INPUT_SCHEMA = 3; +const MTD_PROVIDER = 4; +const MTD_TOOL_NAME = 5; + +const MCP_TOOLS_TOOL = 1; + +const MCP_ARGS_NAME = 1; +const MCP_ARGS_ENTRY = 2; +const MCP_ARGS_CALL_ID = 3; +const MCP_ARGS_TOOL_NAME = 5; + +const MCR_SUCCESS = 1; +const MCR_ERROR = 2; +const MCR_TOOL_NOT_FOUND = 5; +const MCS_CONTENT = 1; +const MCS_IS_ERROR = 2; +const MCC_TEXT = 1; +const MCC_IMAGE = 2; +const MTC_TEXT = 1; +const MIC_DATA = 1; +const MIC_MIME = 2; +const MER_MESSAGE = 1; +const TNF_NAME = 1; + +function asBytes(value) { + if (!value) return Buffer.alloc(0); + return Buffer.isBuffer(value) ? value : Buffer.from(value); +} + +/** + * Encode a JS value as google.protobuf.Value (oneof body, no outer tag). + */ +export function encodeAgentValue(value) { + if (value === null || value === undefined) { + return encodeField(PB_VALUE.NULL, WIRE_TYPE.VARINT, 0); + } + if (typeof value === "boolean") { + return encodeField(PB_VALUE.BOOL, WIRE_TYPE.VARINT, value ? 1 : 0); + } + if (typeof value === "number") { + return encodeField(PB_VALUE.NUMBER, WIRE_TYPE.FIXED64, value); + } + if (typeof value === "string") { + return encodeField(PB_VALUE.STRING, WIRE_TYPE.LEN, value); + } + if (Array.isArray(value)) { + const items = value.map((item) => encodeField(PB_LIST_VALUES, WIRE_TYPE.LEN, encodeAgentValue(item))); + return encodeField(PB_VALUE.LIST, WIRE_TYPE.LEN, concatArrays(...items)); + } + if (typeof value === "object") { + const entries = Object.entries(value).map(([key, val]) => encodeField( + PB_STRUCT_FIELDS, + WIRE_TYPE.LEN, + concatArrays( + encodeField(PB_MAP_KEY, WIRE_TYPE.LEN, key), + encodeField(PB_MAP_VALUE, WIRE_TYPE.LEN, encodeAgentValue(val)), + ), + )); + return encodeField(PB_VALUE.STRUCT, WIRE_TYPE.LEN, concatArrays(...entries)); + } + return encodeField(PB_VALUE.STRING, WIRE_TYPE.LEN, String(value)); +} + +/** + * Decode google.protobuf.Value bytes back to a JS value. + */ +export function decodeAgentValue(bytes) { + const fields = decodeMessage(asBytes(bytes)); + if (fields.has(PB_VALUE.NULL)) return null; + if (fields.has(PB_VALUE.BOOL)) return fields.get(PB_VALUE.BOOL)[0].value !== 0; + if (fields.has(PB_VALUE.NUMBER)) { + return asBytes(fields.get(PB_VALUE.NUMBER)[0].value).readDoubleLE(0); + } + if (fields.has(PB_VALUE.STRING)) { + return asBytes(fields.get(PB_VALUE.STRING)[0].value).toString("utf8"); + } + if (fields.has(PB_VALUE.STRUCT)) { + const result = {}; + for (const entry of decodeMessage(asBytes(fields.get(PB_VALUE.STRUCT)[0].value)).get(PB_STRUCT_FIELDS) || []) { + const pair = decodeMessage(asBytes(entry.value)); + const key = asBytes(pair.get(PB_MAP_KEY)?.[0]?.value).toString("utf8"); + if (key) result[key] = decodeAgentValue(pair.get(PB_MAP_VALUE)?.[0]?.value); + } + return result; + } + if (fields.has(PB_VALUE.LIST)) { + return (decodeMessage(asBytes(fields.get(PB_VALUE.LIST)[0].value)).get(PB_LIST_VALUES) || []) + .map((item) => decodeAgentValue(item.value)); + } + return null; +} + +function toolNameAndSchema(tool) { + const fn = tool?.function || tool || {}; + return { + name: fn.name || tool?.name || "", + description: fn.description || tool?.description || "", + schema: fn.parameters || tool?.parameters || tool?.inputSchema || tool?.input_schema || {}, + }; +} + +/** + * Encode agent.v1.McpToolDefinition body (name, description, Value schema, provider, tool_name). + */ +export function encodeMcpToolDefinition(tool) { + const { name, description, schema } = toolNameAndSchema(tool); + return concatArrays( + encodeField(MTD_NAME, WIRE_TYPE.LEN, name), + encodeField(MTD_DESCRIPTION, WIRE_TYPE.LEN, description), + encodeField(MTD_INPUT_SCHEMA, WIRE_TYPE.LEN, encodeAgentValue(schema)), + encodeField(MTD_PROVIDER, WIRE_TYPE.LEN, "9router"), + encodeField(MTD_TOOL_NAME, WIRE_TYPE.LEN, name), + ); +} + +/** + * Encode AgentRunRequest.mcp_tools: repeated McpToolDefinition under field 1. + */ +export function encodeMcpTools(tools = []) { + if (!tools?.length) return new Uint8Array(); + return concatArrays( + ...tools.map((tool) => encodeField(MCP_TOOLS_TOOL, WIRE_TYPE.LEN, encodeMcpToolDefinition(tool))), + ); +} + +/** + * Decode agent.v1.McpArgs (name, typed args map, toolCallId, toolName). + */ +export function decodeMcpArgs(bytes) { + const msg = decodeMessage(asBytes(bytes)); + const args = {}; + for (const entry of msg.get(MCP_ARGS_ENTRY) || []) { + const pair = decodeMessage(asBytes(entry.value)); + const key = asBytes(pair.get(PB_MAP_KEY)?.[0]?.value).toString("utf8"); + if (key) args[key] = decodeAgentValue(pair.get(PB_MAP_VALUE)?.[0]?.value); + } + const read = (field) => asBytes(msg.get(field)?.[0]?.value).toString("utf8"); + return { + name: read(MCP_ARGS_NAME), + toolCallId: read(MCP_ARGS_CALL_ID), + toolName: read(MCP_ARGS_TOOL_NAME), + args, + }; +} + +function encodeMcpTextItem(text) { + return encodeField( + MCS_CONTENT, + WIRE_TYPE.LEN, + encodeField(MCC_TEXT, WIRE_TYPE.LEN, encodeField(MTC_TEXT, WIRE_TYPE.LEN, text)), + ); +} + +function encodeMcpImageItem(image) { + const data = image?.data || image || new Uint8Array(); + const mimeType = image?.mimeType || "application/octet-stream"; + return encodeField( + MCS_CONTENT, + WIRE_TYPE.LEN, + encodeField( + MCC_IMAGE, + WIRE_TYPE.LEN, + concatArrays( + encodeField(MIC_DATA, WIRE_TYPE.LEN, data), + encodeField(MIC_MIME, WIRE_TYPE.LEN, mimeType), + ), + ), + ); +} + +export function encodeMcpResultSuccess({ textItems = [], imageItems = [], isError = false } = {}) { + const success = concatArrays( + ...textItems.map(encodeMcpTextItem), + ...imageItems.map(encodeMcpImageItem), + encodeField(MCS_IS_ERROR, WIRE_TYPE.VARINT, isError ? 1 : 0), + ); + return encodeField(MCR_SUCCESS, WIRE_TYPE.LEN, success); +} + +export function encodeMcpResultError(message) { + return encodeField( + MCR_ERROR, + WIRE_TYPE.LEN, + encodeField(MER_MESSAGE, WIRE_TYPE.LEN, String(message || "")), + ); +} + +export function encodeMcpResultToolNotFound(name) { + return encodeField( + MCR_TOOL_NOT_FOUND, + WIRE_TYPE.LEN, + encodeField(TNF_NAME, WIRE_TYPE.LEN, String(name || "")), + ); +} + // ==================== EXPORTS ==================== export default { @@ -900,5 +1111,13 @@ export default { decodeField, decodeMessage, parseConnectRPCFrame, - extractTextFromResponse + extractTextFromResponse, + encodeAgentValue, + decodeAgentValue, + encodeMcpToolDefinition, + encodeMcpTools, + decodeMcpArgs, + encodeMcpResultSuccess, + encodeMcpResultError, + encodeMcpResultToolNotFound, }; diff --git a/tests/unit/cursor-agent-exec-request.test.js b/tests/unit/cursor-agent-exec-request.test.js index 347e159f..18389c18 100644 --- a/tests/unit/cursor-agent-exec-request.test.js +++ b/tests/unit/cursor-agent-exec-request.test.js @@ -18,6 +18,18 @@ function textFrame(text) { return Buffer.from(wrapConnectRPCFrame(encodeField(1, LEN, update))); } +// InteractionUpdate.thinking_delta (field 4) + turn_ended (field 14). +function thinkingFrame(text) { + const thinkingPart = Buffer.from(encodeField(1, LEN, text)); + const update = Buffer.from(encodeField(4, LEN, thinkingPart)); + return Buffer.from(wrapConnectRPCFrame(encodeField(1, LEN, update))); +} + +function turnEndedFrame() { + const update = Buffer.from(encodeField(14, LEN, new Uint8Array())); + return Buffer.from(wrapConnectRPCFrame(encodeField(1, LEN, update))); +} + function stubAgentSession(executor, frames) { const written = []; const queue = [...frames]; @@ -48,12 +60,12 @@ function parseSSE(text) { .map((data) => JSON.parse(data)); } -async function runAgent({ frames, stream }) { +async function runAgent({ frames, stream, model = "gpt-5.2", tools }) { const executor = new CursorExecutor(); const written = stubAgentSession(executor, frames); const result = await executor.executeAgent({ - model: "gpt-5.2", - body: { messages: [{ role: "user", content: "hi" }] }, + model, + body: { messages: [{ role: "user", content: "hi" }], ...(tools ? { tools } : {}) }, stream, credentials, }); @@ -73,32 +85,45 @@ describe("CursorExecutor AgentService exec_request handling", () => { expect(content).toBe("hello"); }); + it("does not echo client tools on the request_context ack", async () => { + const { written, result } = await runAgent({ + tools: [{ function: { name: "read_file", parameters: { type: "object" } } }], + frames: [execRequestFrame(10), textFrame("hello")], + stream: true, + }); + + expect(written.length).toBe(2); + expect(written[1].toString("utf8")).not.toContain("read_file"); + const content = parseSSE(await result.response.text()) + .map((e) => e.choices?.[0]?.delta?.content || "") + .join(""); + expect(content).toBe("hello"); + }); + it("does not render an unsupported exec request as assistant content", async () => { - const { result } = await runAgent({ - frames: [textFrame("partial answer"), execRequestFrame(2)], + const { result, written } = await runAgent({ + frames: [textFrame("partial answer"), execRequestFrame(2), textFrame(" more")], stream: true, }); const body = await result.response.text(); - expect(body).not.toContain("unsupported IDE tool\\n"); + expect(body).not.toContain("unsupported IDE tool"); const events = parseSSE(body); const content = events.map((e) => e.choices?.[0]?.delta?.content || "").join(""); - expect(content).toBe("partial answer"); - - const errorEvent = events.find((e) => e.error); - expect(errorEvent?.error?.message).toContain("unsupported IDE tool"); - expect(events.some((e) => e.choices?.[0]?.finish_reason === "stop")).toBe(false); + expect(content).toBe("partial answer more"); + expect(events.some((e) => e.error)).toBe(false); + expect(written.length).toBe(2); // run frame + IDE rejection }); - it("drops frames batched behind an unsupported exec request in the same read", async () => { + it("still emits later text after rejecting an IDE exec in the same read", async () => { const { result } = await runAgent({ frames: [Buffer.concat([execRequestFrame(2), textFrame("late")])], stream: true, }); const body = await result.response.text(); - expect(body).toContain("unsupported IDE tool"); - expect(body).not.toContain("late"); + expect(body).not.toContain("unsupported IDE tool"); + expect(body).toContain("late"); }); it("returns a non-200 error body for an unsupported exec request when not streaming", async () => { @@ -111,4 +136,32 @@ describe("CursorExecutor AgentService exec_request handling", () => { const payload = await result.response.json(); expect(payload.error.message).toContain("unsupported IDE tool"); }); + + it("streams Composer visible content from thinking_delta after ", async () => { + const { result } = await runAgent({ + model: "composer-2.5", + frames: [ + thinkingFrame("private reasoning that must not leakOK"), + turnEndedFrame(), + ], + stream: true, + }); + + const events = parseSSE(await result.response.text()); + const content = events.map((e) => e.choices?.[0]?.delta?.content || "").join(""); + expect(content).toBe("OK"); + expect(JSON.stringify(events)).not.toContain("private reasoning"); + }); + + it("flushes Grok thinking as visible content when the turn has no text_delta", async () => { + const { result } = await runAgent({ + model: "grok-4.5", + frames: [thinkingFrame("hello from grok"), turnEndedFrame()], + stream: true, + }); + + const events = parseSSE(await result.response.text()); + const content = events.map((e) => e.choices?.[0]?.delta?.content || "").join(""); + expect(content).toBe("hello from grok"); + }); }); diff --git a/tests/unit/cursor-agent-proto.test.js b/tests/unit/cursor-agent-proto.test.js index 2d571aba..b112cc58 100644 --- a/tests/unit/cursor-agent-proto.test.js +++ b/tests/unit/cursor-agent-proto.test.js @@ -246,6 +246,15 @@ describe("Cursor AgentService executor helpers (cursor.js)", () => { const run = decodeMessage(clientMsg.get(1)[0].value); expect(run.has(2)).toBe(true); // action expect(run.has(9)).toBe(true); // requested_model + // custom_system_prompt (field 8) makes AgentService return an empty turn. + expect(run.has(8)).toBe(false); + expect(run.has(3)).toBe(true); // ModelDetails — required for thinking variants + const action = decodeMessage(run.get(2)[0].value); + const userAction = decodeMessage(action.get(1)[0].value); + const userMessage = decodeMessage(userAction.get(1)[0].value); + const userText = Buffer.from(userMessage.get(1)[0].value).toString("utf8"); + expect(userText).toContain("be brief"); + expect(userText).toContain("hi"); }); it("encodes mcp_tools (field 4) when tools are provided", () => { diff --git a/tests/unit/rtk-cursor-pretranslate.test.js b/tests/unit/rtk-cursor-pretranslate.test.js new file mode 100644 index 00000000..601fcfec --- /dev/null +++ b/tests/unit/rtk-cursor-pretranslate.test.js @@ -0,0 +1,131 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; + +const { executeMock } = vi.hoisted(() => ({ + executeMock: vi.fn(), +})); + +vi.mock("../../open-sse/executors/index.js", () => ({ + getExecutor: () => ({ + noAuth: true, + execute: executeMock, + }), +})); + +vi.mock("../../open-sse/utils/requestLogger.js", () => ({ + createRequestLogger: async () => ({ + logClientRawRequest: vi.fn(), + logRawRequest: vi.fn(), + logTargetRequest: vi.fn(), + logProviderResponse: vi.fn(), + logConvertedResponse: vi.fn(), + logError: vi.fn(), + }), +})); + +vi.mock("../../open-sse/utils/stream.js", () => ({ + COLORS: { red: "", reset: "" }, + createPassthroughStreamWithLogger: vi.fn(() => new TransformStream()), +})); + +vi.mock("@/lib/usageDb.js", () => ({ + trackPendingRequest: vi.fn(), + appendRequestLog: vi.fn(async () => {}), + saveRequestDetail: vi.fn(async () => {}), +})); + +const { handleChatCore } = await import("../../open-sse/handlers/chatCore.js"); + +function makeLongDiff() { + const lines = ["diff --git a/foo.js b/foo.js", "index abc..def 100644", "--- a/foo.js", "+++ b/foo.js", "@@ -1,3 +1,200 @@"]; + for (let i = 0; i < 200; i++) lines.push(`+added line ${i} UNIQUE_PADDING_${i} ${"x".repeat(20)}`); + return lines.join("\n"); +} + +describe("token savers on Cursor (pre-translate RTK)", () => { + beforeEach(() => { + vi.clearAllMocks(); + global.fetch = vi.fn(async (url, init) => { + if (String(url).includes("/v1/compress")) { + const payload = JSON.parse(init.body); + return new Response(JSON.stringify({ + messages: payload.messages, + tokens_before: 8000, + tokens_after: 2500, + tokens_saved: 5500, + }), { status: 200, headers: { "content-type": "application/json" } }); + } + throw new Error(`unexpected fetch: ${url}`); + }); + executeMock.mockResolvedValue({ + response: new Response(JSON.stringify({ + id: "chatcmpl-test", + object: "chat.completion", + choices: [{ message: { role: "assistant", content: "ok" }, finish_reason: "stop", index: 0 }], + }), { status: 200, headers: { "content-type": "application/json" } }), + url: "https://api2.cursor.sh/agent", + headers: {}, + transformedBody: null, + }); + }); + + it("compresses role:tool git diffs before openai→cursor rewrite, then injects Headroom/Caveman/Ponytail", async () => { + const diff = makeLongDiff(); + const log = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), line: vi.fn() }; + + await handleChatCore({ + body: { + model: "cu/default", + stream: false, + messages: [ + { role: "system", content: "hi" }, + { role: "user", content: "run git diff" }, + { + role: "assistant", + content: null, + tool_calls: [{ id: "call_1", type: "function", function: { name: "Bash", arguments: JSON.stringify({ command: "git diff" }) } }], + }, + { role: "tool", tool_call_id: "call_1", content: diff }, + { role: "user", content: "summarize" }, + ], + }, + modelInfo: { provider: "cursor", model: "default" }, + credentials: { apiKey: "test-key", providerSpecificData: {} }, + log, + connectionId: "test-conn", + rtkEnabled: true, + headroomEnabled: true, + headroomUrl: "http://localhost:8787", + cavemanEnabled: true, + cavemanLevel: "full", + ponytailEnabled: true, + ponytailLevel: "full", + clientRawRequest: { + endpoint: "/v1/chat/completions", + body: { model: "cu/default" }, + headers: { accept: "application/json" }, + }, + }); + + expect(executeMock).toHaveBeenCalled(); + const dispatched = executeMock.mock.calls[0][0].body; + const blob = JSON.stringify(dispatched.messages); + + expect(dispatched.messages.some((m) => m.role === "tool")).toBe(false); + expect(blob).toContain(""); + expect(blob).toContain("lines truncated"); + expect(blob).not.toContain("UNIQUE_PADDING_150"); + expect(blob).toContain("lazy senior developer"); + expect(blob).toMatch(/Respond like a caveman|drop filler|ACTIVE EVERY RESPONSE/i); + + expect(global.fetch).toHaveBeenCalledWith( + "http://localhost:8787/v1/compress", + expect.any(Object) + ); + + const xf = log.line.mock.calls.find((c) => c[1] === "⚙"); + expect(xf, "expected ⚙ saver log").toBeTruthy(); + expect(xf[2]).toContain("RTK:"); + expect(xf[2]).toContain("CAVEMAN:full"); + expect(xf[2]).toContain("PONYTAIL:full"); + }); +}); From 253199f16f0018c7fe2b1889791178566af19e4f Mon Sep 17 00:00:00 2001 From: Amir Seify Date: Mon, 21 Sep 2026 19:49:13 +0700 Subject: [PATCH 09/41] feat(combos): Cursor/Claude Default presets + bulk select/delete/strategy - Add Cursor Default / Claude Default on Dashboard -> Combos to generate unprefixed combo names that match Cursor/Claude client model IDs, seeded with cu/... or cc/... so those clients can route through 9Router. - Add multi-select bulk Delete and bulk Set strategy (Fallback / Round Robin / Fusion). - Docs and unit tests for preset builder. --- .../combo-defaults/cursor-model-list.png | Bin 0 -> 38350 bytes .../override-openai-base-url.png | Bin 0 -> 49400 bytes gitbook/content/en/features/combos.md | 25 ++ src/app/(dashboard)/dashboard/combos/page.js | 352 +++++++++++++++--- src/app/api/combos/presets/route.js | 110 ++++++ src/lib/comboPresets.js | 121 ++++++ tests/unit/combo-presets.test.js | 102 +++++ 7 files changed, 666 insertions(+), 44 deletions(-) create mode 100644 .github/issue-assets/combo-defaults/cursor-model-list.png create mode 100644 .github/issue-assets/combo-defaults/override-openai-base-url.png create mode 100644 src/app/api/combos/presets/route.js create mode 100644 src/lib/comboPresets.js create mode 100644 tests/unit/combo-presets.test.js diff --git a/.github/issue-assets/combo-defaults/cursor-model-list.png b/.github/issue-assets/combo-defaults/cursor-model-list.png new file mode 100644 index 0000000000000000000000000000000000000000..93abfbb1e4ca207905e00aec5ad5f9dcff3c7050 GIT binary patch literal 38350 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 BOxyqf literal 0 HcmV?d00001 diff --git a/.github/issue-assets/combo-defaults/override-openai-base-url.png b/.github/issue-assets/combo-defaults/override-openai-base-url.png new file mode 100644 index 0000000000000000000000000000000000000000..e79238992df0450ffa9d70b3ecfeb8a519263ac1 GIT binary patch literal 49400 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 vhBF`-D? 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 literal 0 HcmV?d00001 diff --git a/gitbook/content/en/features/combos.md b/gitbook/content/en/features/combos.md index 2b94eff5..f91c1f00 100644 --- a/gitbook/content/en/features/combos.md +++ b/gitbook/content/en/features/combos.md @@ -118,6 +118,31 @@ Cursor/Cline/Any tool: --- +## Cursor / Claude Default Combos + +Cursor and Claude Code send **unprefixed** model IDs (`composer-2.5`, `claude-opus-5`, `opus`), while 9Router routes with provider prefixes (`cu/composer-2.5`, `cc/claude-opus-5`). Default combo generators bridge that gap. + +On **Dashboard → Combos**: + +1. Click **Cursor Default** or **Claude Default** +2. Confirm the preview (new vs already-existing names) +3. 9Router creates one combo per client model ID, seeded with the matching prefixed route + +**Examples:** + +| Combo name (what the client sends) | Seeded model (what 9Router routes) | +|------------------------------------|------------------------------------| +| `composer-2.5` | `cu/composer-2.5` | +| `cursor-grok-4.6-high-fast` | `cu/cursor-grok-4.6-high-fast` | +| `claude-opus-5` | `cc/claude-opus-5` | +| `opus` | `cc/claude-opus-5` | + +Existing combo names are **skipped** (not overwritten). Edit any generated combo afterward to add fallbacks. Click the button again later to pick up new catalog IDs. + +> These combos help when Cursor/Claude already talk to 9Router (`/v1` or `ANTHROPIC_BASE_URL`) and send their native model IDs. They do not change Cursor’s built-in Models tab by themselves. + +--- + ## Example Combos ### Example 1: Premium Coding (Subscription → Cheap → Free) diff --git a/src/app/(dashboard)/dashboard/combos/page.js b/src/app/(dashboard)/dashboard/combos/page.js index 52ed7459..c0e20f3e 100644 --- a/src/app/(dashboard)/dashboard/combos/page.js +++ b/src/app/(dashboard)/dashboard/combos/page.js @@ -44,6 +44,12 @@ function normalizeCapEntry(entry) { return { ...EMPTY_CAP_ENTRY }; } +const STRATEGY_OPTIONS = [ + { value: "fallback", label: "Fallback — try in order" }, + { value: "round-robin", label: "Round Robin — rotate" }, + { value: "fusion", label: "Fusion — panel + judge" }, +]; + export default function CombosPage() { const [combos, setCombos] = useState([]); const [loading, setLoading] = useState(true); @@ -52,14 +58,99 @@ export default function CombosPage() { const [activeProviders, setActiveProviders] = useState([]); const [comboStrategies, setComboStrategies] = useState({}); const [capacityAdapter, setCapacityAdapter] = useState(EMPTY_CAPACITY_ADAPTER); - const [confirmState, setConfirmState] = useState(null); const { getCaps } = useModelCaps(); + const [confirmState, setConfirmState] = useState(null); + const [presetLoading, setPresetLoading] = useState(null); // "cursor" | "claude" | null + const [selectedIds, setSelectedIds] = useState([]); + const [bulkBusy, setBulkBusy] = useState(false); const { copied, copy } = useCopyToClipboard(); useEffect(() => { fetchData(); }, []); // eslint-disable-line react-hooks/exhaustive-deps + // Drop stale selection when the combo list changes (delete / refresh). + useEffect(() => { + const alive = new Set(combos.map((c) => c.id)); + setSelectedIds((prev) => prev.filter((id) => alive.has(id))); + }, [combos]); + + const selectedCombos = combos.filter((c) => selectedIds.includes(c.id)); + const allSelected = combos.length > 0 && selectedIds.length === combos.length; + const someSelected = selectedIds.length > 0; + + const toggleSelect = (id) => { + setSelectedIds((prev) => ( + prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id] + )); + }; + + const toggleSelectAll = () => { + setSelectedIds(allSelected ? [] : combos.map((c) => c.id)); + }; + + const clearSelection = () => setSelectedIds([]); + + const handleGeneratePresets = async (source) => { + const label = source === "cursor" ? "Cursor Default" : "Claude Default"; + setPresetLoading(source); + try { + const previewRes = await fetch(`/api/combos/presets?source=${source}`); + const preview = await previewRes.json(); + if (!previewRes.ok) { + alert(preview.error || `Failed to preview ${label}`); + return; + } + + const toCreate = preview.toCreate ?? (preview.items || []).filter((i) => !i.exists).length; + const toSkip = preview.toSkip ?? (preview.items || []).filter((i) => i.exists).length; + const total = (preview.items || []).length; + + if (total === 0) { + alert(`No ${label} models available to generate.`); + return; + } + + if (toCreate === 0) { + alert(`All ${total} ${label} combos already exist. Nothing to create.`); + return; + } + + setConfirmState({ + title: `Generate ${label}`, + message: `Create ${toCreate} combo${toCreate === 1 ? "" : "s"} named like ${source === "cursor" ? "Cursor" : "Claude"} model IDs (seeded with cu/… or cc/…). ${toSkip} already exist and will be skipped. You can edit any combo afterward to add fallbacks.`, + confirmText: "Generate", + variant: "primary", + onConfirm: async () => { + setConfirmState((prev) => prev ? { ...prev, loading: true } : null); + try { + const res = await fetch("/api/combos/presets", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ source }), + }); + const data = await res.json(); + if (!res.ok) { + alert(data.error || `Failed to generate ${label}`); + return; + } + await fetchData(); + setConfirmState(null); + } catch (error) { + console.log(`Error generating ${label}:`, error); + alert(`Failed to generate ${label}`); + setConfirmState((prev) => prev ? { ...prev, loading: false } : null); + } + }, + }); + } catch (error) { + console.log(`Error previewing ${label}:`, error); + alert(`Failed to preview ${label}`); + } finally { + setPresetLoading(null); + } + }; + const fetchData = async () => { try { const [combosRes, providersRes, settingsRes] = await Promise.all([ @@ -141,24 +232,80 @@ export default function CombosPage() { } }; + const pruneStrategiesForNames = (names, base = comboStrategies) => { + const updated = { ...base }; + for (const name of names) delete updated[name]; + return updated; + }; + + const persistComboStrategies = async (updated) => { + await fetch("/api/settings", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ comboStrategies: updated }), + }); + setComboStrategies(updated); + }; + const handleDelete = async (id) => { + const combo = combos.find((c) => c.id === id); setConfirmState({ title: "Delete Combo", - message: "Delete this combo?", + message: combo ? `Delete combo "${combo.name}"?` : "Delete this combo?", onConfirm: async () => { - setConfirmState(null); + setConfirmState((prev) => prev ? { ...prev, loading: true } : null); try { const res = await fetch(`/api/combos/${id}`, { method: "DELETE" }); if (res.ok) { - setCombos(combos.filter(c => c.id !== id)); + if (combo?.name) { + await persistComboStrategies(pruneStrategiesForNames([combo.name])); + } + setCombos((prev) => prev.filter((c) => c.id !== id)); + setSelectedIds((prev) => prev.filter((x) => x !== id)); } + setConfirmState(null); } catch (error) { console.log("Error deleting combo:", error); + setConfirmState((prev) => prev ? { ...prev, loading: false } : null); } } }); }; + const handleBulkDelete = () => { + if (selectedCombos.length === 0) return; + const count = selectedCombos.length; + setConfirmState({ + title: "Delete Selected Combos", + message: `Delete ${count} selected combo${count === 1 ? "" : "s"}? This cannot be undone.`, + confirmText: "Delete", + variant: "danger", + onConfirm: async () => { + setConfirmState((prev) => prev ? { ...prev, loading: true } : null); + setBulkBusy(true); + try { + const ids = selectedCombos.map((c) => c.id); + const names = selectedCombos.map((c) => c.name); + const results = await Promise.all( + ids.map((id) => fetch(`/api/combos/${id}`, { method: "DELETE" })) + ); + const failed = results.filter((r) => !r.ok).length; + await persistComboStrategies(pruneStrategiesForNames(names)); + setCombos((prev) => prev.filter((c) => !ids.includes(c.id))); + clearSelection(); + setConfirmState(null); + if (failed > 0) alert(`Deleted with ${failed} failure${failed === 1 ? "" : "s"}.`); + } catch (error) { + console.log("Error bulk deleting combos:", error); + alert("Failed to delete selected combos"); + setConfirmState((prev) => prev ? { ...prev, loading: false } : null); + } finally { + setBulkBusy(false); + } + }, + }); + }; + // Merge a per-combo strategy patch into settings.comboStrategies. Passing an empty // patch (strategy back to default "fallback") drops the entry entirely. const handleSetComboStrategy = async (comboName, patch) => { @@ -172,18 +319,36 @@ export default function CombosPage() { updated[comboName] = next; } - await fetch("/api/settings", { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ comboStrategies: updated }), - }); - - setComboStrategies(updated); + await persistComboStrategies(updated); } catch (error) { console.log("Error updating combo strategy:", error); } }; + const handleBulkSetStrategy = async (strategy) => { + if (selectedCombos.length === 0 || !strategy) return; + setBulkBusy(true); + try { + const updated = { ...comboStrategies }; + for (const combo of selectedCombos) { + if (!strategy || strategy === "fallback") { + delete updated[combo.name]; + } else { + updated[combo.name] = { + ...(updated[combo.name] || {}), + fallbackStrategy: strategy, + }; + } + } + await persistComboStrategies(updated); + } catch (error) { + console.log("Error bulk updating combo strategy:", error); + alert("Failed to update strategy for selected combos"); + } finally { + setBulkBusy(false); + } + }; + if (loading) { return (
@@ -196,7 +361,7 @@ export default function CombosPage() { return (
{/* Header */} -
+

Group models under one name, then pick a strategy per combo: @@ -206,10 +371,40 @@ export default function CombosPage() {

  • Round Robin — rotates models across requests to spread load
  • Fusion — queries all models in parallel, then a judge synthesizes one answer. Best quality, but costs the most: every request bills all panel models + the judge (N+1 calls)
  • +

    + Cursor / Claude Default create combos named exactly like those clients' model IDs (e.g. composer-2.5, opus), seeded with the matching cu/… or cc/… route so traffic can hit 9router without the prefix. + {" "}Note: Cursor IDE itself often blocks built-in Composer / Grok from Override OpenAI Base URL ("model does not support custom API"); add them via Cursor's Add Custom Model using the combo name, or pick a model Cursor allows through the custom endpoint. +

    +
    +
    + +
    + + +
    -
    {/* Combos List */} @@ -227,25 +422,88 @@ export default function CombosPage() {
    ) : ( -
    - {(() => { - const comboByName = Object.fromEntries(combos.map((c) => [c.name, c.models])); - return combos.map((combo) => ( - setEditingCombo(combo)} - onDelete={() => handleDelete(combo.id)} - strategy={comboStrategies[combo.name] || {}} - onSetStrategy={(patch) => handleSetComboStrategy(combo.name, patch)} +
    + {/* Selection toolbar */} +
    + + +
    + {someSelected && ( + <> +
    + e.stopPropagation()} + className="h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary" + aria-label={`Select ${combo.name}`} + /> +
    layers
    diff --git a/src/app/api/combos/presets/route.js b/src/app/api/combos/presets/route.js new file mode 100644 index 00000000..58d0541b --- /dev/null +++ b/src/app/api/combos/presets/route.js @@ -0,0 +1,110 @@ +import { NextResponse } from "next/server"; +import { getCombos, createCombo, getProviderConnections } from "@/lib/localDb"; +import { buildPresetItems, PRESET_SOURCES } from "@/lib/comboPresets"; +import { resolveCursorModels } from "open-sse/services/cursorModels.js"; + +export const dynamic = "force-dynamic"; + +/** + * Resolve live Cursor catalog from the first active cursor connection, if any. + * @returns {Promise|null>} + */ +async function fetchCursorLiveModels() { + try { + const connections = await getProviderConnections(); + const conn = (connections || []).find( + (c) => c.provider === "cursor" && c.isActive !== false + ); + if (!conn) return null; + const result = await resolveCursorModels({ + accessToken: conn.accessToken, + providerSpecificData: conn.providerSpecificData || {}, + }, { log: console }); + return result?.models?.length ? result.models : null; + } catch (error) { + console.log("combo presets: cursor live catalog failed", error?.message || error); + return null; + } +} + +/** + * @param {string} source + * @returns {Promise<{ name: string, models: string[], exists: boolean }[]>} + */ +async function resolvePresetItems(source) { + const combos = await getCombos(); + const existingNames = (combos || []).map((c) => c.name); + const liveModels = source === "cursor" ? await fetchCursorLiveModels() : null; + return buildPresetItems(source, { + liveModels: liveModels || undefined, + existingNames, + }); +} + +function parseSource(value) { + if (!value || !PRESET_SOURCES.has(value)) return null; + return value; +} + +// GET /api/combos/presets?source=cursor|claude — preview items +export async function GET(request) { + try { + const { searchParams } = new URL(request.url); + const source = parseSource(searchParams.get("source")); + if (!source) { + return NextResponse.json( + { error: "source must be 'cursor' or 'claude'" }, + { status: 400 } + ); + } + + const items = await resolvePresetItems(source); + return NextResponse.json({ + source, + items, + toCreate: items.filter((i) => !i.exists).length, + toSkip: items.filter((i) => i.exists).length, + }); + } catch (error) { + console.log("Error previewing combo presets:", error); + return NextResponse.json({ error: "Failed to preview combo presets" }, { status: 500 }); + } +} + +// POST /api/combos/presets — create missing combos for a source +export async function POST(request) { + try { + const body = await request.json().catch(() => ({})); + const source = parseSource(body?.source); + if (!source) { + return NextResponse.json( + { error: "source must be 'cursor' or 'claude'" }, + { status: 400 } + ); + } + + const items = await resolvePresetItems(source); + const created = []; + const skipped = []; + + for (const item of items) { + if (item.exists) { + skipped.push(item.name); + continue; + } + const combo = await createCombo({ name: item.name, models: item.models }); + created.push(combo); + } + + return NextResponse.json({ + source, + created, + skipped, + createdCount: created.length, + skippedCount: skipped.length, + }); + } catch (error) { + console.log("Error creating combo presets:", error); + return NextResponse.json({ error: "Failed to create combo presets" }, { status: 500 }); + } +} diff --git a/src/lib/comboPresets.js b/src/lib/comboPresets.js new file mode 100644 index 00000000..f45ae058 --- /dev/null +++ b/src/lib/comboPresets.js @@ -0,0 +1,121 @@ +/** + * Build Cursor / Claude default combo presets. + * Combo names match client-native model IDs (no provider prefix); + * each is seeded with the matching prefixed 9router model so routing works. + */ + +import { getProviderModels } from "open-sse/config/providerModels.js"; +import { CLI_TOOLS } from "@/shared/constants/cliTools"; + +export const VALID_COMBO_NAME_REGEX = /^[a-zA-Z0-9_.\-]+$/; +export const PRESET_SOURCES = new Set(["cursor", "claude"]); + +const CURSOR_ALIAS = "cu"; +const CLAUDE_ALIAS = "cc"; + +/** Extra Claude Code aliases not listed in defaultModels. */ +const CLAUDE_EXTRA_ALIAS_TARGETS = { + default: "cc/claude-sonnet-5", + opusplan: "cc/claude-opus-5", +}; + +/** + * @param {string} name + * @returns {boolean} + */ +export function isValidComboPresetName(name) { + return typeof name === "string" && name.length > 0 && VALID_COMBO_NAME_REGEX.test(name); +} + +/** + * @param {string} name + * @param {string[]} models + * @param {Set} [seen] + * @returns {{ name: string, models: string[] }|null} + */ +function pushItem(name, models, seen) { + if (!isValidComboPresetName(name)) return null; + if (seen?.has(name)) return null; + if (!Array.isArray(models) || models.length === 0) return null; + seen?.add(name); + return { name, models }; +} + +/** + * @param {Array<{id?: string}|string>} modelList + * @param {string} providerAlias + * @param {Set} seen + * @returns {{ name: string, models: string[] }[]} + */ +function itemsFromProviderModels(modelList, providerAlias, seen) { + const out = []; + for (const entry of modelList || []) { + const id = typeof entry === "string" ? entry : entry?.id; + if (!id) continue; + const item = pushItem(id, [`${providerAlias}/${id}`], seen); + if (item) out.push(item); + } + return out; +} + +/** + * Build Cursor default presets. + * Prefer live catalog when provided; otherwise static cu registry. + * @param {{ liveModels?: Array<{id: string}|string> }} [opts] + * @returns {{ name: string, models: string[] }[]} + */ +export function buildCursorPresetItems(opts = {}) { + const seen = new Set(); + const live = Array.isArray(opts.liveModels) ? opts.liveModels : null; + if (live?.length) { + return itemsFromProviderModels(live, CURSOR_ALIAS, seen); + } + return itemsFromProviderModels(getProviderModels(CURSOR_ALIAS), CURSOR_ALIAS, seen); +} + +/** + * Build Claude default presets from cc registry + Claude Code aliases. + * @returns {{ name: string, models: string[] }[]} + */ +export function buildClaudePresetItems() { + const seen = new Set(); + const out = itemsFromProviderModels(getProviderModels(CLAUDE_ALIAS), CLAUDE_ALIAS, seen); + + const claudeTool = CLI_TOOLS.claude || {}; + for (const entry of claudeTool.defaultModels || []) { + const name = entry.alias || entry.id; + const target = entry.defaultValue; + if (!name || !target) continue; + const item = pushItem(name, [target], seen); + if (item) out.push(item); + } + + for (const alias of claudeTool.modelAliases || []) { + if (seen.has(alias)) continue; + const target = CLAUDE_EXTRA_ALIAS_TARGETS[alias]; + if (!target) continue; + const item = pushItem(alias, [target], seen); + if (item) out.push(item); + } + + return out; +} + +/** + * @param {"cursor"|"claude"} source + * @param {{ liveModels?: Array<{id: string}|string>, existingNames?: Iterable }} [opts] + * @returns {{ name: string, models: string[], exists: boolean }[]} + */ +export function buildPresetItems(source, opts = {}) { + if (!PRESET_SOURCES.has(source)) return []; + + const items = source === "cursor" + ? buildCursorPresetItems({ liveModels: opts.liveModels }) + : buildClaudePresetItems(); + + const existing = new Set(opts.existingNames || []); + return items.map((item) => ({ + ...item, + exists: existing.has(item.name), + })); +} diff --git a/tests/unit/combo-presets.test.js b/tests/unit/combo-presets.test.js new file mode 100644 index 00000000..e5a06554 --- /dev/null +++ b/tests/unit/combo-presets.test.js @@ -0,0 +1,102 @@ +import { describe, it, expect } from "vitest"; +import { + buildPresetItems, + buildCursorPresetItems, + buildClaudePresetItems, + isValidComboPresetName, +} from "../../src/lib/comboPresets.js"; + +describe("combo presets", () => { + it("rejects combo names with slashes or invalid chars", () => { + expect(isValidComboPresetName("composer-2.5")).toBe(true); + expect(isValidComboPresetName("claude-opus-5")).toBe(true); + expect(isValidComboPresetName("cu/composer-2.5")).toBe(false); + expect(isValidComboPresetName("bad name")).toBe(false); + expect(isValidComboPresetName("")).toBe(false); + }); + + it("Cursor live ids become unprefixed names seeded with cu/…", () => { + const items = buildCursorPresetItems({ + liveModels: [ + { id: "composer-2.5", name: "Composer 2.5" }, + { id: "cursor-grok-4.6-high-fast", name: "Grok" }, + { id: "bad/with-slash", name: "Invalid" }, + ], + }); + + expect(items).toEqual([ + { name: "composer-2.5", models: ["cu/composer-2.5"] }, + { name: "cursor-grok-4.6-high-fast", models: ["cu/cursor-grok-4.6-high-fast"] }, + ]); + }); + + it("Cursor falls back to static cu registry when live catalog is empty", () => { + const items = buildCursorPresetItems({ liveModels: [] }); + expect(items.length).toBeGreaterThan(0); + expect(items.every((i) => i.models[0].startsWith("cu/"))).toBe(true); + expect(items.some((i) => i.name === "default")).toBe(true); + // No slash in combo name + expect(items.every((i) => !i.name.includes("/"))).toBe(true); + }); + + it("Claude aliases map opus → cc/claude-opus-5 and registry models seed cc/…", () => { + const items = buildClaudePresetItems(); + const byName = Object.fromEntries(items.map((i) => [i.name, i])); + + expect(byName["claude-opus-5"]).toEqual({ + name: "claude-opus-5", + models: ["cc/claude-opus-5"], + }); + expect(byName.opus).toEqual({ + name: "opus", + models: ["cc/claude-opus-5"], + }); + expect(byName.sonnet).toEqual({ + name: "sonnet", + models: ["cc/claude-sonnet-5"], + }); + expect(byName.haiku).toEqual({ + name: "haiku", + models: ["cc/claude-haiku-4-5-20251001"], + }); + expect(byName.fable).toEqual({ + name: "fable", + models: ["cc/claude-fable-5"], + }); + expect(byName.default).toEqual({ + name: "default", + models: ["cc/claude-sonnet-5"], + }); + expect(byName.opusplan).toEqual({ + name: "opusplan", + models: ["cc/claude-opus-5"], + }); + }); + + it("marks existing names with exists: true", () => { + const items = buildPresetItems("cursor", { + liveModels: [ + { id: "composer-2.5" }, + { id: "gpt-5.3-codex" }, + ], + existingNames: ["composer-2.5"], + }); + + expect(items).toEqual([ + { name: "composer-2.5", models: ["cu/composer-2.5"], exists: true }, + { name: "gpt-5.3-codex", models: ["cu/gpt-5.3-codex"], exists: false }, + ]); + }); + + it("returns empty for unknown source", () => { + expect(buildPresetItems("unknown")).toEqual([]); + }); + + it("drops invalid names from Claude/Cursor catalogs", () => { + const cursor = buildPresetItems("cursor", { + liveModels: [{ id: "ok-model" }, { id: "no/slash" }, { id: "has space" }], + existingNames: [], + }); + expect(cursor.map((i) => i.name)).toEqual(["ok-model"]); + }); +}); From 7c2b1fe3e146183674c8d75ff9ef51d9d42b5dad Mon Sep 17 00:00:00 2001 From: Anantachoke Date: Mon, 21 Sep 2026 19:58:34 +0700 Subject: [PATCH 10/41] fix(translator): drop replayed reasoning fields for Groq/Mistral/Cerebras (#4220) Strict OpenAI-compatible validators reject unknown assistant-message fields: Groq 400 ("property 'reasoning_content' is unsupported"), Mistral 422 ("extra_forbidden"), Cerebras 400 ("wrong_api_format"). Clients driving reasoning models (Hermes Agent, and anything following the DeepSeek/Kimi convention) echo the previous turn's reasoning_content on every assistant message, so from the second turn on every request to these providers fails and a fallback combo silently skips them. Add a dropMessageFields rule to paramSupport.js that strips reasoning_content / reasoning / reasoning_details from assistant turns for groq, mistral, and cerebras. --- open-sse/translator/concerns/paramSupport.js | 18 ++++++++ tests/unit/param-support.test.js | 44 ++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/open-sse/translator/concerns/paramSupport.js b/open-sse/translator/concerns/paramSupport.js index 863b627e..90ac5f5f 100644 --- a/open-sse/translator/concerns/paramSupport.js +++ b/open-sse/translator/concerns/paramSupport.js @@ -24,6 +24,15 @@ const STRIP_RULES = [ // "integer above maximum value, expected <= 32768". Pin an explicit endpoint cap; // min() with the model ceiling still applies if a variant's own limit is lower. { provider: "volcengine-ark", match: /kimi/i, maxOutputCap: 32768, clampToModelMaxOutput: true }, + // Strict OpenAI-compatible validators reject unknown assistant-message fields. + // Clients that talk to reasoning models (e.g. Hermes) echo the prior turn's + // reasoning back on every assistant message; Groq answers 400 and Mistral 422 + // ("extra_forbidden") on it, which knocks these providers out of every + // multi-turn combo. Providers that *require* the field (DeepSeek, Kimi) are + // handled by reasoningContentInjector and are not listed here. + { provider: "groq", dropMessageFields: ["reasoning_content", "reasoning", "reasoning_details"] }, + { provider: "mistral", dropMessageFields: ["reasoning_content", "reasoning", "reasoning_details"] }, + { provider: "cerebras", dropMessageFields: ["reasoning_content", "reasoning", "reasoning_details"] }, ]; // Test a rule's match (regex or predicate) against the model id. @@ -47,6 +56,15 @@ export function stripUnsupportedParams(provider, model, body) { for (const key of rule.drop || []) { if (body[key] !== undefined) delete body[key]; } + // Per-message field drop (assistant turns only — that is where clients replay reasoning). + if (Array.isArray(rule.dropMessageFields) && Array.isArray(body.messages)) { + for (const msg of body.messages) { + if (!msg || msg.role !== "assistant") continue; + for (const key of rule.dropMessageFields) { + if (msg[key] !== undefined) delete msg[key]; + } + } + } // CF Workers AI oneOf root schema only accepts content as plain string (#1926) if (rule.flattenContent && Array.isArray(body.messages)) { for (const msg of body.messages) { diff --git a/tests/unit/param-support.test.js b/tests/unit/param-support.test.js index c54d132b..f19d0e78 100644 --- a/tests/unit/param-support.test.js +++ b/tests/unit/param-support.test.js @@ -52,4 +52,48 @@ describe("stripUnsupportedParams", () => { expect(body.max_tokens).toBe(64000); }); + + it("drops replayed reasoning fields from assistant messages for strict providers", () => { + const makeBody = () => ({ + messages: [ + { role: "user", content: "hi" }, + { + role: "assistant", + content: "hello", + reasoning_content: "thinking...", + reasoning: "thinking...", + reasoning_details: [{ text: "thinking..." }], + tool_calls: [{ id: "c1", type: "function", function: { name: "f", arguments: "{}" } }], + }, + { role: "user", content: "again", reasoning_content: "user-side field stays" }, + ], + }); + + for (const [provider, model] of [ + ["groq", "openai/gpt-oss-120b"], + ["mistral", "codestral-latest"], + ["cerebras", "gpt-oss-120b"], + ]) { + const body = makeBody(); + stripUnsupportedParams(provider, model, body); + expect(body.messages[1]).toEqual({ + role: "assistant", + content: "hello", + tool_calls: [{ id: "c1", type: "function", function: { name: "f", arguments: "{}" } }], + }); + // only assistant turns are touched + expect(body.messages[2].reasoning_content).toBe("user-side field stays"); + } + }); + + it("leaves reasoning fields alone for providers that accept or require them", () => { + const body = { + messages: [{ role: "assistant", content: "hello", reasoning_content: "thinking..." }], + }; + + stripUnsupportedParams("deepseek", "deepseek-reasoner", body); + stripUnsupportedParams("openrouter", "nvidia/nemotron-3-ultra-550b-a55b:free", body); + + expect(body.messages[0].reasoning_content).toBe("thinking..."); + }); }); From 2daf25ffbe0bf53b367464e4bf5dc45bb492156f Mon Sep 17 00:00:00 2001 From: dinhkarate Date: Mon, 21 Sep 2026 20:07:49 +0700 Subject: [PATCH 11/41] fix(qoder): handle code 110 billing blocks and preserve SSE error status - Match code 110 (billing daily count exceeded) alongside 112/10605/pricingUrl in isBillingBlock, parsing JSON safely and accepting numeric/string codes - Accept numeric strings for statusCodeValue and object bodies in envelope peek - Emit structured 403 quota error chunk instead of synthetic assistant text when a billing envelope appears mid-stream - Preserve upstream HTTP status in handleForcedSSEToJson when error chunk carries a valid 400-599 status - Add unit tests for code-110 detection, mid-stream billing envelopes, and false-positive guard --- open-sse/executors/qoder.js | 53 +++++-- .../handlers/chatCore/sseToJsonHandler.js | 10 +- tests/unit/qoder-billing.test.js | 142 ++++++++++++++++++ 3 files changed, 194 insertions(+), 11 deletions(-) diff --git a/open-sse/executors/qoder.js b/open-sse/executors/qoder.js index 8ee21ac5..d1b0dbae 100644 --- a/open-sse/executors/qoder.js +++ b/open-sse/executors/qoder.js @@ -336,13 +336,21 @@ async function buildQoderRequestBody({ model, body, credentials, log, proxyOptio /** * Check if a qoder error message indicates a billing/quota block. - * Signatures: code 112 (quota exhausted), code 10605 (queue throttle), pricingUrl field. + * Signatures: code 110 (billing daily count exceeded), code 112 (quota + * exhausted), code 10605 (queue throttle), pricingUrl field. */ function isBillingBlock(inner) { if (!inner || typeof inner !== "string") return false; const lowerMsg = inner.toLowerCase(); - // Match: {"code":"112",...}, {"code":"10605",...}, or pricingUrl field - return /\"code\"\s*:\s*\"(112|10605)\"/.test(inner) || lowerMsg.includes("pricingurl"); + if (lowerMsg.includes("pricingurl")) return true; + // Parsed code preferred over regex: matches numeric or string "110"/"112"/"10605". + try { + const parsed = JSON.parse(inner); + const code = String(parsed?.code ?? ""); + if (code === "110" || code === "112" || code === "10605") return true; + } catch { /* not JSON — fall through to legacy shape match */ } + // Match legacy exact shapes: {"code":"112",...}, {"code":"10605",...}. + return /"code"\s*:\s*"(112|10605)"/.test(inner); } /** @@ -369,10 +377,11 @@ async function peekFirstQoderFrame(reader, decoder) { let envelope; try { envelope = JSON.parse(data); } catch { return { isBilling: false, consumed }; } - - const statusVal = typeof envelope.statusCodeValue === "number" ? envelope.statusCodeValue : 200; - const inner = typeof envelope.body === "string" ? envelope.body : ""; - + // statusCodeValue is documented numeric, but accept numeric strings defensively. + const statusVal = Number(envelope.statusCodeValue) || 200; + const inner = typeof envelope.body === "string" + ? envelope.body + : envelope.body != null ? JSON.stringify(envelope.body) : ""; if (statusVal !== 200 && isBillingBlock(inner)) { return { isBilling: true, statusVal, message: inner || `qoder billing block (${statusVal})` }; } @@ -404,7 +413,7 @@ async function peekFirstQoderFrame(reader, decoder) { * If detected, return 403 response so chatCore marks connection unavailable * and triggers combo fallback instead of leaking error text into chat. */ -async function wrapQoderSSE(response, model) { +async function wrapQoderSSE(response, model, log = null) { if (!response.ok || !response.body) return response; const decoder = new TextDecoder(); @@ -448,11 +457,35 @@ async function wrapQoderSSE(response, model) { let envelope; try { envelope = JSON.parse(data); } catch { return; } - const statusVal = typeof envelope.statusCodeValue === "number" ? envelope.statusCodeValue : 200; + const statusVal = Number(envelope.statusCodeValue) || 200; const inner = typeof envelope.body === "string" ? envelope.body : envelope.body != null ? JSON.stringify(envelope.body) : ""; if (statusVal !== 200) { + // Always visible: error envelopes are rare and worth one stderr line at + // any log level (response bodies carry no credentials). + try { + console.error(`[QODER] error envelope status=${statusVal} statusType=${typeof envelope.statusCodeValue} bodyType=${typeof envelope.body} body=${truncate(inner, 300)}`); + } catch { /* logging must not break the stream */ } + if (isBillingBlock(inner)) { + // Billing/quota envelope at any stream position (peek only covers the + // first frame): emit a structured error chunk, not fake assistant text. + // parseSSEToOpenAIResponse understands chunk.error and turns it into a + // non-200 result so chat.js locks the model and falls back. Streaming + // clients receive a real SSE error instead of "[qoder error ...]" text. + const errObj = JSON.stringify({ + error: { + message: inner || `qoder billing block (${statusVal})`, + code: "qoder_billing_block", + status: 403, + type: "quota_error", + }, + }); + controller.enqueue(encoder.encode(`data: ${errObj}\n\n`)); + controller.enqueue(encoder.encode(SSE_DONE)); + doneEmitted = true; + return; + } const msg = inner || `upstream status ${statusVal}`; const errChunk = JSON.stringify({ id: `qoder-error-${Date.now()}`, @@ -676,7 +709,7 @@ export class QoderExecutor extends BaseExecutor { return { response, url, headers, transformedBody: payload }; } - const wrapped = await wrapQoderSSE(response, `qoder/${qoderKey}`); + const wrapped = await wrapQoderSSE(response, `qoder/${qoderKey}`, log); return { response: wrapped, url, headers, transformedBody: payload }; } diff --git a/open-sse/handlers/chatCore/sseToJsonHandler.js b/open-sse/handlers/chatCore/sseToJsonHandler.js index cc7c9aac..800c92a7 100644 --- a/open-sse/handlers/chatCore/sseToJsonHandler.js +++ b/open-sse/handlers/chatCore/sseToJsonHandler.js @@ -295,8 +295,16 @@ export async function handleForcedSSEToJson({ providerResponse, sourceFormat, ta const parsed = parseSSEToOpenAIResponse(sseText, model); if (!parsed) return createErrorResult(HTTP_STATUS.BAD_GATEWAY, "Invalid SSE response for non-streaming request"); if (parsed.error) { + // Structured error chunks may carry the real upstream status (e.g. the + // Qoder executor emits status 403 for billing envelopes). Preserve it so + // the account loop locks/falls back on the right status instead of a + // generic 502. Anything outside 400-599 still maps to 502. + const upstreamStatus = Number(parsed.error.status); + const status = Number.isInteger(upstreamStatus) && upstreamStatus >= 400 && upstreamStatus <= 599 + ? upstreamStatus + : HTTP_STATUS.BAD_GATEWAY; return createErrorResult( - HTTP_STATUS.BAD_GATEWAY, + status, parsed.error.message || "Upstream SSE stream failed" ); } diff --git a/tests/unit/qoder-billing.test.js b/tests/unit/qoder-billing.test.js index f97a1293..d7c5482e 100644 --- a/tests/unit/qoder-billing.test.js +++ b/tests/unit/qoder-billing.test.js @@ -82,6 +82,148 @@ describe("wrapQoderSSE billing detection", () => { expect(wrapped.ok).toBe(false); }); + it("returns 403 response when first frame is billing block (code 110 string)", async () => { + const billingEnv = JSON.stringify({ + statusCodeValue: 403, + body: '{"code":"110","message":"Billing daily count exceeded"}', + }); + const upstream = `data: ${billingEnv}\n\n`; + + const wrapped = await wrapQoderSSE(makeResponse([upstream]), "qoder/qfmodel"); + + expect(wrapped.status).toBe(403); + expect(wrapped.ok).toBe(false); + const json = await wrapped.json(); + expect(json.error.message).toContain("Billing daily count exceeded"); + }); + + it("returns 403 response when first frame is billing block (code 110 numeric)", async () => { + const billingEnv = JSON.stringify({ + statusCodeValue: 403, + body: '{"code":110,"message":"Billing daily count exceeded"}', + }); + const upstream = `data: ${billingEnv}\n\n`; + + const wrapped = await wrapQoderSSE(makeResponse([upstream]), "qoder/qfmodel"); + + expect(wrapped.status).toBe(403); + expect(wrapped.ok).toBe(false); + }); + it("returns 403 response when statusCodeValue is string \"403\" (code 110)", async () => { + const billingEnv = JSON.stringify({ + statusCodeValue: "403", + body: '{"code":"110","message":"Billing daily count exceeded"}', + }); + const upstream = `data: ${billingEnv}\n\n`; + + const wrapped = await wrapQoderSSE(makeResponse([upstream]), "qoder/qfmodel"); + + expect(wrapped.status).toBe(403); + expect(wrapped.ok).toBe(false); + const json = await wrapped.json(); + expect(json.error.message).toContain("Billing daily count exceeded"); + }); + + it("emits structured 403 error chunk for object-body billing after a data frame (peek miss)", async () => { + const okEnv = JSON.stringify({ + statusCodeValue: 200, + body: JSON.stringify({ choices: [{ delta: { content: "hi" } }] }), + }); + const billingEnv = JSON.stringify({ + statusCodeValue: 403, + body: { code: "110", message: "Billing daily count exceeded" }, + }); + const upstream = `data: ${okEnv}\n\ndata: ${billingEnv}\n\n`; + + const wrapped = await wrapQoderSSE(makeResponse([upstream]), "qoder/qfmodel"); + + const reader = wrapped.body.getReader(); + const decoder = new TextDecoder(); + let buf = ""; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buf += decoder.decode(value, { stream: true }); + } + buf += decoder.decode(); + + expect(buf).not.toContain("[qoder error"); + const errLine = buf.split("\n").find((l) => l.includes('"error"')); + expect(errLine).toBeDefined(); + const errChunk = JSON.parse(errLine.slice(5).trim()); + expect(errChunk.error.status).toBe(403); + expect(errChunk.error.message).toContain("Billing daily count exceeded"); + expect(errChunk.choices).toBeUndefined(); + }); + + + it("does not treat legitimate assistant text mentioning code 110 as billing", async () => { + const inner = JSON.stringify({ + choices: [{ delta: { content: "error 110 means billing daily count exceeded in docs" } }], + }); + const successEnv = JSON.stringify({ statusCodeValue: 200, body: inner }); + const upstream = `data: ${successEnv}\n\n`; + + const wrapped = await wrapQoderSSE(makeResponse([upstream]), "qoder/qfmodel"); + + expect(wrapped.status).toBe(200); + const reader = wrapped.body.getReader(); + const decoder = new TextDecoder(); + let buf = ""; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buf += decoder.decode(value, { stream: true }); + } + buf += decoder.decode(); + + expect(buf).toContain("billing daily count exceeded"); + expect(buf).not.toContain("[qoder error"); + }); + + it("emits structured 403 error chunk for billing envelope after a data frame (peek miss)", async () => { + const okEnv = JSON.stringify({ + statusCodeValue: 200, + body: JSON.stringify({ choices: [{ delta: { content: "hi" } }] }), + }); + const billingEnv = JSON.stringify({ + statusCodeValue: 403, + body: '{"code":"110","message":"Billing daily count exceeded"}', + }); + const upstream = `data: ${okEnv}\n\ndata: ${billingEnv}\n\n`; + + const wrapped = await wrapQoderSSE(makeResponse([upstream]), "qoder/qfmodel"); + + const reader = wrapped.body.getReader(); + const decoder = new TextDecoder(); + let buf = ""; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buf += decoder.decode(value, { stream: true }); + } + buf += decoder.decode(); + + expect(buf).not.toContain("[qoder error"); + const errLine = buf.split("\n").find((l) => l.includes('"error"')); + expect(errLine).toBeDefined(); + const errChunk = JSON.parse(errLine.slice(5).trim()); + expect(errChunk.error.status).toBe(403); + expect(errChunk.error.message).toContain("Billing daily count exceeded"); + }); + + it("emits structured 403 error chunk for object-body billing envelope (peek miss)", async () => { + const billingEnv = JSON.stringify({ + statusCodeValue: 403, + body: { code: "110", message: "Billing daily count exceeded" }, + }); + const upstream = `data: ${billingEnv}\n\n`; + + const wrapped = await wrapQoderSSE(makeResponse([upstream]), "qoder/qfmodel"); + + expect(wrapped.status).toBe(403); + }); + it("returns 403 response when first frame has pricingUrl", async () => { const billingEnv = JSON.stringify({ statusCodeValue: 402, From be3bc764b156513b9d4e5acd220d552ce7820d60 Mon Sep 17 00:00:00 2001 From: Christian Gennari Date: Mon, 21 Sep 2026 20:15:11 +0700 Subject: [PATCH 12/41] fix(antigravity): separate weekly and short-window quotas and clean up redundant rows - Track both weekly and 5-hour session buckets in parseWeeklyQuotaSummary, distinguishing sliding-window limits from multi-day weekly limits - Preserve disabled session buckets at 0% rather than dropping them when weekly limits are reached - Target 5-hour session rows (not weekly rows) during family exhaustion reconciliation in getAntigravityUsage - Suppress synthesized per-model duplicate rows in dashboard normalization when family summaries are present - Add unit test coverage for multi-bucket extraction, reconciliation isolation, and dashboard deduplication --- open-sse/services/usage/antigravity-weekly.js | 44 +++-- open-sse/services/usage/google.js | 26 ++- .../usage/components/ProviderLimits/utils.js | 152 +++++++++++++----- .../unit/antigravity-weekly-dashboard.test.js | 92 ++++++++++- tests/unit/antigravity-weekly-quota.test.js | 59 +++++-- 5 files changed, 281 insertions(+), 92 deletions(-) diff --git a/open-sse/services/usage/antigravity-weekly.js b/open-sse/services/usage/antigravity-weekly.js index db92a224..c0b78884 100644 --- a/open-sse/services/usage/antigravity-weekly.js +++ b/open-sse/services/usage/antigravity-weekly.js @@ -25,10 +25,18 @@ export function _clearWeeklyCache() { weeklyCache.clear(); } -// — Group-name to stable key mapping —————————————————————— -const GROUP_MATCHERS = [ - { pattern: /gemini/i, key: "gemini_weekly", displayName: "Gemini (Weekly)" }, - { pattern: /claude|gpt/i, key: "claude_gpt_weekly", displayName: "Claude & GPT (Weekly)" }, +// — Group-name and window to stable key mapping —————————————————————— +const GROUP_CONFIGS = [ + { + pattern: /gemini/i, + weekly: { key: "gemini_weekly", displayName: "Gemini (Weekly)" }, + session: { key: "gemini_session", displayName: "Gemini (5h)" }, + }, + { + pattern: /claude|gpt/i, + weekly: { key: "claude_gpt_weekly", displayName: "Claude & GPT (Weekly)" }, + session: { key: "claude_gpt_session", displayName: "Claude & GPT (5h)" }, + }, ]; /** @@ -60,32 +68,40 @@ export function parseWeeklyQuotaSummary(data) { for (const bucket of buckets) { if (!bucket || typeof bucket !== "object") continue; - // Identify weekly buckets by checking bucketId + displayName for "weekly" + const windowType = String(bucket.window || "").toLowerCase(); const bucketText = `${bucket.bucketId || ""} ${bucket.displayName || ""}`.toLowerCase(); - if (!bucketText.includes("weekly")) continue; + const isWeekly = windowType === "weekly" || bucketText.includes("weekly"); + const isSession = windowType === "5h" || bucketText.includes("five hour") || bucketText.includes("5h") || bucketText.includes("daily") || windowType === "daily"; - // Skip disabled buckets - if (bucket.disabled === true) continue; + if (!isWeekly && !isSession) continue; - const remainingFraction = Number(bucket.remainingFraction); + // If a session (5h) bucket is marked disabled by upstream (because weekly was hit), + // keep it so the UI shows the 5h row, but with remainingFraction: 0. + // Disabled weekly buckets are truly disabled and skipped. + if (bucket.disabled === true && isWeekly) continue; + + const remainingFraction = bucket.disabled === true ? 0 : Number(bucket.remainingFraction); if (!Number.isFinite(remainingFraction)) continue; // Match group to a known family - for (const matcher of GROUP_MATCHERS) { - if (matcher.pattern.test(displayName)) { + for (const config of GROUP_CONFIGS) { + if (config.pattern.test(displayName)) { + const target = isWeekly ? config.weekly : config.session; + if (result[target.key]) break; // first matching bucket per type wins + const total = 1000; const remaining = Math.round(total * remainingFraction); const used = Math.max(0, total - remaining); - result[matcher.key] = { + result[target.key] = { used, total, resetAt: parseResetTime(bucket.resetTime), remainingPercentage: remainingFraction * 100, unlimited: false, - displayName: matcher.displayName, + displayName: target.displayName, }; - break; // first matching bucket per family wins + break; } } } diff --git a/open-sse/services/usage/google.js b/open-sse/services/usage/google.js index 736722a7..197f4364 100644 --- a/open-sse/services/usage/google.js +++ b/open-sse/services/usage/google.js @@ -228,39 +228,37 @@ export async function getAntigravityUsage(accessToken, providerSpecificData, pro proxyOptions ); - // Reconcile weekly quota against model family status: + // Reconcile short-window session quota if models are exhausted: // If every model in a family is locked/exhausted (remainingPercentage === 0) - // until a future reset time, the weekly limit cannot be 100% available. - // On Google's Free Starter tier, retrieveUserQuotaSummary buggily reports - // remainingFraction: 1 even after the starter quota is depleted and all models 429. + // until a future reset time, update the 5h session row (not the weekly row). const entries = Object.entries(quotas); const geminiModels = entries.filter(([k]) => k.startsWith("gemini-") && !k.includes("image")); const claudeModels = entries.filter(([k]) => k.startsWith("claude-")); - if (weeklyQuotas.gemini_weekly && geminiModels.length > 0) { + if (weeklyQuotas.gemini_session && geminiModels.length > 0) { const allGeminiExhausted = geminiModels.every(([, q]) => (q.remainingPercentage ?? 0) === 0); - if (allGeminiExhausted && weeklyQuotas.gemini_weekly.remainingPercentage > 0) { + if (allGeminiExhausted && weeklyQuotas.gemini_session.remainingPercentage > 0) { const maxResetAt = geminiModels.reduce((max, [, q]) => !max || (q.resetAt && new Date(q.resetAt) > new Date(max)) ? q.resetAt : max, null ); - weeklyQuotas.gemini_weekly.used = weeklyQuotas.gemini_weekly.total; - weeklyQuotas.gemini_weekly.remainingPercentage = 0; + weeklyQuotas.gemini_session.used = weeklyQuotas.gemini_session.total; + weeklyQuotas.gemini_session.remainingPercentage = 0; if (maxResetAt) { - weeklyQuotas.gemini_weekly.resetAt = maxResetAt; + weeklyQuotas.gemini_session.resetAt = maxResetAt; } } } - if (weeklyQuotas.claude_gpt_weekly && claudeModels.length > 0) { + if (weeklyQuotas.claude_gpt_session && claudeModels.length > 0) { const allClaudeExhausted = claudeModels.every(([, q]) => (q.remainingPercentage ?? 0) === 0); - if (allClaudeExhausted && weeklyQuotas.claude_gpt_weekly.remainingPercentage > 0) { + if (allClaudeExhausted && weeklyQuotas.claude_gpt_session.remainingPercentage > 0) { const maxResetAt = claudeModels.reduce((max, [, q]) => !max || (q.resetAt && new Date(q.resetAt) > new Date(max)) ? q.resetAt : max, null ); - weeklyQuotas.claude_gpt_weekly.used = weeklyQuotas.claude_gpt_weekly.total; - weeklyQuotas.claude_gpt_weekly.remainingPercentage = 0; + weeklyQuotas.claude_gpt_session.used = weeklyQuotas.claude_gpt_session.total; + weeklyQuotas.claude_gpt_session.remainingPercentage = 0; if (maxResetAt) { - weeklyQuotas.claude_gpt_weekly.resetAt = maxResetAt; + weeklyQuotas.claude_gpt_session.resetAt = maxResetAt; } } } diff --git a/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js b/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js index 784e6e47..e02dc787 100644 --- a/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js +++ b/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js @@ -377,51 +377,112 @@ export function parseQuotaData(provider, data) { if (data.quotas) { const entries = Object.entries(data.quotas); const weeklyKeys = new Set(["gemini_weekly", "claude_gpt_weekly"]); + const sessionKeys = new Set(["gemini_session", "claude_gpt_session"]); + const summaryKeys = new Set([...weeklyKeys, ...sessionKeys]); const geminiModels = entries.filter(([k]) => k.startsWith("gemini-") && !k.includes("image")); const claudeModels = entries.filter(([k]) => k.startsWith("claude-")); const imageModels = entries.filter(([k]) => k.includes("image")); - const weeklyModels = entries.filter(([k]) => weeklyKeys.has(k)); - const otherModels = entries.filter(([k]) => !k.startsWith("gemini-") && !k.startsWith("claude-") && !k.includes("image") && !weeklyKeys.has(k)); + const summaryModels = entries.filter(([k]) => summaryKeys.has(k)); + const otherModels = entries.filter(([k]) => !k.startsWith("gemini-") && !k.startsWith("claude-") && !k.includes("image") && !summaryKeys.has(k)); - if (geminiModels.length > 0) { + // Summary keys from retrieveUserQuotaSummary + const hasGeminiWeekly = Boolean(data.quotas.gemini_weekly); + const hasGeminiSession = Boolean(data.quotas.gemini_session); + const hasClaudeWeekly = Boolean(data.quotas.claude_gpt_weekly); + const hasClaudeSession = Boolean(data.quotas.claude_gpt_session); + + // 1. Gemini Family: + if (hasGeminiSession) { + summaryModels.filter(([k]) => k === "gemini_session").forEach(([modelKey, quota]) => { + normalizedQuotas.push({ + name: quota.displayName || modelKey, + modelKey, + used: quota.used || 0, + total: quota.total || 0, + resetAt: quota.resetAt || null, + remainingPercentage: quota.remainingPercentage, + }); + }); + } else if (geminiModels.length > 0) { const rep = geminiModels.reduce((min, cur) => (cur[1].remainingPercentage ?? 100) < (min[1].remainingPercentage ?? 100) ? cur : min )[1]; - normalizedQuotas.push({ - name: "Gemini (Flash / Pro)", - modelKey: "gemini", - used: rep.used || 0, - total: rep.total || 0, - resetAt: rep.resetAt || null, - remainingPercentage: rep.remainingPercentage, + // Only show synthesized Gemini row if its resetAt differs from weekly (i.e. it represents a separate 5h window) + const weeklyResetAt = data.quotas.gemini_weekly?.resetAt; + const isDuplicateOfWeekly = hasGeminiWeekly && rep.resetAt === weeklyResetAt && (rep.remainingPercentage ?? 0) === 0; + + if (!isDuplicateOfWeekly) { + normalizedQuotas.push({ + name: "Gemini (Flash / Pro)", + modelKey: "gemini", + used: rep.used || 0, + total: rep.total || 0, + resetAt: rep.resetAt || null, + remainingPercentage: rep.remainingPercentage, + }); + } + } + + // Show Gemini weekly row if present + if (hasGeminiWeekly) { + summaryModels.filter(([k]) => k === "gemini_weekly").forEach(([modelKey, quota]) => { + normalizedQuotas.push({ + name: quota.displayName || modelKey, + modelKey, + used: quota.used || 0, + total: quota.total || 0, + resetAt: quota.resetAt || null, + remainingPercentage: quota.remainingPercentage, + }); }); } - if (claudeModels.length > 0) { + // 2. Claude & GPT Family: + if (hasClaudeSession) { + summaryModels.filter(([k]) => k === "claude_gpt_session").forEach(([modelKey, quota]) => { + normalizedQuotas.push({ + name: quota.displayName || modelKey, + modelKey, + used: quota.used || 0, + total: quota.total || 0, + resetAt: quota.resetAt || null, + remainingPercentage: quota.remainingPercentage, + }); + }); + } else if (claudeModels.length > 0) { const rep = claudeModels.reduce((min, cur) => (cur[1].remainingPercentage ?? 100) < (min[1].remainingPercentage ?? 100) ? cur : min )[1]; - normalizedQuotas.push({ - name: "Claude (Sonnet / Opus)", - modelKey: "claude", - used: rep.used || 0, - total: rep.total || 0, - resetAt: rep.resetAt || null, - remainingPercentage: rep.remainingPercentage, + const weeklyResetAt = data.quotas.claude_gpt_weekly?.resetAt; + const isDuplicateOfWeekly = hasClaudeWeekly && rep.resetAt === weeklyResetAt && (rep.remainingPercentage ?? 0) === 0; + + if (!isDuplicateOfWeekly) { + normalizedQuotas.push({ + name: "Claude (Sonnet / Opus)", + modelKey: "claude", + used: rep.used || 0, + total: rep.total || 0, + resetAt: rep.resetAt || null, + remainingPercentage: rep.remainingPercentage, + }); + } + } + + // Show Claude & GPT weekly row if present + if (hasClaudeWeekly) { + summaryModels.filter(([k]) => k === "claude_gpt_weekly").forEach(([modelKey, quota]) => { + normalizedQuotas.push({ + name: quota.displayName || modelKey, + modelKey, + used: quota.used || 0, + total: quota.total || 0, + resetAt: quota.resetAt || null, + remainingPercentage: quota.remainingPercentage, + }); }); } - weeklyModels.forEach(([modelKey, quota]) => { - normalizedQuotas.push({ - name: quota.displayName || modelKey, - modelKey, - used: quota.used || 0, - total: quota.total || 0, - resetAt: quota.resetAt || null, - remainingPercentage: quota.remainingPercentage, - }); - }); - + // 3. Standalone Image Generation Models (unique usage) imageModels.forEach(([modelKey, quota]) => { normalizedQuotas.push({ name: quota.displayName || modelKey, @@ -433,16 +494,23 @@ export function parseQuotaData(provider, data) { }); }); - otherModels.forEach(([modelKey, quota]) => { - normalizedQuotas.push({ - name: quota.displayName || modelKey, - modelKey, - used: quota.used || 0, - total: quota.total || 0, - resetAt: quota.resetAt || null, - remainingPercentage: quota.remainingPercentage, + // 4. Other models: + // In Antigravity, GPT-OSS is explicitly documented by Google as part of the "Claude and GPT models" group: + // ("Models within this group: Claude Opus, Claude Sonnet, GPT-OSS"). + // When summary quotas (claude_gpt_session / claude_gpt_weekly) are present, GPT-OSS is already represented + // by the "Claude & GPT" family rows. We only include otherModels if no summary exists for that pool. + if (!hasClaudeWeekly && !hasClaudeSession) { + otherModels.forEach(([modelKey, quota]) => { + normalizedQuotas.push({ + name: quota.displayName || modelKey, + modelKey, + used: quota.used || 0, + total: quota.total || 0, + resetAt: quota.resetAt || null, + remainingPercentage: quota.remainingPercentage, + }); }); - }); + } } break; @@ -702,10 +770,10 @@ export function parseQuotaData(provider, data) { // Use modelKey for antigravity (mapped to family anchor), otherwise use name let keyA = a.modelKey || a.name; let keyB = b.modelKey || b.name; - if (keyA === "gemini") keyA = "gemini-3.8-flash-high"; - if (keyA === "claude") keyA = "claude-sonnet-4-6"; - if (keyB === "gemini") keyB = "gemini-3.8-flash-high"; - if (keyB === "claude") keyB = "claude-sonnet-4-6"; + if (keyA === "gemini" || keyA === "gemini_session") keyA = "gemini-3.8-flash-high"; + if (keyA === "claude" || keyA === "claude_gpt_session") keyA = "claude-sonnet-4-6"; + if (keyB === "gemini" || keyB === "gemini_session") keyB = "gemini-3.8-flash-high"; + if (keyB === "claude" || keyB === "claude_gpt_session") keyB = "claude-sonnet-4-6"; const orderA = orderMap.get(keyA) ?? 999; const orderB = orderMap.get(keyB) ?? 999; return orderA - orderB; diff --git a/tests/unit/antigravity-weekly-dashboard.test.js b/tests/unit/antigravity-weekly-dashboard.test.js index 1c4a2784..47b618b6 100644 --- a/tests/unit/antigravity-weekly-dashboard.test.js +++ b/tests/unit/antigravity-weekly-dashboard.test.js @@ -82,17 +82,97 @@ describe("Antigravity dashboard normalization with weekly quotas", () => { expect(weeklyRows[1].name).toMatch(/Weekly/); }); - it("order: gemini family, claude family, weekly, then other", () => { - const quotas = parseQuotaData("antigravity", data); + it("order: session, weekly, then other models", () => { + const dataWithBoth = { + quotas: { + gemini_session: { + displayName: "Gemini (5h)", + used: 100, + total: 1000, + resetAt: "2026-09-08T05:00:00Z", + remainingPercentage: 90, + }, + gemini_weekly: { + displayName: "Gemini (Weekly)", + used: 250, + total: 1000, + resetAt: "2026-09-15T00:00:00Z", + remainingPercentage: 75, + }, + claude_gpt_session: { + displayName: "Claude & GPT (5h)", + used: 50, + total: 1000, + resetAt: "2026-09-08T05:00:00Z", + remainingPercentage: 95, + }, + claude_gpt_weekly: { + displayName: "Claude & GPT (Weekly)", + used: 500, + total: 1000, + resetAt: "2026-09-14T00:00:00Z", + remainingPercentage: 50, + }, + }, + }; + const quotas = parseQuotaData("antigravity", dataWithBoth); const keys = quotas.map((q) => q.modelKey); - const geminiIdx = keys.indexOf("gemini"); - const claudeIdx = keys.indexOf("claude"); + const geminiSessionIdx = keys.indexOf("gemini_session"); const geminiWeeklyIdx = keys.indexOf("gemini_weekly"); + const claudeSessionIdx = keys.indexOf("claude_gpt_session"); const claudeWeeklyIdx = keys.indexOf("claude_gpt_weekly"); - expect(geminiIdx).toBeLessThan(geminiWeeklyIdx); - expect(claudeIdx).toBeLessThan(claudeWeeklyIdx); + expect(geminiSessionIdx).toBeLessThan(geminiWeeklyIdx); + expect(claudeSessionIdx).toBeLessThan(claudeWeeklyIdx); + }); + + it("excludes redundant duplicates when individual models mirror weekly reset and summary is present", () => { + // Exact scenario from Christian's account: + const liveLikeData = { + quotas: { + "gemini-3.8-flash-high": { used: 1000, total: 1000, remainingPercentage: 0, resetAt: "2026-09-23T06:00:17Z", displayName: "Gemini 3.8 Flash (High)" }, + "claude-sonnet-4-6": { used: 1000, total: 1000, remainingPercentage: 0, resetAt: "2026-09-20T19:00:21Z", displayName: "Claude 3.7 Sonnet" }, + "gpt-oss-120b-medium": { used: 1000, total: 1000, remainingPercentage: 0, resetAt: "2026-09-20T19:00:21Z", displayName: "GPT-OSS 120B (Medium)" }, + "gemini-3.1-flash-image": { used: 1000, total: 1000, remainingPercentage: 0, resetAt: "2026-09-23T06:00:17Z", displayName: "Gemini 3.1 Flash Image" }, + gemini_weekly: { + displayName: "Gemini (Weekly)", + used: 1000, + total: 1000, + resetAt: "2026-09-23T06:00:17Z", + remainingPercentage: 0, + }, + claude_gpt_weekly: { + displayName: "Claude & GPT (Weekly)", + used: 807, + total: 1000, + resetAt: "2026-09-24T18:09:46Z", + remainingPercentage: 19.3, + }, + claude_gpt_session: { + displayName: "Claude & GPT (5h)", + used: 1000, + total: 1000, + resetAt: "2026-09-20T19:00:21Z", + remainingPercentage: 0, + }, + }, + }; + + const quotas = parseQuotaData("antigravity", liveLikeData); + const names = quotas.map((q) => q.name); + + // Should contain unique usages: + expect(names).toContain("Claude & GPT (5h)"); + expect(names).toContain("Claude & GPT (Weekly)"); + expect(names).toContain("Gemini (Weekly)"); + expect(names).toContain("Gemini 3.1 Flash Image"); + + // Should NOT contain redundant duplicate entries: + expect(names).not.toContain("Gemini (Flash / Pro)"); // duplicate of Gemini (Weekly) + expect(names).not.toContain("Claude (Sonnet / Opus)"); // duplicate of Claude & GPT (5h) + expect(names).not.toContain("GPT-OSS 120B (Medium)"); // covered by Claude & GPT family + expect(quotas).toHaveLength(4); }); it("works with no weekly keys present (backward compat)", () => { diff --git a/tests/unit/antigravity-weekly-quota.test.js b/tests/unit/antigravity-weekly-quota.test.js index 55cb3a81..a565a2c1 100644 --- a/tests/unit/antigravity-weekly-quota.test.js +++ b/tests/unit/antigravity-weekly-quota.test.js @@ -53,7 +53,7 @@ const NESTED_RESPONSE = { // — parseWeeklyQuotaSummary ——————————————————————————————— describe("parseWeeklyQuotaSummary", () => { - it("extracts Gemini weekly quota from top-level groups", () => { + it("extracts Gemini weekly and session quotas from top-level groups", () => { const result = parseWeeklyQuotaSummary(FULL_RESPONSE); expect(result.gemini_weekly).toMatchObject({ used: 250, @@ -63,6 +63,14 @@ describe("parseWeeklyQuotaSummary", () => { unlimited: false, }); expect(result.gemini_weekly.resetAt).toBe("2026-09-15T00:00:00.000Z"); + expect(result.gemini_session).toMatchObject({ + used: 100, + total: 1000, + remainingPercentage: 90, + displayName: "Gemini (5h)", + unlimited: false, + }); + expect(result.gemini_session.resetAt).toBe("2026-09-09T00:00:00.000Z"); }); it("extracts Claude & GPT weekly quota", () => { @@ -85,14 +93,14 @@ describe("parseWeeklyQuotaSummary", () => { expect(result.claude_gpt_weekly.remainingPercentage).toBe(50); }); - it("skips non-weekly buckets", () => { + it("skips unrecognized non-weekly non-session buckets", () => { const data = { groups: [{ displayName: "Gemini Models", buckets: [ { - bucketId: "gemini-daily-bucket", - displayName: "Daily Limit", + bucketId: "gemini-monthly-bucket", + displayName: "Monthly Limit", remainingFraction: 0.9, resetTime: "2026-09-09T00:00:00Z", }, @@ -404,7 +412,7 @@ describe("weekly quota isolation from existing quota", () => { }); }); - it("reconciles weekly quota to 0% when all paid-tier family models are exhausted", async () => { + it("reconciles 5h session quota to 0% when all paid-tier family models are exhausted without clobbering weekly quota", async () => { proxyAwareFetch.mockImplementation(async (url) => { if (url.includes(":loadCodeAssist")) { return { @@ -421,7 +429,7 @@ describe("weekly quota isolation from existing quota", () => { models: { "gemini-3.8-flash-high": { displayName: "Gemini 3.8 Flash (High)", - // Exhausted model: no remainingFraction, future resetTime + // Exhausted model: no remainingFraction, future resetTime (5h window reset) quotaInfo: { resetTime: "2026-09-13T12:00:00Z" }, }, }, @@ -435,30 +443,49 @@ describe("weekly quota isolation from existing quota", () => { json: async () => ({ groups: [{ displayName: "Gemini Models", - buckets: [{ - bucketId: "gemini-weekly", - displayName: "Weekly Limit Remaining", - remainingFraction: 1, - resetTime: "2026-09-15T00:00:00Z", - }], + buckets: [ + { + bucketId: "gemini-weekly", + displayName: "Weekly Limit Remaining", + window: "weekly", + remainingFraction: 0.75, + resetTime: "2026-09-15T00:00:00Z", + }, + { + bucketId: "gemini-5h", + displayName: "Five Hour Limit Remaining", + window: "5h", + remainingFraction: 1, + resetTime: "2026-09-13T11:00:00Z", + }, + ], }], }), }; } - return { ok: false, status: 404 }; + return { ok: true, status: 200, json: async () => ({}) }; }); const { getAntigravityUsage } = await import("../../open-sse/services/usage/google.js"); - const result = await getAntigravityUsage("token", {}); + const result = await getAntigravityUsage("token-exhausted", null); // Per-model quota should show exhausted expect(result.quotas["gemini-3.8-flash-high"].remainingPercentage).toBe(0); - // Weekly quota should be reconciled to 0% with the family reset time - expect(result.quotas.gemini_weekly).toMatchObject({ + + // 5h session quota should be reconciled to 0% with the family reset time + expect(result.quotas.gemini_session).toMatchObject({ used: 1000, total: 1000, remainingPercentage: 0, resetAt: "2026-09-13T12:00:00.000Z", }); + + // Weekly quota should remain intact and NOT be clobbered to 0% or steal the 5h resetAt + expect(result.quotas.gemini_weekly).toMatchObject({ + used: 250, + total: 1000, + remainingPercentage: 75, + resetAt: "2026-09-15T00:00:00.000Z", + }); }); }); From c7df895bbbcd2f3c2a902a2ec854e0da1ddf21c8 Mon Sep 17 00:00:00 2001 From: 82030615 <82030615@qq.com> Date: Mon, 21 Sep 2026 20:20:54 +0700 Subject: [PATCH 13/41] build(docker): apply the apk mirror swap to the runner stage - Add apk mirror swap to mirrors.aliyun.com at the top of runner stage - Prevents docker build hanging when dl-cdn.alpinelinux.org is unreachable --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index dfcee598..547be9dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,10 @@ RUN npm run build FROM ${NODE_IMAGE} AS runner WORKDIR /app +# The base stage's mirror swap does not reach here: runner starts from +# ${NODE_IMAGE} directly, so the apk upgrade below would go to +# dl-cdn.alpinelinux.org and hang forever on networks that cannot reach it. +RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories LABEL org.opencontainers.image.title="9router" From f67d5a0c930af96e9cd2e7dd373ff585c52343d8 Mon Sep 17 00:00:00 2001 From: DaDecky Date: Mon, 21 Sep 2026 20:27:03 +0700 Subject: [PATCH 14/41] fix(docker): publish verified multi-platform images - Build linux/amd64 and linux/arm64 on native GitHub runners - Assemble version manifests from platform digests and promote latest only after verification - Add release/tag validation, manual republishing, timeouts, and health smoke tests - Make Docker build mirrors configurable via build args and remove unnecessary runtime apk upgrades - Update DOCKER.md documentation --- .github/workflows/docker-publish.yml | 429 +++++++++++++++++++++++++-- DOCKER.md | 67 ++++- Dockerfile | 43 ++- 3 files changed, 496 insertions(+), 43 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index e8ef957e..64be9c1c 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -5,22 +5,164 @@ on: tags: - "v*" workflow_dispatch: + inputs: + release_tag: + description: "Existing vX.Y.Z tag to publish" + required: true + type: string + promote_latest: + description: "Promote this republish to latest" + required: false + default: false + type: boolean + +# Keep every release in one FIFO queue. A per-tag group would still allow an +# older release to finish after a newer release and move latest backwards. +concurrency: + group: docker-publish-${{ github.repository }} + cancel-in-progress: false + queue: max env: - GHCR_IMAGE: ghcr.io/${{ github.repository }} DOCKERHUB_IMAGE: decolua/9router jobs: - build-and-push: + prepare: + name: Validate release runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + + outputs: + tag: ${{ steps.release.outputs.tag }} + version: ${{ steps.release.outputs.version }} + commit: ${{ steps.release.outputs.commit }} + publish_dockerhub: ${{ steps.release.outputs.publish_dockerhub }} + promote_latest: ${{ steps.release.outputs.promote_latest }} + ghcr_image: ${{ steps.release.outputs.ghcr_image }} + + steps: + - name: Check out release tag + uses: actions/checkout@v4 + with: + ref: ${{ inputs.release_tag || github.ref_name }} + fetch-depth: 1 + + - name: Validate tag and package versions + id: release + env: + RELEASE_TAG: ${{ inputs.release_tag || github.ref_name }} + REPOSITORY: ${{ github.repository }} + EVENT_NAME: ${{ github.event_name }} + PROMOTE_LATEST_INPUT: ${{ inputs.promote_latest && 'true' || 'false' }} + run: | + node <<'NODE' + const fs = require("fs"); + const { execFileSync } = require("child_process"); + + const tag = process.env.RELEASE_TAG || ""; + const match = /^v((?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)$/.exec(tag); + + if (tag.includes("+")) { + console.error(`Build metadata is not supported in Docker release tags: ${tag}`); + process.exit(1); + } + + if (!match) { + console.error(`Expected a Docker-safe semver tag like v0.5.81 or v0.5.81-rc.1, received: ${tag || ""}`); + process.exit(1); + } + + const version = match[1]; + if (version.length > 128 || !/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/.test(version)) { + console.error(`Version is not a valid Docker tag: ${version}`); + process.exit(1); + } + + const prerelease = version.includes("-") + ? version.slice(version.indexOf("-") + 1).split(".") + : []; + for (const identifier of prerelease) { + if (/^\d+$/.test(identifier) && identifier.length > 1 && identifier.startsWith("0")) { + console.error(`Numeric prerelease identifiers cannot contain leading zeroes: ${identifier}`); + process.exit(1); + } + } + + const rootVersion = require("./package.json").version; + const cliVersion = require("./cli/package.json").version; + + if (rootVersion !== version) { + console.error(`package.json version ${rootVersion} does not match tag ${tag}`); + process.exit(1); + } + + if (cliVersion !== version) { + console.error(`cli/package.json version ${cliVersion} does not match tag ${tag}`); + process.exit(1); + } + + const commit = execFileSync("git", ["rev-parse", "HEAD"], { encoding: "utf8" }).trim(); + const publishDockerHub = process.env.REPOSITORY === "decolua/9router"; + const ghcrImage = `ghcr.io/${process.env.REPOSITORY.toLowerCase()}`; + const isPrerelease = version.includes("-"); + const promoteLatest = (process.env.EVENT_NAME === "push" && !isPrerelease) + || process.env.PROMOTE_LATEST_INPUT === "true"; + const output = process.env.GITHUB_OUTPUT; + + fs.appendFileSync(output, `tag=${tag}\n`); + fs.appendFileSync(output, `version=${version}\n`); + fs.appendFileSync(output, `commit=${commit}\n`); + fs.appendFileSync(output, `publish_dockerhub=${publishDockerHub}\n`); + fs.appendFileSync(output, `promote_latest=${promoteLatest}\n`); + fs.appendFileSync(output, `ghcr_image=${ghcrImage}\n`); + + console.log(`Validated ${tag} at ${commit}`); + console.log(`latest promotion: ${promoteLatest ? "enabled" : "disabled"}`); + NODE + + build: + name: Build ${{ matrix.platform }} + needs: prepare + runs-on: ${{ matrix.runner }} + timeout-minutes: 60 + env: + GHCR_IMAGE: ${{ needs.prepare.outputs.ghcr_image }} + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + suffix: amd64 + runner: ubuntu-24.04 + - platform: linux/arm64 + suffix: arm64 + runner: ubuntu-24.04-arm + permissions: contents: read packages: write steps: - - uses: actions/checkout@v4 + - name: Check out release source at validated commit + uses: actions/checkout@v4 + with: + ref: ${{ needs.prepare.outputs.commit }} + path: source + fetch-depth: 1 - - uses: docker/setup-buildx-action@v3 + - name: Check out publishing Dockerfile + uses: actions/checkout@v4 + with: + ref: ${{ github.workflow_sha }} + path: workflow + sparse-checkout: | + Dockerfile + fetch-depth: 1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - name: Log in to GHCR uses: docker/login-action@v3 @@ -29,32 +171,267 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push platform image by digest + id: build + uses: docker/build-push-action@v6 + with: + context: source + file: workflow/Dockerfile + platforms: ${{ matrix.platform }} + outputs: type=image,name=${{ env.GHCR_IMAGE }},push-by-digest=true,name-canonical=true,push=true + build-args: | + APP_VERSION=${{ needs.prepare.outputs.version }} + ALPINE_MIRROR=${{ vars.ALPINE_MIRROR || 'dl-cdn.alpinelinux.org' }} + NPM_REGISTRY=${{ vars.NPM_REGISTRY || 'https://registry.npmjs.org/' }} + labels: | + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.revision=${{ needs.prepare.outputs.commit }} + org.opencontainers.image.version=${{ needs.prepare.outputs.version }} + cache-from: type=gha,scope=9router-${{ matrix.suffix }} + cache-to: type=gha,mode=max,scope=9router-${{ matrix.suffix }} + provenance: false + sbom: false + + - name: Smoke-test platform image before publishing digest artifact + env: + GHCR_IMAGE: ${{ env.GHCR_IMAGE }} + IMAGE_DIGEST: ${{ steps.build.outputs.digest }} + PLATFORM: ${{ matrix.platform }} + run: | + set -Eeuo pipefail + [[ "$IMAGE_DIGEST" =~ ^sha256:[0-9a-f]{64}$ ]] + + container="9router-platform-smoke-${GITHUB_RUN_ID}-${{ matrix.suffix }}" + trap 'docker rm -f "$container" >/dev/null 2>&1 || true' EXIT + + docker run --detach \ + --name "$container" \ + --platform "$PLATFORM" \ + --publish 20128:20128 \ + "${GHCR_IMAGE}@${IMAGE_DIGEST}" + + for attempt in {1..45}; do + if curl --fail --silent --show-error http://127.0.0.1:20128/api/health; then + echo "${PLATFORM} health check passed" + exit 0 + fi + if (( attempt % 5 == 0 )); then + echo "Waiting for ${PLATFORM} health check (${attempt}/45)" >&2 + fi + sleep 2 + done + + echo "${PLATFORM} health check failed; container logs follow:" >&2 + docker logs "$container" || true + exit 1 + + - name: Save image digest + env: + IMAGE_DIGEST: ${{ steps.build.outputs.digest }} + run: | + set -euo pipefail + test -n "$IMAGE_DIGEST" + mkdir -p "$RUNNER_TEMP/digests" + printf '%s\n' "$IMAGE_DIGEST" > "$RUNNER_TEMP/digests/${{ matrix.suffix }}.txt" + + - name: Upload image digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ matrix.suffix }} + path: ${{ runner.temp }}/digests/${{ matrix.suffix }}.txt + if-no-files-found: error + + publish: + name: Publish and verify manifest + needs: + - prepare + - build + runs-on: ubuntu-latest + timeout-minutes: 30 + env: + GHCR_IMAGE: ${{ needs.prepare.outputs.ghcr_image }} + permissions: + contents: read + packages: write + + steps: + - name: Download platform digests + uses: actions/download-artifact@v4 + with: + pattern: digests-* + path: ${{ runner.temp }}/digests + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create and verify version manifest + env: + GHCR_IMAGE: ${{ env.GHCR_IMAGE }} + VERSION: ${{ needs.prepare.outputs.version }} + run: | + set -euo pipefail + shopt -s nullglob + digest_files=("$RUNNER_TEMP"/digests/*.txt) + + if [[ "${#digest_files[@]}" -ne 2 ]]; then + echo "Expected two platform digests, found ${#digest_files[@]}" >&2 + exit 1 + fi + + sources=() + for digest_file in "${digest_files[@]}"; do + digest="$(tr -d '\n' < "$digest_file")" + if [[ ! "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]; then + echo "Invalid image digest in $digest_file: $digest" >&2 + exit 1 + fi + sources+=("${GHCR_IMAGE}@${digest}") + done + + docker buildx imagetools create \ + --tag "${GHCR_IMAGE}:${VERSION}" \ + "${sources[@]}" + + docker buildx imagetools inspect "${GHCR_IMAGE}:${VERSION}" | tee "$RUNNER_TEMP/version-manifest.txt" + docker buildx imagetools inspect --raw "${GHCR_IMAGE}:${VERSION}" > "$RUNNER_TEMP/version-manifest.json" + + expected=$'linux/amd64\nlinux/arm64' + actual="$(jq -r '[.manifests[] | select(.platform != null and .platform.os != null and .platform.architecture != null) | "\(.platform.os)/\(.platform.architecture)"] | sort | .[]' "$RUNNER_TEMP/version-manifest.json")" + if [[ "$actual" != "$expected" ]]; then + echo "Version manifest platforms do not match exactly:" >&2 + printf '%s\n' "$actual" >&2 + exit 1 + fi + + - name: Smoke-test resolved version manifest + env: + GHCR_IMAGE: ${{ env.GHCR_IMAGE }} + VERSION: ${{ needs.prepare.outputs.version }} + run: | + set -Eeuo pipefail + container="9router-manifest-smoke-${GITHUB_RUN_ID}" + trap 'docker rm -f "$container" >/dev/null 2>&1 || true' EXIT + + docker run --detach \ + --name "$container" \ + --platform linux/amd64 \ + --publish 20128:20128 \ + "${GHCR_IMAGE}:${VERSION}" + + for attempt in {1..30}; do + if curl --fail --silent --show-error http://127.0.0.1:20128/api/health; then + echo "Resolved version manifest health check passed" + exit 0 + fi + if (( attempt % 5 == 0 )); then + echo "Waiting for resolved manifest health check (${attempt}/30)" >&2 + fi + sleep 2 + done + + echo "Resolved version manifest health check failed; container logs follow:" >&2 + docker logs "$container" || true + exit 1 + - name: Log in to Docker Hub + if: needs.prepare.outputs.publish_dockerhub == 'true' uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Extract metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.GHCR_IMAGE }} - ${{ env.DOCKERHUB_IMAGE }} - tags: | - type=semver,pattern={{version}} - type=raw,value=latest,enable={{is_default_branch}} + - name: Publish version image to Docker Hub + if: needs.prepare.outputs.publish_dockerhub == 'true' + env: + DOCKERHUB_IMAGE: ${{ env.DOCKERHUB_IMAGE }} + GHCR_IMAGE: ${{ env.GHCR_IMAGE }} + VERSION: ${{ needs.prepare.outputs.version }} + run: | + set -euo pipefail + docker buildx imagetools create \ + --tag "${DOCKERHUB_IMAGE}:${VERSION}" \ + "${GHCR_IMAGE}:${VERSION}" - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.GHCR_IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.GHCR_IMAGE }}:buildcache,mode=max - platforms: linux/amd64,linux/arm64 - provenance: false - sbom: false + docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:${VERSION}" | tee "$RUNNER_TEMP/dockerhub-version-manifest.txt" + docker buildx imagetools inspect --raw "${DOCKERHUB_IMAGE}:${VERSION}" > "$RUNNER_TEMP/dockerhub-version-manifest.json" + + expected=$'linux/amd64\nlinux/arm64' + actual="$(jq -r '[.manifests[] | select(.platform != null and .platform.os != null and .platform.architecture != null) | "\(.platform.os)/\(.platform.architecture)"] | sort | .[]' "$RUNNER_TEMP/dockerhub-version-manifest.json")" + if [[ "$actual" != "$expected" ]]; then + echo "Docker Hub version manifest platforms do not match exactly:" >&2 + printf '%s\n' "$actual" >&2 + exit 1 + fi + + - name: Record latest promotion policy + env: + PROMOTE_LATEST: ${{ needs.prepare.outputs.promote_latest }} + VERSION: ${{ needs.prepare.outputs.version }} + run: | + if [[ "$PROMOTE_LATEST" == "true" ]]; then + echo "### Latest promotion" >> "$GITHUB_STEP_SUMMARY" + echo "- Policy: promote \`latest\` after the verified ${VERSION} manifest." >> "$GITHUB_STEP_SUMMARY" + else + echo "### Latest promotion" >> "$GITHUB_STEP_SUMMARY" + echo "- Policy: leave \`latest\` unchanged; this is a numbered-tag-only manual republish." >> "$GITHUB_STEP_SUMMARY" + fi + + - name: Promote verified version to latest + if: needs.prepare.outputs.promote_latest == 'true' + env: + DOCKERHUB_IMAGE: ${{ env.DOCKERHUB_IMAGE }} + GHCR_IMAGE: ${{ env.GHCR_IMAGE }} + PUBLISH_DOCKERHUB: ${{ needs.prepare.outputs.publish_dockerhub }} + VERSION: ${{ needs.prepare.outputs.version }} + run: | + set -euo pipefail + + docker buildx imagetools create \ + --tag "${GHCR_IMAGE}:latest" \ + "${GHCR_IMAGE}:${VERSION}" + + if [[ "$PUBLISH_DOCKERHUB" == "true" ]]; then + docker buildx imagetools create \ + --tag "${DOCKERHUB_IMAGE}:latest" \ + "${GHCR_IMAGE}:${VERSION}" + fi + + docker buildx imagetools inspect "${GHCR_IMAGE}:latest" | tee "$RUNNER_TEMP/ghcr-latest-manifest.txt" + docker buildx imagetools inspect --raw "${GHCR_IMAGE}:latest" > "$RUNNER_TEMP/ghcr-latest-manifest.json" + + expected=$'linux/amd64\nlinux/arm64' + actual="$(jq -r '[.manifests[] | select(.platform != null and .platform.os != null and .platform.architecture != null) | "\(.platform.os)/\(.platform.architecture)"] | sort | .[]' "$RUNNER_TEMP/ghcr-latest-manifest.json")" + if [[ "$actual" != "$expected" ]]; then + echo "GHCR latest manifest platforms do not match exactly:" >&2 + printf '%s\n' "$actual" >&2 + exit 1 + fi + + if [[ "$PUBLISH_DOCKERHUB" == "true" ]]; then + docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:latest" | tee "$RUNNER_TEMP/dockerhub-latest-manifest.txt" + docker buildx imagetools inspect --raw "${DOCKERHUB_IMAGE}:latest" > "$RUNNER_TEMP/dockerhub-latest-manifest.json" + actual="$(jq -r '[.manifests[] | select(.platform != null and .platform.os != null and .platform.architecture != null) | "\(.platform.os)/\(.platform.architecture)"] | sort | .[]' "$RUNNER_TEMP/dockerhub-latest-manifest.json")" + if [[ "$actual" != "$expected" ]]; then + echo "Docker Hub latest manifest platforms do not match exactly:" >&2 + printf '%s\n' "$actual" >&2 + exit 1 + fi + fi + + { + echo "### Published Docker images" + echo "- GHCR: \`${GHCR_IMAGE}:${VERSION}\`" + echo "- GHCR latest: \`${GHCR_IMAGE}:latest\`" + if [[ "$PUBLISH_DOCKERHUB" == "true" ]]; then + echo "- Docker Hub: \`${DOCKERHUB_IMAGE}:${VERSION}\`" + echo "- Docker Hub latest: \`${DOCKERHUB_IMAGE}:latest\`" + fi + } >> "$GITHUB_STEP_SUMMARY" diff --git a/DOCKER.md b/DOCKER.md index 1f280d97..727d7bfb 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -100,6 +100,12 @@ docker rm -f 9router # re-run the quick start command ``` +To pin a specific version instead of following `latest`, use a numbered image tag: + +```bash +docker pull decolua/9router:0.5.81 +``` + --- # 🛠 For Developers @@ -107,7 +113,7 @@ docker rm -f 9router ## Build image locally (test) ```bash -cd app && docker build -t 9router . +docker build -t 9router . docker run --rm -p 20128:20128 \ -v "$HOME/.9router:/app/data" \ @@ -115,18 +121,67 @@ docker run --rm -p 20128:20128 \ 9router ``` +The Dockerfile uses the official Alpine and npm registries by default. Regional mirrors can be supplied when needed: + +```bash +docker build \ + --build-arg ALPINE_MIRROR=mirrors.aliyun.com \ + --build-arg NPM_REGISTRY=https://registry.npmmirror.com/ \ + -t 9router . +``` + ## Publish (automatic via CI) -Push a git tag `v*` → GitHub Actions builds multi-platform (amd64+arm64) and pushes to: -- `ghcr.io/decolua/9router:v{version}` + `:latest` -- `decolua/9router:v{version}` + `:latest` +Push a Docker-safe semver git tag `vX.Y.Z` (or a prerelease such as `vX.Y.Z-rc.1`) → GitHub Actions builds `linux/amd64` and `linux/arm64` on native runners, health-checks each platform image, verifies the resulting manifest and `/api/health`, then publishes: + +- `ghcr.io/decolua/9router:X.Y.Z` + `:latest` +- `decolua/9router:X.Y.Z` + `:latest` + +The `v` prefix is used only for the git tag; image tags omit it. A stable tag push promotes `latest`, but a prerelease tag such as `vX.Y.Z-rc.1` publishes only its numbered image by default. Prereleases require an explicit manual `promote_latest` opt-in. Promotion happens only after both native platform builds, both platform health checks, manifest inspection, and the resolved-manifest smoke test succeed. A failed or timed-out platform build therefore cannot move `latest`. + +The workflow rejects SemVer build metadata such as `v1.2.3+build.7` because the `+` form is not a valid Docker image tag. The git tag and both `package.json` versions must match exactly. ```bash # Use scripts/release.js (recommended) node scripts/release.js "Release title" "Notes" # Or manually -git tag v0.4.x && git push origin v0.4.x +git tag v0.5.81 && git push origin v0.5.81 ``` -Workflow: `app/.github/workflows/docker-publish.yml` +To republish an existing tag, run the `Build and Push Docker Image` workflow manually and provide the exact tag, for example `v0.5.81`, in the `release_tag` input. Manual runs publish the numbered tag but leave `latest` unchanged by default: + +```text +release_tag: v0.5.81 +promote_latest: false +``` + +The `promote_latest` checkbox is an explicit opt-in for changing `latest`. Use it when a deliberate rollback or recovery should make that version the current default: + +```text +release_tag: v0.5.75 +promote_latest: true +``` + +Numbered image tags are mutable because a republish can replace their manifest. For a deployment that must be immutable, pin the image digest instead: + +```bash +docker pull decolua/9router@sha256: +``` + +The release workflow runs `/api/health` on each native `amd64` and `arm64` platform image before it uploads the digest artifact or assembles the multi-platform manifest. It then runs a second health check against the resolved version manifest before any requested `latest` promotion. + +During recovery, the selected tag remains the application source while the Dockerfile from the workflow revision is used, so an older tag can be rebuilt with the current publishing fixes. + +The workflow is tag-driven. Creating a git tag does not automatically create a GitHub Release, so the Releases page and the published package/image tags can be at different versions unless a maintainer creates a release separately. + +The upstream repository needs these repository secrets for Docker Hub publishing: + +- `DOCKERHUB_USERNAME` +- `DOCKERHUB_TOKEN` + +GHCR publishing uses the workflow's `GITHUB_TOKEN` with package write permission. Forks can publish to their own GHCR namespace, but Docker Hub publication is restricted to the upstream `decolua/9router` repository. + +The optional repository variables `ALPINE_MIRROR` and `NPM_REGISTRY` can override the default package mirrors used by the CI Docker build. + +Workflow: `.github/workflows/docker-publish.yml` diff --git a/Dockerfile b/Dockerfile index 547be9dd..9309de7e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,29 +1,49 @@ # syntax=docker/dockerfile:1.7 ARG NODE_IMAGE=node:22-alpine +ARG ALPINE_MIRROR=dl-cdn.alpinelinux.org +ARG NPM_REGISTRY=https://registry.npmjs.org/ +ARG APP_VERSION=unknown + FROM ${NODE_IMAGE} AS base +ARG ALPINE_MIRROR WORKDIR /app -# CN mirror for apk (used by builder and runner stages) -RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories + +# Use the official Alpine mirror by default. A repository variable/build arg can +# override it for environments that require a regional mirror. +RUN if [ "$ALPINE_MIRROR" != "dl-cdn.alpinelinux.org" ]; then \ + sed -i "s|dl-cdn.alpinelinux.org|${ALPINE_MIRROR}|g" /etc/apk/repositories; \ + fi FROM base AS builder +ARG NPM_REGISTRY -RUN apk --no-cache upgrade && apk --no-cache add python3 make g++ linux-headers +RUN apk add --no-cache python3 make g++ linux-headers COPY package.json ./ -RUN npm install --registry=https://registry.npmmirror.com +RUN --mount=type=cache,target=/root/.npm \ + npm install \ + --registry="${NPM_REGISTRY}" \ + --fetch-retries=5 \ + --fetch-retry-factor=2 \ + --fetch-retry-mintimeout=10000 \ + --fetch-retry-maxtimeout=120000 \ + --fetch-timeout=300000 COPY . ./ ENV NEXT_TELEMETRY_DISABLED=1 RUN npm run build FROM ${NODE_IMAGE} AS runner +ARG ALPINE_MIRROR +ARG APP_VERSION WORKDIR /app -# The base stage's mirror swap does not reach here: runner starts from -# ${NODE_IMAGE} directly, so the apk upgrade below would go to -# dl-cdn.alpinelinux.org and hang forever on networks that cannot reach it. -RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories -LABEL org.opencontainers.image.title="9router" +RUN if [ "$ALPINE_MIRROR" != "dl-cdn.alpinelinux.org" ]; then \ + sed -i "s|dl-cdn.alpinelinux.org|${ALPINE_MIRROR}|g" /etc/apk/repositories; \ + fi + +LABEL org.opencontainers.image.title="9router" \ + org.opencontainers.image.version="${APP_VERSION}" ENV NODE_ENV=production ENV PORT=20128 @@ -52,8 +72,9 @@ RUN mkdir -p /app/data && chown -R node:node /app && \ mkdir -p /app/data-home && chown node:node /app/data-home && \ ln -sf /app/data-home /root/.9router 2>/dev/null || true -# Fix permissions at runtime (handles mounted volumes) -RUN apk --no-cache upgrade && apk --no-cache add su-exec && \ +# Avoid a full distribution upgrade in the runtime image. It makes builds less +# reproducible and is unrelated to installing the runtime entrypoint helper. +RUN apk add --no-cache su-exec && \ printf '#!/bin/sh\nchown -R node:node /app/data /app/data-home 2>/dev/null\nexec su-exec node "$@"\n' > /entrypoint.sh && \ chmod +x /entrypoint.sh From 402745dc1f30786c09dbee900e0a7326aa0f988c Mon Sep 17 00:00:00 2001 From: "Liang.Xu" <17314823439@163.com> Date: Mon, 21 Sep 2026 20:44:26 +0700 Subject: [PATCH 15/41] feat(providers): add qoder-cn support for Qoder CN (qoder.com.cn) --- CHANGELOG.md | 5 + open-sse/executors/index.js | 1 + open-sse/executors/qoder.js | 21 +- open-sse/providers/capabilities.js | 4 + open-sse/providers/registry/index.js | 2 + open-sse/providers/registry/qoder-cn.js | 61 ++++++ open-sse/services/qoderModels.js | 73 ++++--- open-sse/services/usage.js | 16 +- open-sse/services/usage/misc.js | 4 +- open-sse/shared/qoder/constants.js | 110 ++++++++-- public/providers/qoder-cn.png | Bin 0 -> 8397 bytes .../providers/[id]/AddApiKeyModal.js | 8 +- .../dashboard/providers/[id]/page.js | 11 +- .../ProviderLimits/ProviderLimitCard.js | 1 + .../usage/components/ProviderLimits/utils.js | 1 + .../api/oauth/[provider]/[action]/route.js | 3 +- src/app/api/providers/[id]/models/route.js | 81 +++---- src/app/api/providers/[id]/test/testUtils.js | 16 +- src/app/api/providers/validate/route.js | 5 +- src/app/api/v1/models/route.js | 39 ++-- src/lib/oauth/constants/oauth.js | 4 + src/lib/oauth/providers/index.js | 2 + src/lib/oauth/providers/qoder-cn.js | 5 + src/lib/oauth/providers/qoder.js | 199 +++++++++--------- src/lib/oauth/services/qoder.js | 27 ++- src/shared/components/OAuthModal.js | 3 +- tests/__baseline__/alias-baseline.json | 2 + tests/__baseline__/providers-baseline.json | 10 + tests/unit/qoder.test.js | 5 + tests/unit/usage-dispatch.test.js | 2 +- 30 files changed, 487 insertions(+), 234 deletions(-) create mode 100644 open-sse/providers/registry/qoder-cn.js create mode 100644 public/providers/qoder-cn.png create mode 100644 src/lib/oauth/providers/qoder-cn.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bcc3390..c3ddfcb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v0.5.82 (unreleased) + +## Features +- **Qoder CN**: add the `qoder-cn` provider for qoder.com.cn — same device/OAuth flow and COSY-signed chat protocol as intl Qoder, served from the CN gateway (`gateway.qoder.com.cn` / `openapi.qoder.com.cn`). Region resolution is derived from the provider id (`qoder-cn` → CN) across executor, model catalog, quota usage, validation, and the dashboard. + # v0.5.81 (2026-09-18) ## Features diff --git a/open-sse/executors/index.js b/open-sse/executors/index.js index ed17d330..e8b06ea6 100644 --- a/open-sse/executors/index.js +++ b/open-sse/executors/index.js @@ -35,6 +35,7 @@ const executors = { github: new GithubExecutor(), iflow: new IFlowExecutor(), qoder: new QoderExecutor(), + "qoder-cn": new QoderExecutor("qoder-cn"), kiro: new KiroExecutor(), kimchi: new KimchiExecutor(), codex: new CodexExecutor(), diff --git a/open-sse/executors/qoder.js b/open-sse/executors/qoder.js index d1b0dbae..da6844f4 100644 --- a/open-sse/executors/qoder.js +++ b/open-sse/executors/qoder.js @@ -207,16 +207,16 @@ function truncate(s, n) { /** * Map the OpenAI-style request body into the exact shape Qoder expects. */ -async function buildQoderRequestBody({ model, body, credentials, log, proxyOptions, signal, uploadFn = null }) { +async function buildQoderRequestBody({ model, body, credentials, log, proxyOptions, signal, uploadFn = null, region = "intl" }) { const qoderKey = String(model || "").replace(/^qoder\//, ""); - + // Fetch model config from dynamic API instead of relying on static QODER_MODEL_MAP. // This allows support for new Qoder models (e.g., qmodel_latest) without code changes. - let modelConfig = await getQoderModelConfig(credentials, qoderKey, { log, proxyOptions, signal }); + let modelConfig = await getQoderModelConfig(credentials, qoderKey, { log, proxyOptions, signal, region }); if (!modelConfig) { // Try a forced refresh once before giving up — the cache may simply // not be populated yet on first ever call for this credential. - const refreshed = await resolveQoderModels(credentials, { forceRefresh: true, log, proxyOptions, signal }); + const refreshed = await resolveQoderModels(credentials, { forceRefresh: true, log, proxyOptions, signal, region }); const retried = refreshed?.rawConfigs.get(qoderKey); if (!retried) { throw new Error( @@ -584,12 +584,13 @@ async function wrapQoderSSE(response, model, log = null) { } export class QoderExecutor extends BaseExecutor { - constructor() { - super("qoder", PROVIDERS.qoder); + constructor(provider = "qoder") { + super(provider, PROVIDERS[provider]); + this.region = provider === "qoder-cn" ? "cn" : "intl"; } buildUrl(credentials) { - return `${qoderInferenceBase(credentials)}/algo${QODER_CHAT_SIG_PATH}?FetchKeys=llm_model_result&AgentId=agent_common&Encode=1`; + return `${qoderInferenceBase(credentials, this.region)}/algo${QODER_CHAT_SIG_PATH}?FetchKeys=llm_model_result&AgentId=agent_common&Encode=1`; } // Override execute entirely — Qoder needs: @@ -604,7 +605,7 @@ export class QoderExecutor extends BaseExecutor { const rawToken = credentials?.apiKey || credentials?.accessToken; if (isQoderPat(rawToken)) { try { - credentials = await resolveQoderCredentials(credentials, proxyOptions, signal); + credentials = await resolveQoderCredentials(credentials, proxyOptions, signal, this.region); } catch (err) { log?.error?.("QODER", `PAT exchange failed: ${err.message}`); const fakeResp = new Response( @@ -639,7 +640,7 @@ export class QoderExecutor extends BaseExecutor { let qoderKey; let payload; try { - ({ qoderKey, payload } = await buildQoderRequestBody({ model, body, credentials, log, proxyOptions, signal })); + ({ qoderKey, payload } = await buildQoderRequestBody({ model, body, credentials, log, proxyOptions, signal, region: this.region })); } catch (err) { const fakeResp = new Response( JSON.stringify({ error: { message: err.message } }), @@ -709,7 +710,7 @@ export class QoderExecutor extends BaseExecutor { return { response, url, headers, transformedBody: payload }; } - const wrapped = await wrapQoderSSE(response, `qoder/${qoderKey}`, log); + const wrapped = await wrapQoderSSE(response, `${this.provider}/${qoderKey}`, log); return { response: wrapped, url, headers, transformedBody: payload }; } diff --git a/open-sse/providers/capabilities.js b/open-sse/providers/capabilities.js index 221488cf..7ec47ce8 100644 --- a/open-sse/providers/capabilities.js +++ b/open-sse/providers/capabilities.js @@ -255,6 +255,10 @@ export const PROVIDER_CAPABILITIES = { }, }; +// Qoder CN serves the identical model catalog from the CN gateway, so it shares +// the intl Qoder capability table verbatim (vision/reasoning/contextWindow). +PROVIDER_CAPABILITIES["qoder-cn"] = PROVIDER_CAPABILITIES["qoder"]; + /** * Pattern fallback — glob (* = wildcard), matched case-insensitively and * anchored (^...$) so a pattern must match the full model id. ORDER MATTERS: diff --git a/open-sse/providers/registry/index.js b/open-sse/providers/registry/index.js index 56a8d41d..0e8dbe2e 100644 --- a/open-sse/providers/registry/index.js +++ b/open-sse/providers/registry/index.js @@ -77,6 +77,7 @@ import p72 from "./perplexity.js"; import p73 from "./perplexity-agent.js"; import p74 from "./playht.js"; import p75 from "./qoder.js"; +import p124 from "./qoder-cn.js"; import p77 from "./recraft.js"; import p78 from "./runwayml.js"; import p79 from "./sdwebui.js"; @@ -193,6 +194,7 @@ export default [ p65, p66, p123, + p124, p67, p68, p68z, diff --git a/open-sse/providers/registry/qoder-cn.js b/open-sse/providers/registry/qoder-cn.js new file mode 100644 index 00000000..a8809cfa --- /dev/null +++ b/open-sse/providers/registry/qoder-cn.js @@ -0,0 +1,61 @@ +export default { + id: "qoder-cn", + priority: 30, + alias: "qdcn", + uiAlias: "qdcn", + display: { + name: "Qoder CN", + icon: "water_drop", + color: "#EC4899", + website: "https://qoder.com.cn", + notice: { + signupUrl: "https://qoder.com.cn", + }, + }, + category: "oauth", + authModes: ["oauth", "apikey"], + hasOAuth: true, + authHint: "Personal Access Token (pt-...) from https://qoder.com.cn/account/integrations", + transport: { + baseUrl: "https://gateway.qoder.com.cn/algo/api/v2/service/pro/sse/agent_chat_generation", + headers: {}, + timeoutMs: 120000, + stallTimeoutMs: 120000, + usage: { + url: "https://openapi.qoder.com.cn/api/v2/quota/usage", + }, + }, + models: [ + { id: "ultimate", name: "Ultimate" }, + { id: "auto", name: "Auto" }, + { id: "performance", name: "Performance" }, + { id: "efficient", name: "Efficient" }, + { id: "lite", name: "Lite" }, + { id: "qmodel_38max", name: "Qwen3.8-Max" }, + { id: "qmodel_latest", name: "Qwen3.7-Max" }, + { id: "qmodel", name: "Qwen3.7-Plus" }, + { id: "qfmodel", name: "Qwen3.8-Flash" }, + { id: "kmodel_latest", name: "Kimi-K3" }, + { id: "kmodel", name: "Kimi-K2.7-Code" }, + { id: "gmodel", name: "GLM-5.3" }, + { id: "gfmodel", name: "GLM-5.3-Flash" }, + { id: "dmodel", name: "DeepSeek-V4-Pro" }, + { id: "dfmodel", name: "DeepSeek-V4-Flash" }, + { id: "mmodel", name: "MiniMax-M3" }, + ], + oauth: { + openApiBaseUrl: "https://openapi.qoder.com.cn", + centerBaseUrl: "https://gateway.qoder.com.cn", + chatBaseUrl: "https://gateway.qoder.com.cn", + deviceTokenUrl: "https://openapi.qoder.com.cn/api/v1/deviceToken/poll", + refreshUrl: "https://gateway.qoder.com.cn/algo/api/v3/user/refresh_token", + userInfoUrl: "https://openapi.qoder.com.cn/api/v1/userinfo", + quotaUsageUrl: "https://openapi.qoder.com.cn/api/v2/quota/usage", + loginUrl: "https://qoder.com.cn/device/selectAccounts", + }, + features: { + usage: true, + // PAT (apikey) connections also carry quota usage (via job-token exchange). + usageApikey: true, + }, +}; diff --git a/open-sse/services/qoderModels.js b/open-sse/services/qoderModels.js index e9a7879b..b5bd70fb 100644 --- a/open-sse/services/qoderModels.js +++ b/open-sse/services/qoderModels.js @@ -13,9 +13,13 @@ * * PAT (Personal Access Token, pt-...) connections: a PAT cannot sign COSY * requests directly, so we exchange it for a short-lived job token (jt-...) - * via openapi.qoder.sh/api/v1/jobToken/exchange (plain JSON POST), then use - * that job token for signing. Job-token traffic must hit api2.qoder.sh — - * api3 rejects jt- with "Login expired" (403). + * via the region's jobToken/exchange endpoint (plain JSON POST), then use + * that job token for signing. On intl, job-token traffic must hit api2.qoder.sh — + * api3 rejects jt- with "Login expired" (403); CN serves it from the same + * gateway host. + * + * The region (intl/cn) is derived from credentials.provider (or an explicit + * options.region override) so the same catalog logic works for both sites. */ import { createHash } from "crypto"; @@ -23,12 +27,12 @@ import { createHash } from "crypto"; import { proxyAwareFetch } from "../utils/proxyFetch.js"; import { buildCosyHeaders } from "../shared/qoder/cosy.js"; import { - QODER_MODEL_LIST_URL, - QODER_CHAT_BASE_ALT, - QODER_JOB_TOKEN_EXCHANGE_URL, - QODER_USERINFO_URL, QODER_IDE_VERSION, QODER_CLIENT_TYPE, + qoderRegionOf, + qoderJobTokenExchangeUrl, + qoderUserInfoUrl, + qoderInferenceBase, } from "../shared/qoder/constants.js"; const FETCH_TIMEOUT_MS = 15_000; @@ -63,9 +67,9 @@ const inflight = new Map(); * Exchange a Qoder PAT (pt-...) for a short-lived job token (jt-...). * This endpoint is plain JSON POST — NOT COSY-signed. */ -async function exchangeJobToken(pat, proxyOptions = null, signal = null) { +async function exchangeJobToken(pat, proxyOptions = null, signal = null, region = "intl") { const res = await proxyAwareFetch( - QODER_JOB_TOKEN_EXCHANGE_URL, + qoderJobTokenExchangeUrl(region), { method: "POST", headers: { @@ -101,10 +105,10 @@ async function exchangeJobToken(pat, proxyOptions = null, signal = null) { * Resolve the Qoder userId for a job token (needed for COSY signing). * Returns "" on any failure — callers fall back to the stored userId. */ -async function fetchUserIdForJobToken(jobToken, proxyOptions = null, signal = null) { +async function fetchUserIdForJobToken(jobToken, proxyOptions = null, signal = null, region = "intl") { try { const res = await proxyAwareFetch( - QODER_USERINFO_URL, + qoderUserInfoUrl(region), { method: "GET", headers: { @@ -125,16 +129,17 @@ async function fetchUserIdForJobToken(jobToken, proxyOptions = null, signal = nu } /** - * Resolve a PAT to a job-token credential, cached per-PAT. + * Resolve a PAT to a job-token credential, cached per-PAT-per-region. */ -async function resolvePatCredential(pat, proxyOptions = null, signal = null) { - const cached = patJobCache.get(pat); +async function resolvePatCredential(pat, proxyOptions = null, signal = null, region = "intl") { + const cacheKey = `${region}:${pat}`; + const cached = patJobCache.get(cacheKey); if (cached && cached.expiresAt - Date.now() > PAT_REFRESH_BUFFER_MS) return cached; - const { jobToken, expiresAt } = await exchangeJobToken(pat, proxyOptions, signal); - const userId = await fetchUserIdForJobToken(jobToken, proxyOptions, signal); + const { jobToken, expiresAt } = await exchangeJobToken(pat, proxyOptions, signal, region); + const userId = await fetchUserIdForJobToken(jobToken, proxyOptions, signal, region); const resolved = { accessToken: jobToken, userId, expiresAt }; - patJobCache.set(pat, resolved); + patJobCache.set(cacheKey, resolved); return resolved; } @@ -142,11 +147,14 @@ async function resolvePatCredential(pat, proxyOptions = null, signal = null) { * Resolve connection credentials to COSY-signable form: * - PAT (pt-...) connections → exchanged to a job token (jt-...) + userId * - everything else → passed through unchanged + * + * Region defaults to the one implied by credentials.provider (qoder-cn → cn). */ -export async function resolveQoderCredentials(credentials, proxyOptions = null, signal = null) { +export async function resolveQoderCredentials(credentials, proxyOptions = null, signal = null, region) { const raw = credentials?.apiKey || credentials?.accessToken; if (isQoderPat(raw)) { - const resolved = await resolvePatCredential(raw, proxyOptions, signal); + const effRegion = region || qoderRegionOf(credentials?.provider); + const resolved = await resolvePatCredential(raw, proxyOptions, signal, effRegion); return { ...credentials, accessToken: resolved.accessToken, @@ -163,13 +171,14 @@ export async function resolveQoderCredentials(credentials, proxyOptions = null, } /** - * Stable cache key per credential (so different login sessions for the same - * account share an entry). + * Stable cache key per credential+region (so different login sessions for the + * same account share an entry, and the same PAT on both sites stays apart). */ function cacheKey(credentials) { const psd = credentials?.providerSpecificData || {}; const seed = psd.userId || credentials?.refreshToken || credentials?.accessToken || "anonymous"; - return createHash("sha256").update(`qoder:${seed}`).digest("hex"); + const region = qoderRegionOf(credentials?.provider); + return createHash("sha256").update(`qoder:${region}:${seed}`).digest("hex"); } /** @@ -192,15 +201,13 @@ function cosyCredsFromConnection(credentials) { * rawConfigs: Map } * or `null` on any error. */ -async function fetchQoderCatalogRaw(credentials, signal, proxyOptions = null) { +async function fetchQoderCatalogRaw(credentials, signal, proxyOptions = null, region = "intl") { const creds = cosyCredsFromConnection(credentials); if (!creds.userId || !creds.authToken) return null; - // Job-token traffic is rejected by api3 ("Login expired" 403) — the - // official qodercli serves it from api2 instead. - const modelListUrl = String(creds.authToken).startsWith("jt-") - ? `${QODER_CHAT_BASE_ALT}/algo/api/v2/model/list` - : QODER_MODEL_LIST_URL; + // Intl job-token traffic is rejected by api3 ("Login expired" 403) — the + // official qodercli serves it from api2 instead; CN uses the single gateway. + const modelListUrl = `${qoderInferenceBase(credentials, region)}/algo/api/v2/model/list`; const headers = { Accept: "application/json", @@ -293,14 +300,20 @@ export async function getQoderModelConfig(credentials, modelKey, options = {}) { * one upstream request per credential. */ export async function resolveQoderModels(credentials, options = {}) { + const region = options.region || qoderRegionOf(credentials?.provider); let resolved; try { - resolved = await resolveQoderCredentials(credentials, options.proxyOptions, options.signal); + resolved = await resolveQoderCredentials(credentials, options.proxyOptions, options.signal, region); } catch (error) { options.log?.warn?.("QODER", `PAT exchange failed: ${error.message}`); return null; } if (!resolved?.accessToken || !(resolved.providerSpecificData || {}).userId) return null; + // Stamp the provider so cacheKey/catalog derive the region even when the + // caller's credentials object didn't carry a provider id (e.g. /v1/models). + if (resolved && !resolved.provider) { + resolved.provider = region === "cn" ? "qoder-cn" : "qoder"; + } const key = cacheKey(resolved); const now = Date.now(); @@ -319,7 +332,7 @@ export async function resolveQoderModels(credentials, options = {}) { } const fetchPromise = (async () => { - const fetched = await fetchQoderCatalogRaw(resolved, options.signal, options.proxyOptions); + const fetched = await fetchQoderCatalogRaw(resolved, options.signal, options.proxyOptions, region); if (!fetched) return null; const entry = { expiresAt: Date.now() + CACHE_TTL_MS, diff --git a/open-sse/services/usage.js b/open-sse/services/usage.js index 90ecb0e9..b431e21a 100644 --- a/open-sse/services/usage.js +++ b/open-sse/services/usage.js @@ -42,12 +42,8 @@ const USAGE_HANDLERS = { claude: (c) => getClaudeUsage(c.accessToken, c.proxyOptions, { force: c.force }), codex: (c) => getCodexUsage(c.accessToken, c.proxyOptions), kiro: (c) => getKiroUsage(c.accessToken, c.providerSpecificData, c.proxyOptions), - qoder: async (c) => { - // PAT (pt-...) connections must be exchanged to a job token before the - // quota endpoint accepts them. - const resolved = await resolveQoderCredentials(c, c.proxyOptions).catch(() => null); - return getQoderUsage(resolved?.accessToken || c.accessToken, c.proxyOptions); - }, + qoder: (c) => getQoderUsageFor(c), + "qoder-cn": (c) => getQoderUsageFor(c), iflow: (c) => getIflowUsage(c.accessToken), ollama: (c) => getOllamaUsage(c.apiKey, c.providerSpecificData, c.proxyOptions), glm: (c) => getGlmUsage(c.apiKey, c.provider, c.proxyOptions), @@ -68,6 +64,14 @@ const USAGE_HANDLERS = { commandcode: (c) => getCommandCodeUsage(c.apiKey, c.proxyOptions), }; +// Qoder intl/CN share one usage path: PATs must be exchanged to a job token +// before the quota endpoint accepts them, and the quota URL comes from the +// provider's own registry usage block (region-correct via c.provider). +async function getQoderUsageFor(c) { + const resolved = await resolveQoderCredentials(c, c.proxyOptions).catch(() => null); + return getQoderUsage(resolved?.accessToken || c.accessToken, c.proxyOptions, c.provider || "qoder"); +} + export async function getUsageForProvider(connection, proxyOptions = null, options = {}) { const { provider, accessToken, apiKey, providerSpecificData, projectId } = connection; const providerDataWithProjectId = { diff --git a/open-sse/services/usage/misc.js b/open-sse/services/usage/misc.js index eac37698..567739e8 100644 --- a/open-sse/services/usage/misc.js +++ b/open-sse/services/usage/misc.js @@ -227,13 +227,13 @@ export async function getVercelAiGatewayUsage(apiKey, proxyOptions = null) { } } -export async function getQoderUsage(accessToken, proxyOptions = null) { +export async function getQoderUsage(accessToken, proxyOptions = null, providerId = "qoder") { if (!accessToken) { return { message: "Qoder usage unavailable: no access token" }; } try { const response = await proxyAwareFetch( - U("qoder").url, + U(providerId).url, { method: "GET", headers: { diff --git a/open-sse/shared/qoder/constants.js b/open-sse/shared/qoder/constants.js index 849f67ed..04244b44 100644 --- a/open-sse/shared/qoder/constants.js +++ b/open-sse/shared/qoder/constants.js @@ -1,38 +1,106 @@ /** * Qoder API constants ported from CLIProxyAPIPlus qoder-provider branch. * - * Endpoint set: - * openapi.qoder.sh - device flow + userinfo + quota usage - * center.qoder.sh - token refresh (best-effort, currently 403 for device tokens) - * api3.qoder.sh - inference (chat) + model list, requires COSY signing - * qoder.com/device - browser landing page for device authorization + * Qoder runs two regional sites with parallel endpoint shapes: + * intl (qoder) CN (qoder-cn) + * openapi.qoder.sh openapi.qoder.com.cn - device flow + userinfo + quota usage + * center.qoder.sh gateway.qoder.com.cn - token refresh (best-effort, 403 for device tokens) + * api3.qoder.sh gateway.qoder.com.cn - inference (chat) + model list, requires COSY signing + * qoder.com/device qoder.com.cn/device - browser landing page for device authorization + * + * All path suffixes are identical between regions — only the hosts differ. + * Region-aware consumers call qoder*Url(region) / qoderInferenceBase(creds, region) + * and derive the region from the provider id via qoderRegionOf(). The named + * QODER_* constants below keep the intl defaults for backward compatibility. */ -export const QODER_OPENAPI_BASE = "https://openapi.qoder.sh"; -export const QODER_CENTER_BASE = "https://center.qoder.sh"; -export const QODER_CHAT_BASE = "https://api3.qoder.sh"; +export const QODER_REGION_INTL = "intl"; +export const QODER_REGION_CN = "cn"; + +// Per-region base URLs. CN serves job tokens (jt-...) from the same gateway +// host — there is no api2-style split like intl's api2.qoder.sh. +const QODER_REGION_BASES = { + [QODER_REGION_INTL]: { + chat: "https://api3.qoder.sh", + chatAlt: "https://api2.qoder.sh", + openApi: "https://openapi.qoder.sh", + center: "https://center.qoder.sh", + login: "https://qoder.com/device/selectAccounts", + website: "https://qoder.com", + }, + [QODER_REGION_CN]: { + chat: "https://gateway.qoder.com.cn", + chatAlt: "https://gateway.qoder.com.cn", + openApi: "https://openapi.qoder.com.cn", + center: "https://gateway.qoder.com.cn", + login: "https://qoder.com.cn/device/selectAccounts", + website: "https://qoder.com.cn", + }, +}; + +/** Base URL set for a region; unknown regions fall back to intl. */ +export function qoderRegionBases(region) { + return QODER_REGION_BASES[region] || QODER_REGION_BASES[QODER_REGION_INTL]; +} + +/** Region for a provider id — "cn" for qoder-cn, "intl" otherwise. */ +export function qoderRegionOf(providerId) { + return providerId === "qoder-cn" ? QODER_REGION_CN : QODER_REGION_INTL; +} + +export const QODER_OPENAPI_BASE = QODER_REGION_BASES[QODER_REGION_INTL].openApi; +export const QODER_CENTER_BASE = QODER_REGION_BASES[QODER_REGION_INTL].center; +export const QODER_CHAT_BASE = QODER_REGION_BASES[QODER_REGION_INTL].chat; // Job-token (jt-...) traffic is rejected by api3 with "Login expired" (403); -// the official qodercli serves it from api2 instead. -export const QODER_CHAT_BASE_ALT = "https://api2.qoder.sh"; +// the official qodercli serves it from api2 instead (intl only). +export const QODER_CHAT_BASE_ALT = QODER_REGION_BASES[QODER_REGION_INTL].chatAlt; -export const QODER_LOGIN_URL = "https://qoder.com/device/selectAccounts"; +export const QODER_LOGIN_URL = QODER_REGION_BASES[QODER_REGION_INTL].login; -// Device flow endpoints -export const QODER_DEVICE_TOKEN_URL = `${QODER_OPENAPI_BASE}/api/v1/deviceToken/poll`; -export const QODER_USERINFO_URL = `${QODER_OPENAPI_BASE}/api/v1/userinfo`; -export const QODER_QUOTA_USAGE_URL = `${QODER_OPENAPI_BASE}/api/v2/quota/usage`; -export const QODER_REFRESH_TOKEN_URL = `${QODER_CENTER_BASE}/algo/api/v3/user/refresh_token`; +// Device flow endpoints (region-aware variants; these are the intl defaults) +export function qoderOpenApiBase(region) { + return qoderRegionBases(region).openApi; +} +export function qoderDeviceTokenUrl(region) { + return `${qoderOpenApiBase(region)}/api/v1/deviceToken/poll`; +} +export function qoderUserInfoUrl(region) { + return `${qoderOpenApiBase(region)}/api/v1/userinfo`; +} +export function qoderQuotaUsageUrl(region) { + return `${qoderOpenApiBase(region)}/api/v2/quota/usage`; +} +export function qoderRefreshTokenUrl(region) { + return `${qoderRegionBases(region).center}/algo/api/v3/user/refresh_token`; +} +export function qoderLoginUrl(region) { + return qoderRegionBases(region).login; +} +export function qoderWebsiteUrl(region) { + return qoderRegionBases(region).website; +} + +export const QODER_DEVICE_TOKEN_URL = qoderDeviceTokenUrl(QODER_REGION_INTL); +export const QODER_USERINFO_URL = qoderUserInfoUrl(QODER_REGION_INTL); +export const QODER_QUOTA_USAGE_URL = qoderQuotaUsageUrl(QODER_REGION_INTL); +export const QODER_REFRESH_TOKEN_URL = qoderRefreshTokenUrl(QODER_REGION_INTL); // PAT (Personal Access Token, pt-...) → short-lived job token (jt-...) exchange. // PATs cannot sign COSY requests directly — they must be exchanged first. // This endpoint is NOT COSY-signed (plain JSON POST). -export const QODER_JOB_TOKEN_EXCHANGE_URL = `${QODER_OPENAPI_BASE}/api/v1/jobToken/exchange`; +export function qoderJobTokenExchangeUrl(region) { + return `${qoderOpenApiBase(region)}/api/v1/jobToken/exchange`; +} +export const QODER_JOB_TOKEN_EXCHANGE_URL = qoderJobTokenExchangeUrl(QODER_REGION_INTL); -// Inference endpoints (under /algo on api3.qoder.sh, all COSY-signed) +// Inference endpoints (under /algo on the chat host, all COSY-signed) export const QODER_CHAT_SIG_PATH = "/api/v2/service/pro/sse/agent_chat_generation"; export const QODER_CHAT_URL = `${QODER_CHAT_BASE}/algo${QODER_CHAT_SIG_PATH}?FetchKeys=llm_model_result&AgentId=agent_common`; export const QODER_CHAT_URL_ENCODED = `${QODER_CHAT_URL}&Encode=1`; -export const QODER_MODEL_LIST_URL = `${QODER_CHAT_BASE}/algo/api/v2/model/list`; +export function qoderModelListUrl(region) { + return `${qoderRegionBases(region).chat}/algo/api/v2/model/list`; +} +export const QODER_MODEL_LIST_URL = qoderModelListUrl(QODER_REGION_INTL); // Official qodercli uploads images here (COSY-signed PUT multipart, field "file") // instead of inlining base64 into agent_chat_generation. export const QODER_IMAGE_UPLOAD_SIG_PATH = "/api/v2/image/upload"; @@ -55,7 +123,9 @@ export const QODER_CONTEXT_TIER_MODES = Object.freeze({ AUTO: "auto", MAX: "max" * "Login expired" (403). Device tokens (dt-...) stay on api3. PATs (pt-...) * are exchanged for jt- before this is consulted. */ -export function qoderInferenceBase(credentials) { +export function qoderInferenceBase(credentials, region = QODER_REGION_INTL) { + // CN serves every token kind from the single gateway host. + if (region === QODER_REGION_CN) return QODER_REGION_BASES[QODER_REGION_CN].chat; const raw = credentials?.apiKey || credentials?.accessToken; if ( typeof raw === "string" && diff --git a/public/providers/qoder-cn.png b/public/providers/qoder-cn.png new file mode 100644 index 0000000000000000000000000000000000000000..59da3da55109700ac4778a132cc0bec44366c2b6 GIT binary patch literal 8397 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 {isCloudflareAi ? <>One key per line. Format: name|apiKey|accountId or just apiKey (auto-named by index). - : provider === "qoder" + : provider === "qoder" || provider === "qoder-cn" ? <>One PAT per line. Format: name|pt-... or just pt-... (auto-named by index). : <>One key per line. Format: name|apiKey or just apiKey (auto-named by index). } diff --git a/src/app/(dashboard)/dashboard/providers/[id]/page.js b/src/app/(dashboard)/dashboard/providers/[id]/page.js index bae6ff05..a9722d7f 100644 --- a/src/app/(dashboard)/dashboard/providers/[id]/page.js +++ b/src/app/(dashboard)/dashboard/providers/[id]/page.js @@ -172,7 +172,7 @@ export default function ProviderDetailPage() { const apiKeyConnectionLabel = providerId === "xai" ? "xAI API Key" : providerId === "kimi" ? "Kimi API Key" - : providerId === "qoder" ? "PAT" + : (providerId === "qoder" || providerId === "qoder-cn") ? "PAT" : "API Key"; // Resolve suffix "(level)" for a model when a thinking level is picked and the model supports it. const resolveThinkingSuffix = (modelId) => { @@ -612,8 +612,9 @@ export default function ProviderDetailPage() { const modelId = model.id || model.name; if (!modelId) continue; - // Qoder model ID format may be "qoder/auto" or "auto", need to remove prefix - const cleanModelId = modelId.replace(/^qoder\//, ""); + // Qoder model ID format may be "qoder/auto", "qoder-cn/auto" or "auto", + // need to remove the provider prefix before storing. + const cleanModelId = modelId.replace(/^(qoder-cn|qoder)\//, ""); const alreadyExists = customModels.some( (entry) => entry.providerAlias === providerStorageAlias && entry.id === cleanModelId && (entry.kind || entry.type || "llm") === "llm" ) || Object.values(modelAliases).includes(`${providerStorageAlias}/${cleanModelId}`); @@ -1245,8 +1246,8 @@ export default function ProviderDetailPage() { Add Model - {/* Import Qoder models button — only show for qoder provider */} - {providerId === "qoder" && connections.some((conn) => conn.isActive !== false) && ( + {/* Import Qoder models button — only show for qoder/qoder-cn provider */} + {(providerId === "qoder" || providerId === "qoder-cn") && connections.some((conn) => conn.isActive !== false) && (
    + {/* Question for System One */} + {kind === "systemone" && ( + +
    + setQuestion(e.target.value)} + placeholder="Enter evaluation question or criteria" + className="w-full px-3 py-1.5 pr-7 text-sm border border-border rounded-lg bg-background focus:outline-none focus:border-primary" + /> + {question && ( + + )} +
    +
    + )} + {/* Reference image (only for edit-capable image models) */} {supportsEdit && ( diff --git a/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js b/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js index 9bdf4b41..78bb5df8 100644 --- a/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js +++ b/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js @@ -119,6 +119,7 @@ export default function ModelsCard({ providerId, kindFilter, providerAliasOverri const providerAlias = providerAliasOverride || getProviderAlias(providerId); const effectiveType = kindFilter || "llm"; + const supportsTest = kindFilter !== "systemone"; const fetchData = useCallback(async () => { try { @@ -238,7 +239,7 @@ export default function ModelsCard({ providerId, kindFilter, providerAliasOverri onSetAlias={(alias) => handleSetAlias(model.id, alias)} onDeleteAlias={() => handleDeleteAlias(existingAlias)} testStatus={modelTestResults[model.id]} - onTest={() => handleTestModel(model.id)} + onTest={supportsTest ? () => handleTestModel(model.id) : undefined} isTesting={testingModelId === model.id} isFree={model.isFree} /> @@ -255,7 +256,7 @@ export default function ModelsCard({ providerId, kindFilter, providerAliasOverri onSetAlias={() => {}} onDeleteAlias={() => handleDeleteCustomModel(model.id)} testStatus={modelTestResults[model.id]} - onTest={() => handleTestModel(model.id)} + onTest={supportsTest ? () => handleTestModel(model.id) : undefined} isTesting={testingModelId === model.id} isCustom /> From 20014b31049220482a1b5395c4f199f6fdba565d Mon Sep 17 00:00:00 2001 From: decolua Date: Tue, 22 Sep 2026 14:41:59 +0700 Subject: [PATCH 22/41] fix(dashboard): probe System One models through /v1/systemone The inline model test sent a chat-completions payload and failed with 500 on decision models. Add a systemone branch to pingModelByKind that submits a native state+questions probe, and restore the test button that was hidden for System One models. Co-Authored-By: Claude Code --- .../providers/components/ModelsCard.js | 5 ++-- src/app/api/models/test/ping.js | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js b/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js index 78bb5df8..9bdf4b41 100644 --- a/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js +++ b/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js @@ -119,7 +119,6 @@ export default function ModelsCard({ providerId, kindFilter, providerAliasOverri const providerAlias = providerAliasOverride || getProviderAlias(providerId); const effectiveType = kindFilter || "llm"; - const supportsTest = kindFilter !== "systemone"; const fetchData = useCallback(async () => { try { @@ -239,7 +238,7 @@ export default function ModelsCard({ providerId, kindFilter, providerAliasOverri onSetAlias={(alias) => handleSetAlias(model.id, alias)} onDeleteAlias={() => handleDeleteAlias(existingAlias)} testStatus={modelTestResults[model.id]} - onTest={supportsTest ? () => handleTestModel(model.id) : undefined} + onTest={() => handleTestModel(model.id)} isTesting={testingModelId === model.id} isFree={model.isFree} /> @@ -256,7 +255,7 @@ export default function ModelsCard({ providerId, kindFilter, providerAliasOverri onSetAlias={() => {}} onDeleteAlias={() => handleDeleteCustomModel(model.id)} testStatus={modelTestResults[model.id]} - onTest={supportsTest ? () => handleTestModel(model.id) : undefined} + onTest={() => handleTestModel(model.id)} isTesting={testingModelId === model.id} isCustom /> diff --git a/src/app/api/models/test/ping.js b/src/app/api/models/test/ping.js index a5c882d5..f38bea81 100644 --- a/src/app/api/models/test/ping.js +++ b/src/app/api/models/test/ping.js @@ -132,6 +132,36 @@ export async function pingModelByKind(model, kind, baseUrl = `http://127.0.0.1:$ return { ok: true, latencyMs, error: null, status: res.status }; } + if (kind === "systemone") { + const res = await fetch(`${baseUrl}/api/v1/systemone`, { + method: "POST", + headers, + body: JSON.stringify({ + model, + state: "Customer: I was charged twice for my order this morning.", + questions: { + probe: { type: "noul", instructions: "Is the customer reporting a billing problem?" }, + }, + }), + signal: AbortSignal.timeout(15000), + }); + const latencyMs = Date.now() - start; + const rawText = await res.text().catch(() => ""); + let parsed = null; + try { parsed = rawText ? JSON.parse(rawText) : null; } catch {} + + if (!res.ok) { + const detail = parsed?.error?.message || parsed?.msg || parsed?.message || parsed?.error || rawText; + return { ok: false, latencyMs, error: `HTTP ${res.status}${detail ? `: ${String(detail).slice(0, 240)}` : ""}`, status: res.status }; + } + + const hasAnswers = parsed?.answers && typeof parsed.answers === "object" && Object.keys(parsed.answers).length > 0; + if (!hasAnswers) { + return { ok: false, latencyMs, status: res.status, error: "Provider returned no answers for this model" }; + } + return { ok: true, latencyMs, error: null, status: res.status }; + } + const res = await fetch(`${baseUrl}/api/v1/chat/completions`, { method: "POST", headers, From f84c667d42eaa5fd7880380bb9adfeacf09fe2f4 Mon Sep 17 00:00:00 2001 From: decolua Date: Tue, 22 Sep 2026 14:42:02 +0700 Subject: [PATCH 23/41] feat(providers): add OpenRouter System One lane and New badge OpenRouter serves TypeSafe Jev at POST /api/v1/systemone with the same request/response shape, so it plugs into systemoneConfig directly with model typesafe/jev-1.13. Mark the System One media kind isNew and render a New badge on the sidebar kind item and the Media Providers accordion when any visible kind is new. Co-Authored-By: Claude Code --- open-sse/providers/registry/openrouter.js | 8 +++++++- src/shared/components/Sidebar.js | 6 ++++++ src/shared/constants/providers.js | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/open-sse/providers/registry/openrouter.js b/open-sse/providers/registry/openrouter.js index 68a92857..83d0f54f 100644 --- a/open-sse/providers/registry/openrouter.js +++ b/open-sse/providers/registry/openrouter.js @@ -43,8 +43,14 @@ export default { { id: "google/veo-3.1", name: "Veo 3.1 (via OpenRouter)", params: ["duration","aspect_ratio","resolution"], kind: "video" }, { id: "openai/sora-2-pro", name: "Sora 2 Pro (via OpenRouter)", params: ["duration","aspect_ratio","resolution"], kind: "video" }, { id: "bytedance/seedance-2.0", name: "Seedance 2.0 (via OpenRouter)", params: ["duration","aspect_ratio","resolution"], kind: "video" }, + { id: "typesafe/jev-1.13", name: "Jev 1.13", kind: "systemone" }, ], - serviceKinds: ["llm","embedding","tts","imageToText","video"], + serviceKinds: ["llm","embedding","tts","imageToText","video","systemone"], + // System One decision API (TypeSafe-compatible): https://openrouter.ai/docs/guides/community/typesafe-sdk + systemoneConfig: { + baseUrl: "https://openrouter.ai/api/v1/systemone", + headers: {"HTTP-Referer":"https://endpoint-proxy.local","X-Title":"Endpoint Proxy"}, + }, ttsConfig: { baseUrl: "https://openrouter.ai/api/v1/chat/completions", defaultModel: "openai/gpt-4o-mini-tts", diff --git a/src/shared/components/Sidebar.js b/src/shared/components/Sidebar.js index 885e4c75..098bdcbd 100644 --- a/src/shared/components/Sidebar.js +++ b/src/shared/components/Sidebar.js @@ -200,6 +200,9 @@ export default function Sidebar({ onClose }) { > perm_media Media Providers + {MEDIA_PROVIDER_KINDS.some((k) => VISIBLE_MEDIA_KINDS.includes(k.id) && k.isNew) && ( + New + )} expand_more @@ -220,6 +223,9 @@ export default function Sidebar({ onClose }) { > {kind.icon} {kind.label} + {kind.isNew && ( + New + )} ))} Date: Tue, 22 Sep 2026 14:46:57 +0700 Subject: [PATCH 24/41] style(dashboard): match 9remote NEW badge style on System One tags Co-Authored-By: Claude Code --- src/shared/components/Sidebar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/components/Sidebar.js b/src/shared/components/Sidebar.js index 098bdcbd..35851b56 100644 --- a/src/shared/components/Sidebar.js +++ b/src/shared/components/Sidebar.js @@ -201,7 +201,7 @@ export default function Sidebar({ onClose }) { perm_media Media Providers {MEDIA_PROVIDER_KINDS.some((k) => VISIBLE_MEDIA_KINDS.includes(k.id) && k.isNew) && ( - New + NEW )} expand_more @@ -224,7 +224,7 @@ export default function Sidebar({ onClose }) { {kind.icon} {kind.label} {kind.isNew && ( - New + NEW )} ))} From 6c9fe6f78aa2544a859274f0997ee90baf4fddbe Mon Sep 17 00:00:00 2001 From: decolua Date: Tue, 22 Sep 2026 14:48:04 +0700 Subject: [PATCH 25/41] feat(cli-tools): add dynamic configuration for Pi, OMP, Crush, ForgeCode, Smelt and CodeWhale - Add dedicated settings API routes for pi, omp, crush, forge, smelt, codewhale - Integrate GenericCliToolCard with multi-model support for Pi and auto-discovery for OMP - Register tools in cliTools catalog and all-statuses route - Add official logos for all new CLI tools Co-Authored-By: Claude Code --- public/providers/codewhale.svg | 9 + public/providers/crush.png | Bin 0 -> 791976 bytes public/providers/forge.png | Bin 0 -> 3499 bytes public/providers/omp.png | Bin 0 -> 30118 bytes public/providers/pi.svg | 6 + public/providers/smelt.svg | 101 +++ .../cli-tools/[toolId]/ToolDetailClient.js | 9 +- .../components/GenericCliToolCard.js | 636 ++++++++++++++++++ .../dashboard/cli-tools/components/index.js | 1 + src/app/api/cli-tools/all-statuses/route.js | 12 + .../api/cli-tools/codewhale-settings/route.js | 142 ++++ src/app/api/cli-tools/crush-settings/route.js | 154 +++++ src/app/api/cli-tools/forge-settings/route.js | 142 ++++ src/app/api/cli-tools/omp-settings/route.js | 179 +++++ src/app/api/cli-tools/pi-settings/route.js | 187 +++++ src/app/api/cli-tools/smelt-settings/route.js | 142 ++++ src/shared/constants/cliTools.js | 90 +++ 17 files changed, 1809 insertions(+), 1 deletion(-) create mode 100644 public/providers/codewhale.svg create mode 100644 public/providers/crush.png create mode 100644 public/providers/forge.png create mode 100644 public/providers/omp.png create mode 100644 public/providers/pi.svg create mode 100644 public/providers/smelt.svg create mode 100644 src/app/(dashboard)/dashboard/cli-tools/components/GenericCliToolCard.js create mode 100644 src/app/api/cli-tools/codewhale-settings/route.js create mode 100644 src/app/api/cli-tools/crush-settings/route.js create mode 100644 src/app/api/cli-tools/forge-settings/route.js create mode 100644 src/app/api/cli-tools/omp-settings/route.js create mode 100644 src/app/api/cli-tools/pi-settings/route.js create mode 100644 src/app/api/cli-tools/smelt-settings/route.js diff --git a/public/providers/codewhale.svg b/public/providers/codewhale.svg new file mode 100644 index 00000000..412e4c14 --- /dev/null +++ b/public/providers/codewhale.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/providers/crush.png b/public/providers/crush.png new file mode 100644 index 0000000000000000000000000000000000000000..c893222ea720574b213a2d74fc72889d6fe2517b GIT binary patch literal 791976 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

    *a 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

    l07bbFUWfUR`&Ha}Kdhf4SW7o>vq_b07}T2u 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

    $yZBD;e_U3?f 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

    C_taiK#SUyM$YNfeJfY{kUHeoz0C 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 literal 0 HcmV?d00001 diff --git a/public/providers/omp.png b/public/providers/omp.png new file mode 100644 index 0000000000000000000000000000000000000000..9da36e296aa9bcc58604476ad73eff0c4be81c00 GIT binary patch literal 30118 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 VXk)x=hc`;W|8j%5pB|I{e*lo}V*~&I literal 0 HcmV?d00001 diff --git a/public/providers/pi.svg b/public/providers/pi.svg new file mode 100644 index 00000000..e2851685 --- /dev/null +++ b/public/providers/pi.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/providers/smelt.svg b/public/providers/smelt.svg new file mode 100644 index 00000000..917aea73 --- /dev/null +++ b/public/providers/smelt.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js b/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js index 82211e48..f5df083a 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js +++ b/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js @@ -9,7 +9,7 @@ import { ClaudeToolCard, CodexToolCard, DroidToolCard, OpenClawToolCard, HermesToolCard, DefaultToolCard, OpenCodeToolCard, CoworkToolCard, ClineToolCard, KiloToolCard, DeepSeekTuiToolCard, - JcodeToolCard, GrokBuildToolCard, + JcodeToolCard, GrokBuildToolCard, GenericCliToolCard, } from "../components"; const CLOUD_URL = process.env.NEXT_PUBLIC_CLOUD_URL; @@ -166,6 +166,13 @@ export default function ToolDetailClient({ toolId, machineId }) { return ; case "grok-build": return ; + case "pi": + case "omp": + case "crush": + case "forge": + case "smelt": + case "codewhale": + return ; default: return ; } diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/GenericCliToolCard.js b/src/app/(dashboard)/dashboard/cli-tools/components/GenericCliToolCard.js new file mode 100644 index 00000000..76b95eec --- /dev/null +++ b/src/app/(dashboard)/dashboard/cli-tools/components/GenericCliToolCard.js @@ -0,0 +1,636 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { Card, Button, ModelSelectModal, ManualConfigModal } from "@/shared/components"; +import Image from "next/image"; +import BaseUrlSelect from "./BaseUrlSelect"; +import { rememberEndpoint } from "./cliEndpointPresets"; +import ApiKeySelect from "./ApiKeySelect"; +import { matchKnownEndpoint } from "./cliEndpointMatch"; +import { getModelsByProviderId, PROVIDER_ID_TO_ALIAS } from "@/shared/constants/models"; + +export default function GenericCliToolCard({ + tool, + isExpanded, + onToggle, + baseUrl, + apiKeys, + activeProviders = [], + cloudEnabled, + initialStatus, + tunnelEnabled, + tunnelPublicUrl, + tailscaleEnabled, + tailscaleUrl, +}) { + const [status, setStatus] = useState(() => initialStatus || null); + const [checking, setChecking] = useState(false); + const [applying, setApplying] = useState(false); + const [restoring, setRestoring] = useState(false); + const [message, setMessage] = useState(null); + const [showInstallGuide, setShowInstallGuide] = useState(false); + const [selectedApiKey, setSelectedApiKey] = useState(() => apiKeys?.[0]?.key || ""); + const [selectedModel, setSelectedModel] = useState(() => { + const cfg = initialStatus?.config; + return cfg?.model || cfg?.openai?.model || cfg?.providers?.["9router"]?.models?.[0]?.id || ""; + }); + const [selectedModels, setSelectedModels] = useState(() => { + const cfg = initialStatus?.config; + const list = cfg?.providers?.["9router"]?.models; + if (Array.isArray(list) && list.length > 0) { + return list.map((m) => (typeof m === "string" ? m : m.id)); + } + return []; + }); + const [modalOpen, setModalOpen] = useState(false); + const [showManualConfigModal, setShowManualConfigModal] = useState(false); + const [customBaseUrl, setCustomBaseUrl] = useState(""); + + const endpointUrl = `/api/cli-tools/${tool.id}-settings`; + + useEffect(() => { + let active = true; + if (isExpanded && !initialStatus) { + fetch(endpointUrl) + .then((res) => res.json()) + .then((data) => { + if (active) { + setStatus(data); + const cfg = data?.config; + if (tool.id === "pi") { + const list = cfg?.providers?.["9router"]?.models; + if (Array.isArray(list) && list.length > 0) { + const ids = list.map((m) => (typeof m === "string" ? m : m.id)); + setSelectedModels(ids); + } + } else { + const mod = cfg?.model || cfg?.openai?.model || cfg?.providers?.["9router"]?.models?.[0]?.id; + if (mod) setSelectedModel((prev) => prev || mod); + } + } + }) + .catch((error) => { + if (active) setStatus({ installed: false, error: error.message }); + }); + } + return () => { + active = false; + }; + }, [isExpanded, initialStatus, endpointUrl, tool.id]); + + const checkStatus = async () => { + setChecking(true); + try { + const res = await fetch(endpointUrl); + const data = await res.json(); + setStatus(data); + const cfg = data?.config; + if (tool.id === "pi") { + const list = cfg?.providers?.["9router"]?.models; + if (Array.isArray(list) && list.length > 0) { + const ids = list.map((m) => (typeof m === "string" ? m : m.id)); + setSelectedModels(ids); + } + } else { + const mod = cfg?.model || cfg?.openai?.model || cfg?.providers?.["9router"]?.models?.[0]?.id; + if (mod && !selectedModel) setSelectedModel(mod); + } + } catch (error) { + setStatus({ installed: false, error: error.message }); + } finally { + setChecking(false); + } + }; + + const getEffectiveBaseUrl = () => { + const url = customBaseUrl || `${baseUrl}/v1`; + return url.endsWith("/v1") ? url : `${url}/v1`; + }; + + const getCurrentBaseUrl = () => { + if (!status?.config) return ""; + const cfg = status.config; + if (typeof cfg.baseUrl === "string") return cfg.baseUrl; + if (typeof cfg.openai?.base_url === "string") return cfg.openai.base_url; + if (typeof cfg.providers?.["9router"]?.base_url === "string") return cfg.providers["9router"].base_url; + if (typeof cfg.providers?.["9router"]?.baseUrl === "string") return cfg.providers["9router"].baseUrl; + return ""; + }; + + const currentBaseUrl = getCurrentBaseUrl(); + + const getConfigStatus = () => { + if (!status?.installed) return null; + if (!status.has9Router) return "not_configured"; + if (currentBaseUrl && matchKnownEndpoint(currentBaseUrl, { tunnelPublicUrl, tailscaleUrl })) { + return "configured"; + } + return "configured"; + }; + + const configStatus = getConfigStatus(); + + const handleApply = async () => { + setApplying(true); + setMessage(null); + try { + const keyToUse = (selectedApiKey && selectedApiKey.trim()) + ? selectedApiKey + : (!cloudEnabled ? "sk_9router" : selectedApiKey); + + const payload = { + baseUrl: getEffectiveBaseUrl(), + apiKey: keyToUse, + }; + + if (tool.id === "pi") { + payload.models = selectedModels.length > 0 ? selectedModels : ["provider/model-id"]; + } else { + payload.model = selectedModel; + } + + const res = await fetch(endpointUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload), + }); + const data = await res.json(); + if (res.ok) { + rememberEndpoint(getEffectiveBaseUrl()); + setMessage({ type: "success", text: data.message || "Settings applied successfully!" }); + await checkStatus(); + } else { + setMessage({ type: "error", text: data.error?.message || "Failed to apply settings." }); + } + } catch (error) { + setMessage({ type: "error", text: error.message }); + } finally { + setApplying(false); + } + }; + + const handleRestore = async () => { + setRestoring(true); + setMessage(null); + try { + const res = await fetch(endpointUrl, { method: "DELETE" }); + const data = await res.json(); + if (res.ok) { + setMessage({ type: "success", text: data.message || "Settings removed successfully." }); + await checkStatus(); + } else { + setMessage({ type: "error", text: data.error?.message || "Failed to reset settings." }); + } + } catch (error) { + setMessage({ type: "error", text: error.message }); + } finally { + setRestoring(false); + } + }; + + const handleSelectModel = (model) => { + if (tool.id === "pi") { + if (!selectedModels.includes(model.value)) { + setSelectedModels((prev) => [...prev, model.value]); + } + } else { + setSelectedModel(model.value); + } + setModalOpen(false); + }; + + const handleAddAllActiveModels = () => { + const allModels = []; + activeProviders.forEach((conn) => { + const alias = PROVIDER_ID_TO_ALIAS[conn.provider] || conn.provider; + const providerModels = getModelsByProviderId(conn.provider); + providerModels.forEach((m) => { + const val = `${alias}/${m.id}`; + if (!allModels.includes(val)) allModels.push(val); + }); + }); + if (allModels.length > 0) { + setSelectedModels((prev) => Array.from(new Set([...prev, ...allModels]))); + } + }; + + const handleRemoveModel = (modelToRemove) => { + setSelectedModels((prev) => prev.filter((m) => m !== modelToRemove)); + }; + + const getInstallCommand = () => { + switch (tool.id) { + case "pi": + return "curl -fsSL https://pi.dev/install.sh | sh # or: npm install -g --ignore-scripts @earendil-works/pi-coding-agent"; + case "omp": + return "npm install -g oh-my-pi"; + case "crush": + return "brew install charmbracelet/tap/crush # or go install github.com/charmbracelet/crush@latest"; + case "forge": + return "cargo install forgecode"; + case "smelt": + return "cargo install smelt"; + case "codewhale": + return "cargo install codewhale"; + default: + return `npm install -g ${tool.id}`; + } + }; + + const getManualConfigContent = () => { + const effectiveUrl = getEffectiveBaseUrl(); + const key = selectedApiKey || "sk_9router"; + const mod = selectedModel || "provider/model-id"; + + switch (tool.id) { + case "pi": { + const modelsList = selectedModels.length > 0 ? selectedModels : [mod]; + return [ + { + filename: "~/.pi/agent/models.json", + content: JSON.stringify( + { + providers: { + "9router": { + baseUrl: effectiveUrl, + apiKey: key, + api: "openai-completions", + models: modelsList.map((id) => ({ + id, + name: id, + contextWindow: 128000, + maxTokens: 16384, + })), + }, + }, + }, + null, + 2 + ), + }, + ]; + } + case "omp": + return [ + { + filename: "~/.omp/agent/models.yml", + content: `providers:\n 9router:\n baseUrl: ${effectiveUrl}\n apiKey: ${key}\n api: openai-completions\n authHeader: true\n disableStrictTools: true\n discovery:\n type: proxy`, + }, + ]; + case "crush": + return [ + { + filename: "~/.config/crush/crush.json", + content: JSON.stringify( + { + providers: { + "9router": { + type: "openai-compat", + base_url: effectiveUrl, + api_key: key, + models: [{ id: mod, name: mod, context_window: 128000 }], + }, + }, + }, + null, + 2 + ), + }, + ]; + case "forge": + return [ + { + filename: "~/.forge/config.toml", + content: `# Forge config — managed by 9Router\n\n[openai]\napi_key = "${key}"\nbase_url = "${effectiveUrl}"\nmodel = "${mod}"`, + }, + ]; + case "smelt": + return [ + { + filename: "~/.smelt/config.json", + content: JSON.stringify({ baseUrl: effectiveUrl, apiKey: key, model: mod, _managedBy: "9router" }, null, 2), + }, + ]; + case "codewhale": + return [ + { + filename: "~/.codewhale/config.toml", + content: `# CodeWhale config — managed by 9Router\n\n[openai]\nbase_url = "${effectiveUrl}"\napi_key = "${key}"\nmodel = "${mod}"`, + }, + ]; + default: + return []; + } + }; + + return ( + + {/* Header clickable */} +

    + + {isExpanded && ( +
    + {checking && ( +
    + progress_activity + Checking {tool.name}... +
    + )} + + {!checking && status && !status.installed && ( +
    + )} + + {!checking && status?.installed && ( + <> +
    + {/* Endpoint (selector) */} +
    + Select Endpoint + arrow_forward + +
    + + {/* Current configured */} + {currentBaseUrl ? ( +
    + Current + arrow_forward + + {currentBaseUrl} + +
    + ) : null} + + {/* API Key */} +
    + API Key + arrow_forward + +
    + + {/* Models selector cho Pi (multi-models) */} + {tool.id === "pi" && ( +
    + Models + arrow_forward +
    +
    + {selectedModels.length === 0 ? ( + No models selected. Add models to use in Pi. + ) : ( + selectedModels.map((modelId) => ( + + {modelId} + + + )) + )} +
    +
    + + {activeProviders?.length > 0 && ( + + )} + {selectedModels.length > 0 && ( + + )} +
    +
    +
    + )} + + {/* Model (1 model cho các tool khác, trừ omp) */} + {tool.id !== "omp" && tool.id !== "pi" && ( +
    + Model + arrow_forward +
    + setSelectedModel(e.target.value)} + placeholder="provider/model-id" + className="w-full min-w-0 pl-2 pr-7 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5" + /> + {selectedModel && ( + + )} +
    + +
    + )} +
    + + {/* Messages */} + {message && ( +
    + {message.text} +
    + )} + + {/* Action Buttons */} +
    +
    + + {status?.has9Router && ( + + )} +
    + +
    + + )} +
    + )} + + setModalOpen(false)} + onSelect={handleSelectModel} + activeProviders={activeProviders} + /> + + setShowManualConfigModal(false)} + title={`${tool.name} Configuration`} + configs={getManualConfigContent()} + /> + + ); +} diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/index.js b/src/app/(dashboard)/dashboard/cli-tools/components/index.js index e1399677..8a1465ba 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/components/index.js +++ b/src/app/(dashboard)/dashboard/cli-tools/components/index.js @@ -13,6 +13,7 @@ export { default as KiloToolCard } from "./KiloToolCard"; export { default as DeepSeekTuiToolCard } from "./DeepSeekTuiToolCard"; export { default as JcodeToolCard } from "./JcodeToolCard"; export { default as GrokBuildToolCard } from "./GrokBuildToolCard"; +export { default as GenericCliToolCard } from "./GenericCliToolCard"; export { default as MitmServerCard } from "./MitmServerCard"; export { default as MitmToolCard } from "./MitmToolCard"; export { default as MitmLinkCard } from "./MitmLinkCard"; diff --git a/src/app/api/cli-tools/all-statuses/route.js b/src/app/api/cli-tools/all-statuses/route.js index b4270163..0f4ca8d5 100644 --- a/src/app/api/cli-tools/all-statuses/route.js +++ b/src/app/api/cli-tools/all-statuses/route.js @@ -14,6 +14,12 @@ import { GET as deepseekTuiGet } from "../deepseek-tui-settings/route"; import { GET as jcodeGet } from "../jcode-settings/route"; import { GET as grokBuildGet } from "../grok-build-settings/route"; import { GET as devinGet } from "../devin-settings/route"; +import { GET as piGet } from "../pi-settings/route"; +import { GET as ompGet } from "../omp-settings/route"; +import { GET as crushGet } from "../crush-settings/route"; +import { GET as forgeGet } from "../forge-settings/route"; +import { GET as smeltGet } from "../smelt-settings/route"; +import { GET as codewhaleGet } from "../codewhale-settings/route"; const STATUS_GETTERS = { claude: claudeGet, @@ -29,6 +35,12 @@ const STATUS_GETTERS = { jcode: jcodeGet, "grok-build": grokBuildGet, devin: devinGet, + pi: piGet, + omp: ompGet, + crush: crushGet, + forge: forgeGet, + smelt: smeltGet, + codewhale: codewhaleGet, }; // Batch endpoint: gather all CLI tool statuses in one round-trip diff --git a/src/app/api/cli-tools/codewhale-settings/route.js b/src/app/api/cli-tools/codewhale-settings/route.js new file mode 100644 index 00000000..f561dc06 --- /dev/null +++ b/src/app/api/cli-tools/codewhale-settings/route.js @@ -0,0 +1,142 @@ +"use server"; + +import { NextResponse } from "next/server"; +import fs from "fs/promises"; +import path from "path"; +import os from "os"; +import { exec } from "child_process"; +import { promisify } from "util"; +import { parseTOML, stringifyTOML } from "confbox"; + +const execAsync = promisify(exec); + +const getCodewhaleDir = () => path.join(os.homedir(), ".codewhale"); +const getCodewhaleConfigPath = () => path.join(getCodewhaleDir(), "config.toml"); + +const checkCodewhaleInstalled = async () => { + const isWindows = os.platform() === "win32"; + try { + const command = isWindows ? "where codewhale" : "which codewhale"; + await execAsync(command, { windowsHide: true }); + return true; + } catch { + try { + await fs.access(getCodewhaleConfigPath()); + return true; + } catch { + return false; + } + } +}; + +const has9RouterConfig = (content) => { + if (!content) return false; + return content.includes("managed by 9Router") || content.includes("localhost:20128"); +}; + +const readConfig = async () => { + try { + return await fs.readFile(getCodewhaleConfigPath(), "utf-8"); + } catch { + return null; + } +}; + +export async function GET() { + try { + const installed = await checkCodewhaleInstalled(); + if (!installed) { + return NextResponse.json({ + installed: false, + config: null, + message: "CodeWhale CLI is not installed", + }); + } + + const content = await readConfig(); + let config = null; + try { + if (content) config = parseTOML(content); + } catch {} + + return NextResponse.json({ + installed: true, + config, + has9Router: has9RouterConfig(content), + configPath: getCodewhaleConfigPath(), + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function POST(request) { + let rawBody; + try { + rawBody = await request.json(); + } catch { + return NextResponse.json({ error: { message: "Invalid JSON body" } }, { status: 400 }); + } + + try { + const { baseUrl, apiKey, model } = rawBody || {}; + if (!baseUrl) { + return NextResponse.json({ error: { message: "baseUrl is required" } }, { status: 400 }); + } + + const configPath = getCodewhaleConfigPath(); + await fs.mkdir(getCodewhaleDir(), { recursive: true }); + + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = parseTOML(raw); + } catch {} + + const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`; + + existing.openai = { + base_url: normalizedBaseUrl, + api_key: apiKey || "sk_9router", + model: model || "provider/model-id", + }; + + const header = "# CodeWhale config — managed by 9Router\n\n"; + const content = header + stringifyTOML(existing); + + await fs.writeFile(configPath, content, "utf-8"); + + return NextResponse.json({ + success: true, + message: "CodeWhale settings applied successfully!", + configPath, + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function DELETE() { + try { + const configPath = getCodewhaleConfigPath(); + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = parseTOML(raw); + } catch { + return NextResponse.json({ success: true, message: "No config file to reset" }); + } + + delete existing.openai; + + if (Object.keys(existing).length === 0) { + await fs.rm(configPath, { force: true }); + } else { + await fs.writeFile(configPath, stringifyTOML(existing), "utf-8"); + } + + return NextResponse.json({ success: true, message: "9Router removed from CodeWhale" }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} diff --git a/src/app/api/cli-tools/crush-settings/route.js b/src/app/api/cli-tools/crush-settings/route.js new file mode 100644 index 00000000..dd96d948 --- /dev/null +++ b/src/app/api/cli-tools/crush-settings/route.js @@ -0,0 +1,154 @@ +"use server"; + +import { NextResponse } from "next/server"; +import fs from "fs/promises"; +import path from "path"; +import os from "os"; +import { exec } from "child_process"; +import { promisify } from "util"; + +const execAsync = promisify(exec); + +const getCrushConfigPath = () => { + const configDir = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config"); + return path.join(configDir, "crush", "crush.json"); +}; + +const getCrushDir = () => path.dirname(getCrushConfigPath()); + +const checkCrushInstalled = async () => { + const isWindows = os.platform() === "win32"; + try { + const command = isWindows ? "where crush" : "which crush"; + await execAsync(command, { windowsHide: true }); + return true; + } catch { + try { + await fs.access(getCrushConfigPath()); + return true; + } catch { + return false; + } + } +}; + +const has9RouterConfig = (settings) => { + if (!settings || !settings.providers) return false; + const p = settings.providers["9router"]; + if (p && p.base_url) return true; + for (const prov of Object.values(settings.providers)) { + if (prov.base_url && prov.base_url.includes("20128")) return true; + } + return false; +}; + +const readConfig = async () => { + try { + const content = await fs.readFile(getCrushConfigPath(), "utf-8"); + return JSON.parse(content); + } catch { + return null; + } +}; + +export async function GET() { + try { + const installed = await checkCrushInstalled(); + if (!installed) { + return NextResponse.json({ + installed: false, + config: null, + message: "Crush CLI is not installed", + }); + } + + const config = await readConfig(); + + return NextResponse.json({ + installed: true, + config, + has9Router: has9RouterConfig(config), + configPath: getCrushConfigPath(), + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function POST(request) { + let rawBody; + try { + rawBody = await request.json(); + } catch { + return NextResponse.json({ error: { message: "Invalid JSON body" } }, { status: 400 }); + } + + try { + const { baseUrl, apiKey, model } = rawBody || {}; + if (!baseUrl) { + return NextResponse.json({ error: { message: "baseUrl is required" } }, { status: 400 }); + } + + const configPath = getCrushConfigPath(); + await fs.mkdir(getCrushDir(), { recursive: true }); + + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = JSON.parse(raw); + } catch { + /* No existing config */ + } + + if (!existing.providers) existing.providers = {}; + + const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`; + const modelId = model || "provider/model-id"; + + existing.providers["9router"] = { + type: "openai-compat", + base_url: normalizedBaseUrl, + api_key: apiKey || "sk_9router", + models: [ + { + id: modelId, + name: modelId, + context_window: 128000, + }, + ], + }; + + await fs.writeFile(configPath, JSON.stringify(existing, null, 2), "utf-8"); + + return NextResponse.json({ + success: true, + message: "Crush settings applied successfully!", + configPath, + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function DELETE() { + try { + const configPath = getCrushConfigPath(); + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = JSON.parse(raw); + } catch { + return NextResponse.json({ success: true, message: "No config file to reset" }); + } + + if (existing.providers && existing.providers["9router"]) { + delete existing.providers["9router"]; + if (Object.keys(existing.providers).length === 0) delete existing.providers; + await fs.writeFile(configPath, JSON.stringify(existing, null, 2), "utf-8"); + } + + return NextResponse.json({ success: true, message: "9Router removed from Crush" }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} diff --git a/src/app/api/cli-tools/forge-settings/route.js b/src/app/api/cli-tools/forge-settings/route.js new file mode 100644 index 00000000..2f7c45dc --- /dev/null +++ b/src/app/api/cli-tools/forge-settings/route.js @@ -0,0 +1,142 @@ +"use server"; + +import { NextResponse } from "next/server"; +import fs from "fs/promises"; +import path from "path"; +import os from "os"; +import { exec } from "child_process"; +import { promisify } from "util"; +import { parseTOML, stringifyTOML } from "confbox"; + +const execAsync = promisify(exec); + +const getForgeDir = () => path.join(os.homedir(), ".forge"); +const getForgeConfigPath = () => path.join(getForgeDir(), "config.toml"); + +const checkForgeInstalled = async () => { + const isWindows = os.platform() === "win32"; + try { + const command = isWindows ? "where forge" : "which forge"; + await execAsync(command, { windowsHide: true }); + return true; + } catch { + try { + await fs.access(getForgeConfigPath()); + return true; + } catch { + return false; + } + } +}; + +const has9RouterConfig = (content) => { + if (!content) return false; + return content.includes("managed by 9Router") || content.includes("localhost:20128"); +}; + +const readConfig = async () => { + try { + return await fs.readFile(getForgeConfigPath(), "utf-8"); + } catch { + return null; + } +}; + +export async function GET() { + try { + const installed = await checkForgeInstalled(); + if (!installed) { + return NextResponse.json({ + installed: false, + config: null, + message: "ForgeCode CLI is not installed", + }); + } + + const content = await readConfig(); + let config = null; + try { + if (content) config = parseTOML(content); + } catch {} + + return NextResponse.json({ + installed: true, + config, + has9Router: has9RouterConfig(content), + configPath: getForgeConfigPath(), + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function POST(request) { + let rawBody; + try { + rawBody = await request.json(); + } catch { + return NextResponse.json({ error: { message: "Invalid JSON body" } }, { status: 400 }); + } + + try { + const { baseUrl, apiKey, model } = rawBody || {}; + if (!baseUrl) { + return NextResponse.json({ error: { message: "baseUrl is required" } }, { status: 400 }); + } + + const configPath = getForgeConfigPath(); + await fs.mkdir(getForgeDir(), { recursive: true }); + + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = parseTOML(raw); + } catch {} + + const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`; + + existing.openai = { + api_key: apiKey || "sk_9router", + base_url: normalizedBaseUrl, + model: model || "provider/model-id", + }; + + const header = "# Forge config — managed by 9Router\n\n"; + const content = header + stringifyTOML(existing); + + await fs.writeFile(configPath, content, "utf-8"); + + return NextResponse.json({ + success: true, + message: "ForgeCode settings applied successfully!", + configPath, + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function DELETE() { + try { + const configPath = getForgeConfigPath(); + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = parseTOML(raw); + } catch { + return NextResponse.json({ success: true, message: "No config file to reset" }); + } + + delete existing.openai; + + if (Object.keys(existing).length === 0) { + await fs.rm(configPath, { force: true }); + } else { + await fs.writeFile(configPath, stringifyTOML(existing), "utf-8"); + } + + return NextResponse.json({ success: true, message: "9Router removed from ForgeCode" }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} diff --git a/src/app/api/cli-tools/omp-settings/route.js b/src/app/api/cli-tools/omp-settings/route.js new file mode 100644 index 00000000..52df53e1 --- /dev/null +++ b/src/app/api/cli-tools/omp-settings/route.js @@ -0,0 +1,179 @@ +"use server"; + +import { NextResponse } from "next/server"; +import fs from "fs/promises"; +import path from "path"; +import os from "os"; +import { exec } from "child_process"; +import { promisify } from "util"; + +const execAsync = promisify(exec); + +const PROVIDER_ID = "9router"; +const getOmpDir = () => path.join(os.homedir(), ".omp", "agent"); +const getOmpDbPath = () => path.join(getOmpDir(), "agent.db"); +const getOmpModelsYmlPath = () => path.join(getOmpDir(), "models.yml"); + +const checkOmpInstalled = async () => { + const isWindows = os.platform() === "win32"; + try { + const command = isWindows ? "where omp" : "which omp"; + await execAsync(command, { windowsHide: true }); + return true; + } catch { + try { + await fs.access(getOmpDbPath()); + return true; + } catch { + try { + await fs.access(getOmpModelsYmlPath()); + return true; + } catch { + return false; + } + } + } +}; + +const readModelsYml = async () => { + try { + return await fs.readFile(getOmpModelsYmlPath(), "utf-8"); + } catch { + return ""; + } +}; + +const has9RouterInYml = (content) => { + if (!content) return false; + return content.includes("9router:") || content.includes("localhost:20128"); +}; + +// Build standard 9Router provider block for models.yml +const buildOmpProviderYaml = (baseUrl, apiKey) => { + const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`; + const key = apiKey || "sk_9router"; + return ` ${PROVIDER_ID}: + baseUrl: ${normalizedBaseUrl} + apiKey: ${key} + api: openai-completions + authHeader: true + disableStrictTools: true + discovery: + type: proxy`; +}; + +export async function GET() { + try { + const installed = await checkOmpInstalled(); + if (!installed) { + return NextResponse.json({ + installed: false, + config: null, + message: "Oh My Pi is not installed", + }); + } + + const ymlContent = await readModelsYml(); + const has9Router = has9RouterInYml(ymlContent); + + return NextResponse.json({ + installed: true, + has9Router, + configPath: getOmpModelsYmlPath(), + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function POST(request) { + let rawBody; + try { + rawBody = await request.json(); + } catch { + return NextResponse.json({ error: { message: "Invalid JSON body" } }, { status: 400 }); + } + + try { + const { baseUrl, apiKey } = rawBody || {}; + if (!baseUrl) { + return NextResponse.json({ error: { message: "baseUrl is required" } }, { status: 400 }); + } + + await fs.mkdir(getOmpDir(), { recursive: true }); + + let ymlContent = await readModelsYml(); + const providerBlock = buildOmpProviderYaml(baseUrl, apiKey); + + // Remove existing 9router provider if present + const regex = new RegExp(`\\s*${PROVIDER_ID}:[\\s\\S]*?(?=\\n\\s*\\w+:|$)`, "g"); + ymlContent = ymlContent.replace(regex, ""); + + if (!ymlContent.trim()) { + ymlContent = `providers:\n${providerBlock}\n`; + } else if (ymlContent.includes("providers:")) { + ymlContent = ymlContent.replace(/providers:/, `providers:\n${providerBlock}`); + } else { + ymlContent = `${ymlContent.trim()}\n\nproviders:\n${providerBlock}\n`; + } + + await fs.writeFile(getOmpModelsYmlPath(), ymlContent, "utf-8"); + + // Best-effort update to agent.db if better-sqlite3 or node:sqlite is present + try { + let Database; + try { + const mod = await import("better-sqlite3"); + Database = mod.default || mod; + } catch { + // fallback ignored + } + if (Database) { + const dbPath = getOmpDbPath(); + const db = new Database(dbPath); + db.prepare("DELETE FROM auth_credentials WHERE provider = ?").run(PROVIDER_ID); + db.prepare( + "INSERT INTO auth_credentials (provider, credential_type, data, disabled_cause, identity_key, created_at, updated_at) VALUES (?, ?, ?, NULL, NULL, ?, ?)" + ).run( + PROVIDER_ID, + "api_key", + JSON.stringify({ apiKey: apiKey || "sk_9router", baseUrl }), + Math.floor(Date.now() / 1000), + Math.floor(Date.now() / 1000) + ); + db.close(); + } + } catch { + // Non-critical: models.yml is primary + } + + return NextResponse.json({ + success: true, + message: "Oh My Pi settings applied! Run 'omp' and all 9Router models appear under 9router in /model.", + configPath: getOmpModelsYmlPath(), + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function DELETE() { + try { + let ymlContent = await readModelsYml(); + const regex = new RegExp(`\\s*${PROVIDER_ID}:[\\s\\S]*?(?=\\n\\s*\\w+:|$)`, "g"); + ymlContent = ymlContent.replace(regex, ""); + + if (ymlContent.trim() === "providers:") { + await fs.rm(getOmpModelsYmlPath(), { force: true }); + } else { + await fs.writeFile(getOmpModelsYmlPath(), ymlContent, "utf-8"); + } + + return NextResponse.json({ + success: true, + message: "9Router removed from Oh My Pi", + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} diff --git a/src/app/api/cli-tools/pi-settings/route.js b/src/app/api/cli-tools/pi-settings/route.js new file mode 100644 index 00000000..ee5c507b --- /dev/null +++ b/src/app/api/cli-tools/pi-settings/route.js @@ -0,0 +1,187 @@ +"use server"; + +import { NextResponse } from "next/server"; +import fs from "fs/promises"; +import path from "path"; +import os from "os"; +import { exec } from "child_process"; +import { promisify } from "util"; + +const execAsync = promisify(exec); + +const getPiModelsJsonPath = () => { + const agentPath = path.join(os.homedir(), ".pi", "agent", "models.json"); + return agentPath; +}; + +const getPiDir = () => path.dirname(getPiModelsJsonPath()); + +const checkPiInstalled = async () => { + const isWindows = os.platform() === "win32"; + try { + const command = isWindows ? "where pi" : "which pi"; + await execAsync(command, { windowsHide: true }); + return true; + } catch { + try { + await fs.access(getPiModelsJsonPath()); + return true; + } catch { + try { + await fs.access(path.join(os.homedir(), ".pi", "models.json")); + return true; + } catch { + return false; + } + } + } +}; + +const has9RouterConfig = (settings) => { + if (!settings || !settings.providers) return false; + const p = settings.providers["9router"]; + if (p && p.baseUrl) return true; + for (const prov of Object.values(settings.providers)) { + if (prov.baseUrl && prov.baseUrl.includes("20128")) return true; + } + return false; +}; + +const resolveModelsJsonPath = async () => { + const agentPath = path.join(os.homedir(), ".pi", "agent", "models.json"); + const rootPath = path.join(os.homedir(), ".pi", "models.json"); + try { + await fs.access(agentPath); + return agentPath; + } catch { + try { + await fs.access(rootPath); + return rootPath; + } catch { + return agentPath; + } + } +}; + +const readConfig = async () => { + try { + const targetPath = await resolveModelsJsonPath(); + const content = await fs.readFile(targetPath, "utf-8"); + return JSON.parse(content); + } catch { + return null; + } +}; + +export async function GET() { + try { + const installed = await checkPiInstalled(); + if (!installed) { + return NextResponse.json({ + installed: false, + config: null, + message: "Pi CLI is not installed", + }); + } + + const config = await readConfig(); + const configPath = await resolveModelsJsonPath(); + + return NextResponse.json({ + installed: true, + config, + has9Router: has9RouterConfig(config), + configPath, + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function POST(request) { + let rawBody; + try { + rawBody = await request.json(); + } catch { + return NextResponse.json({ error: { message: "Invalid JSON body" } }, { status: 400 }); + } + + try { + const { baseUrl, apiKey, model } = rawBody || {}; + if (!baseUrl) { + return NextResponse.json({ error: { message: "baseUrl is required" } }, { status: 400 }); + } + + const configPath = await resolveModelsJsonPath(); + await fs.mkdir(path.dirname(configPath), { recursive: true }); + + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = JSON.parse(raw); + } catch { + /* No existing config */ + } + + if (!existing.providers) existing.providers = {}; + + const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`; + let modelList = []; + if (Array.isArray(rawBody.models) && rawBody.models.length > 0) { + modelList = rawBody.models.map((m) => { + if (typeof m === "string") { + return { id: m, name: m, contextWindow: 128000, maxTokens: 16384 }; + } + return { + id: m.id || "provider/model-id", + name: m.name || m.id || "provider/model-id", + contextWindow: m.contextWindow || 128000, + maxTokens: m.maxTokens || 16384, + }; + }); + } else { + const modelId = model || "provider/model-id"; + modelList = [{ id: modelId, name: modelId, contextWindow: 128000, maxTokens: 16384 }]; + } + + existing.providers["9router"] = { + baseUrl: normalizedBaseUrl, + apiKey: apiKey || "sk_9router", + api: "openai-completions", + models: modelList, + }; + + await fs.writeFile(configPath, JSON.stringify(existing, null, 2), "utf-8"); + + return NextResponse.json({ + success: true, + message: "Pi settings applied! Use /model in Pi to select the 9Router model.", + configPath, + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function DELETE() { + try { + const configPath = await resolveModelsJsonPath(); + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = JSON.parse(raw); + } catch { + return NextResponse.json({ success: true, message: "No config file to reset" }); + } + + if (existing.providers && existing.providers["9router"]) { + delete existing.providers["9router"]; + if (Object.keys(existing.providers).length === 0) delete existing.providers; + await fs.writeFile(configPath, JSON.stringify(existing, null, 2), "utf-8"); + } + + return NextResponse.json({ success: true, message: "9Router removed from Pi" }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} diff --git a/src/app/api/cli-tools/smelt-settings/route.js b/src/app/api/cli-tools/smelt-settings/route.js new file mode 100644 index 00000000..6592d0d9 --- /dev/null +++ b/src/app/api/cli-tools/smelt-settings/route.js @@ -0,0 +1,142 @@ +"use server"; + +import { NextResponse } from "next/server"; +import fs from "fs/promises"; +import path from "path"; +import os from "os"; +import { exec } from "child_process"; +import { promisify } from "util"; + +const execAsync = promisify(exec); + +const getSmeltConfigPath = () => path.join(os.homedir(), ".smelt", "config.json"); +const getSmeltDir = () => path.dirname(getSmeltConfigPath()); + +const checkSmeltInstalled = async () => { + const isWindows = os.platform() === "win32"; + try { + const command = isWindows ? "where smelt" : "which smelt"; + await execAsync(command, { windowsHide: true }); + return true; + } catch { + try { + await fs.access(getSmeltConfigPath()); + return true; + } catch { + return false; + } + } +}; + +const has9RouterConfig = (settings) => { + if (!settings) return false; + return ( + settings._managedBy === "9router" || + (typeof settings.baseUrl === "string" && settings.baseUrl.length > 0 && settings.baseUrl.includes("20128")) + ); +}; + +const readConfig = async () => { + try { + const content = await fs.readFile(getSmeltConfigPath(), "utf-8"); + return JSON.parse(content); + } catch { + return null; + } +}; + +export async function GET() { + try { + const installed = await checkSmeltInstalled(); + if (!installed) { + return NextResponse.json({ + installed: false, + config: null, + message: "Smelt CLI is not installed", + }); + } + + const config = await readConfig(); + + return NextResponse.json({ + installed: true, + config, + has9Router: has9RouterConfig(config), + configPath: getSmeltConfigPath(), + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function POST(request) { + let rawBody; + try { + rawBody = await request.json(); + } catch { + return NextResponse.json({ error: { message: "Invalid JSON body" } }, { status: 400 }); + } + + try { + const { baseUrl, apiKey, model } = rawBody || {}; + if (!baseUrl) { + return NextResponse.json({ error: { message: "baseUrl is required" } }, { status: 400 }); + } + + const configPath = getSmeltConfigPath(); + await fs.mkdir(getSmeltDir(), { recursive: true }); + + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = JSON.parse(raw); + } catch {} + + const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`; + const updated = { + ...existing, + baseUrl: normalizedBaseUrl, + apiKey: apiKey || "sk_9router", + model: model || existing.model || "provider/model-id", + _managedBy: "9router", + }; + + await fs.writeFile(configPath, JSON.stringify(updated, null, 2), "utf-8"); + + return NextResponse.json({ + success: true, + message: "Smelt settings applied successfully!", + configPath, + }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} + +export async function DELETE() { + try { + const configPath = getSmeltConfigPath(); + let existing = {}; + try { + const raw = await fs.readFile(configPath, "utf-8"); + existing = JSON.parse(raw); + } catch { + return NextResponse.json({ success: true, message: "No config file to reset" }); + } + + delete existing.baseUrl; + delete existing.apiKey; + delete existing.model; + delete existing._managedBy; + + if (Object.keys(existing).length === 0) { + await fs.rm(configPath, { force: true }); + } else { + await fs.writeFile(configPath, JSON.stringify(existing, null, 2), "utf-8"); + } + + return NextResponse.json({ success: true, message: "Smelt 9Router settings removed" }); + } catch (err) { + return NextResponse.json({ error: { message: err.message } }, { status: 500 }); + } +} diff --git a/src/shared/constants/cliTools.js b/src/shared/constants/cliTools.js index a6bb4685..77c307fb 100644 --- a/src/shared/constants/cliTools.js +++ b/src/shared/constants/cliTools.js @@ -468,6 +468,96 @@ gemini extensions install https://github.com/manalkaff/opendesign # Fetch and follow .opencode/INSTALL.md from the repo`, }, }, + pi: { + id: "pi", + name: "Pi (pi-coding-agent)", + image: "/providers/pi.svg", + color: "#6366F1", + description: "Pi coding agent — minimal, extensible agent harness (pi.dev)", + configType: "custom", + docsUrl: "https://pi.dev", + notes: [ + { + type: "info", + text: "Pi uses ~/.pi/agent/models.json. 9Router is configured under providers.9router as an OpenAI-compatible endpoint.", + }, + ], + }, + omp: { + id: "omp", + name: "Oh My Pi", + image: "/providers/omp.png", + color: "#EC4899", + description: "Oh My Pi terminal AI agent with auto-discovery support", + configType: "custom", + docsUrl: "https://github.com/can1357/oh-my-pi", + notes: [ + { + type: "info", + text: "Oh My Pi uses ~/.omp/agent/models.yml and agent.db. 9Router is configured with proxy discovery so all models appear automatically under /model.", + }, + ], + }, + crush: { + id: "crush", + name: "Crush", + image: "/providers/crush.png", + color: "#FB923C", + description: "Charm Crush terminal AI coding agent", + configType: "custom", + docsUrl: "https://github.com/charmbracelet/crush", + notes: [ + { + type: "info", + text: "Crush uses ~/.config/crush/crush.json. 9Router registers as an openai-compat provider.", + }, + ], + }, + forge: { + id: "forge", + name: "ForgeCode", + image: "/providers/forge.png", + color: "#EAB308", + description: "Antinomy HQ ForgeCode agent harness", + configType: "custom", + docsUrl: "https://github.com/antinomyhq/forge", + notes: [ + { + type: "info", + text: "ForgeCode uses ~/.forge/config.toml. 9Router updates the [openai] section with your baseUrl, apiKey, and model.", + }, + ], + }, + smelt: { + id: "smelt", + name: "Smelt", + image: "/providers/smelt.svg", + color: "#EF4444", + description: "Smelt terminal AI coding assistant", + configType: "custom", + docsUrl: "https://github.com/leonardcser/smelt", + notes: [ + { + type: "info", + text: "Smelt uses ~/.smelt/config.json for OpenAI-compatible endpoint configuration.", + }, + ], + }, + codewhale: { + id: "codewhale", + name: "CodeWhale", + image: "/providers/codewhale.svg", + color: "#4F46E5", + description: "CodeWhale terminal coding agent (successor to DeepSeek TUI)", + configType: "custom", + docsUrl: "https://github.com/Hmbown/CodeWhale", + notes: [ + { + type: "info", + text: "CodeWhale uses ~/.codewhale/config.toml. 9Router configures the [openai] provider with your base_url, api_key, and model.", + }, + ], + }, // HIDDEN: gemini-cli // "gemini-cli": { // id: "gemini-cli", From c73bb2cd669f26a0777e98b9b925fd852136903e Mon Sep 17 00:00:00 2001 From: cokvrindaa <90091811+cokvrindaa@users.noreply.github.com> Date: Tue, 22 Sep 2026 14:53:30 +0700 Subject: [PATCH 26/41] docs(readme): add Indonesian video guide by Neptiver --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b81116b..004082ea 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,14 @@ Default URLs: 🇻🇳 Tiếng Việt
    Hướng Dẫn Setup OpenClaw + 9Router: Tạo Bot Zalo AI Tự Động Từ A-Z
    by tuanminhhole
    - + + + Bye Limit! Cara Bikin Sistem 'AI Unlimited' 100% Gratis Dengan 9Router!
+ +
    + 🇮🇩 Indonesia
    + Bye Limit! Cara Bikin Sistem "AI Unlimited" 100% Gratis Dengan 9Router!
    by neptiver
    + From aa2bc53f3a1f3ba481649bf8f4c5997df1fc55f3 Mon Sep 17 00:00:00 2001 From: rspersahabatan Date: Tue, 22 Sep 2026 14:53:49 +0700 Subject: [PATCH 27/41] docs(readme): add temporary swap instructions for low-memory production builds --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 004082ea..1e4d3386 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,22 @@ PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev Production mode: ```bash +# Create Temporary Memory For Build +sudo fallocate -l 2G /swapfile_temp +sudo chmod 600 /swapfile_temp +sudo mkswap /swapfile_temp +sudo swapon /swapfile_temp + +export MAKEFLAGS="-j1" +export DLIB_NO_GUI_SUPPORT=1 +export CFLAGS="-mno-avx" + npm run build + +# Clear temporary swap +sudo swapoff /swapfile_temp +sudo rm /swapfile_temp + PORT=20128 HOSTNAME=0.0.0.0 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run start ``` From 3279d310243979db33fe412fbbf9253a5694111e Mon Sep 17 00:00:00 2001 From: dajiaohuang Date: Tue, 22 Sep 2026 14:53:42 +0700 Subject: [PATCH 28/41] docs(cli): fix source README link --- cli/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/README.md b/cli/README.md index 050d996a..19ad230f 100644 --- a/cli/README.md +++ b/cli/README.md @@ -111,7 +111,7 @@ Any tool supporting OpenAI/Claude-compatible API works. Full docs, advanced setup, video tutorials & development guide: - **GitHub**: https://github.com/decolua/9router -- **Full README**: https://github.com/decolua/9router/blob/main/app/README.md +- **Full README**: https://github.com/decolua/9router/blob/master/README.md - **Website**: https://9router.com --- From 0d50fe3610ca2e53a7e91a7e2f4f752ff6b40813 Mon Sep 17 00:00:00 2001 From: Ghost Machine <244155089+GhostMachine-ai@users.noreply.github.com> Date: Tue, 22 Sep 2026 14:55:12 +0700 Subject: [PATCH 29/41] feat(analytics): add Requests mode and provider/model breakdown charts --- .../usage/components/ProviderBarChart.js | 107 ++++++++++++++++ .../usage/components/TopModelsChart.js | 114 ++++++++++++++++++ .../dashboard/usage/components/UsageChart.js | 83 +++++++------ src/lib/db/repos/usageRepo.js | 7 +- src/shared/components/UsageStats.js | 10 ++ 5 files changed, 279 insertions(+), 42 deletions(-) create mode 100644 src/app/(dashboard)/dashboard/usage/components/ProviderBarChart.js create mode 100644 src/app/(dashboard)/dashboard/usage/components/TopModelsChart.js diff --git a/src/app/(dashboard)/dashboard/usage/components/ProviderBarChart.js b/src/app/(dashboard)/dashboard/usage/components/ProviderBarChart.js new file mode 100644 index 00000000..12eafa60 --- /dev/null +++ b/src/app/(dashboard)/dashboard/usage/components/ProviderBarChart.js @@ -0,0 +1,107 @@ +"use client"; + +import { useState, useMemo } from "react"; +import PropTypes from "prop-types"; +import { + BarChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, + Cell, +} from "recharts"; +import Card from "@/shared/components/Card"; + +const COLORS = ["#6366f1", "#14b8a6", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4", "#10b981", "#f97316"]; + +const fmtTokens = (n) => { + if (n >= 1000000) return `${(n / 1000000).toFixed(1)}M`; + if (n >= 1000) return `${(n / 1000).toFixed(1)}K`; + return String(n || 0); +}; + +export default function ProviderBarChart({ byProvider }) { + const [viewMode, setViewMode] = useState("tokens"); + + const chartData = useMemo(() => { + if (!byProvider) return []; + return Object.entries(byProvider) + .map(([id, data]) => ({ + name: id, + tokens: (data.promptTokens || 0) + (data.completionTokens || 0), + requests: data.requests || 0, + })) + .filter((d) => d[viewMode] > 0) + .sort((a, b) => b[viewMode] - a[viewMode]); + }, [byProvider, viewMode]); + + const fmt = viewMode === "tokens" ? fmtTokens : String; + const label = viewMode === "tokens" ? "Tokens" : "Requests"; + + return ( + +
    + By Provider +
    + + +
    +
    + + {!chartData.length ? ( +
    No provider usage yet
    + ) : ( + + + + v.length > 10 ? v.slice(0, 10) + "…" : v} + /> + + [fmt(value), label]} + /> + + {chartData.map((_, i) => ( + + ))} + + + + )} +
    + ); +} + +ProviderBarChart.propTypes = { + byProvider: PropTypes.object, +}; diff --git a/src/app/(dashboard)/dashboard/usage/components/TopModelsChart.js b/src/app/(dashboard)/dashboard/usage/components/TopModelsChart.js new file mode 100644 index 00000000..abf87cd7 --- /dev/null +++ b/src/app/(dashboard)/dashboard/usage/components/TopModelsChart.js @@ -0,0 +1,114 @@ +"use client"; + +import { useState, useMemo } from "react"; +import PropTypes from "prop-types"; +import { + BarChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, + Cell, +} from "recharts"; +import Card from "@/shared/components/Card"; + +const COLORS = ["#6366f1", "#14b8a6", "#f59e0b", "#ef4444", "#8b5cf6"]; + +const fmtTokens = (n) => { + if (n >= 1000000) return `${(n / 1000000).toFixed(1)}M`; + if (n >= 1000) return `${(n / 1000).toFixed(1)}K`; + return String(n || 0); +}; + +const truncate = (s, max = 22) => (s && s.length > max ? s.slice(0, max) + "…" : s || ""); + +export default function TopModelsChart({ byModel }) { + const [viewMode, setViewMode] = useState("tokens"); + + const chartData = useMemo(() => { + if (!byModel) return []; + return Object.values(byModel) + .map((data) => ({ + name: truncate(data.rawModel || "Unknown"), + tokens: (data.promptTokens || 0) + (data.completionTokens || 0), + requests: data.requests || 0, + })) + .filter((d) => d[viewMode] > 0) + .sort((a, b) => b[viewMode] - a[viewMode]) + .slice(0, 5); + }, [byModel, viewMode]); + + const fmt = viewMode === "tokens" ? fmtTokens : String; + const label = viewMode === "tokens" ? "Tokens" : "Requests"; + + return ( + +
    + Top Models +
    + + +
    +
    + + {!chartData.length ? ( +
    No model usage yet
    + ) : ( + + + + + + [fmt(value), label]} + /> + + {chartData.map((_, i) => ( + + ))} + + + + )} +
    + ); +} + +TopModelsChart.propTypes = { + byModel: PropTypes.object, +}; diff --git a/src/app/(dashboard)/dashboard/usage/components/UsageChart.js b/src/app/(dashboard)/dashboard/usage/components/UsageChart.js index 14a19c42..8300e97d 100644 --- a/src/app/(dashboard)/dashboard/usage/components/UsageChart.js +++ b/src/app/(dashboard)/dashboard/usage/components/UsageChart.js @@ -10,7 +10,6 @@ import { CartesianGrid, Tooltip, ResponsiveContainer, - Legend, } from "recharts"; import Card from "@/shared/components/Card"; @@ -21,6 +20,19 @@ const fmtTokens = (n) => { }; const fmtCost = (n) => `$${(n || 0).toFixed(4)}`; +const fmtRequests = (n) => String(n || 0); + +const VIEW_MODES = [ + { value: "tokens", label: "Tokens" }, + { value: "requests", label: "Requests" }, + { value: "cost", label: "Cost" }, +]; + +const VIEW_CONFIG = { + tokens: { dataKey: "tokens", color: "#6366f1", gradId: "gradTokens", formatter: fmtTokens, label: "Tokens" }, + requests: { dataKey: "requests", color: "#14b8a6", gradId: "gradRequests", formatter: fmtRequests, label: "Requests" }, + cost: { dataKey: "cost", color: "#f59e0b", gradId: "gradCost", formatter: fmtCost, label: "Cost" }, +}; export default function UsageChart({ period = "7d" }) { const [data, setData] = useState([]); @@ -46,23 +58,24 @@ export default function UsageChart({ period = "7d" }) { fetchData(); }, [fetchData]); - const hasData = data.some((d) => d.tokens > 0 || d.cost > 0); + const cfg = VIEW_CONFIG[viewMode]; + const hasData = data.some((d) => (d[cfg.dataKey] || 0) > 0); return ( -
    - - +
    + {VIEW_MODES.map((m) => ( + + ))}
    {loading ? ( @@ -77,6 +90,10 @@ export default function UsageChart({ period = "7d" }) { + + + + @@ -94,7 +111,7 @@ export default function UsageChart({ period = "7d" }) { tick={{ fontSize: 10, fill: "currentColor", fillOpacity: 0.5 }} tickLine={false} axisLine={false} - tickFormatter={viewMode === "tokens" ? fmtTokens : fmtCost} + tickFormatter={cfg.formatter} width={50} /> - name === "tokens" ? [fmtTokens(value), "Tokens"] : [fmtCost(value), "Cost"] - } + formatter={(value) => [cfg.formatter(value), cfg.label]} + /> + - {viewMode === "tokens" ? ( - - ) : ( - - )} )} diff --git a/src/lib/db/repos/usageRepo.js b/src/lib/db/repos/usageRepo.js index 6b1966cb..0d8aa96f 100644 --- a/src/lib/db/repos/usageRepo.js +++ b/src/lib/db/repos/usageRepo.js @@ -670,7 +670,7 @@ export async function getChartData(period = "7d") { const startTime = startOfDay.getTime(); const endTime = startTime + bucketCount * bucketMs; const labelFn = (ts) => new Date(ts).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }); - const buckets = Array.from({ length: bucketCount }, (_, i) => ({ label: labelFn(startTime + i * bucketMs), tokens: 0, cost: 0 })); + const buckets = Array.from({ length: bucketCount }, (_, i) => ({ label: labelFn(startTime + i * bucketMs), tokens: 0, cost: 0, requests: 0 })); const rows = db.all( `SELECT timestamp, promptTokens, completionTokens, cost FROM usageHistory WHERE timestamp >= ?`, @@ -683,6 +683,7 @@ export async function getChartData(period = "7d") { if (idx >= 0 && idx < bucketCount) { buckets[idx].tokens += (r.promptTokens || 0) + (r.completionTokens || 0); buckets[idx].cost += r.cost || 0; + buckets[idx].requests += 1; } } return buckets; @@ -693,7 +694,7 @@ export async function getChartData(period = "7d") { const bucketMs = 3600000; const labelFn = (ts) => new Date(ts).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }); const startTime = now - bucketCount * bucketMs; - const buckets = Array.from({ length: bucketCount }, (_, i) => ({ label: labelFn(startTime + i * bucketMs), tokens: 0, cost: 0 })); + const buckets = Array.from({ length: bucketCount }, (_, i) => ({ label: labelFn(startTime + i * bucketMs), tokens: 0, cost: 0, requests: 0 })); const rows = db.all( `SELECT timestamp, promptTokens, completionTokens, cost FROM usageHistory WHERE timestamp >= ?`, @@ -705,6 +706,7 @@ export async function getChartData(period = "7d") { const idx = Math.min(Math.floor((t - startTime) / bucketMs), bucketCount - 1); buckets[idx].tokens += (r.promptTokens || 0) + (r.completionTokens || 0); buckets[idx].cost += r.cost || 0; + buckets[idx].requests += 1; } return buckets; } @@ -727,6 +729,7 @@ export async function getChartData(period = "7d") { label: labelFn(d), tokens: dayData ? (dayData.promptTokens || 0) + (dayData.completionTokens || 0) : 0, cost: dayData ? (dayData.cost || 0) : 0, + requests: dayData ? (dayData.requests || 0) : 0, }; }); } diff --git a/src/shared/components/UsageStats.js b/src/shared/components/UsageStats.js index ecab40b1..093c8b3a 100644 --- a/src/shared/components/UsageStats.js +++ b/src/shared/components/UsageStats.js @@ -18,6 +18,8 @@ import dynamic from "next/dynamic"; // Lazy-load: keeps @xyflow/react out of the shared bundle until topology renders const ProviderTopology = dynamic(() => import("@/app/(dashboard)/dashboard/usage/components/ProviderTopology"), { ssr: false }); import UsageChart from "@/app/(dashboard)/dashboard/usage/components/UsageChart"; +import ProviderBarChart from "@/app/(dashboard)/dashboard/usage/components/ProviderBarChart"; +import TopModelsChart from "@/app/(dashboard)/dashboard/usage/components/TopModelsChart"; function timeAgo(timestamp) { const diff = Math.floor((Date.now() - new Date(timestamp)) / 1000); @@ -483,6 +485,14 @@ export default function UsageStats({ period: periodProp, setPeriod: setPeriodPro {/* Token / Cost chart - sync period */} {loading ? spinner : } + {/* Provider and model breakdown charts */} + {!loading && (stats.byProvider || stats.byModel) && ( +
    + + +
    + )} + {/* Table with dropdown selector */}
    From 782c137b1fd6db0928544a1a08d45b435eb9b885 Mon Sep 17 00:00:00 2001 From: yiwen65 <1053909200@qq.com> Date: Tue, 22 Sep 2026 14:58:31 +0700 Subject: [PATCH 30/41] fix(qoder): prevent signed request replay and surface upstream errors --- CHANGELOG.md | 4 ++ open-sse/executors/qoder.js | 76 ++++++++++++-------- tests/unit/qoder-billing.test.js | 23 ++---- tests/unit/qoder-proxy-replay.test.js | 97 ++++++++++++++++++++++++++ tests/unit/qoder-stream-errors.test.js | 81 +++++++++++++++++++++ tests/unit/qoder.test.js | 13 ++-- 6 files changed, 243 insertions(+), 51 deletions(-) create mode 100644 tests/unit/qoder-proxy-replay.test.js create mode 100644 tests/unit/qoder-stream-errors.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ddfcb2..9962eab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## Features - **Qoder CN**: add the `qoder-cn` provider for qoder.com.cn — same device/OAuth flow and COSY-signed chat protocol as intl Qoder, served from the CN gateway (`gateway.qoder.com.cn` / `openapi.qoder.com.cn`). Region resolution is derived from the provider id (`qoder-cn` → CN) across executor, model catalog, quota usage, validation, and the dashboard. +## Fixes +- **Qoder**: prevent proxy failures from silently replaying signed inference requests over a direct connection with the same COSY request ID (`403/103 Duplicate request`). +- **Qoder**: return first-frame upstream errors, including `403/103 Duplicate request`, as HTTP failures instead of assistant text; handle fragmented frames and heartbeat prefixes while preserving billing error mapping. + # v0.5.81 (2026-09-18) ## Features diff --git a/open-sse/executors/qoder.js b/open-sse/executors/qoder.js index da6844f4..f9e7d769 100644 --- a/open-sse/executors/qoder.js +++ b/open-sse/executors/qoder.js @@ -29,7 +29,7 @@ import { BaseExecutor } from "./base.js"; import { PROVIDERS } from "../config/providers.js"; import { proxyAwareFetch } from "../utils/proxyFetch.js"; import { SSE_DONE } from "../utils/sseConstants.js"; -import { FETCH_CONNECT_TIMEOUT_MS } from "../config/runtimeConfig.js"; +import { FETCH_CONNECT_TIMEOUT_MS, HTTP_STATUS } from "../config/runtimeConfig.js"; import { QODER_CHAT_SIG_PATH, QODER_CONTEXT_TIER_ENV, @@ -354,38 +354,47 @@ function isBillingBlock(inner) { } /** - * Peek the first SSE frame to detect billing errors before piping. - * Returns { isBilling, statusVal, message, consumed } — `consumed` is every + * Peek the first SSE data line to detect upstream errors before piping. + * Returns { isError, isBilling, statusVal, message, consumed } — `consumed` is every * byte read so far (including the peeked line) so the caller can re-process * it and nothing is dropped from the stream. */ async function peekFirstQoderFrame(reader, decoder) { let consumed = ""; + let offset = 0; + let upstreamDone = false; while (true) { - const { done, value } = await reader.read(); - if (done) return { isBilling: false, consumed, upstreamDone: true }; + let nl = consumed.indexOf("\n", offset); + if (nl === -1 && !upstreamDone) { + const { done, value } = await reader.read(); + upstreamDone = done; + consumed += done ? decoder.decode() : decoder.decode(value, { stream: true }); + continue; + } + if (offset >= consumed.length) return { isError: false, consumed, upstreamDone }; + if (nl === -1) nl = consumed.length; - consumed += decoder.decode(value, { stream: true }); - const nl = consumed.indexOf("\n"); - if (nl === -1) continue; // need a full line first - - const line = consumed.slice(0, nl).replace(/\r$/, "").trim(); + const line = consumed.slice(offset, nl).replace(/\r$/, "").trim(); + offset = nl + 1; if (!line.startsWith("data:")) continue; const data = line.slice(5).trimStart(); - if (data === "[DONE]") return { isBilling: false, consumed }; + if (data === "[DONE]") return { isError: false, consumed, upstreamDone }; let envelope; - try { envelope = JSON.parse(data); } catch { return { isBilling: false, consumed }; } + try { envelope = JSON.parse(data); } catch { return { isError: false, consumed, upstreamDone }; } + // statusCodeValue is documented numeric, but accept numeric strings defensively. - const statusVal = Number(envelope.statusCodeValue) || 200; - const inner = typeof envelope.body === "string" + const raw = Number(envelope?.statusCodeValue); + const statusVal = Number.isNaN(raw) ? 200 : raw; + const inner = typeof envelope?.body === "string" ? envelope.body - : envelope.body != null ? JSON.stringify(envelope.body) : ""; - if (statusVal !== 200 && isBillingBlock(inner)) { - return { isBilling: true, statusVal, message: inner || `qoder billing block (${statusVal})` }; + : envelope?.body != null ? JSON.stringify(envelope.body) : ""; + + if (statusVal !== 200) { + return { isError: true, isBilling: isBillingBlock(inner), statusVal, message: inner || `upstream status ${statusVal}` }; } - return { isBilling: false, consumed }; + return { isError: false, consumed, upstreamDone }; } } @@ -396,8 +405,8 @@ async function peekFirstQoderFrame(reader, decoder) { * Each upstream line looks like: * data: {"statusCodeValue":200,"body":"{\"choices\":[{\"delta\":{...}}]}"} * The inner body is an OpenAI streaming chunk (or "[DONE]"). We unwrap it - * and re-emit as `data: \n\n`. Errors become a synthetic OpenAI error - * chunk + [DONE]. + * and re-emit as `data: \n\n`. First-frame errors become HTTP errors; + * errors after streaming starts retain the synthetic chunk + [DONE] path. * * Critical: Qoder's SSE often keeps the socket open after the terminal * [DONE]/error frame (agent keepalive). Non-streaming clients drain via @@ -409,9 +418,10 @@ async function peekFirstQoderFrame(reader, decoder) { * usage from the finish chunk, so we coalesce those two frames (see * createQoderSseCoalescer) before forwarding. * - * NEW: Peek first frame to detect billing blocks (code 112/10605/pricingUrl). - * If detected, return 403 response so chatCore marks connection unavailable - * and triggers combo fallback instead of leaking error text into chat. + * Peek the first frame for errors before committing to HTTP 200. Preserve + * upstream error statuses so chatCore can handle failures instead of recording + * error text as a successful completion. Billing blocks retain the existing + * 403 mapping for quota/account fallback. */ async function wrapQoderSSE(response, model, log = null) { if (!response.ok || !response.body) return response; @@ -419,14 +429,17 @@ async function wrapQoderSSE(response, model, log = null) { const decoder = new TextDecoder(); const reader = response.body.getReader(); - // Peek first frame to detect billing block + // Detect errors before returning a successful streaming response. const peek = await peekFirstQoderFrame(reader, decoder); - if (peek?.isBilling) { - // Billing block detected — return 403 so chatCore fails this connection + if (peek.isError) { await reader.cancel().catch(() => {}); + const status = peek.isBilling + ? HTTP_STATUS.FORBIDDEN + : Number.isInteger(peek.statusVal) && peek.statusVal >= HTTP_STATUS.BAD_REQUEST && peek.statusVal <= 599 + ? peek.statusVal : HTTP_STATUS.BAD_GATEWAY; return new Response( JSON.stringify({ error: { message: peek.message, code: peek.statusVal } }), - { status: 403, headers: { "Content-Type": "application/json" } } + { status, headers: { "Content-Type": "application/json" } } ); } @@ -699,8 +712,15 @@ export class QoderExecutor extends BaseExecutor { response = await proxyAwareFetch( url, { method: "POST", headers, body: encodedBodyBuf, signal: mergedSignal }, - proxyOptions, + // A failed proxy request may already have reached Qoder. Replaying + // the same COSY signature directly reuses its requestId and returns + // 403/code 103. Let the caller retry through execute() with fresh signing. + { ...proxyOptions, strictProxy: true }, ); + } catch (err) { + // strictProxy wraps transport errors; retain caller cancellation semantics. + if (mergedSignal.aborted) throw mergedSignal.reason; + throw err; } finally { clearTimeout(connectTimer); } diff --git a/tests/unit/qoder-billing.test.js b/tests/unit/qoder-billing.test.js index d7c5482e..4900f2df 100644 --- a/tests/unit/qoder-billing.test.js +++ b/tests/unit/qoder-billing.test.js @@ -236,7 +236,7 @@ describe("wrapQoderSSE billing detection", () => { expect(wrapped.status).toBe(403); }); - it("passes through normal errors (non-billing) as wrapped SSE", async () => { + it("returns non-billing errors with their upstream HTTP status", async () => { const errorEnv = JSON.stringify({ statusCodeValue: 500, body: "Internal server error", @@ -245,22 +245,11 @@ describe("wrapQoderSSE billing detection", () => { const wrapped = await wrapQoderSSE(makeResponse([upstream]), "qoder/ultimate"); - // Normal error: still 200 response, error text in SSE body - expect(wrapped.status).toBe(200); - expect(wrapped.ok).toBe(true); - - const reader = wrapped.body.getReader(); - const decoder = new TextDecoder(); - let buf = ""; - while (true) { - const { done, value } = await reader.read(); - if (done) break; - buf += decoder.decode(value, { stream: true }); - } - buf += decoder.decode(); - - expect(buf).toContain("[qoder error 500"); - expect(buf).toContain("data: [DONE]"); + expect(wrapped.status).toBe(500); + expect(wrapped.ok).toBe(false); + expect(await wrapped.json()).toEqual({ + error: { message: "Internal server error", code: 500 }, + }); }); it("passes through successful responses unchanged", async () => { diff --git a/tests/unit/qoder-proxy-replay.test.js b/tests/unit/qoder-proxy-replay.test.js new file mode 100644 index 00000000..1a3ff0c6 --- /dev/null +++ b/tests/unit/qoder-proxy-replay.test.js @@ -0,0 +1,97 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +vi.mock("../../open-sse/services/qoderModels.js", () => ({ + getQoderModelConfig: vi.fn(async () => ({ key: "auto", max_output_tokens: 32 })), + resolveQoderModels: vi.fn(), + isQoderPat: () => false, + resolveQoderCredentials: vi.fn(), +})); + +const request = { + model: "auto", + body: { messages: [{ role: "user", content: "hello" }], max_tokens: 32 }, + stream: true, + credentials: { + accessToken: "dt-test-token", + providerSpecificData: { userId: "test-user", machineId: "test-machine" }, + }, +}; + +function success() { + return new Response('data: {"statusCodeValue":200,"body":"[DONE]"}\n\n', { + headers: { "Content-Type": "text/event-stream" }, + }); +} + +async function loadExecutor(fetchMock, useProxy = true) { + vi.resetModules(); + for (const key of ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "all_proxy", "no_proxy"]) { + vi.stubEnv(key, ""); + } + if (useProxy) vi.stubEnv("HTTPS_PROXY", "http://proxy.test:3128"); + // Exercise the real proxyAwareFetch: it captures fetch when imported. + vi.stubGlobal("fetch", fetchMock); + const { QoderExecutor } = await import("../../open-sse/executors/qoder.js"); + return new QoderExecutor(); +} + +afterEach(() => { + vi.unstubAllGlobals(); + vi.unstubAllEnvs(); +}); + +describe("Qoder signed inference transport", () => { + it.each([null, { strictProxy: false }])("does not replay a signed POST after proxy response loss (%j)", async (proxyOptions) => { + const seen = new Set(); + const fetchMock = vi.fn(async (_url, options) => { + const authorization = options.headers.Authorization; + if (seen.has(authorization)) { + return new Response('data: {"statusCodeValue":403,"body":"{\\"code\\":\\"103\\",\\"message\\":\\"Duplicate request\\"}"}\n\n'); + } + seen.add(authorization); + throw new TypeError("response lost after upstream accepted request"); + }); + const executor = await loadExecutor(fetchMock); + await expect(executor.execute({ ...request, proxyOptions })).rejects.toThrow("response lost"); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(fetchMock.mock.calls[0][1].dispatcher).toBeDefined(); + if (proxyOptions) expect(proxyOptions.strictProxy).toBe(false); + }); + + it("generates a fresh COSY identity when the caller retries after transport failure", async () => { + const fetchMock = vi.fn() + .mockRejectedValueOnce(new TypeError("response lost")) + .mockResolvedValueOnce(success()); + const executor = await loadExecutor(fetchMock); + await expect(executor.execute(request)).rejects.toThrow("response lost"); + const result = await executor.execute(request); + expect(result.response.ok).toBe(true); + await result.response.text(); + expect(fetchMock).toHaveBeenCalledTimes(2); + const ids = fetchMock.mock.calls.map(([, options]) => JSON.parse( + Buffer.from(options.headers.Authorization.split(".")[1], "base64").toString(), + ).requestId); + expect(ids[0]).not.toBe(ids[1]); + }); + + it.each([true, false])("still supports successful inference with proxy=%s", async (useProxy) => { + const fetchMock = vi.fn(async () => success()); + const executor = await loadExecutor(fetchMock, useProxy); + const result = await executor.execute(request); + expect(result.response.ok).toBe(true); + await result.response.text(); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(!!fetchMock.mock.calls[0][1].dispatcher).toBe(useProxy); + }); + + it("preserves caller cancellation without replaying the request", async () => { + const controller = new AbortController(); + const fetchMock = vi.fn(async (_url, options) => { + controller.abort(); + throw options.signal.reason; + }); + const executor = await loadExecutor(fetchMock); + await expect(executor.execute({ ...request, signal: controller.signal })).rejects.toMatchObject({ name: "AbortError" }); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/tests/unit/qoder-stream-errors.test.js b/tests/unit/qoder-stream-errors.test.js new file mode 100644 index 00000000..60b316b0 --- /dev/null +++ b/tests/unit/qoder-stream-errors.test.js @@ -0,0 +1,81 @@ +import { describe, it, expect, vi } from "vitest"; +import { __test__ } from "../../open-sse/executors/qoder.js"; + +const { wrapQoderSSE } = __test__; +const duplicate = '{"code":"103","message":"Duplicate request"}'; +const frame = (statusCodeValue, body) => `data: ${JSON.stringify({ statusCodeValue, body })}\n\n`; + +function upstream(chunks, { keepOpen = false } = {}) { + const cancel = vi.fn(); + const response = new Response(new ReadableStream({ + start(controller) { + for (const chunk of chunks) controller.enqueue(new TextEncoder().encode(chunk)); + if (!keepOpen) controller.close(); + }, + cancel, + })); + return { response, cancel }; +} + +describe("Qoder first-frame errors", () => { + it.each([ + ["one chunk", [frame(403, duplicate)]], + ["fragmented frame", [frame(403, duplicate).slice(0, 35), frame(403, duplicate).slice(35)]], + ["heartbeat prefix", [": keepalive\r\n\r\n", frame(403, duplicate)]], + ["prefix and frame in one chunk", [": keepalive\n\nevent: message\n" + frame(403, duplicate)]], + ["EOF without newline", [frame(403, duplicate).trimEnd()]], + ["object body", [frame(403, JSON.parse(duplicate))]], + ])("surfaces duplicate-request errors as HTTP 403: %s", async (_name, chunks) => { + const { response } = upstream(chunks); + const wrapped = await wrapQoderSSE(response, "qoder/kmodel_latest"); + expect(wrapped.status).toBe(403); + expect(wrapped.ok).toBe(false); + expect(wrapped.headers.get("content-type")).toBe("application/json"); + const body = await wrapped.json(); + expect(body.error.message).toBe(duplicate); + expect(body).not.toHaveProperty("choices"); + }); + + it("cancels the upstream keepalive immediately after an error", async () => { + const { response, cancel } = upstream([": keepalive\n\n", frame(403, duplicate)], { keepOpen: true }); + const wrapped = await wrapQoderSSE(response, "qoder/kmodel_latest"); + expect(wrapped.status).toBe(403); + expect(cancel).toHaveBeenCalledOnce(); + }); + + it.each([401, 429, 500, 503])("preserves non-billing HTTP status %s", async (status) => { + const { response } = upstream([frame(status, "upstream failure")]); + const wrapped = await wrapQoderSSE(response, "qoder/auto"); + expect(wrapped.status).toBe(status); + expect((await wrapped.json()).error.message).toBe("upstream failure"); + }); + + it.each([0, 302, 600, 403.5])("maps invalid error status %s to 502", async (status) => { + const { response } = upstream([frame(status, "invalid upstream status")]); + const wrapped = await wrapQoderSSE(response, "qoder/auto"); + expect(wrapped.status).toBe(502); + }); + + it("replays successful frames after a heartbeat without losing or duplicating content", async () => { + const first = JSON.stringify({ choices: [{ delta: { content: "hello" } }] }); + const second = JSON.stringify({ choices: [{ delta: { content: "world" } }] }); + const { response } = upstream([": keepalive\n\n", frame(200, first) + frame(200, second) + "data: [DONE]\n\n"]); + const wrapped = await wrapQoderSSE(response, "qoder/auto"); + expect(wrapped.status).toBe(200); + expect(await wrapped.text()).toBe(`data: ${first}\n\ndata: ${second}\n\ndata: [DONE]\n\n`); + }); + + it("starts forwarding success without waiting for the upstream to close", async () => { + const inner = JSON.stringify({ choices: [{ delta: { content: "hello" } }] }); + const { response, cancel } = upstream([": keepalive\n\n", frame(200, inner)], { keepOpen: true }); + const wrapped = await wrapQoderSSE(response, "qoder/auto"); + const reader = wrapped.body.getReader(); + try { + const { value } = await reader.read(); + expect(new TextDecoder().decode(value)).toBe(`data: ${inner}\n\n`); + } finally { + await reader.cancel(); + } + expect(cancel).toHaveBeenCalledOnce(); + }); +}); diff --git a/tests/unit/qoder.test.js b/tests/unit/qoder.test.js index 5f8246e8..ce7edd67 100644 --- a/tests/unit/qoder.test.js +++ b/tests/unit/qoder.test.js @@ -506,14 +506,14 @@ describe("wrapQoderSSE", () => { // Regression for review finding #3: chunks could leak past [DONE] when // the success branch had no doneEmitted guard. We synthesize an error - // envelope (which sets doneEmitted=true) followed by a valid envelope + // envelope after content (which sets doneEmitted=true), followed by a valid envelope // and assert the second envelope is NOT forwarded. it("does not forward chunks after [DONE] has been emitted", async () => { const errorEnv = JSON.stringify({ statusCodeValue: 500, body: "boom" }); const validInner = JSON.stringify({ choices: [{ delta: { content: "leak" } }] }); const validEnv = JSON.stringify({ statusCodeValue: 200, body: validInner }); const wrapped = await wrapQoderSSE( - makeResponse([`data: ${errorEnv}\n\ndata: ${validEnv}\n\n`]), + makeResponse([envelope(JSON.stringify({ choices: [{ delta: { content: "hi" } }] })) + `data: ${errorEnv}\n\ndata: ${validEnv}\n\n`]), "qoder/auto", ); const out = await drain(wrapped); @@ -539,12 +539,13 @@ describe("wrapQoderSSE", () => { expect(() => JSON.parse(dataLine.slice("data: ".length))).not.toThrow(); }); - it("upstream error envelope produces an error chunk + [DONE]", async () => { + it("upstream first-frame error envelope produces an HTTP error", async () => { const env = JSON.stringify({ statusCodeValue: 503, body: "service unavailable" }); const wrapped = await wrapQoderSSE(makeResponse([`data: ${env}\n\n`]), "qoder/lite"); - const out = await drain(wrapped); - expect(out).toContain("[qoder error 503"); - expect(out).toContain("data: [DONE]\n\n"); + expect(wrapped.status).toBe(503); + expect(await wrapped.json()).toEqual({ + error: { message: "service unavailable", code: 503 }, + }); }); it("non-ok responses are returned unchanged (no transform)", async () => { From 5798b308419d3798a706b2756e39d59dda9d8a29 Mon Sep 17 00:00:00 2001 From: BFLabsAI Date: Tue, 22 Sep 2026 15:04:03 +0700 Subject: [PATCH 31/41] fix(antigravity): drop requestType "agent" to avoid false 429 RESOURCE_EXHAUSTED --- open-sse/executors/antigravity.js | 9 ++++++++- open-sse/translator/request/openai-to-gemini.js | 12 +++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/open-sse/executors/antigravity.js b/open-sse/executors/antigravity.js index da4a7981..b8a25eed 100644 --- a/open-sse/executors/antigravity.js +++ b/open-sse/executors/antigravity.js @@ -293,12 +293,19 @@ export class AntigravityExecutor extends BaseExecutor { this._lastSessionId = transformedRequest.sessionId; // cached for buildHeaders (base.execute order) + // Official Antigravity client omits `requestType` entirely on the agent + // (chat) path. Sending `requestType: "agent"` here (or leaking it through + // from an upstream envelope via the ...body spread below) makes Google + // bucket the request and return a detail-free 429 RESOURCE_EXHAUSTED even + // with quota available. `image_gen` and + // `search` buckets are unaffected and keep their own requestType. + delete body.requestType; + return { ...body, project: projectId, model: body.model || model, userAgent: "antigravity", - requestType: "agent", requestId: buildIdeRequestId({ body, request: transformedRequest, credentials, model, requestType: "agent" }), request: transformedRequest }; diff --git a/open-sse/translator/request/openai-to-gemini.js b/open-sse/translator/request/openai-to-gemini.js index 305eaca0..918ba9c4 100644 --- a/open-sse/translator/request/openai-to-gemini.js +++ b/open-sse/translator/request/openai-to-gemini.js @@ -279,10 +279,11 @@ function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigra } }; - // Antigravity specific fields - if (isAntigravity) { - envelope.requestType = "agent"; - } else { + // Antigravity specific fields. + // NOTE: the official Antigravity client omits `requestType` entirely on the + // agent (chat) path. Sending `requestType: "agent"` triggers a detail-free + // 429 RESOURCE_EXHAUSTED even with quota available. + if (!isAntigravity) { // Keep safetySettings for Gemini CLI envelope.request.safetySettings = geminiCLI.safetySettings; } @@ -305,7 +306,8 @@ function wrapInCloudCodeEnvelopeForClaude(model, claudeRequest, credentials = nu model: model, userAgent: "antigravity", requestId: `agent-${generateUUID()}`, - requestType: "agent", + // NOTE: official Antigravity client omits `requestType` on the agent (chat) + // path — see the note in wrapInCloudCodeEnvelope() above. request: { sessionId: toNumericSessionId(credentials?._clientSessionId) || deriveSessionId(credentials?.email || credentials?.connectionId), contents: [], From ce9ac43da55ffa2f7852549f264a518c5e62dca1 Mon Sep 17 00:00:00 2001 From: decolua Date: Tue, 22 Sep 2026 15:08:09 +0700 Subject: [PATCH 32/41] style(sidebar): match NEW badge style across 9Remote, Media Providers, and System One Co-Authored-By: Claude Code --- src/shared/components/Sidebar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/components/Sidebar.js b/src/shared/components/Sidebar.js index 35851b56..716f59fb 100644 --- a/src/shared/components/Sidebar.js +++ b/src/shared/components/Sidebar.js @@ -224,7 +224,7 @@ export default function Sidebar({ onClose }) { {kind.icon} {kind.label} {kind.isNew && ( - NEW + NEW )} ))} @@ -309,8 +309,8 @@ export default function Sidebar({ onClose }) { computer 9Remote - - New + + NEW From d1de324586ff0e2511f1f29c22be09f379963b84 Mon Sep 17 00:00:00 2001 From: Rafli Ahmad Zulfikar Date: Tue, 22 Sep 2026 15:06:03 +0700 Subject: [PATCH 33/41] perf(usage): bound lastUsed overlay scan to 2-day window; reach max thinking tier getUsageStats("all") shipped the entire usageHistory table to JS just to refine lastUsed (~2s on 290K rows, on every statsEmitter update per SSE listener). Bound the overlay to a 2-day indexed range scan; older entries keep day-level lastUsed from usageDaily aggregates. Totals unaffected. budgetToLevel now maps budgets > 80384 (midpoint of 32768/128000) to "max" instead of clamping to "xhigh", so the top reasoning tier is reachable from large budget_tokens requests. --- open-sse/translator/concerns/thinking.js | 5 ++- src/lib/db/repos/usageRepo.js | 11 +++++- tests/unit/thinking-budget-max-level.test.js | 39 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tests/unit/thinking-budget-max-level.test.js diff --git a/open-sse/translator/concerns/thinking.js b/open-sse/translator/concerns/thinking.js index 3db892c4..4bcf559c 100644 --- a/open-sse/translator/concerns/thinking.js +++ b/open-sse/translator/concerns/thinking.js @@ -34,6 +34,8 @@ export function effortToThinkingLevel(effort) { // Numeric budget → nearest discrete level (reverse map via thresholds). // Returns null when budget <= 0 (no reasoning). +// Thresholds are midpoints between LEVEL_TO_BUDGET values: max (128000) is +// reachable, with the xhigh/max boundary at the 32768/128000 midpoint (80384). export function budgetToLevel(budget) { const b = Number(budget); if (!b || b <= 0) return null; @@ -41,7 +43,8 @@ export function budgetToLevel(budget) { if (b <= 4096) return "low"; if (b <= 16384) return "medium"; if (b <= 28672) return "high"; - return "xhigh"; + if (b <= 80384) return "xhigh"; + return "max"; } // Gemini thinkingBudget (numeric) → OpenAI reasoning_effort (antigravity reverse map). diff --git a/src/lib/db/repos/usageRepo.js b/src/lib/db/repos/usageRepo.js index 0d8aa96f..75267847 100644 --- a/src/lib/db/repos/usageRepo.js +++ b/src/lib/db/repos/usageRepo.js @@ -537,8 +537,15 @@ export async function getUsageStats(period = "all") { } } - // Overlay precise lastUsed timestamps from history - const overlayCutoff = maxDays ? Date.now() - maxDays * 86400000 : 0; + // Overlay precise lastUsed timestamps from history. + // ponytail: overlay scans only a recent window; entries older than that keep + // day-level lastUsed from usageDaily. Upgrade to a materialized per-key + // MAX(timestamp) table if exact old timestamps ever matter. + const OVERLAY_WINDOW_MS = 2 * 86400000; + const overlayCutoff = Math.max( + maxDays ? Date.now() - maxDays * 86400000 : 0, + Date.now() - OVERLAY_WINDOW_MS + ); const histRows = db.all( `SELECT timestamp, provider, model, connectionId, apiKey, endpoint FROM usageHistory WHERE timestamp >= ?`, [new Date(overlayCutoff).toISOString()] diff --git a/tests/unit/thinking-budget-max-level.test.js b/tests/unit/thinking-budget-max-level.test.js new file mode 100644 index 00000000..c098ab91 --- /dev/null +++ b/tests/unit/thinking-budget-max-level.test.js @@ -0,0 +1,39 @@ +import { describe, expect, it } from "vitest"; +import { budgetToLevel } from "../../open-sse/translator/concerns/thinking.js"; +import { applyThinking } from "../../open-sse/translator/concerns/thinkingUnified.js"; +import { FORMATS } from "../../open-sse/translator/formats.js"; + +// Reverse map must be able to reach "max": LEVEL_TO_BUDGET.max = 128000 and +// xhigh = 32768, so the xhigh/max threshold is their midpoint (80384). +// Previously any budget > 28672 collapsed to "xhigh", making "max" +// unreachable from Claude Code budget_tokens — its default thinking budget +// (MAX_THINKING_TOKENS) could never produce effort "max". +describe("budgetToLevel reaches max tier", () => { + it("budget 98304 → \"max\"", () => { + expect(budgetToLevel(98304)).toBe("max"); + }); + + it("budget 128000 → \"max\"", () => { + expect(budgetToLevel(128000)).toBe("max"); + }); + + it("budget 80385 → \"max\" (just above midpoint)", () => { + expect(budgetToLevel(80385)).toBe("max"); + }); + + it("budget 80384 → \"xhigh\" (midpoint still xhigh)", () => { + expect(budgetToLevel(80384)).toBe("xhigh"); + }); + + it("budget 31999 stays \"xhigh\"", () => { + expect(budgetToLevel(31999)).toBe("xhigh"); + }); +}); + +describe("applyThinking (openai-responses): large budgets map to max effort", () => { + it("budget 98304 → reasoning_effort \"max\" for gpt-5.6-sol (openai wire)", () => { + const body = { thinking: { type: "enabled", budget_tokens: 98304 } }; + const out = applyThinking(FORMATS.OPENAI_RESPONSES, "gpt-5.6-sol", body, "codex"); + expect(out?.reasoning_effort).toBe("max"); + }); +}); From b53260ca54b52ec5652a0ec3946ef3f8d09abe07 Mon Sep 17 00:00:00 2001 From: decolua Date: Tue, 22 Sep 2026 15:31:24 +0700 Subject: [PATCH 34/41] feat(usage): add All Time period option and refine overview cards - Add "all" period option to usage dashboard and chart API - Aggregate all days in getChartData when period is "all" - Center overview card metrics and adjust font size to prevent truncation Co-Authored-By: Claude Code --- .../usage/components/OverviewCards.js | 30 ++++++++--------- src/app/(dashboard)/dashboard/usage/page.js | 1 + src/app/api/usage/chart/route.js | 2 +- src/lib/db/repos/usageRepo.js | 32 +++++++++++++++++-- src/shared/components/UsageStats.js | 3 +- 5 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js b/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js index 22020ff2..5d64c085 100644 --- a/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js +++ b/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js @@ -9,25 +9,25 @@ const fmtCost = (n) => `$${(n || 0).toFixed(2)}`; export default function OverviewCards({ stats }) { return (
    - - Total Requests - {fmt(stats.totalRequests)} + + Total Requests + {fmt(stats.totalRequests)} - - Total Input Tokens - {fmt(stats.totalPromptTokens)} + + Total Input Tokens + {fmt(stats.totalPromptTokens)} - - Cached Tokens - {fmt(stats.totalCachedTokens)} + + Cached Tokens + {fmt(stats.totalCachedTokens)} - - Output Tokens - {fmt(stats.totalCompletionTokens)} + + Output Tokens + {fmt(stats.totalCompletionTokens)} - - Est. Cost - ~{fmtCost(stats.totalCost)} + + Est. Cost + ~{fmtCost(stats.totalCost)} Estimated, not actual billing
    diff --git a/src/app/(dashboard)/dashboard/usage/page.js b/src/app/(dashboard)/dashboard/usage/page.js index 075b211a..2b43198b 100644 --- a/src/app/(dashboard)/dashboard/usage/page.js +++ b/src/app/(dashboard)/dashboard/usage/page.js @@ -11,6 +11,7 @@ const PERIODS = [ { value: "7d", label: "7D" }, { value: "30d", label: "30D" }, { value: "60d", label: "60D" }, + { value: "all", label: "All" }, ]; export default function UsagePage() { diff --git a/src/app/api/usage/chart/route.js b/src/app/api/usage/chart/route.js index 063cedd6..0321c3a4 100644 --- a/src/app/api/usage/chart/route.js +++ b/src/app/api/usage/chart/route.js @@ -1,7 +1,7 @@ import { NextResponse } from "next/server"; import { getChartData } from "@/lib/usageDb"; -const VALID_PERIODS = new Set(["today", "24h", "7d", "30d", "60d"]); +const VALID_PERIODS = new Set(["today", "24h", "7d", "30d", "60d", "all"]); export async function GET(request) { try { diff --git a/src/lib/db/repos/usageRepo.js b/src/lib/db/repos/usageRepo.js index 75267847..2f86ff14 100644 --- a/src/lib/db/repos/usageRepo.js +++ b/src/lib/db/repos/usageRepo.js @@ -335,12 +335,12 @@ export async function getUsageHistory(filter = {}) { function loadDaysInRange(adapter, maxDays) { if (maxDays == null) { - return adapter.all(`SELECT dateKey, data FROM usageDaily`); + return adapter.all(`SELECT dateKey, data FROM usageDaily ORDER BY dateKey ASC`); } const today = new Date(); const cutoff = new Date(today.getFullYear(), today.getMonth(), today.getDate() - maxDays + 1); const cutoffKey = `${cutoff.getFullYear()}-${String(cutoff.getMonth() + 1).padStart(2, "0")}-${String(cutoff.getDate()).padStart(2, "0")}`; - return adapter.all(`SELECT dateKey, data FROM usageDaily WHERE dateKey >= ?`, [cutoffKey]); + return adapter.all(`SELECT dateKey, data FROM usageDaily WHERE dateKey >= ? ORDER BY dateKey ASC`, [cutoffKey]); } export async function getUsageStats(period = "all") { @@ -718,9 +718,35 @@ export async function getChartData(period = "7d") { return buckets; } + const labelFn = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric" }); + + if (period === "all") { + const dayRows = loadDaysInRange(db, null); + if (!dayRows.length) return []; + const dayMap = {}; + for (const r of dayRows) dayMap[r.dateKey] = parseJson(r.data, {}); + + const earliest = new Date(dayRows[0].dateKey + "T00:00:00"); + const today = new Date(); + today.setHours(0, 0, 0, 0); + const diffDays = Math.max(1, Math.round((today - earliest) / 86400000) + 1); + + return Array.from({ length: diffDays }, (_, i) => { + const d = new Date(earliest); + d.setDate(d.getDate() + i); + const dateKey = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; + const dayData = dayMap[dateKey]; + return { + label: labelFn(d), + tokens: dayData ? (dayData.promptTokens || 0) + (dayData.completionTokens || 0) : 0, + cost: dayData ? (dayData.cost || 0) : 0, + requests: dayData ? (dayData.requests || 0) : 0, + }; + }); + } + const bucketCount = period === "7d" ? 7 : period === "30d" ? 30 : 60; const today = new Date(); - const labelFn = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric" }); // Build map of dateKey → day data const dayRows = loadDaysInRange(db, bucketCount); diff --git a/src/shared/components/UsageStats.js b/src/shared/components/UsageStats.js index 093c8b3a..bcac0bad 100644 --- a/src/shared/components/UsageStats.js +++ b/src/shared/components/UsageStats.js @@ -200,6 +200,7 @@ const PERIODS = [ { value: "7d", label: "7D" }, { value: "30d", label: "30D" }, { value: "60d", label: "60D" }, + { value: "all", label: "All" }, ]; export default function UsageStats({ period: periodProp, setPeriod: setPeriodProp, hidePeriodSelector = false } = {}) { @@ -448,7 +449,7 @@ export default function UsageStats({ period: periodProp, setPeriod: setPeriodPro {/* Period selector (hidden when controlled by parent) */} {!hidePeriodSelector && (
    -
    +
    {PERIODS.map((p) => ( -
    +
    diff --git a/src/lib/db/repos/settingsRepo.js b/src/lib/db/repos/settingsRepo.js index b94f770a..8b8023f0 100644 --- a/src/lib/db/repos/settingsRepo.js +++ b/src/lib/db/repos/settingsRepo.js @@ -86,6 +86,16 @@ export function mergeWithDefaults(raw) { } } } + if (merged.capacityAdapter && typeof merged.capacityAdapter === "object") { + for (const capKey of Object.keys(merged.capacityAdapter)) { + const entry = merged.capacityAdapter[capKey]; + if (Array.isArray(entry?.models)) { + entry.models = entry.models.map((m) => + m === "oc/mimo-v2.5-free" ? "oc/mimo-v2.6-flash-free" : m + ); + } + } + } return merged; } From 0f488c702706154b2a2c1a95b0f1dcb6ffcfeaa1 Mon Sep 17 00:00:00 2001 From: Welington Date: Tue, 22 Sep 2026 15:25:09 +0700 Subject: [PATCH 36/41] fix(translator): map Claude "refusal" stop_reason to content_filter and surface its explanation Anthropic's API-level refusal (streaming classifier / ToS) ends the stream with stop_reason "refusal", stop_details carrying the reason, zero output tokens and no content blocks. Map refusal to content_filter in both directions, surface stop_details.explanation as message text, and add CLAUDE_STOP.REFUSAL to schema. --- open-sse/translator/concerns/finishReason.js | 5 ++ .../translator/response/claude-to-openai.js | 7 ++ open-sse/translator/schema/finishReasons.js | 3 + tests/unit/claude-refusal-stream.test.js | 76 +++++++++++++++++++ tests/unit/finish-reason-concern.test.js | 6 ++ 5 files changed, 97 insertions(+) create mode 100644 tests/unit/claude-refusal-stream.test.js diff --git a/open-sse/translator/concerns/finishReason.js b/open-sse/translator/concerns/finishReason.js index 684a7001..6bfd021b 100644 --- a/open-sse/translator/concerns/finishReason.js +++ b/open-sse/translator/concerns/finishReason.js @@ -11,6 +11,10 @@ export function toOpenAIFinish(reason, format) { case CLAUDE_STOP.MAX_TOKENS: return OPENAI_FINISH.LENGTH; case CLAUDE_STOP.TOOL_USE: return OPENAI_FINISH.TOOL_CALLS; case CLAUDE_STOP.STOP_SEQUENCE: return OPENAI_FINISH.STOP; + // A refusal is a blocked turn, not a clean stop: with the default mapping an + // OpenAI client saw finish_reason "stop" and an empty message (9Router logged + // "succeeded", OUT 0) and could not tell it from a real answer. + case CLAUDE_STOP.REFUSAL: return OPENAI_FINISH.CONTENT_FILTER; default: return OPENAI_FINISH.STOP; } case "commandcode": @@ -55,6 +59,7 @@ export function fromOpenAIFinish(reason, format) { case OPENAI_FINISH.STOP: return CLAUDE_STOP.END_TURN; case OPENAI_FINISH.LENGTH: return CLAUDE_STOP.MAX_TOKENS; case OPENAI_FINISH.TOOL_CALLS: return CLAUDE_STOP.TOOL_USE; + case OPENAI_FINISH.CONTENT_FILTER: return CLAUDE_STOP.REFUSAL; default: return CLAUDE_STOP.END_TURN; } default: diff --git a/open-sse/translator/response/claude-to-openai.js b/open-sse/translator/response/claude-to-openai.js index 4651d3cf..80de2f18 100644 --- a/open-sse/translator/response/claude-to-openai.js +++ b/open-sse/translator/response/claude-to-openai.js @@ -149,6 +149,13 @@ export function claudeToOpenAIResponse(chunk, state) { if (chunk.delta?.stop_reason) { state.finishReason = convertStopReason(chunk.delta.stop_reason); + // A refusal produces no content blocks at all. Surface Anthropic's own + // explanation as the message text so the client shows *why* the turn is + // empty instead of a blank reply. + const refusalNote = chunk.delta.stop_reason === "refusal" && chunk.delta.stop_details?.explanation; + if (refusalNote) { + results.push(createChunk(state, { content: refusalNote })); + } const finalChunk = createChunk(state, {}, state.finishReason); if (state.usage) { diff --git a/open-sse/translator/schema/finishReasons.js b/open-sse/translator/schema/finishReasons.js index 73535dae..88c320f1 100644 --- a/open-sse/translator/schema/finishReasons.js +++ b/open-sse/translator/schema/finishReasons.js @@ -14,6 +14,9 @@ export const CLAUDE_STOP = { MAX_TOKENS: "max_tokens", TOOL_USE: "tool_use", STOP_SEQUENCE: "stop_sequence", + // Anthropic's API-level refusal (streaming classifier / ToS). Arrives in + // message_delta with zero output tokens; stop_details carries the reason. + REFUSAL: "refusal", }; // Gemini finishReason values. diff --git a/tests/unit/claude-refusal-stream.test.js b/tests/unit/claude-refusal-stream.test.js new file mode 100644 index 00000000..5c281f84 --- /dev/null +++ b/tests/unit/claude-refusal-stream.test.js @@ -0,0 +1,76 @@ +// A refusal from the Anthropic API (stop_reason "refusal", zero output tokens, no +// content blocks) must reach an OpenAI-format client as finish_reason +// "content_filter" carrying Anthropic's explanation — not as a clean, empty "stop". +// Captured live on 2026-09-20 against claude-opus-5 via a Claude Code OAuth +// connection: 9Router logged "Model succeeded · OUT 0" and the client saw nothing. +import { describe, it, expect } from "vitest"; +import { claudeToOpenAIResponse } from "../../open-sse/translator/response/claude-to-openai.js"; + +const EXPLANATION = + "This request was blocked as it seems to violate Anthropic's Terms of Service restrictions on reverse engineering or duplicating model outputs."; + +function runStream(events) { + const state = {}; + const out = []; + for (const ev of events) { + const r = claudeToOpenAIResponse(ev, state); + if (Array.isArray(r)) out.push(...r); + else if (r) out.push(r); + } + return { state, out }; +} + +const refusalStream = [ + { + type: "message_start", + message: { + id: "msg_refusal", model: "claude-opus-5", role: "assistant", content: [], + usage: { input_tokens: 637, cache_creation_input_tokens: 206779, cache_read_input_tokens: 0, output_tokens: 0 } + } + }, + { + type: "message_delta", + delta: { + stop_reason: "refusal", + stop_sequence: null, + stop_details: { type: "refusal", category: "reasoning_extraction", explanation: EXPLANATION } + }, + usage: { input_tokens: 637, cache_creation_input_tokens: 206779, cache_read_input_tokens: 0, output_tokens: 0 } + }, + { type: "message_stop" } +]; + +describe("claude-to-openai: refusal stop_reason", () => { + it("finishes with content_filter, not stop", () => { + const { out } = runStream(refusalStream); + const finishes = out.map(c => c.choices?.[0]?.finish_reason).filter(Boolean); + expect(finishes).toEqual(["content_filter"]); + }); + + it("surfaces Anthropic's explanation as message content", () => { + const { out } = runStream(refusalStream); + const text = out.map(c => c.choices?.[0]?.delta?.content || "").join(""); + expect(text).toBe(EXPLANATION); + }); + + it("keeps usage on the final chunk (prompt tokens were billed)", () => { + const { out } = runStream(refusalStream); + const final = out.find(c => c.choices?.[0]?.finish_reason === "content_filter"); + expect(final.usage.prompt_tokens).toBe(637 + 206779); + expect(final.usage.completion_tokens).toBe(0); + }); + + it("leaves a normal end_turn untouched", () => { + const { out } = runStream([ + { type: "message_start", message: { id: "m", model: "claude-opus-5", role: "assistant", content: [], usage: { input_tokens: 5, output_tokens: 0 } } }, + { type: "content_block_start", index: 0, content_block: { type: "text", text: "" } }, + { type: "content_block_delta", index: 0, delta: { type: "text_delta", text: "ok" } }, + { type: "content_block_stop", index: 0 }, + { type: "message_delta", delta: { stop_reason: "end_turn", stop_sequence: null, stop_details: null }, usage: { output_tokens: 1 } }, + { type: "message_stop" } + ]); + const finishes = out.map(c => c.choices?.[0]?.finish_reason).filter(Boolean); + expect(finishes).toEqual(["stop"]); + expect(out.map(c => c.choices?.[0]?.delta?.content || "").join("")).toBe("ok"); + }); +}); diff --git a/tests/unit/finish-reason-concern.test.js b/tests/unit/finish-reason-concern.test.js index d4fc4713..bb233bf3 100644 --- a/tests/unit/finish-reason-concern.test.js +++ b/tests/unit/finish-reason-concern.test.js @@ -40,6 +40,9 @@ describe("toOpenAIFinish - claude", () => { ["end_turn", "stop"], ["max_tokens", "length"], ["tool_use", "tool_calls"], + ["stop_sequence", "stop"], + ["refusal", "content_filter"], + ["unknown_xyz", "stop"], ])("%s -> %s", (input, expected) => { expect(toOpenAIFinish(input, "claude")).toBe(expected); }); @@ -58,6 +61,9 @@ describe("fromOpenAIFinish round-trip - claude", () => { it("tool_calls -> tool_use", () => { expect(fromOpenAIFinish("tool_calls", "claude")).toBe("tool_use"); }); + it("content_filter -> refusal", () => { + expect(fromOpenAIFinish("content_filter", "claude")).toBe("refusal"); + }); it("length -> max_tokens", () => { expect(fromOpenAIFinish("length", "claude")).toBe("max_tokens"); }); From 21583c03e5c5d5276924efad82328ebe6e215854 Mon Sep 17 00:00:00 2001 From: decolua Date: Tue, 22 Sep 2026 15:43:30 +0700 Subject: [PATCH 37/41] # v0.5.85 (2026-09-22) ## Features - **System One**: add `/v1/systemone` decision endpoint for Jev models (OpenCode Zen and OpenRouter lanes), wire into sidebar and Media Providers page with interactive probe testing - **CLI Tools**: add dynamic configuration, settings APIs, and official logos for Pi, OMP, Crush, ForgeCode, Smelt, and CodeWhale - **Analytics & Usage**: add Requests mode, provider/model breakdown charts, All Time period filter, and refined overview cards - **Combos**: add Cursor/Claude Default presets; support bulk select/delete and bulk strategy changes (Fallback / Round Robin / Fusion) - **Model Capabilities**: expose model capability metadata on `/v1/models` and aggregate capabilities across combo targets - **OpenCode Zen & MiMo**: add OpenCode Zen (`opencode-zen`) provider with free-tier fingerprint; switch default vision fallback to MiMo V2.6 Flash Free - **Qoder CN**: add `qoder-cn` provider for qoder.com.cn with OAuth flow, COSY protocol, and CN gateway routing ## Fixes - **Translator**: map Claude `refusal` stop_reason to `content_filter` and surface explanation; strip replayed reasoning fields for Groq, Mistral, and Cerebras (#4220) - **Antigravity**: drop requestType `agent` to avoid false 429 `RESOURCE_EXHAUSTED`; separate weekly and short-window (5-hour) quotas and deduplicate dashboard rows - **Responses API**: report usage on `response.completed` so clients can auto-compact (#3432) - **Hugging Face**: migrate to Inference Providers router (`router.huggingface.co`), expand image models catalog, and add STT route - **Qoder**: prevent signed request replay (`403/103 Duplicate request`), handle code 110 billing blocks, and preserve upstream SSE error status - **Performance**: bound usage `lastUsed` scan to a 2-day window; map large budget tokens to `max` reasoning tier - **Docker**: publish verified multi-platform images (linux/amd64 and linux/arm64) with configurable apk build mirrors --- CHANGELOG.md | 19 +++++++++++++++---- cli/package.json | 2 +- package.json | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9962eab9..c0132bc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,22 @@ -# v0.5.82 (unreleased) +# v0.5.85 (2026-09-22) ## Features -- **Qoder CN**: add the `qoder-cn` provider for qoder.com.cn — same device/OAuth flow and COSY-signed chat protocol as intl Qoder, served from the CN gateway (`gateway.qoder.com.cn` / `openapi.qoder.com.cn`). Region resolution is derived from the provider id (`qoder-cn` → CN) across executor, model catalog, quota usage, validation, and the dashboard. +- **System One**: add `/v1/systemone` decision endpoint for Jev models (OpenCode Zen and OpenRouter lanes), wire into sidebar and Media Providers page with interactive probe testing +- **CLI Tools**: add dynamic configuration, settings APIs, and official logos for Pi, OMP, Crush, ForgeCode, Smelt, and CodeWhale +- **Analytics & Usage**: add Requests mode, provider/model breakdown charts, All Time period filter, and refined overview cards +- **Combos**: add Cursor/Claude Default presets; support bulk select/delete and bulk strategy changes (Fallback / Round Robin / Fusion) +- **Model Capabilities**: expose model capability metadata on `/v1/models` and aggregate capabilities across combo targets +- **OpenCode Zen & MiMo**: add OpenCode Zen (`opencode-zen`) provider with free-tier fingerprint; switch default vision fallback to MiMo V2.6 Flash Free +- **Qoder CN**: add `qoder-cn` provider for qoder.com.cn with OAuth flow, COSY protocol, and CN gateway routing ## Fixes -- **Qoder**: prevent proxy failures from silently replaying signed inference requests over a direct connection with the same COSY request ID (`403/103 Duplicate request`). -- **Qoder**: return first-frame upstream errors, including `403/103 Duplicate request`, as HTTP failures instead of assistant text; handle fragmented frames and heartbeat prefixes while preserving billing error mapping. +- **Translator**: map Claude `refusal` stop_reason to `content_filter` and surface explanation; strip replayed reasoning fields for Groq, Mistral, and Cerebras (#4220) +- **Antigravity**: drop requestType `agent` to avoid false 429 `RESOURCE_EXHAUSTED`; separate weekly and short-window (5-hour) quotas and deduplicate dashboard rows +- **Responses API**: report usage on `response.completed` so clients can auto-compact (#3432) +- **Hugging Face**: migrate to Inference Providers router (`router.huggingface.co`), expand image models catalog, and add STT route +- **Qoder**: prevent signed request replay (`403/103 Duplicate request`), handle code 110 billing blocks, and preserve upstream SSE error status +- **Performance**: bound usage `lastUsed` scan to a 2-day window; map large budget tokens to `max` reasoning tier +- **Docker**: publish verified multi-platform images (linux/amd64 and linux/arm64) with configurable apk build mirrors # v0.5.81 (2026-09-18) diff --git a/cli/package.json b/cli/package.json index c75e6dc9..5692c953 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "9router", - "version": "0.5.81", + "version": "0.5.85", "description": "9Router CLI - Start and manage 9Router server", "bin": { "9router": "./cli.js" diff --git a/package.json b/package.json index c354a14a..1a09786c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "9router-app", - "version": "0.5.81", + "version": "0.5.85", "description": "9Router web dashboard", "private": true, "scripts": { From cbffeb97708662b079811ac375a3617c826081cc Mon Sep 17 00:00:00 2001 From: Reid Nguyen Date: Wed, 23 Sep 2026 09:01:51 +0700 Subject: [PATCH 38/41] feat(claude): support Claude Opus 5.5 --- open-sse/providers/registry/claude.js | 1 + open-sse/providers/shared.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/open-sse/providers/registry/claude.js b/open-sse/providers/registry/claude.js index 428e66ad..d0bc9302 100644 --- a/open-sse/providers/registry/claude.js +++ b/open-sse/providers/registry/claude.js @@ -57,6 +57,7 @@ export default { }, }, models: [ + { id: "claude-opus-5-5", name: "Claude Opus 5.5" }, { id: "claude-opus-5", name: "Claude Opus 5" }, { id: "claude-fable-5-1", name: "Claude Fable 5.1" }, { id: "claude-fable-5", name: "Claude Fable 5" }, diff --git a/open-sse/providers/shared.js b/open-sse/providers/shared.js index c0699c6f..176c82e9 100644 --- a/open-sse/providers/shared.js +++ b/open-sse/providers/shared.js @@ -22,7 +22,7 @@ export function mapStainlessArch() { // Anthropic API version (single source — reused across claude-format providers/executors) export const ANTHROPIC_API_VERSION = "2023-06-01"; -export const CLAUDE_CLI_VERSION = "2.1.258"; +export const CLAUDE_CLI_VERSION = "2.1.280"; // Shared Claude-compatible API headers (reused across claude-format providers) export const CLAUDE_API_HEADERS = { From 6af26a9ee8bd3edc556f71917fd4de063b3c3903 Mon Sep 17 00:00:00 2001 From: savioruz Date: Wed, 23 Sep 2026 09:11:50 +0700 Subject: [PATCH 39/41] fix(proxy-pools): lossless header forwarding for relay pools Preserve request headers through the Vercel/Cloudflare/Deno relay. - proxyFetch: normalize options.headers via Object.fromEntries before spreading into the relay headers. Spreading a Headers instance yields {} and silently dropped every entry (auth + content-type), which is why the same pool worked on one path and failed on another. - vercel relay: build the forwarded header object from req.headers.entries() instead of new Headers(req.headers), avoiding edge-runtime normalization of casing/duplicate keys that some providers reject. --- open-sse/utils/proxyFetch.js | 5 ++++- src/app/api/proxy-pools/vercel-deploy/route.js | 11 ++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/open-sse/utils/proxyFetch.js b/open-sse/utils/proxyFetch.js index 341b8158..b5403fde 100644 --- a/open-sse/utils/proxyFetch.js +++ b/open-sse/utils/proxyFetch.js @@ -298,8 +298,11 @@ export async function proxyAwareFetch(url, options = {}, proxyOptions = null) { const vercelRelayUrl = normalizeString(proxyOptions?.vercelRelayUrl); if (vercelRelayUrl) { const parsed = new URL(targetUrl); + const baseHeaders = options.headers instanceof Headers + ? Object.fromEntries(options.headers.entries()) + : { ...(options.headers || {}) }; const relayHeaders = { - ...options.headers, + ...baseHeaders, "x-relay-target": `${parsed.protocol}//${parsed.host}`, "x-relay-path": `${parsed.pathname}${parsed.search}`, }; diff --git a/src/app/api/proxy-pools/vercel-deploy/route.js b/src/app/api/proxy-pools/vercel-deploy/route.js index e87390f5..f6501331 100644 --- a/src/app/api/proxy-pools/vercel-deploy/route.js +++ b/src/app/api/proxy-pools/vercel-deploy/route.js @@ -20,14 +20,15 @@ export default async function handler(req) { const targetUrl = target.replace(/\\/$/, "") + relayPath; - const headers = new Headers(req.headers); - headers.delete("x-relay-target"); - headers.delete("x-relay-path"); - headers.delete("host"); + const rawHeaders = {}; + for (const [k, v] of req.headers.entries()) rawHeaders[k] = v; + delete rawHeaders["x-relay-target"]; + delete rawHeaders["x-relay-path"]; + delete rawHeaders["host"]; const response = await fetch(targetUrl, { method: req.method, - headers, + headers: rawHeaders, body: req.method !== "GET" && req.method !== "HEAD" ? req.body : undefined, duplex: "half", }); From 910db749aa52da368658e8949b54c1b85a4bc070 Mon Sep 17 00:00:00 2001 From: wismyzhizi Date: Wed, 23 Sep 2026 09:43:39 +0700 Subject: [PATCH 40/41] feat(xiaomi-mimo): server-assisted desktop login, five account clusters, v2.6 models Reproduce the MiMo Desktop login surface server-side so headless/Docker deployments can link a Xiaomi account without the Desktop client. The account session (passToken) is captured during the proxied login and stored per connection. - Five account clusters (cn/sgp/ams/ru/in): per-region mimo-server host and SSO sid, unknown region falls back to sgp - mimo-v2.6-pro/flash/pro-ultraspeed dual-route models: account-service route when desktop credentials exist, cloud API (sk- key) otherwise; drops obsolete mimo-x-*-preview ids - Desktop ServiceTokenManager 2-phase handshake (single serviceLogin with target sid, raw 64-bit nonce preserved), per-region session cache - reasoning_effort bridged to output_config.effort; i18n runtime now observes characterData mutations so React text rewrites get translated - Security hardening on the login proxy: session travels only in the httpOnly cookie (never in the URL), proxy branch requires dashboard auth, authorization/proxy-authorization never forwarded upstream, and upstream Set-Cookie is not replayed onto the app origin --- open-sse/executors/xiaomi-mimo.js | 63 +- open-sse/providers/registry/xiaomi-mimo.js | 24 +- open-sse/providers/thinkingLevels.js | 1 + open-sse/shared/mimoAccount.js | 191 +++-- open-sse/translator/concerns/paramSupport.js | 3 - public/i18n/literals/zh-CN.json | 27 +- .../api/oauth/xiaomi-mimo/api-key/route.js | 76 +- .../oauth/xiaomi-mimo/login/start/route.js | 140 ++++ .../oauth/xiaomi-mimo/login/status/route.js | 45 ++ src/dashboardGuard.js | 3 + src/i18n/runtime.js | 47 +- src/lib/mimoLoginSession.js | 726 ++++++++++++++++++ src/proxy.js | 66 +- src/shared/components/XiaomiMimoAuthModal.js | 471 +++++++----- tests/unit/xiaomi-mimo-executor.test.js | 116 ++- ...xiaomi-mimo-login-session-security.test.js | 40 + 16 files changed, 1687 insertions(+), 352 deletions(-) create mode 100644 src/app/api/oauth/xiaomi-mimo/login/start/route.js create mode 100644 src/app/api/oauth/xiaomi-mimo/login/status/route.js create mode 100644 src/lib/mimoLoginSession.js create mode 100644 tests/unit/xiaomi-mimo-login-session-security.test.js diff --git a/open-sse/executors/xiaomi-mimo.js b/open-sse/executors/xiaomi-mimo.js index 8b69412a..79f1bf30 100644 --- a/open-sse/executors/xiaomi-mimo.js +++ b/open-sse/executors/xiaomi-mimo.js @@ -1,10 +1,15 @@ import { DefaultExecutor } from "./default.js"; -import { getMimoAccountCookie, invalidateMimoAccountCookieCache, MIMO_API_BASE, MIMO_API_UA } from "../shared/mimoAccount.js"; +import { getMimoAccountCookie, invalidateMimoAccountCookieCache, resolveMimoServerBase, MIMO_API_UA } from "../shared/mimoAccount.js"; -// Desktop-exclusive Preview models. These are served by the account service's -// /api/route proxy, authorized by the Xiaomi account session (NOT the sk- key). -// See shared/mimoAccount.js for the session handshake. -const PREVIEW_MODELS = new Set(["mimo-x-pro-preview", "mimo-x-flash-preview"]); +// Dual-route v2.6 models. +// v2.6 models dynamically route to the account service when desktop session credentials +// (mimoPassToken or account cookie) are present to consume weekly quota, falling back to +// the cloud API (sk- key) otherwise. +const ACCOUNT_MODELS = new Set([ + "mimo-v2.6-pro", + "mimo-v2.6-flash", + "mimo-v2.6-pro-ultraspeed", +]); // Session cookie resolved in execute() (async) and read back by buildHeaders() // (sync — BaseExecutor.execute does not await it). Carried on the per-request @@ -23,15 +28,24 @@ export class XiaomiMimoExecutor extends DefaultExecutor { super("xiaomi-mimo"); } - static isPreviewModel(model) { - return PREVIEW_MODELS.has(bareModel(model)); + static isAccountRoute(model, credentials) { + const bare = bareModel(model); + if (!ACCOUNT_MODELS.has(bare)) return false; + return Boolean( + credentials?.[COOKIE_KEY] || + credentials?.providerSpecificData?.mimoPassToken + ); + } + + isAccountRoute(model, credentials) { + return XiaomiMimoExecutor.isAccountRoute(model, credentials); } buildUrl(model, stream, urlIndex = 0, credentials = null) { - // Preview models live on the account-service route, which is not one of the + // Account route models live on the account-service route, which is not one of the // declared transports — resolve it before the default runtimeTransport path. - if (XiaomiMimoExecutor.isPreviewModel(model)) { - return `${MIMO_API_BASE}/api/route/chat/completions`; + if (this.isAccountRoute(model, credentials)) { + return `${resolveMimoServerBase(credentials?.providerSpecificData)}/api/route/chat/completions`; } // Cloud API models keep default handling, so a Claude-format client reaches // the /anthropic/v1/messages transport. @@ -39,8 +53,8 @@ export class XiaomiMimoExecutor extends DefaultExecutor { } buildHeaders(credentials, stream = true, url, model) { - if (XiaomiMimoExecutor.isPreviewModel(model) && credentials?.[COOKIE_KEY]) { - // Preview models authenticate with the account-session cookie, not the key. + if (this.isAccountRoute(model, credentials) && credentials?.[COOKIE_KEY]) { + // Account route models authenticate with the account-session cookie, not the key. return { "Content-Type": "application/json", Accept: stream ? "text/event-stream" : "application/json", @@ -52,17 +66,22 @@ export class XiaomiMimoExecutor extends DefaultExecutor { } transformRequest(model, body, stream, credentials) { - // super runs stripUnsupportedParams, which flattens Preview content-part + // super runs stripUnsupportedParams, which flattens content-part // arrays (see the xiaomi-mimo rule in translator/concerns/paramSupport.js). const out = super.transformRequest(model, body, stream, credentials); - // Preview models: thinking/params get defaults only — never override what the - // caller set explicitly. (body.model is already `xiaomi/` via upstreamModelId.) - if (XiaomiMimoExecutor.isPreviewModel(model)) { - if (out.thinking == null) out.thinking = { type: "enabled" }; + // Account route models: bridge reasoning_effort to official output_config.effort + // (matches MiMo Desktop app.asar behavior). + if (this.isAccountRoute(model, credentials)) { + const rawEffort = out.reasoning_effort || body?.reasoning_effort || body?.output_config?.effort; + if (rawEffort) { + delete out.reasoning_effort; + const norm = String(rawEffort).toLowerCase() === "xhigh" ? "high" : String(rawEffort).toLowerCase(); + out.output_config = { ...(out.output_config || {}), effort: norm }; + } + if (out.temperature == null) out.temperature = 1.0; if (out.top_p == null) out.top_p = 0.95; - if (!out.max_tokens) out.max_tokens = 4096; } return out; @@ -70,13 +89,11 @@ export class XiaomiMimoExecutor extends DefaultExecutor { async execute(args) { const { model, credentials, proxyOptions = null } = args; - if (!XiaomiMimoExecutor.isPreviewModel(model)) return super.execute(args); + if (!this.isAccountRoute(model, credentials)) return super.execute(args); const cookie = await getMimoAccountCookie(credentials?.providerSpecificData, proxyOptions); if (!cookie) { - throw new Error( - "Xiaomi MiMo account session unavailable. Sign in to MiMo Desktop once so its passToken is present, then retry.", - ); + return super.execute(args); } credentials[COOKIE_KEY] = cookie; const result = await super.execute(args); @@ -94,6 +111,6 @@ export class XiaomiMimoExecutor extends DefaultExecutor { } } -export const __test__ = { PREVIEW_MODELS, bareModel, COOKIE_KEY }; +export const __test__ = { ACCOUNT_MODELS, bareModel, COOKIE_KEY }; export default XiaomiMimoExecutor; diff --git a/open-sse/providers/registry/xiaomi-mimo.js b/open-sse/providers/registry/xiaomi-mimo.js index cb0139b3..a92d48c5 100644 --- a/open-sse/providers/registry/xiaomi-mimo.js +++ b/open-sse/providers/registry/xiaomi-mimo.js @@ -2,9 +2,9 @@ import { CLAUDE_API_HEADERS } from "../shared.js"; // Dual auth (same pattern as kimi): // - API key (sk-...) → cloud API on api.xiaomimimo.com -// - Desktop account/OAuth → same cloud host, plus the Desktop-exclusive Preview -// models served by the account-service route on mimo-server-cn.xiaomimimo.com -// (authorized by a Xiaomi account session cookie, not the key). +// - Desktop account/OAuth → same cloud host, plus the dual-route v2.6 models +// served by the account-service route (mimo-server-.xiaomimimo.com), +// authorized by a Xiaomi account session cookie, not the key. // Endpoint is picked per model in the executor, same as opencode-go's /responses split. export default { id: "xiaomi-mimo", @@ -30,6 +30,16 @@ export default { category: "oauth", authModes: ["oauth", "apikey"], hasOAuth: true, + // Keys are cluster-specific. MiMo Desktop declares five regions + // (CN/SGP/AMS/RU/IN) — host + sid follow mimo-server- / mimo. + regions: [ + { id: "cn", label: "China (中国大陆)" }, + { id: "sgp", label: "Singapore (新加坡)" }, + { id: "ams", label: "Europe · Amsterdam (欧洲)" }, + { id: "ru", label: "Russia (俄罗斯)" }, + { id: "in", label: "India (印度)" }, + ], + defaultRegion: "sgp", serviceKinds: ["llm", "tts"], transport: { baseUrl: "https://api.xiaomimimo.com/v1/chat/completions", @@ -50,10 +60,10 @@ export default { }, ], models: [ - // Desktop-exclusive — served by the account-service route, which only accepts - // OpenAI format, so supportedFormats pins them to the openai transport. - { id: "mimo-x-pro-preview", name: "MiMo-X-Pro-Preview", upstreamModelId: "xiaomi/mimo-x-pro-preview", supportedFormats: ["openai"] }, - { id: "mimo-x-flash-preview", name: "MiMo-X-Flash-Preview", upstreamModelId: "xiaomi/mimo-x-flash-preview", supportedFormats: ["openai"] }, + // Cloud API & Desktop dual-route models (prefers the desktop account quota when available) + { id: "mimo-v2.6-pro", name: "MiMo V2.6 Pro", upstreamModelId: "xiaomi/mimo-v2.6-pro", supportedFormats: ["openai"] }, + { id: "mimo-v2.6-flash", name: "MiMo V2.6 Flash", upstreamModelId: "xiaomi/mimo-v2.6-flash", supportedFormats: ["openai"] }, + { id: "mimo-v2.6-pro-ultraspeed", name: "MiMo V2.6 Pro UltraSpeed", upstreamModelId: "xiaomi/mimo-v2.6-pro-ultraspeed", supportedFormats: ["openai"] }, // Cloud API models (api.xiaomimimo.com/v1) { id: "mimo-v2.5-pro", name: "MiMo V2.5 Pro" }, { id: "mimo-v2.5", name: "MiMo V2.5" }, diff --git a/open-sse/providers/thinkingLevels.js b/open-sse/providers/thinkingLevels.js index 94897ec7..0890e4ec 100644 --- a/open-sse/providers/thinkingLevels.js +++ b/open-sse/providers/thinkingLevels.js @@ -41,6 +41,7 @@ const PATTERN_THINKING = [ { provider: "codex", pattern: "*gpt-5.6-terra*", levels: [...CODEX_GPT_5_6_LEVELS, "ultra"] }, { provider: "codex", pattern: "*gpt-5.6-luna*", levels: CODEX_GPT_5_6_LEVELS }, { pattern: "*codex*", levels: ["low", "medium", "high", "xhigh"] }, // codex cannot disable thinking + { pattern: "*mimo*v2.6*", levels: ["none", "low", "medium", "high", "xhigh"] }, // DeepSeek v4.* (Alibaba MaaS, probed live): effort low|medium|high|xhigh|max // all 200 via output_config.effort; "none" is a 400 on the anthropic route // (disable thinking instead). none kept for the picker = disable. diff --git a/open-sse/shared/mimoAccount.js b/open-sse/shared/mimoAccount.js index 996f38df..9da593a8 100644 --- a/open-sse/shared/mimoAccount.js +++ b/open-sse/shared/mimoAccount.js @@ -8,20 +8,42 @@ import { proxyAwareFetch } from "../utils/proxyFetch.js"; * Xiaomi MiMo account-session helpers (used for weekly quota). * * The weekly quota endpoint lives on the account service domain and is authorized - * by an account session cookie, NOT the sk- API key. Acquiring that cookie mirrors - * MiMo Desktop: a passToken (persisted in Desktop's cookie store) is exchanged via - * the passportapi SSO, then authorized for the `mimopc` service, and finally stamped - * by the mimo-server /api/sts callback into a `serviceToken` cookie. + * by an account session cookie, NOT the sk- API key. Acquiring that cookie is a + * 1:1 port of MiMo Desktop's ServiceTokenManager (app.asar) — the GOLD STANDARD: * - * Flow (verified against MiMo Desktop traffic): - * 1. GET {api}/api/user/xiaomi/me -> 302 to account SSO (sid=mimopc) - * 2. GET account /pass/serviceLogin?sid=passportapi&_json=true -> nonce/ssecurity - * 3. GET {location}&clientSign=... -> account-level serviceToken - * 4. GET account /pass/serviceLogin?sid=mimopc&callback=&_json=true - * 5. GET {api}/api/sts?...&ticket... -> Set-Cookie: serviceToken (mimopc scope) + * getServiceToken(sid) / refreshServiceToken(sid): + * PHASE 1: GET https://account.xiaomi.com/pass/serviceLogin + * ?_locale=zh_CN&_snsNone=true&sid=&_json=true + * Cookie: {userId, passToken, cUserId} + * -> {code, location, ssecurity, nonce, bSecondValidation, notificationUrl} + * -> code !== 0 is an error (never silent) + * PHASE 2: GET {location}&clientSign=sha1(nonce & ssecurity), follow the + * redirect chain absorbing Set-Cookie -> serviceToken + * + * sid is per-cluster (SID_BY_REGION): CN = mimopc, SGP = mimosgp. */ -const API_BASE = "https://mimo-server-cn.xiaomimimo.com"; +// Account-service cluster hosts. MiMo Desktop declares five regions +// (rn = {CN, SGP, RU, IN, EU}); the EU cluster is deployed in Amsterdam. +// Host + sid naming is unified: mimo-server- / sid = mimo +// (ams is the only non-country code). Verified live via /api/user/xiaomi/me. +const API_BASE_BY_REGION = { + cn: "https://mimo-server-cn.xiaomimimo.com", + sgp: "https://mimo-server-sgp.xiaomimimo.com", + ams: "https://mimo-server-ams.xiaomimimo.com", + ru: "https://mimo-server-ru.xiaomimimo.com", + in: "https://mimo-server-in.xiaomimimo.com", +}; +const DEFAULT_API_BASE = API_BASE_BY_REGION.sgp; + +// Cluster service sid — 1:1 with the host code: mimo. +// Unknown/absent region falls back to SGP (the international/open cluster). +const SID_BY_REGION = { cn: "mimopc", sgp: "mimosgp", ams: "mimoams", ru: "mimoru", in: "mimoin" }; +function sidForRegion(region) { + const r = String(region || "").toLowerCase(); + return SID_BY_REGION[r] || SID_BY_REGION.sgp; +} +const API_BASE = DEFAULT_API_BASE; const ACCOUNT_HOST = "account.xiaomi.com"; const API_UA = "miNative PC/Normal Windows_NT/10.0.19045 SDKV/1.0.0 DEVT/PC DEVS/Windows APP/miaccount_desktop APPV/0.1.0"; @@ -112,65 +134,106 @@ function cookieHeader(jar) { .join("; "); } +/** + * Resolve the account-service base URL for a connection. + * @param {object|null} providerSpecificData - may carry `region` ("cn"|"sgp"|"ams"|"ru"|"in") + */ +export function resolveMimoServerBase(providerSpecificData = null) { + const region = String(providerSpecificData?.region || "").toLowerCase(); + return API_BASE_BY_REGION[region] || DEFAULT_API_BASE; +} + /** * Exchange a passToken for a mimo-server service session cookie. + * Primary path mirrors the Desktop ServiceTokenManager (app.asar): + * PHASE 1: GET /pass/serviceLogin?_locale=zh_CN&_snsNone=true&sid=&_json=true + * Cookie {userId,passToken,cUserId} -> {code,location,ssecurity,nonce} + * PHASE 2: GET {location}&clientSign=sha1(nonce&ssecurity), follow the chain + * (manual, absorbing Set-Cookie) -> serviceToken + * sid is per-cluster (SID_BY_REGION): cn=mimopc, sgp=mimosgp, ams=mimoams, ru=mimoru, in=mimoin. * @returns {Promise} Cookie header value, or null on failure. */ -async function acquireServiceCookie(passJar, proxyOptions) { +async function acquireServiceCookie(passJar, proxyOptions, apiBase = DEFAULT_API_BASE, region = "sgp") { + const r = String(region || "").toLowerCase(); + // Hard constraint: CN is ALWAYS direct (ignores proxy even if set) + const effectiveProxy = r === "cn" ? null : proxyOptions; + const sid = sidForRegion(r); + const viaDesktop = await acquireViaDesktopPhases(passJar, effectiveProxy, apiBase, sid); + if (viaDesktop) console.log(`[mimoAccount] desktop 2-phase OK (sid=${sid})`); + return viaDesktop; +} + +async function acquireViaDesktopPhases(passJar, proxyOptions, apiBase, sid) { + const failLog = (reason) => console.log(`[mimoAccount] desktopPhase fail: ${reason}`); const jar = { ...passJar }; - const ck = () => cookieHeader(jar); - // 1. Unauthenticated API call -> 302 carrying the sts callback (sid=mimopc) - const r1 = await proxyAwareFetch( - `${API_BASE}/api/user/xiaomi/me`, - { redirect: "manual", headers: { "User-Agent": API_UA, Cookie: ck() } }, + // PHASE 1 — single serviceLogin call with the TARGET sid (no passportapi + // prelude; ssecurity/nonce come straight from this response). + // Desktop only sends: userId, passToken, cUserId (no extra cookies) + const p1Jar = {}; + if (jar.userId) p1Jar.userId = jar.userId; + if (jar.passToken) p1Jar.passToken = jar.passToken; + if (jar.cUserId) p1Jar.cUserId = jar.cUserId; + + const p1Url = `https://${ACCOUNT_HOST}/pass/serviceLogin?_locale=zh_CN&_snsNone=true&sid=${encodeURIComponent(sid)}&_json=true`; + const p1 = await proxyAwareFetch( + p1Url, + { headers: { Cookie: cookieHeader(p1Jar), "User-Agent": SSO_UA, Accept: "application/json" } }, proxyOptions, ); - const redirect = r1.headers.get("location"); - if (!redirect) return null; - const stsCallback = new URL(redirect).searchParams.get("callback"); - if (!stsCallback) return null; + const raw = await p1.text(); + const clean = raw.replace(/^&&&START&&&/, ""); + // Nonce > 2^53 loses precision in JSON.parse — extract raw literal for signing + const rawNonce = clean.match(/"nonce"\s*:\s*(\d+)/)?.[1]; + let j = null; + try { j = JSON.parse(clean); } catch { /* handled below */ } + if (rawNonce && j) j.nonce = rawNonce; - // 2. passportapi SSO phase 1 -> nonce + ssecurity - const sso1 = await proxyAwareFetch( - `https://${ACCOUNT_HOST}/pass/serviceLogin?sid=passportapi&_json=true`, - { headers: { Cookie: ck(), "User-Agent": SSO_UA, Accept: "application/json" } }, - proxyOptions, - ); - const j1 = JSON.parse((await sso1.text()).replace(/^&&&START&&&/, "")); - const nonce = j1.nonce || (j1.location ? new URL(j1.location).searchParams.get("nonce") : null); - if (!nonce || !j1.location) return null; + if (!j || typeof j.code !== "number" || j.code !== 0 || !j.location || !j.nonce || !j.ssecurity) { + failLog( + `phase1 sid=${sid} http=${p1.status} code=${j?.code ?? "?"} hasLoc=${!!j?.location}` + + ` secondValidation=${j?.bSecondValidation ?? "?"} notificationUrl=${j?.notificationUrl ? "present" : "no"}` + + ` body=${JSON.stringify(raw.slice(0, 200))}`, + ); + return null; + } + absorbSetCookie(jar, p1); - // 3. passportapi SSO phase 2 -> account-level serviceToken - const sso2 = await proxyAwareFetch( - `${j1.location}&clientSign=${signatureClientSign(nonce, j1.ssecurity)}`, - { redirect: "manual", headers: { Cookie: ck(), "User-Agent": SSO_UA } }, - proxyOptions, - ); - absorbSetCookie(jar, sso2); + // PHASE 2 — clientSign the redirect, follow the redirect chain server-side. + // ⚠️ CRITICAL DESKTOP SPEC (app.asar / SSO_curl.cpp line 728: cookies.clear()): + // Phase 2 MUST NOT send ANY Cookie header! The server returns 200 OK with Set-Cookie: serviceToken! + const sep = j.location.includes("?") ? "&" : "?"; + let current = `${j.location}${sep}clientSign=${signatureClientSign(rawNonce || j.nonce, j.ssecurity)}`; - // 4. mimopc SSO -> sts callback carrying a ticket - const sso3 = await proxyAwareFetch( - `https://${ACCOUNT_HOST}/pass/serviceLogin?sid=mimopc&callback=${encodeURIComponent(stsCallback)}&_json=true`, - { headers: { Cookie: ck(), "User-Agent": SSO_UA, Accept: "application/json" } }, - proxyOptions, - ); - const j3 = JSON.parse((await sso3.text()).replace(/^&&&START&&&/, "")); - absorbSetCookie(jar, sso3); - if (!j3?.location || !/\/api\/sts/.test(j3.location)) return null; + for (let hop = 0; hop < 8; hop++) { + const res = await proxyAwareFetch( + current, + { redirect: "manual", headers: { "User-Agent": SSO_UA } }, + proxyOptions, + ); + absorbSetCookie(jar, res); + const loc = res.headers.get("location"); + if (res.status >= 300 && res.status < 400 && loc) { + current = new URL(loc, current).toString(); + continue; + } + break; + } - // 5. sts callback -> Set-Cookie: serviceToken (mimopc scope) - const sts = await proxyAwareFetch( - j3.location, - { redirect: "manual", headers: { "User-Agent": API_UA, Cookie: ck() } }, - proxyOptions, - ); - absorbSetCookie(jar, sts); + const sidKey = `${sid}_serviceToken`; + if (!jar.serviceToken && jar[sidKey]) { + jar.serviceToken = jar[sidKey]; + } - const needed = ["serviceToken", "mimopc_ph", "mimopc_slh", "userId"]; - if (!jar.serviceToken) return null; + if (!jar.serviceToken) { + failLog(`phase2 no serviceToken sid=${sid} jar=[${Object.keys(jar).join(",")}]`); + return null; + } const out = {}; - for (const k of needed) if (jar[k]) out[k] = jar[k]; + for (const [k, v] of Object.entries(jar)) { + if (!v) continue; + if (k === "serviceToken" || k === "userId" || /_(ph|slh)$/.test(k)) out[k] = v; + } return cookieHeader(out); } @@ -179,13 +242,15 @@ async function acquireServiceCookie(passJar, proxyOptions) { * @param {object|null} providerSpecificData - may carry `mimoPassToken` override */ async function getServiceCookie(providerSpecificData, proxyOptions) { + const apiBase = resolveMimoServerBase(providerSpecificData); const passJar = providerSpecificData?.mimoPassToken ? { passToken: providerSpecificData.mimoPassToken, userId: providerSpecificData.mimoUserId, cUserId: providerSpecificData.mimoCUserId } : await readDesktopAccountCookies(); if (!passJar) return { cookie: null, reason: "no-pass-token" }; - // One cached session per passToken — accounts/connections rotate independently. - const key = crypto.createHash("sha256").update(passJar.passToken).digest("hex"); + // One cached session per passToken+cluster — accounts/connections rotate + // independently, and the same passToken maps to different sessions per region. + const key = crypto.createHash("sha256").update(`${apiBase}|${passJar.passToken}`).digest("hex"); const cached = _cache.get(key); if (cached && Date.now() - cached.at < COOKIE_TTL_MS) { @@ -202,8 +267,9 @@ async function getServiceCookie(providerSpecificData, proxyOptions) { const promise = (async () => { try { - return await acquireServiceCookie(passJar, proxyOptions); - } catch { + return await acquireServiceCookie(passJar, proxyOptions, apiBase, providerSpecificData?.region); + } catch (e) { + console.log(`[mimoAccount] acquire threw: ${e?.message || e} | ${String(e?.stack || "").split("\n").slice(1, 4).join(" <- ")}`); return null; // network/parse failure — callers degrade, never throw } finally { _inflight.delete(key); @@ -234,7 +300,8 @@ export async function getMimoAccountCookie(providerSpecificData = null, proxyOpt try { const { cookie } = await getServiceCookie(providerSpecificData, proxyOptions); return cookie; - } catch { + } catch (e) { + console.log(`[mimoAccount] getMimoAccountCookie threw: ${e?.message || e} | ${String(e?.stack || "").split("\n").slice(1, 4).join(" <- ")}`); return null; } } @@ -250,7 +317,7 @@ export async function getMimoAccountUsage(providerSpecificData = null, proxyOpti } try { const res = await proxyAwareFetch( - `${API_BASE}/api/user/usage`, + `${resolveMimoServerBase(providerSpecificData)}/api/user/usage`, { headers: { "User-Agent": API_UA, Cookie: cookie, Accept: "application/json" }, signal: AbortSignal.timeout(10000) }, proxyOptions, ); diff --git a/open-sse/translator/concerns/paramSupport.js b/open-sse/translator/concerns/paramSupport.js index 90ac5f5f..b5c8a926 100644 --- a/open-sse/translator/concerns/paramSupport.js +++ b/open-sse/translator/concerns/paramSupport.js @@ -14,9 +14,6 @@ const STRIP_RULES = [ { provider: "github", match: (m) => /claude/i.test(m) && !/claude.*(opus|sonnet).*4\.6/i.test(m), drop: ["thinking", "reasoning_effort"] }, // Cloudflare Workers AI: content must be plain string, rejects OpenAI content-part array (#1926) { provider: "cloudflare-ai", flattenContent: true }, - // MiMo Desktop Preview models (account-service route): content must be plain string, - // rejects OpenAI content-part array. Cloud models keep their parts (mimo-v2-omni is multi-modal). - { provider: "xiaomi-mimo", match: /preview/i, flattenContent: true }, { provider: "volcengine-ark", match: /glm-5/i, clampToModelMaxOutput: true }, // VolcEngine Ark caps the Kimi family at max_tokens <= 32768, but the model's // advertised ceiling is far higher (Kimi-K2.7-Code resolves to maxOutput 262144), diff --git a/public/i18n/literals/zh-CN.json b/public/i18n/literals/zh-CN.json index 5de38ff0..178da2ae 100644 --- a/public/i18n/literals/zh-CN.json +++ b/public/i18n/literals/zh-CN.json @@ -1390,5 +1390,30 @@ "⚠️ Risk Notice: This provider uses a subscription/OAuth session not officially licensed for proxy/router use. Account may be restricted or banned. Use at your own risk.": "⚠️ 风险提示:此提供商使用的订阅/OAuth 会话未获官方授权用于代理/路由器使用。账户可能被限制或封禁。使用风险自负。", "✓ Confirm Add": "✓ 确认添加", "📝 Configure providers in dashboard or use environment variables": "📝 在仪表盘中配置提供商或使用环境变量", - "🔐 OAuth required. Add now and authenticate after Apply; tool list will be discovered after first connect.": "🔐 需要 OAuth。立即添加并在应用后认证;工具列表将在首次连接后自动发现。" + "🔐 OAuth required. Add now and authenticate after Apply; tool list will be discovered after first connect.": "🔐 需要 OAuth。立即添加并在应用后认证;工具列表将在首次连接后自动发现。", + "Reading local MiMo Desktop credentials...": "正在读取本地 MiMo 桌面版凭证...", + "Desktop Plan · Local credentials": "Desktop Plan · 本地凭证", + "This account is already connected (no need to import again)": "该账号已连接(无需重复导入)", + "Untested": "未测试", + "Re-sync local credentials": "重新同步本地凭证", + "Connect with local credentials": "使用本地凭证连接", + "or": "或", + "Browser Login": "网页登录", + "No Desktop required": "无需桌面客户端", + "Weekly quota": "周额度", + "Waiting for login...": "等待登录中...", + "Reopen login window": "重新打开登录窗口", + "Choose cluster & sign in": "选择集群并登录", + "Login session expired — please retry.": "登录会话已过期,请重试。", + "Failed to save credentials": "保存凭据失败", + "Import failed": "导入失败", + "No local Desktop credentials found": "未检测到本地桌面凭证", + "You can still sign in via browser — no Desktop client needed.": "仍可通过网页登录,无需桌面客户端。", + "Select account cluster": "选择小米账号集群", + "Choose the region cluster of your Xiaomi account:": "请选择你的小米账号所在地区集群:", + "China (Mainland)": "中国大陆", + "Singapore": "新加坡", + "Europe · Amsterdam": "欧洲 · 阿姆斯特丹", + "Russia": "俄罗斯", + "India": "印度" } diff --git a/src/app/api/oauth/xiaomi-mimo/api-key/route.js b/src/app/api/oauth/xiaomi-mimo/api-key/route.js index d8ceee97..02f4fe04 100644 --- a/src/app/api/oauth/xiaomi-mimo/api-key/route.js +++ b/src/app/api/oauth/xiaomi-mimo/api-key/route.js @@ -10,17 +10,19 @@ import { createProviderConnection } from "@/models"; */ export async function POST(request) { try { - const { apiKey, uid, baseUrl, mimoPassToken, mimoUserId, mimoCUserId } = await request.json(); + const { apiKey, uid, baseUrl, mimoPassToken, mimoUserId, mimoCUserId, region } = await request.json(); - if (!apiKey || typeof apiKey !== "string" || !apiKey.trim()) { + const key = typeof apiKey === "string" ? apiKey.trim() : ""; + const sessionOnly = !key && !!mimoPassToken; + + if (!key && !mimoPassToken) { return NextResponse.json( { error: "API key is required" }, { status: 400 }, ); } - const key = apiKey.trim(); - if (!key.startsWith("sk-")) { + if (key && !key.startsWith("sk-")) { return NextResponse.json( { error: "Invalid key format — expected sk- prefix" }, { status: 400 }, @@ -29,47 +31,55 @@ export async function POST(request) { const effectiveBaseUrl = (baseUrl || "https://api.xiaomimimo.com/v1").replace(/\/+$/, ""); - // Validate the key against the models endpoint + // Validate the key against the models endpoint (skipped for session-only) let validated = false; let modelCount = 0; - try { - const resp = await fetch(`${effectiveBaseUrl}/models`, { - method: "GET", - headers: { - Authorization: `Bearer ${key}`, - "X-Mimo-Source": "mimocode-cli", - }, - signal: AbortSignal.timeout(10000), - }); - if (resp.ok) { - const data = await resp.json(); - modelCount = Array.isArray(data?.data) ? data.data.length : 0; - validated = true; + if (key) { + try { + const resp = await fetch(`${effectiveBaseUrl}/models`, { + method: "GET", + headers: { + Authorization: `Bearer ${key}`, + "X-Mimo-Source": "mimocode-cli", + }, + signal: AbortSignal.timeout(10000), + }); + if (resp.ok) { + const data = await resp.json(); + modelCount = Array.isArray(data?.data) ? data.data.length : 0; + validated = true; + } + } catch { + // Network error — still allow import (key may be valid but network blocked) } - } catch { - // Network error — still allow import (key may be valid but network blocked) } - if (!validated) { + if (key && !validated) { // Soft-fail: store the key but mark as untested console.log("[xiaomi-mimo] key validation failed, storing as untested"); } - // Dedup: if a connection with the same uid or same key already exists, update it + // Dedup: same uid, same key, or same session identity+region const { getProviderConnections, updateProviderConnection } = await import("@/models"); + const normRegion = (typeof region === "string" && region) || undefined; const existing = (await getProviderConnections()).find( (c) => c.provider === "xiaomi-mimo" && ( (uid && c.email === `${uid}@xiaomi`) || - c.accessToken === key + (key && c.accessToken === key) || + (sessionOnly && mimoUserId && + c.providerSpecificData?.mimoUserId === mimoUserId && + (normRegion ? (c.providerSpecificData?.region || "cn") === normRegion : true)) ), ); if (existing) { const updated = await updateProviderConnection(existing.id, { - accessToken: key, + accessToken: key || existing.accessToken, providerSpecificData: { ...existing.providerSpecificData, uid: uid || existing.providerSpecificData?.uid || null, - baseUrl: effectiveBaseUrl, + baseUrl: key ? effectiveBaseUrl : (existing.providerSpecificData?.baseUrl || effectiveBaseUrl), + region: normRegion || existing.providerSpecificData?.region || "cn", + authMethod: sessionOnly ? "session" : (existing.providerSpecificData?.authMethod || "api_key"), // Per-account session credential — enables multi-account rotation. mimoPassToken: mimoPassToken || existing.providerSpecificData?.mimoPassToken || null, mimoUserId: mimoUserId || existing.providerSpecificData?.mimoUserId || null, @@ -94,25 +104,29 @@ export async function POST(request) { const connection = await createProviderConnection({ provider: "xiaomi-mimo", - authType: "api_key", - accessToken: key, + // "oauth" is the official authType for imported credential connections + // ([action]/route.js) — the list card and filters key off it; never + // invent new values ("session" hid the row from the provider card). + authType: sessionOnly ? "oauth" : "api_key", + accessToken: key || null, refreshToken: null, // API keys don't expire on a fixed schedule; use a long horizon expiresAt: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(), email: uid ? `${uid}@xiaomi` : null, - displayName: uid ? `Xiaomi ${uid}` : "Xiaomi MiMo", + displayName: uid ? `Xiaomi ${uid}${sessionOnly ? " (Session)" : ""}` : "Xiaomi MiMo", providerSpecificData: { uid: uid || null, baseUrl: effectiveBaseUrl, - authMethod: "api_key", - provider: "API Key", + authMethod: sessionOnly ? "session" : "api_key", + provider: sessionOnly ? "Session Login" : "API Key", + region: normRegion || "cn", modelCount, // Per-account session credential — enables multi-account rotation. mimoPassToken: mimoPassToken || null, mimoUserId: mimoUserId || null, mimoCUserId: mimoCUserId || null, }, - testStatus: validated ? "active" : "untested", + testStatus: validated ? "active" : (sessionOnly ? "active" : "untested"), }); return NextResponse.json({ diff --git a/src/app/api/oauth/xiaomi-mimo/login/start/route.js b/src/app/api/oauth/xiaomi-mimo/login/start/route.js new file mode 100644 index 00000000..712f3bca --- /dev/null +++ b/src/app/api/oauth/xiaomi-mimo/login/start/route.js @@ -0,0 +1,140 @@ +import { NextResponse } from "next/server"; +import { request as httpRequest } from "node:http"; +import { beginSession, encodeSessionCookie, rewriteMimoBases, absorbSetCookies as absorbResponseCookies, originOf, loginUpstreamFetch, SESSION_COOKIE } from "@/lib/mimoLoginSession"; + +/** + * POST /api/oauth/xiaomi-mimo/login/start + * Body: { region: "cn" | "sgp" | "ams" | "ru" | "in" } + * + * Walks the first two hops of the Desktop login surface server-side + * (me -> 302 account/pass/serviceLogin -> 302 /fe/service/login) and hands + * the browser a same-origin pageUrl carrying the 9r_mimo_login session cookie. + * All subsequent account.xiaomi.com traffic flows through src/proxy.js. + * + * Egress resolution: MIMO_LOGIN_PROXY env > (region=sgp: probe common LOCAL + * HTTP proxy ports — v2rayN/clash defaults) > direct. The resolved URL rides + * the session cookie so every hop/XHR uses the same exit. + */ + +const API_UA = + "miNative PC/Normal Windows_NT/10.0.19045 SDKV/1.0.0 DEVT/PC DEVS/Windows APP/miaccount_desktop APPV/0.1.0"; +const SSO_UA = "MiClaw/1.0"; +const LOCAL_PROXY_PORTS = [10808, 10809, 7890, 7891, 1080, 1081, 8080, 8888]; + +/** First local port answering a CONNECT to account.xiaomi.com (or null). */ +function probeLocalHttpProxy(timeoutMs = 500) { + const attempts = LOCAL_PROXY_PORTS.map( + (port) => + new Promise((resolve, reject) => { + let settled = false; + const done = (v) => { + if (settled) return; + settled = true; + // Promise.any picks the first FULFILLED value — failures must reject, + // otherwise an instant ECONNREFUSED from a closed candidate port would + // "win" with null before the real proxy answers. + if (v) resolve(v); + else reject(new Error(`no-proxy-${port}`)); + }; + try { + const req = httpRequest({ + host: "127.0.0.1", + port, + method: "CONNECT", + path: "account.xiaomi.com:443", + timeout: timeoutMs, + }); + req.on("connect", (res, socket) => { + socket.destroy(); + done(res.statusCode === 200 || res.statusCode === 202 ? `http://127.0.0.1:${port}` : null); + }); + req.on("timeout", () => { req.destroy(); done(null); }); + req.on("error", () => done(null)); + req.on("response", () => done(null)); + req.end(); + } catch { + done(null); + } + }), + ); + return Promise.any(attempts).catch(() => null); +} + +async function hop(sess, url, ua) { + return loginUpstreamFetch(url, { + redirect: "manual", + headers: { "User-Agent": ua, Accept: "text/html,application/json,*/*" }, + signal: AbortSignal.timeout(15000), + }, sess); +} + +export async function POST(request) { + try { + let region = "cn"; + try { + const body = await request.json(); + const r = String(body?.region || "").toLowerCase(); + // Known MiMo Desktop clusters (cn/sgp/ams/ru/in) — default cn. + if (r === "cn" || r === "sgp" || r === "ams" || r === "ru" || r === "in") region = r; + } catch { /* empty body — default cn */ } + + const sess = beginSession(region); + + // Egress — non-CN clusters may need an overseas exit for the login page's + // geo-decided features (e.g. Google sign-in); CN is always direct. + let egress = null; + let egressSource = "direct"; + if (region !== "cn") { + const found = await probeLocalHttpProxy(); + if (found) { + egress = found; + egressSource = "local-probe"; + } + } + sess.proxyUrl = egress; + + // Hop 1: me -> account SSO (callback carries the sts callback for THIS cluster) + const meRes = await hop(sess, `${sess.upstreamBase}/api/user/xiaomi/me`, API_UA); + absorbResponseCookies(sess, meRes, `${sess.upstreamBase}/api/user/xiaomi/me`); + const ssoLoc = meRes.headers.get("location"); + if (!ssoLoc || !/account\.xiaomi\.com/.test(ssoLoc)) { + return NextResponse.json( + { error: `Unexpected me response (${meRes.status}) — no account redirect` }, + { status: 502 }, + ); + } + + // Hop 2: serviceLogin -> /fe/service/login SPA (also seeds deviceId cookies) + const loginRes = await hop(sess, ssoLoc, SSO_UA); + absorbResponseCookies(sess, loginRes, ssoLoc); + const pageLoc = loginRes.headers.get("location"); + if (!pageLoc) { + return NextResponse.json( + { error: `Unexpected serviceLogin response (${loginRes.status})` }, + { status: 502 }, + ); + } + + // Same-origin path for the SPA (middleware proxies native prefixes). + const pageUrl = new URL(pageLoc, "https://account.xiaomi.com"); + const origin = originOf(request); + // Session travels ONLY in the httpOnly cookie — never in the URL (history, + // logs, Referer). /login/status re-arms the cookie on every poll, so a + // dropped-cookie browser still recovers on the next poll cycle. + const proxiedPath = rewriteMimoBases(pageUrl.pathname + pageUrl.search, "toProxy", origin); + const egressLog = egress ? egress.replace(/\/\/[^@/]+@/, "//***@") : ""; + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] start region=${sess.region} origin=${origin} egress=${egressSource}${egressLog ? ` (${egressLog})` : ""} page=${pageUrl.pathname}`); + + const res = NextResponse.json({ success: true, state: sess.state, pageUrl: proxiedPath, region }); + res.cookies.set(SESSION_COOKIE, encodeSessionCookie(sess), { + path: "/", + httpOnly: true, + sameSite: "lax", + maxAge: 15 * 60, + }); + return res; + } catch (error) { + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] start error:`, error?.message || error); + return NextResponse.json({ error: error?.message || "login start failed" }, { status: 500 }); + } +} diff --git a/src/app/api/oauth/xiaomi-mimo/login/status/route.js b/src/app/api/oauth/xiaomi-mimo/login/status/route.js new file mode 100644 index 00000000..840788ef --- /dev/null +++ b/src/app/api/oauth/xiaomi-mimo/login/status/route.js @@ -0,0 +1,45 @@ +import { NextResponse } from "next/server"; +import { sessionFromRequest, readSessionIdentity, attachSessionCookie } from "@/lib/mimoLoginSession"; + +/** + * GET /api/oauth/xiaomi-mimo/login/status?state=... + * Polls the server-side login session (state lives in the httpOnly session + * cookie — route handlers and the proxy don't share module memory). When a + * passToken is in the jar, probes /api/user/xiaomi/me once to confirm the + * session works, then returns the identity for the client to persist. + */ +export async function GET(request) { + const url = new URL(request.url); + const state = url.searchParams.get("state") || ""; + const sess = sessionFromRequest(request); + if (!sess || (state && sess.state !== state)) { + return NextResponse.json({ status: "expired" }, { status: 404 }); + } + + if (sess.status !== "done") { + // AUTHORIZATION = passToken in the jar (captured during the proxied login + // XHRs). No serviceToken exchange — weekly-quota API moved; re-wire later. + if (readSessionIdentity(sess)) sess.status = "done"; + } + + if (sess.status !== "done") { + // Re-arm the session cookie on every poll — the modal may sit on the login + // form much longer than the 15min TTL, and only proxied responses used to + // refresh it (browser silently drops an expired cookie before the POST). + return attachSessionCookie(NextResponse.json({ status: "pending", region: sess.region }), sess); + } + + const id = readSessionIdentity(sess); + if (!id) { + return attachSessionCookie( + NextResponse.json({ status: "error", error: "session captured but passToken missing" }), + sess, + ); + } + + const payload = { status: "done", region: sess.region, ...id }; + // One-shot: don't let the identity linger past the client reading it. + const res = NextResponse.json(payload); + res.cookies.set("9r_mimo_login", "", { path: "/", httpOnly: true, maxAge: 0 }); + return res; +} diff --git a/src/dashboardGuard.js b/src/dashboardGuard.js index 3d4b2e32..fab0b291 100644 --- a/src/dashboardGuard.js +++ b/src/dashboardGuard.js @@ -191,6 +191,9 @@ function isPublicApi(pathname) { return PUBLIC_API_PATHS.some((p) => pathname === p || pathname.startsWith(`${p}/`)); } +// Shared with src/proxy.js — the mimo login branch must respect dashboard auth. +export { isAuthenticated }; + export const __test__ = { isLocalRequest, isPublicLlmApi, diff --git a/src/i18n/runtime.js b/src/i18n/runtime.js index fef93328..7391a7c9 100644 --- a/src/i18n/runtime.js +++ b/src/i18n/runtime.js @@ -56,12 +56,13 @@ export function onLocaleChange(callback) { // Process text node function processTextNode(node) { - if (!node.nodeValue || !node.nodeValue.trim()) return; - + const current = node.nodeValue; + if (!current || !current.trim()) return; + // Skip if parent is script, style, code, or structural elements const parent = node.parentElement; if (!parent) return; - + // Skip if parent or any ancestor has data-i18n-skip attribute let element = parent; while (element) { @@ -70,27 +71,33 @@ function processTextNode(node) { } element = element.parentElement; } - + const tagName = parent.tagName?.toLowerCase(); - + // Skip elements that don't allow text nodes const skipTags = [ "script", "style", "code", "pre", "colgroup", "table", "thead", "tbody", "tfoot", "tr", "select", "datalist", "optgroup" ]; - + if (skipTags.includes(tagName)) return; - - // Store original text if not already stored - if (!node._originalText) { - node._originalText = node.nodeValue; + + // React reuses text nodes and rewrites their value on re-render (a + // characterData mutation, no childList event). When the current value is + // neither our last translation nor the recorded original, it is fresh + // source text — re-capture it as the new original before translating. + const isOurTranslation = node._translated != null && current === node._translated; + const isSameAsOriginal = current === node._originalText; + if (!isOurTranslation && !isSameAsOriginal) { + node._originalText = current; } - - // Use original text for translation - const original = node._originalText; - const translated = translate(original); - + if (node._originalText == null) node._originalText = current; + + // Translate from the recorded original so locale switches stay idempotent + const translated = translate(node._originalText); + node._translated = translated; + // Only update if different to avoid unnecessary DOM mutations if (translated !== node.nodeValue) { node.nodeValue = translated; @@ -130,9 +137,16 @@ export async function initRuntimeI18n() { // Process existing DOM processElement(document.body); - // Watch for new nodes + // Watch for new nodes AND in-place text rewrites. React reuses text nodes on + // re-render (only nodeValue changes → a characterData mutation with no + // childList event), so observing childList alone leaves later-updated labels + // untranslated. const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { + if (mutation.type === "characterData") { + processTextNode(mutation.target); + return; + } mutation.addedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE) { processElement(node); @@ -146,6 +160,7 @@ export async function initRuntimeI18n() { observer.observe(document.body, { childList: true, subtree: true, + characterData: true, }); } diff --git a/src/lib/mimoLoginSession.js b/src/lib/mimoLoginSession.js new file mode 100644 index 00000000..07d458f4 --- /dev/null +++ b/src/lib/mimoLoginSession.js @@ -0,0 +1,726 @@ +/** + * Server-side Xiaomi account session login (mimics MiMo Desktop's login surface). + * + * Flow (reverse-engineered from Desktop traffic / mimoAccount.js): + * 1. GET {mimo-server}/api/user/xiaomi/me -> 302 account /pass/serviceLogin?sid=mimopc&callback={sts} + * 2. GET account /pass/serviceLogin -> 302 /fe/service/login (the SPA) + * 3. Browser (via the src/proxy.js reverse proxy) completes login on the REAL + * page (password / whatever the page offers) — every account.xiaomi.com + * request passes through the proxy; Set-Cookie lands in OUR jar (which + * travels in the httpOnly 9r_mimo_login cookie between hops). + * 4. SPA navigates to the sts callback -> rewritten to /__mimo_login/mimo/*, + * middleware takes over and follows the chain server-side: + * sts -> Set-Cookie serviceToken -> me (200 JSON = logged in). + * 5. passToken/userId/cUserId read from the jar -> stored on the connection. + * + * Edge-safe: no Node-only APIs (used from both middleware and API routes). + */ + +const ACCOUNT_HOST = "account.xiaomi.com"; +export const SESSION_COOKIE = "9r_mimo_login"; +const SESSION_TTL_MS = 15 * 60 * 1000; +const API_UA = + "miNative PC/Normal Windows_NT/10.0.19045 SDKV/1.0.0 DEVT/PC DEVS/Windows APP/miaccount_desktop APPV/0.1.0"; +const SSO_UA = "MiClaw/1.0"; +const BROWSER_UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; + +// Paths that belong to the 9router app itself — never proxy these upstream, +// even while a login session is active. Everything else is fair game: the +// login SPA hits evolving endpoints (/pass2/config, /v3/...), so a static +// allowlist rots fast. (Edge-safe: plain strings only.) +const APP_PREFIXES = [ + "/_next/", "/api/", "/dashboard", "/v1/", "/v1beta/", + "/login", "/landing", "/__mimo_login/", "/i18n/", "/icons/", "/providers/", +]; +const APP_FILES = new Set([ + "/favicon.svg", "/favicon.ico", "/file.svg", "/globe.svg", "/next.svg", + "/vercel.svg", "/window.svg", "/sw.js", "/robots.txt", "/manifest.webmanifest", +]); + +const APP_PATH_MATCHES = (pathname) => + APP_FILES.has(pathname) || + APP_PREFIXES.some((p) => pathname === p || pathname.startsWith(p.endsWith("/") ? p : p + "/")); + +const MIMO_BASES = { + cn: "https://mimo-server-cn.xiaomimimo.com", + sgp: "https://mimo-server-sgp.xiaomimimo.com", + ams: "https://mimo-server-ams.xiaomimimo.com", + ru: "https://mimo-server-ru.xiaomimimo.com", + in: "https://mimo-server-in.xiaomimimo.com", +}; +// Unknown/absent region falls back to SGP (the international/open cluster). +const DEFAULT_REGION = "sgp"; +// passToken-prefix -> last failure ts (60s backoff for the service exchange) +const _exchangeBackoff = new Map(); + +export function resolveMimoRegionBase(region) { + const r = String(region || "").toLowerCase(); + return MIMO_BASES[r] || MIMO_BASES[DEFAULT_REGION]; +} + +/** + * Browser-facing origin for this request. Prefer the Host header — request.url + * / nextUrl may carry the bind address (0.0.0.0), which must never leak into + * rewritten callbacks (start and proxy must agree on the exact same origin, + * and both see the same Host header). + */ +export function originOf(request) { + const proto = request.nextUrl?.protocol + || (request.headers?.get?.("x-forwarded-proto") || "http"); + const host = request.headers?.get?.("host") || request.nextUrl?.host; + return host ? `${proto}//${host}` : (request.nextUrl?.origin || "http://localhost:20131"); +} + +// The session (incl. the accumulated cookie jar) travels in the SESSION_COOKIE +// itself — Next runs route handlers and the proxy in separate bundles, so a +// module-level Map is NOT shared between them. Cookie-carried state works +// regardless of runtime topology. httpOnly + SameSite=Lax, TTL-bounded. + +export function beginSession(region) { + const normalizedRegion = String(region || "").toLowerCase(); + return { + state: crypto.randomUUID(), + region: normalizedRegion in MIMO_BASES ? normalizedRegion : DEFAULT_REGION, + proxyUrl: null, // resolved by the start route (env | local-probe for sgp | null) + jar: new Map(), // "name|domain|path" -> { name, value, domain, path } + status: "pending", + createdAt: Date.now(), + upstreamBase: resolveMimoRegionBase(region), + }; +} + +const KEEP_ON_OVERFLOW = /^(passToken|userId|cUserId|serviceToken|.*_serviceToken|.*_ph|.*_slh|deviceId)$/; +// Browser hard limit for one cookie value is 4096 bytes. base64url inflates +// ~1.34x, so the JSON payload must stay under ~2800 to be safe. +const COOKIE_JSON_BUDGET = 2800; + +function b64urlEncode(str) { + const bytes = new TextEncoder().encode(str); + let bin = ""; + for (const b of bytes) bin += String.fromCharCode(b); + return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); +} + +function b64urlDecode(s) { + let t = s.replace(/-/g, "+").replace(/_/g, "/"); + while (t.length % 4) t += "="; + const bin = atob(t); + return new TextDecoder().decode(Uint8Array.from(bin, (c) => c.charCodeAt(0))); +} + +export function encodeSessionCookie(sess) { + const entries = [...sess.jar.values()].map((c) => [c.name, c.value, c.domain, c.path]); + const base = { s: sess.state, r: sess.region, t: sess.createdAt, p: sess.proxyUrl || "" }; + let payload = JSON.stringify({ ...base, j: entries }); + if (payload.length > COOKIE_JSON_BUDGET) { + // Cookie budget: drop everything but identity/session essentials. + payload = JSON.stringify({ ...base, j: entries.filter(([name]) => KEEP_ON_OVERFLOW.test(name)) }); + } + return `v2.${b64urlEncode(payload)}`; +} + +export function decodeSessionCookie(value) { + if (!value) return null; + let payload; + try { + if (value.startsWith("v2.")) { + payload = JSON.parse(b64urlDecode(value.slice(3))); + } else if (value.startsWith("v1.")) { + payload = JSON.parse(decodeURIComponent(value.slice(3))); // legacy + } else { + return null; + } + } catch { + return null; + } + if (!payload || typeof payload.t !== "number") return null; + if (Date.now() - payload.t > SESSION_TTL_MS) return null; + const jar = new Map(); + for (const raw of payload.j || []) { + if (!Array.isArray(raw) || raw.length < 4) continue; + const [name, val, domain, path] = raw; + jar.set(`${name}|${domain}|${path}`, { name, value: val, domain, path }); + } + return { + state: payload.s, + region: payload.r in MIMO_BASES ? payload.r : DEFAULT_REGION, + proxyUrl: typeof payload.p === "string" && payload.p ? payload.p : null, + jar, + status: "pending", + createdAt: payload.t, + upstreamBase: resolveMimoRegionBase(payload.r), + }; +} + +/** Read the session straight from an incoming request (any runtime). */ +export function sessionFromRequest(request) { + const raw = request.cookies?.get?.(SESSION_COOKIE)?.value + ?? parseCookieHeader(request.headers?.get?.("cookie"))?.[SESSION_COOKIE]; + return decodeSessionCookie(raw || null); +} + +function parseCookieHeader(header) { + if (!header) return null; + const out = {}; + for (const part of header.split(";")) { + const i = part.indexOf("="); + if (i < 0) continue; + out[part.slice(0, i).trim()] = part.slice(i + 1).trim(); + } + return out; +} + +/** Append the re-encoded session to any Response (proxy writes go through here). */ +export function attachSessionCookie(response, sess) { + const headers = new Headers(response.headers); + headers.append( + "Set-Cookie", + `${SESSION_COOKIE}=${encodeSessionCookie(sess)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${Math.floor(SESSION_TTL_MS / 1000)}`, + ); + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers, + }); +} + +export function clearedSessionCookie() { + return `${SESSION_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`; +} + +// ---------- cookie jar (server-side) ---------- + +function jarKey(c) { + return `${c.name}|${c.domain}|${c.path}`; +} + +function domainMatch(cookieDomain, host) { + const d = String(cookieDomain || "").replace(/^\./, "").toLowerCase(); + const h = String(host || "").toLowerCase(); + return h === d || h.endsWith("." + d); +} + +/** Parse one Set-Cookie header value. Returns { cookie, expired } or null. */ +function parseSetCookie(raw, requestUrl) { + if (!raw) return null; + const parts = raw.split(";"); + const nv = /^([^=]+)=([\s\S]*)$/.exec(parts[0].trim()); + if (!nv) return null; + const name = nv[1].trim(); + const value = (nv[2] || "").trim(); + const url = new URL(requestUrl); + const cookie = { + name, + value, + domain: url.hostname, + path: (url.pathname || "/").replace(/[^/]*$/, "") || "/", + }; + let expired = value === "EXPIRED"; + for (let i = 1; i < parts.length; i++) { + const f = parts[i].trim(); + const eq = f.indexOf("="); + const k = (eq >= 0 ? f.slice(0, eq) : f).trim().toLowerCase(); + const v = eq >= 0 ? f.slice(eq + 1).trim() : ""; + if (k === "domain" && v) cookie.domain = v.replace(/^\./, ""); + else if (k === "path" && v) cookie.path = v; + else if (k === "expires") { + if (/expired/i.test(v)) expired = true; + else { + const t = Date.parse(v); + if (!Number.isNaN(t) && t <= Date.now()) expired = true; + } + } else if (k === "max-age" && Number(v) <= 0) expired = true; + } + return { cookie, expired }; +} + +export function absorbSetCookies(sess, res, requestUrl) { + for (const raw of res.headers.getSetCookie?.() || []) { + const parsed = parseSetCookie(raw, requestUrl); + if (!parsed) continue; + const key = jarKey(parsed.cookie); + if (parsed.expired || !parsed.cookie.value) sess.jar.delete(key); + else sess.jar.set(key, parsed.cookie); + } +} + +function cookieHeaderFor(sess, targetUrl) { + const u = new URL(targetUrl); + const out = []; + for (const c of sess.jar.values()) { + if (!domainMatch(c.domain, u.hostname)) continue; + if (!(u.pathname || "/").startsWith(c.path)) continue; + out.push(`${c.name}=${c.value}`); + } + return out.join("; "); +} + +/** Extract identity cookies from the account host jar. */ +export function readSessionIdentity(sess) { + const pick = (name) => { + for (const c of sess.jar.values()) { + if (c.name === name && domainMatch(c.domain, ACCOUNT_HOST)) return c.value; + } + return null; + }; + const passToken = pick("passToken"); + if (!passToken || passToken === "EXPIRED") return null; + return { passToken, userId: pick("userId"), cUserId: pick("cUserId") }; +} + +/** + * Redeem the captured passToken for a mimo-server service session using the + * BATTLE-TESTED desktop handshake (serviceLogin sid=mimopc + clientSign) that + * powers every existing CN desktop connection — instead of the interactive + * /api/sts webview callback, which rejects server-side calls (401). + * Merges the resulting serviceCookie into sess.jar, then confirms via me. + * @returns {Promise} true when the me probe answers 200 (logged in). + */ +export async function ensureServiceSession(sess) { + const id = readSessionIdentity(sess); + if (!id) return false; + const T = () => new Date().toISOString().slice(11, 23); + const log = (m) => console.log(`${T()} [mimo-login][exchange] ${m}`); + // Backoff: a failed full 5-step chain must not re-run on every 2.5s poll. + const bkKey = id.passToken.slice(0, 24); + const lastFail = _exchangeBackoff.get(bkKey); + if (lastFail && Date.now() - lastFail < 60_000) { + log("exchange in backoff (60s), skip"); + return false; + } + try { + const mod = await import("../../open-sse/shared/mimoAccount.js"); + const proxyOptions = sess.proxyUrl ? { enabled: true, url: sess.proxyUrl } : null; + log(`exchanging passToken (region=${sess.region}, egress=${sess.proxyUrl || "direct"}) ...`); + const serviceCookie = await mod.getMimoAccountCookie( + { + region: sess.region, + mimoPassToken: id.passToken, + mimoUserId: id.userId, + mimoCUserId: id.cUserId, + }, + proxyOptions, + ); + if (!serviceCookie) { + log("exchange failed: no service cookie"); + _exchangeBackoff.set(bkKey, Date.now()); + return false; + } + // Flatten "a=b; c=d" into the jar under the mimo-server host. + _exchangeBackoff.delete(bkKey); + const host = new URL(sess.upstreamBase).hostname; + for (const pair of String(serviceCookie).split(";")) { + const eq = pair.indexOf("="); + if (eq <= 0) continue; + const name = pair.slice(0, eq).trim(); + const value = pair.slice(eq + 1).trim(); + if (!name || !value) continue; + sess.jar.set(`${name}|${host}|/`, { name, value, domain: host, path: "/" }); + } + log(`serviceCookie merged, jar=[${[...sess.jar.keys()].map((k) => k.split("|")[0]).join(",").slice(0, 160)}]`); + + const meUrl = `${sess.upstreamBase}/api/user/xiaomi/me`; + const res = await fetchUpstream( + sess, + meUrl, + { method: "GET", headers: { "User-Agent": API_UA } }, + cookieHeaderFor(sess, meUrl), + ); + absorbSetCookies(sess, res, meUrl); + log(`me confirm http=${res.status}`); + return res.status === 200; + } catch (e) { + log(`exchange error: ${e?.message || e}`); + _exchangeBackoff.set(bkKey, Date.now()); + return false; + } +} + +// ---------- URL rewriting (mimo-server base <-> /__mimo_login/mimo) ---------- + +function encodingVariants(s) { + // The callback/followup params appear raw, url-encoded once, twice... + const out = [s]; + let cur = s; + for (let i = 0; i < 3; i++) { + cur = encodeURIComponent(cur); + out.push(cur); + } + return out; +} + +/** + * Rewrite mimo-server base URLs (any encoding depth) in a string. + * direction "toProxy": mimo-base -> `${origin}/__mimo_login/mimo` + * direction "toUpstream": reverse. + */ +export function rewriteMimoBases(text, direction, origin, upstreamBase = null) { + if (!text) return text; + let out = String(text); + const proxyBase = `${origin}/__mimo_login/mimo`; + const bases = [...new Set(Object.values(MIMO_BASES))]; + const fromBases = direction === "toProxy" ? bases : [proxyBase]; + const toBase = direction === "toProxy" ? proxyBase : (upstreamBase || bases[0]); + for (const fromBase of fromBases) { + const variants = [ + fromBase, + fromBase.replace("https://", "http://"), + fromBase.replace(/^https?:/, ""), + fromBase.replaceAll("/", "\\/"), + fromBase.replace("https://", "http://").replaceAll("/", "\\/"), + ]; // + protocol-relative + json escaped slashes + const toVariants = [ + toBase, + toBase.replace("https://", "http://"), + toBase, + toBase.replaceAll("/", "\\/"), + toBase.replaceAll("/", "\\/"), + ]; + for (let vIdx = 0; vIdx < variants.length; vIdx++) { + const fromList = encodingVariants(variants[vIdx]); + const toList = encodingVariants(toVariants[vIdx]); + for (let i = 0; i < fromList.length; i++) { + out = out.split(fromList[i]).join(toList[i]); + } + } + } + + // account.xiaomi.com absolute URLs: keep navigation (e.g. identity/authStart + // 2FA prompts) on our origin — every path on that host is already proxied + // natively. Reverse applies to request URLs/bodies before hitting upstream. + const acctOrigins = ["https://account.xiaomi.com", "http://account.xiaomi.com", "//account.xiaomi.com"]; + if (direction === "toProxy") { + const toL = encodingVariants(origin); + for (const a of acctOrigins) { + const fromL = encodingVariants(a); + for (let i = 0; i < fromL.length; i++) out = out.split(fromL[i]).join(toL[i]); + } + } else { + const toA = encodingVariants("https://account.xiaomi.com"); + const toAEscaped = encodingVariants("https:\\/\\/account.xiaomi.com"); + const fromL = encodingVariants(origin); + const fromLProto = encodingVariants(origin.replace(/^https?:/, "")); + const fromLEscaped = encodingVariants(origin.replaceAll("/", "\\/")); + for (let i = 0; i < fromL.length; i++) { + out = out.split(fromL[i]).join(toA[i]); + out = out.split(fromLProto[i]).join(toA[i]); + out = out.split(fromLEscaped[i]).join(toAEscaped[i]); + } + } + return out; +} + +/** Reverse the proxy rewrite in an incoming URL before hitting upstream. */ +export function deRewriteUrl(rawUrl, origin, upstreamBase = null) { + return rewriteMimoBases(rawUrl, "toUpstream", origin, upstreamBase); +} + +export function isAccountProxyPath(pathname) { + // Inverted: proxy EVERYTHING except the app's own paths (only consulted + // while a login session cookie/param is present). + return !APP_PATH_MATCHES(pathname); +} + +export function isMimoTakeoverPath(pathname) { + return pathname.startsWith("/__mimo_login/mimo/"); +} + +/** Map /__mimo_login/mimo/* back to the upstream mimo-server path. */ +export function takeoverUpstreamPath(pathname) { + return pathname.slice("/__mimo_login/mimo".length) || "/"; +} + +// ---------- upstream fetch with optional egress proxy ---------- +// +// The login page's feature set (Google sign-in etc.) is geo-decided by the +// egress IP of THESE requests. The proxy applies ONLY when the user picked +// region=sgp — the start route resolves it (via local-port probe) and rides it +// on the session cookie as sess.proxyUrl. CN sessions never proxy (null -> direct). + +let _pafPromise = null; +let _socksPromise = null; + +/** fetch-compatible wrapper over socks-proxy-agent (undici ProxyAgent has no socks support). */ +async function socksFetch(url, init, proxyUrl) { + if (!_socksPromise) { + _socksPromise = import("socks-proxy-agent") + .then((m) => m.SocksProxyAgent || m.default?.SocksProxyAgent || m.default) + .catch((e) => { + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] socks-proxy-agent unavailable:`, e?.message || e); + return null; + }); + } + const SocksProxyAgent = await _socksPromise; + if (!SocksProxyAgent) throw new Error("socks agent unavailable"); + + const nodeUrl = new URL(url); + // Literal specifiers on both branches — webpack forbids fully dynamic import(). + const protoMod = nodeUrl.protocol === "http:" ? await import("node:http") : await import("node:https"); + const lib = protoMod.default ?? protoMod; + const { Readable } = await import("node:stream"); + + let headers = {}; + const raw = init?.headers; + if (raw instanceof Headers) for (const [k, v] of raw) headers[k] = v; + else if (raw) headers = { ...raw }; + + let body = init?.body; + if (body && typeof body !== "string" && !Buffer.isBuffer(body)) body = Buffer.from(body); + if (body) headers["content-length"] = String(Buffer.byteLength(body)); + + const agent = new SocksProxyAgent(proxyUrl); + return new Promise((resolve, reject) => { + const req = lib.request( + nodeUrl, + { method: init?.method || "GET", agent, headers, timeout: 20000 }, + (res) => { + const outHeaders = new Headers(); + for (const [k, v] of Object.entries(res.headers || {})) { + if (Array.isArray(v)) v.forEach((x) => outHeaders.append(k, String(x))); + else if (v != null) outHeaders.set(k, String(v)); + } + resolve(new Response(Readable.toWeb(res), { status: res.statusCode || 200, headers: outHeaders })); + }, + ); + const signal = init?.signal; + if (signal) { + if (signal.aborted) req.destroy(new Error("aborted")); + else signal.addEventListener("abort", () => req.destroy(new Error("aborted")), { once: true }); + } + req.on("timeout", () => req.destroy(new Error("socks fetch timeout"))); + req.on("error", reject); + if (body) req.write(body); + req.end(); + }); +} + +async function loginFetch(url, init, sessionProxyUrl = null) { + if (!sessionProxyUrl) return fetch(url, init); // direct — no agent machinery needed + const proxyOptions = { enabled: true, url: sessionProxyUrl }; + try { + if (/^socks/i.test(sessionProxyUrl)) return await socksFetch(url, init, sessionProxyUrl); + if (!_pafPromise) { + _pafPromise = import("../../open-sse/utils/proxyFetch.js") + .then((m) => m.proxyAwareFetch) + .catch((e) => { + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] proxyAwareFetch unavailable (runtime?), direct only:`, e?.message || e); + return null; + }); + } + const paf = await _pafPromise; + if (paf) return await paf(url, init, proxyOptions); + } catch (e) { + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] proxied fetch failed, falling back to direct:`, e?.message || e); + } + return fetch(url, init); +} + +/** Public alias — start/status routes share the same egress path. */ +export const loginUpstreamFetch = (url, init, sess = null) => loginFetch(url, init, sess?.proxyUrl || null); + +// ---------- upstream proxying ---------- + +async function fetchUpstream(sess, url, init, cookieValue) { + const headers = new Headers(init.headers); + if (cookieValue) headers.set("Cookie", cookieValue); + return loginFetch(url, { ...init, headers, redirect: "manual", signal: AbortSignal.timeout(20000) }, sess?.proxyUrl || null); +} + +function browserCookieHeader(req) { + return req.headers.get("cookie") || ""; +} + +// Headers never forwarded to the upstream account host. +const STRIP_UPSTREAM_HEADERS = new Set([ + "host", "cookie", "connection", "content-length", "transfer-encoding", + "keep-alive", "upgrade", "expect", "proxy-connection", + // Credentials for 9router itself — must never reach a third-party upstream. + "authorization", "proxy-authorization", +]); + +/** + * Proxy one account.xiaomi.com request from the browser. + * Captures Set-Cookie into the server jar, strips frame-blocking headers, + * rewrites Location/body mimo-base references back into the proxy space. + */ +export async function proxyAccountRequest(sess, req, origin) { + const u = new URL(req.url); + u.searchParams.delete("__9r_sess"); // never forward our session to upstream + const upstream = new URL(u.pathname + u.search, `https://${ACCOUNT_HOST}`); + + // The SPA's callback params were rewritten to our proxy — undo before upstream + // so signature (_sign) validation on the real callback still passes. + const upstreamStr = deRewriteUrl(upstream.toString(), origin, sess.upstreamBase); + + const headers = {}; + // Forward EVERYTHING the browser sent (minus hop-by-hop + host/cookie) so no + // custom SDK header gets silently dropped. Then fix up cross-origin fields: + // the SPA talks to account.xiaomi.com, so Origin/Referer must be rewritten + // from our origin to the account origin — keeping the original path/query + // (a wrong Referer path trips Xiaomi's login risk control, error 10025). + for (const [k, v] of req.headers) { + if (STRIP_UPSTREAM_HEADERS.has(k.toLowerCase())) continue; + headers[k] = v; + } + const ourOrigin = origin; + const fixOriginUrl = (val) => { + if (!val) return null; + try { + const u = new URL(val); + if (u.origin === ourOrigin) { + u.protocol = "https:"; + u.host = ACCOUNT_HOST; + return u.toString(); + } + if (u.hostname === ACCOUNT_HOST) return u.toString(); + return null; // some other origin — let our forced account values win + } catch { return null; } + }; + const rawOrigin = headers.origin || headers.Origin || null; + delete headers.origin; + delete headers.Origin; + // Real browsers only send Origin on XHR POSTs — preserve that shape, but + // point it at the account host (never leak localhost upstream). + if (rawOrigin) headers.Origin = `https://${ACCOUNT_HOST}`; + const fixedReferer = fixOriginUrl(headers.referer || headers.Referer); + headers.Referer = fixedReferer + ? deRewriteUrl(fixedReferer, origin, sess.upstreamBase) + : `https://${ACCOUNT_HOST}/fe/service/login`; + delete headers.referer; + + const init = { method: req.method || "GET", headers }; + if (init.method !== "GET" && init.method !== "HEAD") { + let buf = Buffer.from(await req.arrayBuffer()); + // The SPA reads callback params from location.search (which we rewrote to + // our origin) and can echo them in the POST BODY — reverse that too, or + // Xiaomi rejects with 10025 "Callback连接不合法". + const ctBody = String(headers["Content-Type"] || headers["content-type"] || ""); + if (buf.length && /urlencoded|json|text/i.test(ctBody)) { + const before = buf.toString("utf8"); + const after = rewriteMimoBases(before, "toUpstream", origin, sess.upstreamBase); + if (after !== before) { + buf = Buffer.from(after, "utf8"); + headers["Content-Length"] = String(buf.length); + } else if (/__mimo_login|localhost/.test(before)) { + // Anomaly: a local callback shape we cannot rewrite — must never reach Xiaomi. + console.log(`${new Date().toISOString().slice(11, 23)} [mimo-login] body STILL local, not matchable: ${before.slice(0, 200)}`); + } + } + init.body = buf; + } + + // Follow same-host redirects server-side (they carry Set-Cookie we must keep). + let current = upstreamStr; + let res = null; + const requestCookies = cookieHeaderFor(sess, current) || browserCookieHeader(req); + for (let hop = 0; hop < 8; hop++) { + res = await fetchUpstream(sess, current, hop === 0 ? init : { ...init, body: undefined }, requestCookies); + absorbSetCookies(sess, res, current); + const loc = res.headers.get("location"); + if (res.status >= 300 && res.status < 400 && loc) { + const nextAbs = new URL(loc, current); + if (nextAbs.hostname === ACCOUNT_HOST) { + current = nextAbs.toString(); + continue; + } + // Cross-host redirect to mimo-server: rewrite into our takeover space so + // the browser stays on our origin. + if (/mimo-server-(cn|sgp)\.xiaomimimo\.com/.test(nextAbs.hostname)) { + const proxiedLoc = rewriteMimoBases(nextAbs.toString(), "toProxy", origin); + return new Response(null, { status: res.status, headers: { Location: proxiedLoc, "Cache-Control": "no-store" } }); + } + // Any other host: pass through. + return new Response(null, { status: res.status, headers: { Location: loc } }); + } + break; + } + + return buildBrowserResponse(sess, res, origin, u.pathname, current); +} + +function buildBrowserResponse(sess, res, origin, reqPath = "", upstreamUrl = "") { + const outHeaders = new Headers(); + const pass = ["content-type", "cache-control", "etag", "last-modified", "date"]; + for (const h of pass) { + const v = res.headers.get(h); + if (v) outHeaders.set(h, v); + } + // Allow embedding in our modal (upstream often sends X-Frame-Options). + outHeaders.delete("x-frame-options"); + outHeaders.delete("content-security-policy"); + outHeaders.delete("content-security-policy-report-only"); + outHeaders.set("Cache-Control", "no-store"); + // Deliberately NOT forwarding upstream Set-Cookie to the browser: every + // proxied request already strips the browser Cookie header, so upstream + // auth lives only in the server-side jar. Replayed cookies would land on + // our origin's jar (some without HttpOnly → readable by any script here). + + const ctType = res.headers.get("content-type") || ""; + const isText = /text\/|javascript|json/.test(ctType); + if (!isText) return new Response(res.body, { status: res.status, headers: outHeaders }); + + return res.text().then((rawBody) => { + // JSON allows \/ as an escaped slash — Xiaomi backends (PHP-style) emit + // "https:\/\/mimo-server..." which defeats scheme-based string matching + // AND the SPA JSON.parses it back to a real URL (this leaked the sts + // callback straight to the browser -> cross-origin 401). Unescaping \/ to + // / inside JSON string values is semantics-preserving and stays valid. + const body = /json/.test(ctType) ? rawBody.replaceAll("\\/", "/") : rawBody; + // Surface upstream API errors (Xiaomi wraps JSON as &&&START&&&{code:...}). + if (/^\/(pass|sts)/.test(reqPath) || res.status >= 400) { + const m = body.match(/"code"\s*:\s*(-?\d+)/); + if ((m && m[1] !== "0") || res.status >= 400) { + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] upstream ${reqPath} http=${res.status} code=${m ? m[1] : "?"} | url=${upstreamUrl.slice(0, 180)} | ${body.replace(/\s+/g, " ").slice(0, 160)}`); + } + } + const rewritten = rewriteMimoBases(body, "toProxy", origin); + return new Response(rewritten, { status: res.status, headers: outHeaders }); + }); +} + +/** + * Take over the mimo-server tail of the flow (sts -> me) server-side. + * Runs the whole redirect chain, absorbs cookies, verifies me=logged-in. + */ +export async function runTakeover(sess, upstreamUrl, origin) { + const T = () => new Date().toISOString().slice(11, 23); + const log = (m) => console.log(`${T()} [mimo-login][takeover] ${m}`); + const idSnap = () => { + const id = readSessionIdentity(sess); + const names = [...sess.jar.keys()].map((k) => k.split("|")[0]).join(","); + return `passToken=${id ? "Y" : "N"} jar=[${names.slice(0, 160)}]`; + }; + log(`sts-nav url=${upstreamUrl.slice(0, 160)} origin=${origin} | ${idSnap()}`); + const id = readSessionIdentity(sess); + // AUTHORIZATION COMPLETION = passToken captured (that IS the credential the + // connection persists for the account route). The serviceToken exchange + // (weekly quota) is intentionally NOT part of completion — its API moved; + // ensureServiceSession stays exported for when that gets re-wired. + if (id) { + sess.status = "done"; + return donePage(); + } + return pendingPage(); +} + +function htmlPage(title, lines, autoClose = false) { + const body = `${title} + +

    ${title}

    ${lines.map((l) => `

    ${l}

    `).join("")}
    + +`; + return new Response(body, { status: 200, headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" } }); +} + +function donePage() { + return htmlPage("登录成功 ✅", ["账号会话已捕获,可以关闭此窗口。", "回到 9router 弹窗继续。"], true); +} + +function pendingPage() { + return htmlPage("登录未完成", ["未检测到有效会话,请重试。"]); +} + +export const __test__ = { STRIP_UPSTREAM_HEADERS, buildBrowserResponse }; diff --git a/src/proxy.js b/src/proxy.js index 566dd14c..b42dd193 100644 --- a/src/proxy.js +++ b/src/proxy.js @@ -1,6 +1,70 @@ -import { proxy as dashboardProxy } from "./dashboardGuard"; +import { proxy as dashboardProxy, isAuthenticated } from "./dashboardGuard"; +import { + sessionFromRequest, + isAccountProxyPath, + isMimoTakeoverPath, + takeoverUpstreamPath, + proxyAccountRequest, + runTakeover, + attachSessionCookie, + originOf, +} from "./lib/mimoLoginSession"; export default async function proxy(request) { + // Xiaomi account session-login proxy (src/lib/mimoLoginSession.js). + // Session state (region + accumulated cookie jar) travels in the httpOnly + // 9r_mimo_login cookie — route handlers and this proxy run in separate + // bundles, so module-level maps are NOT shared. The cookie is only set by + // the auth-gated login/start route, and the branch below ALSO requires a + // valid dashboard session: a forged 9r_mimo_login cookie (client-controlled + // header, unsigned payload) must never turn the app into an unauthenticated + // forwarder. No URL-carried session — it would leak the jar via history/logs/Referer. + const cookies = request.headers.get("cookie") || ""; + const hasSessionCookie = cookies.includes("9r_mimo_login="); + const { pathname } = request.nextUrl; + if (hasSessionCookie && !(await isAuthenticated(request))) { + // Forged or stale session cookie without dashboard auth — drop it early. + const res = await dashboardProxy(request); + const headers = new Headers(res.headers); + headers.append("Set-Cookie", "9r_mimo_login=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0"); + return new Response(res.body, { status: res.status, statusText: res.statusText, headers }); + } + if (!hasSessionCookie && /^\/(fe\/|pass)/.test(pathname) && !pathname.startsWith("/_next")) { + // Anomaly: a login-flow XHR arrived without the session — the classic + // cause of silent SPA "Something went wrong" 404s. Narrow to login paths + // so unrelated unknown routes don't spam this. + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] no-session ${pathname} (cookie header: ${cookies ? cookies.slice(0, 80) : ""})`); + } + if (hasSessionCookie) { + const sess = sessionFromRequest(request); + if (sess) { + const origin = originOf(request); + try { + if (isMimoTakeoverPath(pathname)) { + const upstreamUrl = `${sess.upstreamBase}${takeoverUpstreamPath(pathname)}${request.nextUrl.search || ""}`; + return attachSessionCookie(await runTakeover(sess, upstreamUrl, origin), sess); + } + if (isAccountProxyPath(pathname)) { + return attachSessionCookie(await proxyAccountRequest(sess, request, origin), sess); + } + } catch (e) { + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] proxy error:`, e?.message || e); + return new Response("mimo login proxy error", { status: 502 }); + } + } else { + // Anomaly (should not happen in a healthy flow): cookie present but unparseable. + console.log(`${new Date().toISOString().slice(11,23)} [mimo-login] session cookie undecodable — falling through (${pathname})`); + } + } + + // Cookie present but expired/invalid — clear it on the way past. + if (hasSessionCookie) { + const res = await dashboardProxy(request); + const headers = new Headers(res.headers); + headers.append("Set-Cookie", "9r_mimo_login=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0"); + return new Response(res.body, { status: res.status, statusText: res.statusText, headers }); + } + return dashboardProxy(request); } diff --git a/src/shared/components/XiaomiMimoAuthModal.js b/src/shared/components/XiaomiMimoAuthModal.js index e501698f..1081953c 100644 --- a/src/shared/components/XiaomiMimoAuthModal.js +++ b/src/shared/components/XiaomiMimoAuthModal.js @@ -1,60 +1,105 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import PropTypes from "prop-types"; import { Modal, Button } from "@/shared/components"; +import { translate } from "@/i18n/runtime"; /** - * Xiaomi MiMo Auth Modal + * Xiaomi MiMo Desktop Plan auth modal. * - * Auto-imports credentials from the local Xiaomi MiMo Desktop auth.json (~/.local/share/mimocode/auth.json). - * If auto-import fails, offers a one-click browser OAuth fallback. - * Reached only via the "Connect with OAuth" button — the API-key path uses the - * standard Add API Key modal, since Xiaomi MiMo supports both auth modes. + * Desktop Plan = Xiaomi account weekly quota (mimo-v2.6 family). Two ways in: + * 1. Import local MiMo Desktop credentials (~/.local/share/mimocode/auth.json) + * 2. Server-side login — no Desktop needed; picks a MiMo account cluster + * (cn / sgp / ams / ru / in). The account session (passToken) is captured + * server-side and stored per connection. + * + * Token Plan (cloud sk- API key) uses the standard "API Key" entry point. */ -export default function XiaomiMimoAuthModal({ isOpen, onSuccess, onClose }) { - const [phase, setPhase] = useState("detecting"); // detecting | found | not-found | importing | error - const [detectResult, setDetectResult] = useState(null); - const [error, setError] = useState(null); - const [oauthUrl, setOauthUrl] = useState(null); - const [oauthState, setOauthState] = useState(null); - // Auto-detect local credentials when modal opens +const CLUSTERS = [ + { id: "cn", flag: "🇨🇳", name: "China (Mainland)", host: "mimo-server-cn" }, + { id: "sgp", flag: "🇸🇬", name: "Singapore", host: "mimo-server-sgp" }, + { id: "ams", flag: "🇪🇺", name: "Europe · Amsterdam", host: "mimo-server-ams" }, + { id: "ru", flag: "🇷🇺", name: "Russia", host: "mimo-server-ru" }, + { id: "in", flag: "🇮🇳", name: "India", host: "mimo-server-in" }, +]; + +export default function XiaomiMimoAuthModal({ isOpen, onSuccess, onClose }) { + const [phase, setPhase] = useState("detecting"); // detecting | found | not-found | importing + const [detectResult, setDetectResult] = useState(null); + const [existingConnection, setExistingConnection] = useState(null); + const [error, setError] = useState(null); + + // Server-side session login + const [showClusterModal, setShowClusterModal] = useState(false); + const [sessBusy, setSessBusy] = useState(false); + const [sessPolling, setSessPolling] = useState(false); + const [sessError, setSessError] = useState(null); + const [sessPageUrl, setSessPageUrl] = useState(null); + const [sessRegion, setSessRegion] = useState("cn"); + const sessTimerRef = useRef(null); + + const stopSessionPoll = () => { + if (sessTimerRef.current) { + clearInterval(sessTimerRef.current); + sessTimerRef.current = null; + } + setSessPolling(false); + }; + + useEffect(() => () => stopSessionPoll(), []); + + // Detect local credentials when the modal opens (non-blocking: never trap the spinner) useEffect(() => { if (!isOpen) return; - let cancelled = false; - (async () => { - setPhase("detecting"); - setError(null); - setDetectResult(null); - setOauthUrl(null); + setPhase("detecting"); + setError(null); + setDetectResult(null); + setExistingConnection(null); + setShowClusterModal(false); + setSessError(null); + const runDetect = async () => { try { - const res = await fetch("/api/oauth/xiaomi-mimo/auto-import"); + const res = await fetch("/api/oauth/xiaomi-mimo/auto-import", { + signal: AbortSignal.timeout(5000), + }); const data = await res.json(); - if (cancelled) return; if (data.found && data.apiKey) { setDetectResult(data); setPhase("found"); + + // Non-blocking: flag an already-imported account + fetch("/api/providers", { signal: AbortSignal.timeout(3000) }) + .then((r) => r.json()) + .then((provData) => { + const foundConn = (provData.connections || []).find( + (c) => + c.provider === "xiaomi-mimo" && + data.uid && + (c.email === `${data.uid}@xiaomi` || + c.providerSpecificData?.uid === data.uid || + c.providerSpecificData?.mimoUserId === data.uid), + ); + if (foundConn) setExistingConnection(foundConn); + }) + .catch(() => {}); } else { setPhase("not-found"); - setError(data.error || "Xiaomi MiMo Desktop credentials not found on this machine."); } } catch { - if (!cancelled) { - setPhase("not-found"); - setError("Failed to read local Xiaomi MiMo Desktop credentials."); - } + setPhase("not-found"); } - })(); + }; - return () => { cancelled = true; }; + runDetect(); }, [isOpen]); - // Import the auto-detected key - const handleImport = async () => { + // Import the auto-detected local desktop credentials + const handleImportLocal = async () => { if (!detectResult?.apiKey) return; setPhase("importing"); setError(null); @@ -73,11 +118,7 @@ export default function XiaomiMimoAuthModal({ isOpen, onSuccess, onClose }) { }), }); const data = await res.json(); - - if (!res.ok || !data.success) { - throw new Error(data.error || "Import failed"); - } - + if (!res.ok || !data.success) throw new Error(data.error || "Import failed"); onSuccess?.(data.connection); onClose(); } catch (err) { @@ -86,183 +127,265 @@ export default function XiaomiMimoAuthModal({ isOpen, onSuccess, onClose }) { } }; - // Start browser OAuth fallback - const handleStartOAuth = async () => { - setError(null); + // Server-side login (account.xiaomi.com) for the chosen cluster + const startSessionLogin = async (region) => { + setSessBusy(true); + setSessError(null); + setShowClusterModal(false); + setSessRegion(region); try { - const state = crypto.randomUUID(); - const res = await fetch(`/api/oauth/xiaomi-mimo/authorize?state=${state}`); + const res = await fetch("/api/oauth/xiaomi-mimo/login/start", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ region }), + }); const data = await res.json(); - if (data.authorizeUrl) { - setOauthUrl(data.authorizeUrl); - setOauthState(data.state); - window.open(data.authorizeUrl, "_blank", "width=600,height=700"); - } else { - throw new Error(data.error || "Failed to start OAuth"); - } - } catch (err) { - setError(err.message); - } - }; - - // Poll OAuth result - const handlePollOAuth = async () => { - if (!oauthState) return; - setError(null); - try { - const res = await fetch(`/api/oauth/xiaomi-mimo/poll-status?state=${oauthState}`); - const data = await res.json(); - - if (data.status === "done" && data.result) { - // Exchange to create the connection - const exRes = await fetch("/api/oauth/xiaomi-mimo/exchange", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ state: oauthState }), - }); - const exData = await exRes.json(); - if (exData.success) { - onSuccess?.(exData.connection); - onClose(); - } else { - throw new Error(exData.error || "Exchange failed"); + if (!res.ok || !data.pageUrl) throw new Error(data.error || "Failed to start login"); + setSessPageUrl(data.pageUrl); + window.open(data.pageUrl, "mimo-session-login", "width=500,height=760"); + setSessPolling(true); + const startedAt = Date.now(); + sessTimerRef.current = setInterval(async () => { + if (Date.now() - startedAt > 14 * 60 * 1000) { + stopSessionPoll(); + setSessError("Login timed out. Please retry."); + return; } - } else if (data.status === "error") { - throw new Error(data.error || "OAuth failed"); - } else { - setError("Authorization not completed yet. Finish in the browser, then click Check Again."); - } + try { + const sres = await fetch(`/api/oauth/xiaomi-mimo/login/status?state=${data.state}`); + const sd = await sres.json(); + if (sd.status === "pending") return; + stopSessionPoll(); + if (sd.status !== "done") { + setSessError(sd.error || "Login session expired — please retry."); + return; + } + const save = await fetch("/api/oauth/xiaomi-mimo/api-key", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + apiKey: "", + uid: sd.userId || null, + mimoPassToken: sd.passToken, + mimoUserId: sd.userId || null, + mimoCUserId: sd.cUserId || null, + region: sd.region || sessRegion, + }), + }); + const saved = await save.json(); + if (!save.ok || !saved.success) throw new Error(saved.error || "Failed to save credentials"); + onSuccess?.(saved.connection); + onClose(); + } catch (err) { + stopSessionPoll(); + setSessError(err.message); + } + }, 2500); } catch (err) { - setError(err.message); + setSessError(err.message); + } finally { + setSessBusy(false); } }; + // The server-login card, shown in both the found and not-found states + const renderServerLogin = () => ( +
    +
    +
    + login + Browser Login + No Desktop required +
    + Weekly quota +
    + {sessPolling ? ( +
    + + {sessPageUrl && ( + + )} +
    + ) : ( + + )} + {sessError &&

    {translate(sessError)}

    } +
    + ); + return ( - -
    + +
    {/* Detecting */} {phase === "detecting" && (
    -
    - +
    + progress_activity
    -

    Reading local credentials...

    -

    - Checking ~/.local/share/mimocode/auth.json -

    +

    Reading local MiMo Desktop credentials...

    )} - {/* Found — one-click import */} - {phase === "found" && detectResult && ( - <> -
    -
    - check_circle -
    -

    Xiaomi MiMo Desktop credentials found!

    -

    - UID: {detectResult.uid || "—"} · Source: {detectResult.source?.split(/[\\/]/).pop()} -

    -
    -
    -
    - - {error && ( -
    -

    {error}

    -
    - )} - -
    - - -
    - - )} - {/* Importing */} {phase === "importing" && (
    -
    - +
    + progress_activity
    -

    Connecting...

    +

    Connecting...

    )} - {/* Not found — offer OAuth fallback */} + {/* Found local desktop credentials */} + {phase === "found" && detectResult && ( +
    +
    + desktop_windows + Desktop Plan · Local credentials +
    + + {existingConnection ? ( +
    +
    + + check_circle + +
    +

    This account is already connected (no need to import again)

    +

    + UID: {detectResult.uid || "—"} · Status: {existingConnection.testStatus === "active" ? "Active" : "Untested"} +

    +
    +
    +
    + ) : ( +
    +
    + + check_circle + +
    +

    Xiaomi MiMo Desktop credentials found!

    +

    + UID: {detectResult.uid || "—"} · Source: {detectResult.source?.split(/[\\/]/).pop()} +

    +
    +
    +
    + )} + + {error && ( +
    +

    {translate(error)}

    +
    + )} + +
    + + +
    + +
    +
    +
    +
    +
    + or +
    +
    + + {renderServerLogin()} +
    + )} + + {/* No local desktop credentials */} {phase === "not-found" && ( - <> +
    -
    - info +
    + info
    -

    Local credentials not found

    -

    {error}

    -

    - Make sure Xiaomi MiMo Desktop is installed and you are signed in, then retry. - Or sign in via browser below. +

    No local Desktop credentials found

    +

    + You can still sign in via browser — no Desktop client needed.

    - {!oauthUrl ? ( -
    - +
    +
    + )} + + {/* Cluster selection sub-modal */} + {showClusterModal && ( +
    +
    +
    +
    + public +

    Select account cluster

    +
    + - + close +
    - ) : ( + +

    Choose the region cluster of your Xiaomi account:

    +
    -
    -

    - Browser opened. Complete the Xiaomi sign-in, then click{" "} - Check Again. -

    -
    -
    - - -
    + {CLUSTERS.map((c) => ( + + ))}
    - )} - + + +
    +
    )}
    diff --git a/tests/unit/xiaomi-mimo-executor.test.js b/tests/unit/xiaomi-mimo-executor.test.js index 10c6a520..1a3c790c 100644 --- a/tests/unit/xiaomi-mimo-executor.test.js +++ b/tests/unit/xiaomi-mimo-executor.test.js @@ -1,6 +1,7 @@ -import { describe, it, expect, vi, beforeEach } from "vitest"; +import { describe, it, expect, beforeEach, vi } from "vitest"; import { XiaomiMimoExecutor, __test__ } from "../../open-sse/executors/xiaomi-mimo.js"; import { getExecutor } from "../../open-sse/executors/index.js"; +import * as mimoAccount from "../../open-sse/shared/mimoAccount.js"; const { bareModel, COOKIE_KEY } = __test__; @@ -17,22 +18,52 @@ describe("xiaomi-mimo executor", () => { expect(getExecutor("xiaomi-mimo")).toBeInstanceOf(XiaomiMimoExecutor); }); - it("routes Preview models to the account-service route regardless of transport", () => { - const expected = "https://mimo-server-cn.xiaomimimo.com/api/route/chat/completions"; - expect(ex.buildUrl("mimo-x-pro-preview", true, 0, OPENAI_T)).toBe(expected); - expect(ex.buildUrl("mimo-x-pro-preview", true, 0, CLAUDE_T)).toBe(expected); - // body.model arrives as `xiaomi/` via upstreamModelId - expect(ex.buildUrl("xiaomi/mimo-x-flash-preview", true, 0, OPENAI_T)).toBe(expected); - }); - it("keeps the sourceFormat-matched endpoint for cloud models", () => { - // Regression: a Claude client must reach /anthropic/v1/messages, not /v1/chat/completions. expect(ex.buildUrl("mimo-v2.5-pro", true, 0, CLAUDE_T)).toBe(CLAUDE_T.runtimeTransport.baseUrl); expect(ex.buildUrl("mimo-v2.5-pro", true, 0, OPENAI_T)).toBe(OPENAI_T.runtimeTransport.baseUrl); }); - it("authenticates Preview calls with the account cookie", () => { - const headers = ex.buildHeaders({ [COOKIE_KEY]: "serviceToken=abc", accessToken: "sk-x" }, true, "u", "mimo-x-pro-preview"); + it("routes v2.6 models to account route when desktop credentials are present", () => { + // No region → SGP default + const expected = "https://mimo-server-sgp.xiaomimimo.com/api/route/chat/completions"; + const credsWithToken = { providerSpecificData: { mimoPassToken: "token123" } }; + const credsWithCookie = { [COOKIE_KEY]: "serviceToken=abc" }; + + expect(ex.buildUrl("mimo-v2.6-flash", true, 0, credsWithToken)).toBe(expected); + expect(ex.buildUrl("mimo-v2.6-pro", true, 0, credsWithCookie)).toBe(expected); + expect(ex.buildUrl("xiaomi/mimo-v2.6-flash", true, 0, credsWithToken)).toBe(expected); + }); + + it("routes v2.6 models to cloud API when no desktop credentials are present", () => { + expect(ex.buildUrl("mimo-v2.6-flash", true, 0, OPENAI_T)).toBe(OPENAI_T.runtimeTransport.baseUrl); + expect(ex.buildUrl("mimo-v2.6-pro", true, 0, CLAUDE_T)).toBe(CLAUDE_T.runtimeTransport.baseUrl); + }); + + it("resolves the account-service cluster per connection region", () => { + const cn = "https://mimo-server-cn.xiaomimimo.com/api/route/chat/completions"; + const sgp = "https://mimo-server-sgp.xiaomimimo.com/api/route/chat/completions"; + const ams = "https://mimo-server-ams.xiaomimimo.com/api/route/chat/completions"; + const ru = "https://mimo-server-ru.xiaomimimo.com/api/route/chat/completions"; + const inRegion = "https://mimo-server-in.xiaomimimo.com/api/route/chat/completions"; + // default (no region) falls back to SGP (the international cluster) + expect(ex.buildUrl("mimo-v2.6-flash", true, 0, { providerSpecificData: { mimoPassToken: "t" } })).toBe(sgp); + expect(ex.buildUrl("mimo-v2.6-pro", true, 0, { providerSpecificData: { region: "cn", mimoPassToken: "t" } })).toBe(cn); + expect(ex.buildUrl("mimo-v2.6-pro", true, 0, { providerSpecificData: { region: "sgp", mimoPassToken: "t" } })).toBe(sgp); + expect(ex.buildUrl("mimo-v2.6-flash", true, 0, { providerSpecificData: { region: "SGP", mimoPassToken: "t" } })).toBe(sgp); + expect(ex.buildUrl("mimo-v2.6-pro", true, 0, { providerSpecificData: { region: "ams", mimoPassToken: "t" } })).toBe(ams); + expect(ex.buildUrl("mimo-v2.6-pro", true, 0, { providerSpecificData: { region: "ru", mimoPassToken: "t" } })).toBe(ru); + expect(ex.buildUrl("mimo-v2.6-pro", true, 0, { providerSpecificData: { region: "in", mimoPassToken: "t" } })).toBe(inRegion); + // unknown region falls back to SGP + expect(ex.buildUrl("mimo-v2.6-pro", true, 0, { providerSpecificData: { region: "eu", mimoPassToken: "t" } })).toBe(sgp); + }); + + it("authenticates v2.6 calls with account cookie when on account route", () => { + const headers = ex.buildHeaders( + { [COOKIE_KEY]: "serviceToken=abc", accessToken: "sk-x" }, + true, + "u", + "mimo-v2.6-flash", + ); expect(headers.Cookie).toBe("serviceToken=abc"); expect(headers.Authorization).toBeUndefined(); }); @@ -43,38 +74,55 @@ describe("xiaomi-mimo executor", () => { expect(headers.Cookie).toBeUndefined(); }); - it("fails fast when a Preview call has no account session", async () => { - await expect( - ex.execute({ model: "mimo-x-pro-preview", body: {}, stream: true, credentials: {}, log: null }), - ).rejects.toThrow(/account session unavailable/); - }); - - it("flattens content-part arrays to plain strings", () => { + it("preserves content-part arrays for multimodal inputs", () => { + const parts = [{ type: "image_url", image_url: { url: "data:image/png;base64,xyz" } }, { type: "text", text: "hi" }]; const out = ex.transformRequest( - "mimo-x-pro-preview", - { messages: [{ role: "user", content: [{ type: "text", text: "a" }, { type: "text", text: "b" }] }] }, + "mimo-v2.6-pro", + { messages: [{ role: "user", content: parts }] }, true, - {}, + { providerSpecificData: { mimoPassToken: "token" } }, ); - expect(out.messages[0].content).toBe("ab"); + expect(out.messages[0].content).toEqual(parts); }); - it("applies Preview defaults without overriding explicit values", () => { + it("bridges reasoning_effort to official output_config.effort", () => { + const creds = { providerSpecificData: { mimoPassToken: "token" } }; + const body = { + messages: [{ role: "user", content: "solve" }], + reasoning_effort: "high", + }; + const out = ex.transformRequest("mimo-v2.6-pro", body, true, creds); + expect(out.reasoning_effort).toBeUndefined(); + expect(out.output_config).toEqual({ effort: "high" }); + }); + + it("normalizes xhigh reasoning_effort to high in output_config.effort", () => { + const creds = { providerSpecificData: { mimoPassToken: "token" } }; + const body = { + messages: [{ role: "user", content: "complex" }], + reasoning_effort: "xhigh", + }; + const out = ex.transformRequest("mimo-v2.6-pro", body, true, creds); + expect(out.reasoning_effort).toBeUndefined(); + expect(out.output_config).toEqual({ effort: "high" }); + }); + + it("applies defaults without overriding explicit values", () => { + const creds = { providerSpecificData: { mimoPassToken: "token" } }; const body = { messages: [{ role: "user", content: "hi" }], temperature: 0.2 }; - const out = ex.transformRequest("mimo-x-pro-preview", body, true, {}); - expect(out.temperature).toBe(0.2); // caller's value kept - expect(out.top_p).toBe(0.95); // default filled in - expect(out.max_tokens).toBe(4096); + const out = ex.transformRequest("mimo-v2.6-pro", body, true, creds); + expect(out.temperature).toBe(0.2); + expect(out.top_p).toBe(0.95); }); - it("leaves cloud bodies free of Preview defaults", () => { + it("leaves cloud bodies free of account defaults", () => { const out = ex.transformRequest("mimo-v2.5-pro", { messages: [{ role: "user", content: "hi" }] }, true, {}); - expect(out.thinking).toBeUndefined(); - expect(out.max_tokens).toBeUndefined(); + expect(out.output_config).toBeUndefined(); + expect(out.temperature).toBeUndefined(); }); - it("strips a provider/model prefix when testing preview ids", () => { - expect(bareModel("xiaomi/mimo-x-pro-preview")).toBe("mimo-x-pro-preview"); - expect(bareModel("mimo-x-pro-preview")).toBe("mimo-x-pro-preview"); + it("strips a provider/model prefix when testing model ids", () => { + expect(bareModel("xiaomi/mimo-v2.6-pro")).toBe("mimo-v2.6-pro"); + expect(bareModel("mimo-v2.6-flash")).toBe("mimo-v2.6-flash"); }); }); diff --git a/tests/unit/xiaomi-mimo-login-session-security.test.js b/tests/unit/xiaomi-mimo-login-session-security.test.js new file mode 100644 index 00000000..b9ec79a7 --- /dev/null +++ b/tests/unit/xiaomi-mimo-login-session-security.test.js @@ -0,0 +1,40 @@ +/** + * Security invariants of the server-assisted MiMo login proxy + * (src/lib/mimoLoginSession.js): + * - credentials bound to 9router's own origin are never forwarded upstream + * - upstream Set-Cookie is never replayed onto the app's own cookie jar + */ +import { describe, it, expect } from "vitest"; +import { __test__ } from "../../src/lib/mimoLoginSession.js"; + +const { STRIP_UPSTREAM_HEADERS, buildBrowserResponse } = __test__; + +describe("mimo login proxy security", () => { + it("strips auth credentials and session cookies before forwarding upstream", () => { + for (const h of ["authorization", "proxy-authorization", "cookie", "host"]) { + expect(STRIP_UPSTREAM_HEADERS.has(h)).toBe(true); + } + }); + + it("does not replay upstream Set-Cookie onto the app origin", async () => { + const upstream = new Response("ok", { + status: 200, + headers: { + "content-type": "text/html", + "set-cookie": "userId=123; Path=/", // plain object header: visible via getSetCookie + }, + }); + const out = await buildBrowserResponse({ jar: new Map() }, upstream, "http://localhost:20128", "/pass/"); + expect(out.headers.getSetCookie()).toEqual([]); + }); + + it("keeps ordinary response headers intact", async () => { + const upstream = new Response("", { + status: 200, + headers: { "content-type": "text/html" }, + }); + const out = await buildBrowserResponse({ jar: new Map() }, upstream, "http://localhost:20128", "/fe/"); + expect(out.status).toBe(200); + expect(out.headers.get("content-type")).toBe("text/html"); + }); +}); From 39e36d3d0c849e0e01dfeacddf111edf892448fc Mon Sep 17 00:00:00 2001 From: decolua Date: Wed, 23 Sep 2026 10:05:33 +0700 Subject: [PATCH 41/41] # v0.5.86 (2026-09-23) ## Features - **Xiaomi MiMo**: server-assisted desktop login for headless/Docker deployments, five account clusters (cn/sgp/ams/ru/in), and v2.6 pro/flash/pro-ultraspeed models with dual-route (account service vs. cloud API) - **Claude**: add Claude Opus 5.5 support - **i18n**: translate React text rewrites via characterData mutation observer ## Fixes - **Proxy Pools**: keep request headers intact through Vercel/Cloudflare/Deno relays (spreading a `Headers` instance yielded `{}`, dropping auth and content-type) - **Xiaomi MiMo login**: keep the session in the httpOnly cookie only, require dashboard auth on the proxy branch, and stop forwarding authorization headers upstream --- CHANGELOG.md | 11 +++++++++++ cli/package.json | 2 +- package.json | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0132bc9..12f32475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +# v0.5.86 (2026-09-23) + +## Features +- **Xiaomi MiMo**: server-assisted desktop login for headless/Docker deployments, five account clusters (cn/sgp/ams/ru/in), and v2.6 pro/flash/pro-ultraspeed models with dual-route (account service vs. cloud API) +- **Claude**: add Claude Opus 5.5 support +- **i18n**: translate React text rewrites via characterData mutation observer + +## Fixes +- **Proxy Pools**: keep request headers intact through Vercel/Cloudflare/Deno relays (spreading a `Headers` instance yielded `{}`, dropping auth and content-type) +- **Xiaomi MiMo login**: keep the session in the httpOnly cookie only, require dashboard auth on the proxy branch, and stop forwarding authorization headers upstream + # v0.5.85 (2026-09-22) ## Features diff --git a/cli/package.json b/cli/package.json index 5692c953..f7a0c677 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "9router", - "version": "0.5.85", + "version": "0.5.86", "description": "9Router CLI - Start and manage 9Router server", "bin": { "9router": "./cli.js" diff --git a/package.json b/package.json index 1a09786c..4dbc5247 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "9router-app", - "version": "0.5.85", + "version": "0.5.86", "description": "9Router web dashboard", "private": true, "scripts": {

    og6cs>8ph&m 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�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�e2loIkF7> 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%0DLrBQ{W?lNex{~7uA6&3kRQZ%PUXaM+(dG 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