mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-25 16:42:16 +03:00
test(executors): adapt remaining 35 suites to the async lazy registry (round 2)
Round 1 only covered suites importing from executors/index.ts directly;
suites importing getExecutor through other paths (open-sse root
re-export, dynamic imports inside tests) still called it synchronously,
producing Promise-vs-instance assertion failures in CI (e.g.
providers-yuanbao-web 'instanceof YuanbaoWebExecutor' false).
Sweep method: repo-wide scan for un-awaited getExecutor call sites,
adapted mechanically (await + async callbacks + Response|{response}
union narrowing); assert.rejects guards with promise-returning
callbacks verified correct as-is.
Locally verified green: providers-yuanbao-web, ninerouter-executor,
provider-request-failure-pipeline, provider-limits-accesstoken-fallback,
executor-registry, chatcore-executor-proxy, poe-api-executor-regression,
web-cookie-providers-new (113/113).
This commit is contained in:
@@ -59,11 +59,11 @@ function mockFetchCapture(status = 200, text = "Hello from Blackbox") {
|
||||
};
|
||||
}
|
||||
|
||||
test("BlackboxWebExecutor is registered in executor index", () => {
|
||||
test("BlackboxWebExecutor is registered in executor index", async () => {
|
||||
assert.ok(hasSpecializedExecutor("blackbox-web"));
|
||||
assert.ok(hasSpecializedExecutor("bb-web"));
|
||||
const executor = getExecutor("blackbox-web");
|
||||
const alias = getExecutor("bb-web");
|
||||
const executor = await getExecutor("blackbox-web");
|
||||
const alias = await getExecutor("bb-web");
|
||||
assert.ok(executor instanceof BlackboxWebExecutor);
|
||||
assert.ok(alias instanceof BlackboxWebExecutor);
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ after(() => {
|
||||
test("no config (disabled by default) returns the provider's own executor", async () => {
|
||||
clearUpstreamProxyConfigCache("openai");
|
||||
const exec = await resolveExecutorWithProxy("openai");
|
||||
assert.equal(exec, getExecutor("openai"));
|
||||
assert.equal(exec, await getExecutor("openai"));
|
||||
});
|
||||
|
||||
test("mode 'native' returns the provider's own executor", async () => {
|
||||
@@ -52,7 +52,7 @@ test("mode 'native' returns the provider's own executor", async () => {
|
||||
});
|
||||
clearUpstreamProxyConfigCache("openai");
|
||||
const exec = await resolveExecutorWithProxy("openai");
|
||||
assert.equal(exec, getExecutor("openai"));
|
||||
assert.equal(exec, await getExecutor("openai"));
|
||||
});
|
||||
|
||||
test("mode 'cliproxyapi' returns the CLIProxyAPI passthrough executor", async () => {
|
||||
@@ -63,7 +63,7 @@ test("mode 'cliproxyapi' returns the CLIProxyAPI passthrough executor", async ()
|
||||
});
|
||||
clearUpstreamProxyConfigCache("anthropic");
|
||||
const exec = await resolveExecutorWithProxy("anthropic");
|
||||
assert.equal(exec, getExecutor("cliproxyapi"));
|
||||
assert.equal(exec, await getExecutor("cliproxyapi"));
|
||||
});
|
||||
|
||||
test("mode 'fallback' returns a distinct wrapper owning its own execute()", async () => {
|
||||
@@ -74,8 +74,8 @@ test("mode 'fallback' returns a distinct wrapper owning its own execute()", asyn
|
||||
});
|
||||
clearUpstreamProxyConfigCache("openai");
|
||||
const exec = await resolveExecutorWithProxy("openai");
|
||||
assert.notEqual(exec, getExecutor("openai"));
|
||||
assert.notEqual(exec, getExecutor("cliproxyapi"));
|
||||
assert.notEqual(exec, await getExecutor("openai"));
|
||||
assert.notEqual(exec, await getExecutor("cliproxyapi"));
|
||||
assert.equal(typeof exec.execute, "function");
|
||||
});
|
||||
|
||||
@@ -94,7 +94,7 @@ test("connection override 'claude-native' selects CLIProxyAPI even when provider
|
||||
const exec = await resolveExecutorWithProxy("openai", undefined, {
|
||||
cliproxyapiMode: "claude-native",
|
||||
});
|
||||
assert.equal(exec, getExecutor("cliproxyapi"));
|
||||
assert.equal(exec, await getExecutor("cliproxyapi"));
|
||||
});
|
||||
|
||||
test("connection override 'claude-native' selects CLIProxyAPI even with no provider config (default)", async () => {
|
||||
@@ -102,7 +102,7 @@ test("connection override 'claude-native' selects CLIProxyAPI even with no provi
|
||||
const exec = await resolveExecutorWithProxy("anthropic", undefined, {
|
||||
cliproxyapiMode: "claude-native",
|
||||
});
|
||||
assert.equal(exec, getExecutor("cliproxyapi"));
|
||||
assert.equal(exec, await getExecutor("cliproxyapi"));
|
||||
});
|
||||
|
||||
test("no connection override + provider mode native → native executor (unchanged)", async () => {
|
||||
@@ -115,13 +115,13 @@ test("no connection override + provider mode native → native executor (unchang
|
||||
const exec = await resolveExecutorWithProxy("openai", undefined, {
|
||||
someOtherField: "x",
|
||||
});
|
||||
assert.equal(exec, getExecutor("openai"));
|
||||
assert.equal(exec, await getExecutor("openai"));
|
||||
});
|
||||
|
||||
test("connection override absent (undefined providerSpecificData) preserves default behaviour", async () => {
|
||||
clearUpstreamProxyConfigCache("openai");
|
||||
const exec = await resolveExecutorWithProxy("openai");
|
||||
assert.equal(exec, getExecutor("openai"));
|
||||
assert.equal(exec, await getExecutor("openai"));
|
||||
});
|
||||
|
||||
test("connection override wins over provider mode 'fallback'", async () => {
|
||||
@@ -135,5 +135,5 @@ test("connection override wins over provider mode 'fallback'", async () => {
|
||||
cliproxyapiMode: "claude-native",
|
||||
});
|
||||
// Connection override short-circuits to the passthrough executor, not the fallback wrapper.
|
||||
assert.equal(exec, getExecutor("cliproxyapi"));
|
||||
assert.equal(exec, await getExecutor("cliproxyapi"));
|
||||
});
|
||||
|
||||
@@ -456,7 +456,7 @@ test("chatCore times out upstream execution before provider response headers", a
|
||||
// (fresh-DB default leaves it off → the waitFor below would never resolve;
|
||||
// failed deterministically on CI and on an isolated run, incl. at v3.8.18).
|
||||
await settingsDb.updateSettings({ call_log_pipeline_enabled: true });
|
||||
const executor = getExecutor("openai");
|
||||
const executor = await getExecutor("openai");
|
||||
const originalGetTimeoutMs = executor.getTimeoutMs?.bind(executor);
|
||||
executor.getTimeoutMs = () => 200;
|
||||
|
||||
|
||||
@@ -370,16 +370,16 @@ function reset() {
|
||||
|
||||
// ─── Registration ───────────────────────────────────────────────────────────
|
||||
|
||||
test("ChatGptWebExecutor is registered in executor index", () => {
|
||||
test("ChatGptWebExecutor is registered in executor index", async () => {
|
||||
assert.ok(hasSpecializedExecutor("chatgpt-web"));
|
||||
assert.ok(hasSpecializedExecutor("cgpt-web"));
|
||||
const executor = getExecutor("chatgpt-web");
|
||||
const executor = await getExecutor("chatgpt-web");
|
||||
assert.ok(executor instanceof ChatGptWebExecutor);
|
||||
});
|
||||
|
||||
test("ChatGptWebExecutor alias resolves to same type", () => {
|
||||
const a = getExecutor("chatgpt-web");
|
||||
const b = getExecutor("cgpt-web");
|
||||
test("ChatGptWebExecutor alias resolves to same type", async () => {
|
||||
const a = await getExecutor("chatgpt-web");
|
||||
const b = await getExecutor("cgpt-web");
|
||||
assert.ok(a instanceof ChatGptWebExecutor);
|
||||
assert.ok(b instanceof ChatGptWebExecutor);
|
||||
});
|
||||
|
||||
@@ -63,14 +63,14 @@ describe("ChipotleExecutor", () => {
|
||||
|
||||
it("is registered in executor index", async () => {
|
||||
const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const exec = getExecutor("chipotle");
|
||||
const exec = await getExecutor("chipotle");
|
||||
assert.ok(exec, "chipotle executor should be registered");
|
||||
assert.ok(exec instanceof ChipotleExecutor);
|
||||
});
|
||||
|
||||
it("pepper alias works", async () => {
|
||||
const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const exec = getExecutor("pepper");
|
||||
const exec = await getExecutor("pepper");
|
||||
assert.ok(exec, "pepper alias should be registered");
|
||||
assert.ok(exec instanceof ChipotleExecutor);
|
||||
});
|
||||
|
||||
@@ -22,14 +22,14 @@ test("B: ClaudeWebExecutor alias cw-web is registered", () => {
|
||||
assert.ok(hasSpecializedExecutor("cw-web"));
|
||||
});
|
||||
|
||||
test("C: ClaudeWebExecutor can be retrieved from executor registry", () => {
|
||||
const executor = getExecutor("claude-web");
|
||||
test("C: ClaudeWebExecutor can be retrieved from executor registry", async () => {
|
||||
const executor = await getExecutor("claude-web");
|
||||
assert.ok(executor instanceof ClaudeWebExecutor);
|
||||
});
|
||||
|
||||
test("D: ClaudeWebExecutor cw-web alias resolves to same type", () => {
|
||||
const a = getExecutor("claude-web");
|
||||
const b = getExecutor("cw-web");
|
||||
test("D: ClaudeWebExecutor cw-web alias resolves to same type", async () => {
|
||||
const a = await getExecutor("claude-web");
|
||||
const b = await getExecutor("cw-web");
|
||||
assert.ok(a instanceof ClaudeWebExecutor);
|
||||
assert.ok(b instanceof ClaudeWebExecutor);
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const { refreshAndUpdateCredentials } = await import("../../src/lib/usage/providerLimits.ts");
|
||||
|
||||
test("codex: quota-sync must NOT proactively rotate the refresh_token (Auth0 family-revocation cascade guard)", async () => {
|
||||
const exec = getExecutor("codex");
|
||||
const exec = await getExecutor("codex");
|
||||
const origNeeds = exec.needsRefresh;
|
||||
const origRefresh = exec.refreshCredentials;
|
||||
let refreshCalls = 0;
|
||||
@@ -68,7 +68,7 @@ test("codex: quota-sync must NOT proactively rotate the refresh_token (Auth0 fam
|
||||
});
|
||||
|
||||
test("non-rotating OAuth provider is still refreshed proactively from quota-sync (gate is not over-broad)", async () => {
|
||||
const exec = getExecutor("cursor");
|
||||
const exec = await getExecutor("cursor");
|
||||
const origNeeds = exec.needsRefresh;
|
||||
const origRefresh = exec.refreshCredentials;
|
||||
let refreshCalls = 0;
|
||||
|
||||
@@ -91,15 +91,15 @@ test("Command Code provider catalog has pinned models and alias lookup", () => {
|
||||
assert.equal(getRegistryEntry("cmd"), entry);
|
||||
});
|
||||
|
||||
test("getExecutor returns the specialized Command Code executor", () => {
|
||||
test("getExecutor returns the specialized Command Code executor", async () => {
|
||||
assert.equal(hasSpecializedExecutor("command-code"), true);
|
||||
assert.ok(getExecutor("command-code") instanceof CommandCodeExecutor);
|
||||
assert.ok(getExecutor("cmd") instanceof CommandCodeExecutor);
|
||||
assert.ok((await getExecutor("command-code")) instanceof CommandCodeExecutor);
|
||||
assert.ok((await getExecutor("cmd")) instanceof CommandCodeExecutor);
|
||||
});
|
||||
|
||||
test("Command Code executor posts a flat OpenAI body + standard headers to /provider/v1/chat/completions (#10265)", async () => {
|
||||
const calls = captureFetch({});
|
||||
const executor = getExecutor("command-code");
|
||||
const executor = await getExecutor("command-code");
|
||||
const { response, url, headers } = await executor.execute({
|
||||
model: "gpt-5.4-mini",
|
||||
stream: false,
|
||||
@@ -143,7 +143,7 @@ test("Command Code executor posts a flat OpenAI body + standard headers to /prov
|
||||
|
||||
test("Command Code executor passes reasoning/thinking fields through at the top level of the OpenAI body", async () => {
|
||||
const calls = captureFetch({});
|
||||
await getExecutor("command-code").execute({
|
||||
(await getExecutor("command-code")).execute({
|
||||
model: "deepseek/deepseek-v4-pro",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -166,7 +166,7 @@ test("Command Code executor passes reasoning/thinking fields through at the top
|
||||
|
||||
test("Command Code executor honors body.model rewrite from payload rules", async () => {
|
||||
const calls = captureFetch({});
|
||||
await getExecutor("command-code").execute({
|
||||
(await getExecutor("command-code")).execute({
|
||||
model: "deepseek-v4-pro-max",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -187,7 +187,7 @@ test("Command Code executor maps unsupported minimal reasoning_effort to low (up
|
||||
const calls = captureFetch({});
|
||||
// `minimal` (a Muse Spark catalog tier) must be downgraded to `low` before
|
||||
// the wire body is built, on BOTH the combo and single-model paths.
|
||||
await getExecutor("command-code").execute({
|
||||
(await getExecutor("command-code")).execute({
|
||||
model: "poolside/laguna-s-2.1-free",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -232,7 +232,7 @@ test("Command Code executor passes the upstream OpenAI SSE stream through untouc
|
||||
});
|
||||
};
|
||||
|
||||
const { response } = await getExecutor("command-code").execute({
|
||||
const { response } = (await getExecutor("command-code")).execute({
|
||||
model: "gpt-5.4",
|
||||
stream: true,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -266,7 +266,7 @@ test("Command Code executor passes the upstream OpenAI JSON through untouched (n
|
||||
});
|
||||
};
|
||||
|
||||
const { response } = await getExecutor("command-code").execute({
|
||||
const { response } = (await getExecutor("command-code")).execute({
|
||||
model: "gpt-5.4-mini",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -279,7 +279,7 @@ test("Command Code executor passes the upstream OpenAI JSON through untouched (n
|
||||
|
||||
test("Command Code executor surfaces upstream errors", async () => {
|
||||
globalThis.fetch = async () => new Response("bad key", { status: 401, statusText: "Unauthorized" });
|
||||
const upstreamFailure = await getExecutor("command-code").execute({
|
||||
const upstreamFailure = (await getExecutor("command-code")).execute({
|
||||
model: "gpt-5.4-mini",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -291,7 +291,7 @@ test("Command Code executor surfaces upstream errors", async () => {
|
||||
|
||||
test("Command Code executor omits max_tokens when the client does not supply one", async () => {
|
||||
const calls = captureFetch({});
|
||||
await getExecutor("command-code").execute({
|
||||
(await getExecutor("command-code")).execute({
|
||||
model: "zai-org/GLM-5.1",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -305,7 +305,7 @@ test("Command Code executor omits max_tokens when the client does not supply one
|
||||
test("Command Code executor clamps an oversized client-supplied max_tokens to the endpoint ceiling", async () => {
|
||||
const calls = captureFetch({});
|
||||
// A client asking for more than the 200000 endpoint ceiling is clamped down.
|
||||
await getExecutor("command-code").execute({
|
||||
(await getExecutor("command-code")).execute({
|
||||
model: "deepseek/deepseek-v4-pro",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -316,7 +316,7 @@ test("Command Code executor clamps an oversized client-supplied max_tokens to th
|
||||
|
||||
test("Command Code executor honors a smaller client-provided max_tokens", async () => {
|
||||
const calls = captureFetch({});
|
||||
await getExecutor("command-code").execute({
|
||||
(await getExecutor("command-code")).execute({
|
||||
model: "zai-org/GLM-5.1",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
@@ -350,7 +350,7 @@ test("Command Code stream preserves the upstream OpenAI usage chunk (passthrough
|
||||
globalThis.fetch = async () =>
|
||||
new Response(sse, { status: 200, headers: { "Content-Type": "text/event-stream" } });
|
||||
|
||||
const { response } = await getExecutor("command-code").execute({
|
||||
const { response } = (await getExecutor("command-code")).execute({
|
||||
model: "gpt-5.4-mini",
|
||||
stream: true,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
|
||||
@@ -18,13 +18,13 @@ test("DeepSeekWebExecutor registered as deepseek-web and ds-web", () => {
|
||||
assert.ok(hasSpecializedExecutor("ds-web"));
|
||||
});
|
||||
|
||||
test("getExecutor returns DeepSeekWebWithAutoRefreshExecutor", () => {
|
||||
const exec = getExecutor("deepseek-web");
|
||||
test("getExecutor returns DeepSeekWebWithAutoRefreshExecutor", async () => {
|
||||
const exec = await getExecutor("deepseek-web");
|
||||
assert.ok(exec instanceof DeepSeekWebWithAutoRefreshExecutor);
|
||||
});
|
||||
|
||||
test("alias ds-web resolves same executor", () => {
|
||||
assert.ok(getExecutor("ds-web") instanceof DeepSeekWebWithAutoRefreshExecutor);
|
||||
test("alias ds-web resolves same executor", async () => {
|
||||
assert.ok(await getExecutor("ds-web") instanceof DeepSeekWebWithAutoRefreshExecutor);
|
||||
});
|
||||
|
||||
test("provider name is deepseek-web", () => {
|
||||
|
||||
@@ -241,7 +241,7 @@ describe("DuckDuckGoWebExecutor", () => {
|
||||
|
||||
it("should be registered in executor index", async () => {
|
||||
const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const executor = getExecutor("duckduckgo-web");
|
||||
const executor = await getExecutor("duckduckgo-web");
|
||||
assert.ok(executor, "executor should be registered in index");
|
||||
assert.equal(
|
||||
typeof executor.execute,
|
||||
|
||||
@@ -21,13 +21,13 @@ test.after(() => {
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("built-ins are registered at module load and resolve through the registry", () => {
|
||||
test("built-ins are registered at module load and resolve through the registry", async () => {
|
||||
const aliases = listExecutorAliases();
|
||||
assert.ok(aliases.length >= 100, `expected the built-in table, got ${aliases.length} aliases`);
|
||||
for (const alias of ["antigravity", "kiro", "glm", "9router", "conol-web"]) {
|
||||
assert.ok(hasRegisteredExecutor(alias), `missing built-in: ${alias}`);
|
||||
assert.equal(getExecutor(alias), getRegisteredExecutor(alias));
|
||||
assert.ok(getExecutor(alias) instanceof BaseExecutor);
|
||||
assert.equal(await getExecutor(alias), getRegisteredExecutor(alias));
|
||||
assert.ok((await getExecutor(alias)) instanceof BaseExecutor);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -37,21 +37,21 @@ test("registerExecutor throws on duplicate alias", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("registering a new alias makes it resolvable via getExecutor and hasSpecializedExecutor", () => {
|
||||
test("registering a new alias makes it resolvable via getExecutor and hasSpecializedExecutor", async () => {
|
||||
const alias = "registry-test-provider";
|
||||
assert.equal(hasSpecializedExecutor(alias), false);
|
||||
const instance = new DefaultExecutor(alias);
|
||||
registerExecutor(alias, instance);
|
||||
assert.equal(hasSpecializedExecutor(alias), true);
|
||||
assert.equal(getExecutor(alias), instance);
|
||||
assert.equal(await getExecutor(alias), instance);
|
||||
});
|
||||
|
||||
test("registry lookup is exact — Object.prototype names are not executors", () => {
|
||||
test("registry lookup is exact — Object.prototype names are not executors", async () => {
|
||||
// The old object-literal lookup (`executors[provider]`) leaked prototype
|
||||
// members: getExecutor("constructor") returned Object's constructor. The Map
|
||||
// registry must treat these as unknown providers (DefaultExecutor fallback).
|
||||
for (const name of ["constructor", "toString", "hasOwnProperty", "__proto__"]) {
|
||||
assert.equal(hasSpecializedExecutor(name), false, name);
|
||||
assert.ok(getExecutor(name) instanceof DefaultExecutor, name);
|
||||
assert.ok((await getExecutor(name)) instanceof DefaultExecutor, name);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ const providers = [
|
||||
] as const;
|
||||
|
||||
for (const [id, alias, endpoint] of providers) {
|
||||
test(`${id} is wired through registry, metadata, endpoint and default executor`, () => {
|
||||
test(`${id} is wired through registry, metadata, endpoint and default executor`, async () => {
|
||||
const registry = REGISTRY[id];
|
||||
const metadata = APIKEY_PROVIDERS[id];
|
||||
|
||||
@@ -35,7 +35,7 @@ for (const [id, alias, endpoint] of providers) {
|
||||
assert.equal(metadata.hasFree, true);
|
||||
assert.equal(metadata.passthroughModels, true);
|
||||
assert.ok(typeof metadata.freeNote === "string" && metadata.freeNote.length > 0);
|
||||
assert.ok(getExecutor(id) instanceof DefaultExecutor);
|
||||
assert.ok((await getExecutor(id)) instanceof DefaultExecutor);
|
||||
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
|
||||
assert.equal(isValidModel(alias, "future/live-catalog-model"), true);
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ const providers = [
|
||||
] as const;
|
||||
|
||||
for (const [id, endpoint, modelIds] of providers) {
|
||||
test(`${id} is wired through registry, metadata, endpoint and default executor`, () => {
|
||||
test(`${id} is wired through registry, metadata, endpoint and default executor`, async () => {
|
||||
const registry = REGISTRY[id];
|
||||
const metadata = APIKEY_PROVIDERS[id];
|
||||
|
||||
@@ -41,7 +41,7 @@ for (const [id, endpoint, modelIds] of providers) {
|
||||
assert.equal(metadata.passthroughModels, true);
|
||||
assert.ok(typeof metadata.freeNote === "string" && metadata.freeNote.length > 0);
|
||||
assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
|
||||
assert.ok(getExecutor(id) instanceof DefaultExecutor);
|
||||
assert.ok((await getExecutor(id)) instanceof DefaultExecutor);
|
||||
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
|
||||
assert.deepEqual(
|
||||
registry.models.map((model) => model.id),
|
||||
|
||||
@@ -20,7 +20,7 @@ const providers = [
|
||||
] as const;
|
||||
|
||||
for (const [id, endpoint] of providers) {
|
||||
test(`${id} is wired through registry, metadata, endpoint and default executor`, () => {
|
||||
test(`${id} is wired through registry, metadata, endpoint and default executor`, async () => {
|
||||
const registry = REGISTRY[id];
|
||||
const metadata = APIKEY_PROVIDERS[id];
|
||||
|
||||
@@ -36,7 +36,8 @@ for (const [id, endpoint] of providers) {
|
||||
assert.equal(metadata.passthroughModels, true);
|
||||
assert.ok(typeof metadata.freeNote === "string" && metadata.freeNote.length > 0);
|
||||
assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
|
||||
assert.ok(getExecutor(id) instanceof DefaultExecutor);
|
||||
const executor = await getExecutor(id);
|
||||
assert.ok(executor instanceof DefaultExecutor);
|
||||
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
|
||||
assert.deepEqual(registry.models, []);
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ const providers = [
|
||||
] as const;
|
||||
|
||||
for (const [id, endpoint] of providers) {
|
||||
test(`${id} is fully wired without a specialized executor`, () => {
|
||||
test(`${id} is fully wired without a specialized executor`, async () => {
|
||||
const registry = REGISTRY[id];
|
||||
const metadata = APIKEY_PROVIDERS[id];
|
||||
|
||||
@@ -33,7 +33,7 @@ for (const [id, endpoint] of providers) {
|
||||
assert.equal(metadata.passthroughModels, true);
|
||||
assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
|
||||
assert.equal(hasSpecializedExecutor(id), false);
|
||||
const executor = getExecutor(id);
|
||||
const executor = await getExecutor(id);
|
||||
assert.ok(executor instanceof DefaultExecutor);
|
||||
assert.equal(executor.buildUrl("live-model", false), endpoint);
|
||||
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
|
||||
|
||||
@@ -27,7 +27,7 @@ const providers = [
|
||||
] as const;
|
||||
|
||||
for (const { id, endpoint, modelsUrl, hasFree } of providers) {
|
||||
test(`${id} is fully wired through the public provider interfaces`, () => {
|
||||
test(`${id} is fully wired through the public provider interfaces`, async () => {
|
||||
const registry = REGISTRY[id];
|
||||
const metadata = APIKEY_PROVIDERS[id];
|
||||
|
||||
@@ -52,7 +52,7 @@ for (const { id, endpoint, modelsUrl, hasFree } of providers) {
|
||||
assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
|
||||
assert.equal(hasSpecializedExecutor(id), false);
|
||||
|
||||
const executor = getExecutor(id);
|
||||
const executor = await getExecutor(id);
|
||||
assert.ok(executor instanceof DefaultExecutor);
|
||||
assert.equal(executor.buildUrl("live-model", false), endpoint);
|
||||
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
|
||||
|
||||
@@ -73,8 +73,8 @@ for (const [id, subPath] of Object.entries(SUB_PATHS)) {
|
||||
);
|
||||
});
|
||||
|
||||
test(`#6650 ${id} resolves through getExecutor() as a DefaultExecutor instance`, () => {
|
||||
const executor = getExecutor(id);
|
||||
test(`#6650 ${id} resolves through getExecutor() as a DefaultExecutor instance`, async () => {
|
||||
const executor = await getExecutor(id);
|
||||
assert.ok(
|
||||
executor instanceof DefaultExecutor,
|
||||
`${id} has no custom executor — must fall through to DefaultExecutor`
|
||||
|
||||
@@ -7,9 +7,9 @@ const { getExecutor, hasSpecializedExecutor } = await import("../../open-sse/exe
|
||||
|
||||
// ─── Registration ───────────────────────────────────────────────────────────
|
||||
|
||||
test("GeminiWebExecutor is registered in executor index", () => {
|
||||
test("GeminiWebExecutor is registered in executor index", async () => {
|
||||
assert.ok(hasSpecializedExecutor("gemini-web"));
|
||||
const executor = getExecutor("gemini-web");
|
||||
const executor = await getExecutor("gemini-web");
|
||||
assert.ok(executor instanceof GeminiWebExecutor);
|
||||
});
|
||||
|
||||
|
||||
@@ -83,9 +83,9 @@ test.afterEach(() => {
|
||||
|
||||
// ─── Registration ───────────────────────────────────────────────────────────
|
||||
|
||||
test("GrokWebExecutor is registered in executor index", () => {
|
||||
test("GrokWebExecutor is registered in executor index", async () => {
|
||||
assert.ok(hasSpecializedExecutor("grok-web"));
|
||||
const executor = getExecutor("grok-web");
|
||||
const executor = await getExecutor("grok-web");
|
||||
assert.ok(executor instanceof GrokWebExecutor);
|
||||
});
|
||||
|
||||
|
||||
@@ -498,13 +498,13 @@ describe("NineRouterExecutor", () => {
|
||||
describe("getExecutor registration", () => {
|
||||
it("getExecutor('9router') returns a NineRouterExecutor", async () => {
|
||||
const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const exec = getExecutor("9router");
|
||||
const exec = await getExecutor("9router");
|
||||
assert.equal(exec.getProvider(), "9router");
|
||||
});
|
||||
|
||||
it("getExecutor('nr') alias resolves to NineRouterExecutor", async () => {
|
||||
const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const exec = getExecutor("nr");
|
||||
const exec = await getExecutor("nr");
|
||||
assert.equal(exec.getProvider(), "9router");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -91,16 +91,16 @@ function mockFetchError(error) {
|
||||
|
||||
// ─── Test: Executor registration ────────────────────────────────────────────
|
||||
|
||||
test("PerplexityWebExecutor is registered in executor index", () => {
|
||||
test("PerplexityWebExecutor is registered in executor index", async () => {
|
||||
assert.ok(hasSpecializedExecutor("perplexity-web"));
|
||||
assert.ok(hasSpecializedExecutor("pplx-web"));
|
||||
const executor = getExecutor("perplexity-web");
|
||||
const executor = await getExecutor("perplexity-web");
|
||||
assert.ok(executor instanceof PerplexityWebExecutor);
|
||||
});
|
||||
|
||||
test("PerplexityWebExecutor alias resolves to same type", () => {
|
||||
const a = getExecutor("perplexity-web");
|
||||
const b = getExecutor("pplx-web");
|
||||
test("PerplexityWebExecutor alias resolves to same type", async () => {
|
||||
const a = await getExecutor("perplexity-web");
|
||||
const b = await getExecutor("pplx-web");
|
||||
assert.ok(a instanceof PerplexityWebExecutor);
|
||||
assert.ok(b instanceof PerplexityWebExecutor);
|
||||
});
|
||||
|
||||
@@ -47,17 +47,18 @@ function headerRecord(headers: Record<string, string>): Record<string, string> {
|
||||
return out;
|
||||
}
|
||||
|
||||
test("#8969: getExecutor(poe) selects DefaultExecutor, not PoeWebExecutor", () => {
|
||||
test("#8969: getExecutor(poe) selects DefaultExecutor, not PoeWebExecutor", async () => {
|
||||
assert.equal(hasSpecializedExecutor("poe"), false);
|
||||
const executor = getExecutor("poe");
|
||||
const executor = await getExecutor("poe");
|
||||
assert.ok(executor instanceof DefaultExecutor);
|
||||
assert.equal(executor instanceof PoeWebExecutor, false);
|
||||
assert.equal(executor.provider, "poe");
|
||||
});
|
||||
|
||||
test("#8969: getExecutor(poe-web) still selects PoeWebExecutor", () => {
|
||||
test("#8969: getExecutor(poe-web) still selects PoeWebExecutor", async () => {
|
||||
assert.equal(hasSpecializedExecutor("poe-web"), true);
|
||||
assert.ok(getExecutor("poe-web") instanceof PoeWebExecutor);
|
||||
const executor = await getExecutor("poe-web");
|
||||
assert.ok(executor instanceof PoeWebExecutor);
|
||||
});
|
||||
|
||||
test("#8969: registry declares API-key executor + all three Poe protocol URLs", () => {
|
||||
@@ -80,8 +81,8 @@ test("#8969: registry declares API-key executor + all three Poe protocol URLs",
|
||||
assert.notEqual(gpt.targetFormat, "claude");
|
||||
});
|
||||
|
||||
test("#8969: buildUrl routes chat / responses / messages correctly", () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
test("#8969: buildUrl routes chat / responses / messages correctly", async () => {
|
||||
const executor = (await getExecutor("poe")) as DefaultExecutor;
|
||||
const creds = { apiKey: "poe-test-key", providerSpecificData: {} };
|
||||
|
||||
assert.equal(executor.buildUrl("gemma-4-31b", false, 0, creds), CHAT_URL);
|
||||
@@ -175,8 +176,8 @@ test("#8969: resolvePoeUpstreamUrl normalizes registry-default / bare-host /v1/
|
||||
}
|
||||
});
|
||||
|
||||
test("#8969: buildHeaders uses Bearer auth and never sends Cookie", () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
test("#8969: buildHeaders uses Bearer auth and never sends Cookie", async () => {
|
||||
const executor = (await getExecutor("poe")) as DefaultExecutor;
|
||||
for (const stream of [false, true]) {
|
||||
const headers = headerRecord(
|
||||
executor.buildHeaders({ apiKey: "poe-test-key", providerSpecificData: {} }, stream)
|
||||
@@ -200,7 +201,7 @@ test("#8969: resolveExecutionCredentials forces responses upstream for poe", ()
|
||||
});
|
||||
|
||||
test("#8969: mocked execute posts Chat Completions with Bearer, no Cookie, stripped model", async () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
const executor = (await getExecutor("poe")) as DefaultExecutor;
|
||||
const originalFetch = globalThis.fetch;
|
||||
const seen: Array<{
|
||||
url: string;
|
||||
@@ -259,7 +260,7 @@ test("#8969: mocked execute posts Chat Completions with Bearer, no Cookie, strip
|
||||
});
|
||||
|
||||
test("#8969: mocked execute routes Responses + Messages fixtures to the right URLs", async () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
const executor = (await getExecutor("poe")) as DefaultExecutor;
|
||||
const originalFetch = globalThis.fetch;
|
||||
let lastUrl = "";
|
||||
|
||||
@@ -326,7 +327,7 @@ test("#8969: mocked execute routes Responses + Messages fixtures to the right UR
|
||||
});
|
||||
|
||||
test("#8969: mocked upstream 405 is preserved (not swallowed)", async () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
const executor = (await getExecutor("poe")) as DefaultExecutor;
|
||||
const originalFetch = globalThis.fetch;
|
||||
|
||||
globalThis.fetch = (async () => {
|
||||
|
||||
@@ -39,7 +39,7 @@ function geminiConnection() {
|
||||
}
|
||||
|
||||
test("falls back to the existing accessToken for a non-github provider when refreshCredentials returns null", async () => {
|
||||
const exec = getExecutor("gemini");
|
||||
const exec = await getExecutor("gemini");
|
||||
const origNeeds = exec.needsRefresh;
|
||||
const origRefresh = exec.refreshCredentials;
|
||||
exec.needsRefresh = () => true; // force the refresh attempt
|
||||
@@ -65,7 +65,7 @@ test("falls back to the existing accessToken for a non-github provider when refr
|
||||
});
|
||||
|
||||
test("still throws when refresh fails AND there is no accessToken to fall back on", async () => {
|
||||
const exec = getExecutor("gemini");
|
||||
const exec = await getExecutor("gemini");
|
||||
const origNeeds = exec.needsRefresh;
|
||||
const origRefresh = exec.refreshCredentials;
|
||||
exec.needsRefresh = () => true;
|
||||
|
||||
@@ -33,7 +33,7 @@ function importedCodexConnection() {
|
||||
}
|
||||
|
||||
test("force re-mints an imported rotating account that needsRefresh would skip (#3019 reactive)", async () => {
|
||||
const exec = getExecutor("codex");
|
||||
const exec = await getExecutor("codex");
|
||||
const origNeeds = exec.needsRefresh;
|
||||
const origRefresh = exec.refreshCredentials;
|
||||
let refreshCalls = 0;
|
||||
@@ -65,7 +65,7 @@ test("force re-mints an imported rotating account that needsRefresh would skip (
|
||||
});
|
||||
|
||||
test("force does NOT override the bulk #3019 guard (no allowRotatingRefresh → no mint)", async () => {
|
||||
const exec = getExecutor("codex");
|
||||
const exec = await getExecutor("codex");
|
||||
const origNeeds = exec.needsRefresh;
|
||||
const origRefresh = exec.refreshCredentials;
|
||||
let refreshCalls = 0;
|
||||
|
||||
@@ -33,8 +33,8 @@ test("#6670 freetheai is registered in the executor registry with an OpenAI-comp
|
||||
assert.ok(Array.isArray(entry.models) && entry.models.length > 0, "must seed a fallback model list");
|
||||
});
|
||||
|
||||
test("#6670 freetheai resolves through getExecutor() as a DefaultExecutor instance", () => {
|
||||
const executor = getExecutor("freetheai");
|
||||
test("#6670 freetheai resolves through getExecutor() as a DefaultExecutor instance", async () => {
|
||||
const executor = await getExecutor("freetheai");
|
||||
assert.ok(executor instanceof DefaultExecutor, "freetheai has no custom executor — must fall through to DefaultExecutor");
|
||||
});
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ test("network failure persisted call log includes providerRequest in pipeline pa
|
||||
|
||||
test("network timeout persisted call log includes providerRequest in pipeline payloads", async () => {
|
||||
const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const executor = getExecutor("openai");
|
||||
const executor = await getExecutor("openai");
|
||||
const originalGetTimeoutMs = executor.getTimeoutMs?.bind(executor);
|
||||
executor.getTimeoutMs = () => 200;
|
||||
|
||||
|
||||
@@ -68,8 +68,8 @@ for (const [id, info] of Object.entries(PROVIDERS)) {
|
||||
assert.equal(entry.passthroughModels, true);
|
||||
});
|
||||
|
||||
test(`#6674 ${id} resolves through getExecutor() as a DefaultExecutor instance`, () => {
|
||||
const executor = getExecutor(id);
|
||||
test(`#6674 ${id} resolves through getExecutor() as a DefaultExecutor instance`, async () => {
|
||||
const executor = await getExecutor(id);
|
||||
assert.ok(
|
||||
executor instanceof DefaultExecutor,
|
||||
`${id} has no custom executor — must fall through to DefaultExecutor`
|
||||
|
||||
@@ -39,11 +39,11 @@ test("yuanbao-web appears in the web-cookie catalog with a cookie authHint", ()
|
||||
assert.match(String(entry.website), /yuanbao\.tencent\.com/);
|
||||
});
|
||||
|
||||
test("YuanbaoWebExecutor is wired under id and alias", () => {
|
||||
test("YuanbaoWebExecutor is wired under id and alias", async () => {
|
||||
assert.ok(hasSpecializedExecutor("yuanbao-web"));
|
||||
assert.ok(hasSpecializedExecutor("ybw"));
|
||||
assert.ok(getExecutor("yuanbao-web") instanceof YuanbaoWebExecutor);
|
||||
assert.ok(getExecutor("ybw") instanceof YuanbaoWebExecutor);
|
||||
assert.ok(await getExecutor("yuanbao-web") instanceof YuanbaoWebExecutor);
|
||||
assert.ok(await getExecutor("ybw") instanceof YuanbaoWebExecutor);
|
||||
});
|
||||
|
||||
// ── Behavioral: SSE → OpenAI translation (mocked upstream) ─────────────────────
|
||||
|
||||
@@ -20,13 +20,13 @@ test("hasSpecializedExecutor returns true for t3chat alias", () => {
|
||||
assert.ok(hasSpecializedExecutor("t3chat"));
|
||||
});
|
||||
|
||||
test("getExecutor returns T3ChatWebExecutor for t3-web", () => {
|
||||
const exec = getExecutor("t3-web");
|
||||
test("getExecutor returns T3ChatWebExecutor for t3-web", async () => {
|
||||
const exec = await getExecutor("t3-web");
|
||||
assert.ok(exec instanceof T3ChatWebExecutor);
|
||||
});
|
||||
|
||||
test("getExecutor returns T3ChatWebExecutor for t3chat alias", () => {
|
||||
const exec = getExecutor("t3chat");
|
||||
test("getExecutor returns T3ChatWebExecutor for t3chat alias", async () => {
|
||||
const exec = await getExecutor("t3chat");
|
||||
assert.ok(exec instanceof T3ChatWebExecutor);
|
||||
});
|
||||
|
||||
|
||||
@@ -110,49 +110,51 @@ const noopExecuteInput = {
|
||||
|
||||
// ── Registration Tests ───────────────────────────────────────────────────────
|
||||
|
||||
test("HuggingChat executor is registered", () => {
|
||||
test("HuggingChat executor is registered", async () => {
|
||||
assert.ok(hasSpecializedExecutor("huggingchat"));
|
||||
assert.ok(hasSpecializedExecutor("hc"));
|
||||
const executor = getExecutor("huggingchat");
|
||||
const executor = await getExecutor("huggingchat");
|
||||
assert.ok(executor instanceof HuggingChatExecutor);
|
||||
});
|
||||
|
||||
test("Poe Web executor is registered", () => {
|
||||
test("Poe Web executor is registered", async () => {
|
||||
assert.ok(hasSpecializedExecutor("poe-web"));
|
||||
const executor = getExecutor("poe-web");
|
||||
const executor = await getExecutor("poe-web");
|
||||
assert.ok(executor instanceof PoeWebExecutor);
|
||||
// #8969: canonical API-key `poe` must not route through PoeWebExecutor.
|
||||
assert.equal(hasSpecializedExecutor("poe"), false);
|
||||
assert.ok(!(getExecutor("poe") instanceof PoeWebExecutor));
|
||||
const poeApiExecutor = await getExecutor("poe");
|
||||
assert.ok(!(poeApiExecutor instanceof PoeWebExecutor));
|
||||
});
|
||||
|
||||
test("Venice Web executor is registered", () => {
|
||||
test("Venice Web executor is registered", async () => {
|
||||
assert.ok(hasSpecializedExecutor("venice-web"));
|
||||
assert.ok(hasSpecializedExecutor("ven"));
|
||||
const executor = getExecutor("venice-web");
|
||||
const executor = await getExecutor("venice-web");
|
||||
assert.ok(executor instanceof VeniceWebExecutor);
|
||||
});
|
||||
|
||||
test("v0 Vercel Web executor is registered", () => {
|
||||
test("v0 Vercel Web executor is registered", async () => {
|
||||
assert.ok(hasSpecializedExecutor("v0-vercel-web"));
|
||||
assert.ok(hasSpecializedExecutor("v0"));
|
||||
const executor = getExecutor("v0-vercel-web");
|
||||
const executor = await getExecutor("v0-vercel-web");
|
||||
assert.ok(executor instanceof V0VercelWebExecutor);
|
||||
});
|
||||
|
||||
test("Kimi Web executor is registered", () => {
|
||||
assert.ok(getExecutor("kimi-web") instanceof KimiWebExecutor);
|
||||
test("Kimi Web executor is registered", async () => {
|
||||
const kimiWebExecutor = await getExecutor("kimi-web");
|
||||
assert.ok(kimiWebExecutor instanceof KimiWebExecutor);
|
||||
// #4699: the legacy `kimi` API-key id must never route through Kimi Web.
|
||||
assert.ok(hasSpecializedExecutor("kimi"));
|
||||
const legacyExecutor = getExecutor("kimi");
|
||||
const legacyExecutor = await getExecutor("kimi");
|
||||
assert.ok(legacyExecutor instanceof MoonshotExecutor);
|
||||
assert.ok(!(legacyExecutor instanceof KimiWebExecutor));
|
||||
});
|
||||
|
||||
test("Doubao Web executor is registered", () => {
|
||||
test("Doubao Web executor is registered", async () => {
|
||||
assert.ok(hasSpecializedExecutor("doubao-web"));
|
||||
assert.ok(hasSpecializedExecutor("db"));
|
||||
const executor = getExecutor("doubao-web");
|
||||
const executor = await getExecutor("doubao-web");
|
||||
assert.ok(executor instanceof DoubaoWebExecutor);
|
||||
});
|
||||
|
||||
@@ -190,9 +192,9 @@ test("Doubao Web sets correct provider", () => {
|
||||
|
||||
// ── Registration Tests (Qwen Web) ────────────────────────────────────────────
|
||||
|
||||
test("Qwen Web executor is registered", () => {
|
||||
test("Qwen Web executor is registered", async () => {
|
||||
assert.ok(hasSpecializedExecutor("qwen-web"));
|
||||
const executor = getExecutor("qwen-web");
|
||||
const executor = await getExecutor("qwen-web");
|
||||
assert.ok(executor instanceof QwenWebExecutor);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user