mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
fix(auth): opencode-zen falls back to anonymous no-auth when no key (#2962)
opencode-zen serves the public, signup-free OpenCode Zen endpoint (https://opencode.ai/zen/v1). With no API-key connection configured, getProviderCredentials returned null, so the Playground/combos surfaced "No credentials for provider: opencode-zen" when selecting an OpenCode free model. Fall back to synthetic no-auth credentials for opencode-zen when no usable connection exists (a configured active key is still selected first; a rate-limited/terminal key returns its own signal before this point). Other api-key providers are unaffected. Closes #2962
This commit is contained in:
@@ -94,6 +94,12 @@
|
||||
validation falls through to the chat probe for such 403s instead of returning
|
||||
"Invalid API key", and `checkFallbackError` short-circuits them to no cooldown.
|
||||
Genuine auth failures (401 / generic 403) still fail fast. (#2929)
|
||||
- **auth/opencode-zen:** the OpenCode Zen free model now works in the Playground
|
||||
and combos without an API key. `opencode-zen` serves the public, signup-free
|
||||
endpoint (`https://opencode.ai/zen/v1`); when no api-key connection is
|
||||
configured, credential resolution now falls back to anonymous (no-auth) access
|
||||
instead of failing with "No credentials for provider: opencode-zen". A
|
||||
configured, active key is still used when present. (#2962)
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
|
||||
@@ -943,6 +943,31 @@ export async function getProviderCredentials(
|
||||
};
|
||||
}
|
||||
}
|
||||
// #2962: opencode-zen exposes the public, signup-free OpenCode Zen endpoint
|
||||
// (https://opencode.ai/zen/v1). With no usable API-key connection, fall back
|
||||
// to anonymous (no-auth) access — the free tier — instead of erroring with
|
||||
// "No credentials". This is what the Playground/combos hit when selecting an
|
||||
// OpenCode free model. A configured, active key is still selected above; a
|
||||
// rate-limited/terminal key returns its own signal before reaching here.
|
||||
if (resolvedId === "opencode-zen") {
|
||||
return {
|
||||
apiKey: null,
|
||||
accessToken: null,
|
||||
refreshToken: null,
|
||||
expiresAt: null,
|
||||
projectId: null,
|
||||
copilotToken: null,
|
||||
providerSpecificData: {},
|
||||
connectionId: "noauth",
|
||||
testStatus: "active",
|
||||
lastError: null,
|
||||
lastErrorType: null,
|
||||
lastErrorSource: null,
|
||||
errorCode: null,
|
||||
rateLimitedUntil: null,
|
||||
maxConcurrent: null,
|
||||
};
|
||||
}
|
||||
log.warn("AUTH", `No credentials for ${provider}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
48
tests/unit/auth-opencode-zen-noauth-fallback.test.ts
Normal file
48
tests/unit/auth-opencode-zen-noauth-fallback.test.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Issue #2962 — Playground cannot use the OpenCode free model:
|
||||
* "No credentials for the provider: opencode-zen".
|
||||
*
|
||||
* opencode-zen serves the public, signup-free OpenCode Zen endpoint
|
||||
* (https://opencode.ai/zen/v1). When no API-key connection is configured,
|
||||
* getProviderCredentials returned null → the chat handler surfaced
|
||||
* "No credentials for provider: opencode-zen". It must instead fall back to
|
||||
* anonymous (no-auth) credentials so the free tier works.
|
||||
*/
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-opencode-zen-noauth-"));
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const core = await import("../../src/lib/db/core.ts");
|
||||
const { getProviderCredentials } = await import("../../src/sse/services/auth.ts");
|
||||
|
||||
test.after(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("#2962 opencode-zen with no connection falls back to anonymous no-auth credentials", async () => {
|
||||
const creds = await getProviderCredentials("opencode-zen");
|
||||
assert.ok(creds, "opencode-zen must resolve to credentials, not null (no-auth free tier)");
|
||||
assert.equal(
|
||||
(creds as { connectionId?: string }).connectionId,
|
||||
"noauth",
|
||||
"should be synthetic no-auth credentials"
|
||||
);
|
||||
assert.equal(
|
||||
(creds as { apiKey?: unknown }).apiKey,
|
||||
null,
|
||||
"anonymous access carries no api key"
|
||||
);
|
||||
});
|
||||
|
||||
test("#2962 a normal api-key provider with no connection still returns null (no over-broadening)", async () => {
|
||||
const creds = await getProviderCredentials("openai");
|
||||
// Must NOT synthesize no-auth creds for a real api-key provider.
|
||||
const connectionId = (creds as { connectionId?: string } | null)?.connectionId;
|
||||
assert.notEqual(connectionId, "noauth", "openai must not get anonymous no-auth credentials");
|
||||
});
|
||||
Reference in New Issue
Block a user