refactor(open-sse): registry consolidation + DRY media/oauth/adhoc cleanup

- Single-source registry: oauth clientId/tokenUrl, usage URLs, image/embed
  configs, search defaultModel, codex fixedPort, google token url derive.
- Remove 29 unused OmniRoute providers (registry 100→71); media intact.
- De-adhoc: codex literals → registry format/oauth flags; reasoningInject,
  image/embed openrouter headers + xai bodyFields config-driven.
- Add REGISTRY_TEMPLATE.js + expand PROVIDER_DEFAULTS/schema JSDoc.
- Baselines updated; PROVIDERS 62 + alias 90 byte-for-byte, golden snapshots.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
decolua
2026-06-14 13:15:48 +07:00
co-authored by Cursor
parent 9105dd0e25
commit bb9e9aa91f
166 changed files with 3089 additions and 3067 deletions
+4 -3
View File
@@ -31,8 +31,7 @@ describe("antigravity oauth client (deduped)", () => {
expect(gc.transport.clientSecret).toBe(GOOGLE.clientSecret);
});
// Vitest can't resolve the `@/` alias used inside oauth.js (pre-existing infra gap),
// so guard the refactor textually: it must spread the shared client + keep other fields.
// Guard: oauth.js must spread shared clients + derive from registry (PROVIDER_OAUTH).
it("src oauth.js imports shared client + keeps full shape", async () => {
const { readFileSync } = await import("node:fs");
const { fileURLToPath } = await import("node:url");
@@ -42,7 +41,9 @@ describe("antigravity oauth client (deduped)", () => {
expect(src).toContain('import { ANTIGRAVITY_OAUTH_CLIENT, GOOGLE_OAUTH_CLIENT } from "open-sse/providers/shared.js"');
expect(src).toContain("...ANTIGRAVITY_OAUTH_CLIENT");
expect(src).toContain("...GOOGLE_OAUTH_CLIENT");
expect(src).toContain('authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth"');
// authorizeUrl now lives in registry; oauth.js derives via PROVIDER_OAUTH spread
expect(src).toContain('PROVIDER_OAUTH["antigravity"]');
expect(src).toContain('PROVIDER_OAUTH["gemini-cli"]');
expect(src).not.toContain(EXPECTED.clientSecret); // antigravity secret no longer hardcoded here
expect(src).not.toContain(GOOGLE.clientSecret); // gemini secret no longer hardcoded here
});
+44
View File
@@ -0,0 +1,44 @@
// Guards D3: antigravity 429/503 retry merged into base via computeRetryDelay hook.
import { describe, it, expect } from "vitest";
import { AntigravityExecutor } from "../../open-sse/executors/antigravity.js";
const MAX = 10000;
function res(status, headers = {}, body = null) {
return {
status,
headers: { get: (k) => headers[k.toLowerCase()] ?? null },
clone: () => ({ text: async () => (body == null ? "" : JSON.stringify(body)) }),
};
}
describe("antigravity computeRetryDelay hook (D3)", () => {
const ag = new AntigravityExecutor();
it("uses Retry-After header (seconds → ms) when within cap", async () => {
expect(await ag.computeRetryDelay(res(429, { "retry-after": "5" }), 1)).toBe(5000);
});
it("vetoes (false) when Retry-After exceeds cap", async () => {
expect(await ag.computeRetryDelay(res(429, { "retry-after": "60" }), 1)).toBe(false);
});
it("parses retry time from error body when no header", async () => {
const r = res(429, {}, { error: { message: "quota will reset after 3s" } });
expect(await ag.computeRetryDelay(r, 1)).toBe(3000);
});
it("exponential backoff for 429 when no retry info", async () => {
expect(await ag.computeRetryDelay(res(429), 1)).toBe(Math.min(1000 * 2 ** 1, MAX));
expect(await ag.computeRetryDelay(res(429), 3)).toBe(Math.min(1000 * 2 ** 3, MAX));
});
it("503 without retry info → veto (no auto backoff)", async () => {
expect(await ag.computeRetryDelay(res(503), 1)).toBe(false);
});
it("buildHeaders includes cached session id after transformRequest", () => {
ag._lastSessionId = "sess-123";
const h = ag.buildHeaders({ accessToken: "tok" }, true);
expect(h["X-Machine-Session-Id"]).toBe("sess-123");
});
});
+97
View File
@@ -0,0 +1,97 @@
// Locks BaseExecutor.execute retry/fallback behavior (docs 04 GAP #1, docs 11 §7).
import { describe, it, expect, vi, beforeEach } from "vitest";
// Mock the network layer so we can script upstream responses.
const fetchMock = vi.fn();
vi.mock("../../open-sse/utils/proxyFetch.js", () => ({
proxyAwareFetch: (...args) => fetchMock(...args),
}));
const { BaseExecutor } = await import("../../open-sse/executors/base.js");
function res(status) {
return { status, headers: { get: () => "" } };
}
function makeExec(config) {
const ex = new BaseExecutor("test", config);
// make headers trivial; credentials empty
return ex;
}
const creds = { apiKey: "k" };
beforeEach(() => fetchMock.mockReset());
describe("BaseExecutor.execute — retry by status (config-driven)", () => {
it("retries 502 `attempts` times then succeeds", async () => {
const ex = makeExec({ baseUrl: "https://x/api", retry: { 502: { attempts: 3, delayMs: 0 } } });
fetchMock
.mockResolvedValueOnce(res(502))
.mockResolvedValueOnce(res(502))
.mockResolvedValueOnce(res(200));
const out = await ex.execute({ model: "m", body: {}, stream: false, credentials: creds });
expect(out.response.status).toBe(200);
expect(fetchMock).toHaveBeenCalledTimes(3);
});
it("stops after exhausting 502 attempts on a single url and throws", async () => {
const ex = makeExec({ baseUrl: "https://x/api", retry: { 502: { attempts: 2, delayMs: 0 } } });
fetchMock.mockResolvedValue(res(502));
// single url: 1 initial + 2 retries = 3 calls, then returns the 502 response (no fallback url)
const out = await ex.execute({ model: "m", body: {}, stream: false, credentials: creds });
expect(out.response.status).toBe(502);
expect(fetchMock).toHaveBeenCalledTimes(3);
});
});
describe("BaseExecutor.execute — baseUrls fallback", () => {
it("falls over to the next url on 429 (shouldRetry)", async () => {
const ex = makeExec({ baseUrls: ["https://a/api", "https://b/api"], retry: { 429: { attempts: 0 } } });
fetchMock
.mockResolvedValueOnce(res(429)) // url[0] → fallback
.mockResolvedValueOnce(res(200)); // url[1] ok
const out = await ex.execute({ model: "m", body: {}, stream: false, credentials: creds });
expect(out.response.status).toBe(200);
expect(out.url).toBe("https://b/api");
expect(fetchMock).toHaveBeenCalledTimes(2);
});
});
describe("BaseExecutor.execute — network error retry/fallback", () => {
it("maps network exception to 502 retry config", async () => {
const ex = makeExec({ baseUrl: "https://x/api", retry: { 502: { attempts: 1, delayMs: 0 } } });
fetchMock
.mockImplementationOnce(async () => { throw new Error("ECONNRESET"); })
.mockResolvedValueOnce(res(200));
const out = await ex.execute({ model: "m", body: {}, stream: false, credentials: creds });
expect(out.response.status).toBe(200);
expect(fetchMock).toHaveBeenCalledTimes(2);
});
it("throws when the only url fails with network error and no retries left", async () => {
const ex = makeExec({ baseUrl: "https://x/api", retry: { 502: { attempts: 0 } } });
// mockImplementationOnce (not persistent) avoids vitest flagging a reused rejection.
fetchMock.mockImplementationOnce(async () => { throw new Error("boom"); });
let thrown = null;
try {
await ex.execute({ model: "m", body: {}, stream: false, credentials: creds });
} catch (e) {
thrown = e;
}
expect(thrown?.message).toBe("boom");
expect(fetchMock).toHaveBeenCalledTimes(1);
});
});
describe("BaseExecutor.execute — computeRetryDelay hook veto", () => {
it("hook returning false skips retry (uses fallback path)", async () => {
const ex = makeExec({ baseUrl: "https://x/api", retry: { 429: { attempts: 5, delayMs: 0 } } });
ex.computeRetryDelay = vi.fn().mockResolvedValue(false);
fetchMock.mockResolvedValueOnce(res(429));
const out = await ex.execute({ model: "m", body: {}, stream: false, credentials: creds });
// hook vetoes retry → no fallback url → returns the 429 response as-is
expect(out.response.status).toBe(429);
expect(fetchMock).toHaveBeenCalledTimes(1);
});
});
+28
View File
@@ -0,0 +1,28 @@
// Guards C2: regex name fallback (no catalog). Terse entries derive name; existing names untouched.
import { describe, it, expect } from "vitest";
import { deriveModelName } from "../../open-sse/providers/models/namePatterns.js";
import { normalizeModel } from "../../open-sse/providers/models/schema.js";
describe("model name regex fallback (C2)", () => {
it("derives display name from id per family", () => {
expect(deriveModelName("kimi-k2.5")).toBe("Kimi K2.5");
expect(deriveModelName("glm-4.6v")).toBe("GLM 4.6V (Vision)");
expect(deriveModelName("minimax-m2.7")).toBe("MiniMax M2.7");
expect(deriveModelName("gpt-5.4-mini")).toBe("GPT 5.4 Mini");
expect(deriveModelName("grok-4")).toBe("Grok 4");
});
it("falls back to id verbatim when no pattern matches", () => {
expect(deriveModelName("some-unknown-model")).toBe("some-unknown-model");
});
it("normalizeModel: explicit name always wins over regex", () => {
expect(normalizeModel({ id: "kimi-k2.5", name: "Custom" }).name).toBe("Custom");
});
it("normalizeModel: terse string id becomes object with derived name", () => {
const m = normalizeModel("glm-5");
expect(m.id).toBe("glm-5");
expect(m.name).toBe("GLM 5");
});
});
+58
View File
@@ -0,0 +1,58 @@
// Locks multimodal quirks flagged in docs 11 §4: image_url.detail drop + input_audio per-format.
import { describe, it, expect } from "vitest";
import { openaiToClaudeRequest } from "../../open-sse/translator/request/openai-to-claude.js";
import { convertOpenAIContentToParts } from "../../open-sse/translator/helpers/geminiHelper.js";
function userImage(detail) {
return {
model: "claude-sonnet-4-6",
messages: [{
role: "user",
content: [
{ type: "text", text: "look" },
{ type: "image_url", image_url: { url: "data:image/png;base64,AAAB", detail } },
],
}],
};
}
describe("openai→claude: image_url.detail is dropped (docs 11 §4)", () => {
it("converts image to base64 source WITHOUT a detail field", () => {
const out = openaiToClaudeRequest("claude-sonnet-4-6", userImage("high"), false);
const imgBlock = out.messages[0].content.find((b) => b.type === "image");
expect(imgBlock).toBeTruthy();
expect(imgBlock.source).toEqual({ type: "base64", media_type: "image/png", data: "AAAB" });
expect("detail" in imgBlock).toBe(false);
expect("detail" in imgBlock.source).toBe(false);
});
it("drops input_audio entirely (claude has no audio block)", () => {
const body = {
model: "claude-sonnet-4-6",
messages: [{ role: "user", content: [
{ type: "text", text: "hi" },
{ type: "input_audio", input_audio: { data: "ZZZ", format: "wav" } },
] }],
};
const out = openaiToClaudeRequest("claude-sonnet-4-6", body, false);
const blocks = out.messages[0].content;
expect(blocks.some((b) => b.type === "audio" || b.type === "input_audio")).toBe(false);
});
});
describe("openai→gemini: input_audio is mapped to inlineData (docs 11 §4)", () => {
it("maps wav → audio/wav inlineData", () => {
const parts = convertOpenAIContentToParts([{ type: "input_audio", input_audio: { data: "ZZZ", format: "wav" } }]);
expect(parts).toEqual([{ inlineData: { mime_type: "audio/wav", data: "ZZZ" } }]);
});
it("maps mp3 → audio/mpeg inlineData", () => {
const parts = convertOpenAIContentToParts([{ type: "input_audio", input_audio: { data: "ZZZ", format: "mp3" } }]);
expect(parts[0].inlineData.mime_type).toBe("audio/mpeg");
});
it("drops image_url.detail (not carried into inlineData)", () => {
const parts = convertOpenAIContentToParts([{ type: "image_url", image_url: { url: "data:image/png;base64,AAAB", detail: "high" } }]);
expect(parts).toEqual([{ inlineData: { mime_type: "image/png", data: "AAAB" } }]);
});
});
+34
View File
@@ -0,0 +1,34 @@
// Guards E1: display fields live in providersDisplay.js, merged back into AI_PROVIDERS (shape unchanged).
import { describe, it, expect } from "vitest";
const DISPLAY_FIELDS = ["name", "icon", "color"];
describe("provider display split (E1)", () => {
it("AI_PROVIDERS entries still carry merged display + transport", async () => {
const { AI_PROVIDERS } = await import("../../src/shared/constants/providers.js");
const kiro = AI_PROVIDERS.kiro;
// display merged
expect(kiro.name).toBe("Kiro AI");
expect(kiro.icon).toBe("psychology_alt");
// transport kept
expect(kiro.id).toBe("kiro");
expect(kiro.alias).toBe("kr");
// transport-heavy provider keeps its config
expect(AI_PROVIDERS.gemini.serviceKinds).toContain("tts");
expect(AI_PROVIDERS.gemini.ttsConfig).toBeTruthy();
});
it("display fields source from providersDisplay.js", async () => {
const { PROVIDER_DISPLAY } = await import("../../src/shared/constants/providersDisplay.js");
const { AI_PROVIDERS } = await import("../../src/shared/constants/providers.js");
for (const f of DISPLAY_FIELDS) {
expect(PROVIDER_DISPLAY.kiro[f]).toBe(AI_PROVIDERS.kiro[f]);
}
});
it("helpers still work after split", async () => {
const m = await import("../../src/shared/constants/providers.js");
expect(m.ALIAS_TO_ID.kr).toBe("kiro");
expect(m.getProvidersByKind("tts").length).toBeGreaterThan(0);
});
});
@@ -0,0 +1,47 @@
// Locks edge cases flagged in docs 11 §1/§4 that were only covered indirectly.
import { describe, it, expect } from "vitest";
import { normalizeClaudePassthrough } from "../../open-sse/translator/helpers/claudeHelper.js";
import { parseDataUri, encodeDataUri } from "../../open-sse/translator/helpers/imageHelper.js";
describe("normalizeClaudePassthrough — haiku adaptive thinking (docs 11 §1)", () => {
it("downgrades adaptive thinking to enabled+budget for haiku models", () => {
const out = normalizeClaudePassthrough({ thinking: { type: "adaptive" } }, "claude-haiku-4-5");
expect(out.thinking).toEqual({ type: "enabled", budget_tokens: 10000 });
});
it("keeps adaptive thinking for sonnet/opus", () => {
const out = normalizeClaudePassthrough({ thinking: { type: "adaptive" } }, "claude-sonnet-4-6");
expect(out.thinking).toEqual({ type: "adaptive" });
});
it("hoists mid-conversation system messages into top-level system", () => {
const out = normalizeClaudePassthrough({
messages: [
{ role: "user", content: "hi" },
{ role: "system", content: "be brief" },
],
});
expect(out.system).toEqual([{ type: "text", text: "be brief" }]);
expect(out.messages.every((m) => m.role !== "system")).toBe(true);
});
});
describe("parseDataUri / encodeDataUri (docs 11 §4)", () => {
it("parses a base64 data uri", () => {
expect(parseDataUri("data:image/png;base64,AAAB")).toEqual({ mimeType: "image/png", base64: "AAAB" });
});
it("tolerates newlines inside base64 payload", () => {
expect(parseDataUri("data:image/jpeg;base64,AA\nBB")?.base64).toBe("AA\nBB");
});
it("returns null for http urls and non-strings", () => {
expect(parseDataUri("https://x/y.png")).toBeNull();
expect(parseDataUri(null)).toBeNull();
});
it("encode/parse roundtrip", () => {
const uri = encodeDataUri("image/webp", "ZZZ");
expect(parseDataUri(uri)).toEqual({ mimeType: "image/webp", base64: "ZZZ" });
});
});