mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-03 05:45:04 +03:00
getNoAuthCandidates() in open-sse/services/autoCombo/virtualFactory.ts built the candidate pool for no-auth providers (opencode/mimocode/etc.) without ever consulting getHiddenModelsByProvider(), unlike the credentialed-connection loop a few lines above it. A model hidden via the dashboard eye icon stayed in every auto/* candidate pool forever and could still be selected. Wire hiddenModelsMap into getNoAuthCandidates() the same way #7622 wired noAuthProviderSpecificData in, mirroring the existing credentialed-connection check.
This commit is contained in:
committed by
GitHub
parent
c95a161709
commit
ded4ac830e
1
changelog.d/fixes/7620-noauth-hidden-filter.md
Normal file
1
changelog.d/fixes/7620-noauth-hidden-filter.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(routing): honor eye-icon hidden models for no-auth providers in auto-combo candidate pools (#7620)
|
||||
@@ -140,7 +140,8 @@ function getNoAuthCandidates(
|
||||
excludedProviders: Set<string>,
|
||||
blockedProviders: Set<string>,
|
||||
disabledNoAuthProviders: Set<string>,
|
||||
noAuthProviderSpecificData: Map<string, Record<string, unknown> | null | undefined>
|
||||
noAuthProviderSpecificData: Map<string, Record<string, unknown> | null | undefined>,
|
||||
hiddenModelsMap: Map<string, Set<string>>
|
||||
): VirtualAutoComboCandidate[] {
|
||||
const registry = getProviderRegistry();
|
||||
const candidates: VirtualAutoComboCandidate[] = [];
|
||||
@@ -190,10 +191,19 @@ function getNoAuthCandidates(
|
||||
? noAuthProviderSpecificData.get(providerDef.alias)
|
||||
: undefined);
|
||||
|
||||
// #7620: honor the eye-icon "hidden" flag (isHidden, from the
|
||||
// modelCompatOverrides/customModels key_value namespaces) the same way the
|
||||
// credentialed-connection loop below does, so a hidden no-auth model never
|
||||
// enters the auto-combo/fusion candidate pool either.
|
||||
const hiddenModels =
|
||||
hiddenModelsMap.get(providerId) ??
|
||||
(typeof providerDef.alias === "string" ? hiddenModelsMap.get(providerDef.alias) : undefined);
|
||||
|
||||
for (const model of registryModels) {
|
||||
const modelId = typeof model?.id === "string" && model.id.trim().length > 0 ? model.id : null;
|
||||
if (!modelId) continue;
|
||||
if (isModelExcludedByConnection(modelId, providerSpecificData)) continue;
|
||||
if (hiddenModels?.has(modelId)) continue;
|
||||
candidates.push({
|
||||
provider: providerId,
|
||||
connectionId: SYNTHETIC_NOAUTH_CONNECTION_ID,
|
||||
@@ -323,7 +333,8 @@ export async function createVirtualAutoCombo(
|
||||
new Set(validConnections.map((conn) => conn.provider)),
|
||||
blockedProviders,
|
||||
disabledNoAuthProviders,
|
||||
noAuthProviderSpecificData
|
||||
noAuthProviderSpecificData,
|
||||
hiddenModelsMap
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
73
tests/unit/noauth-autocombo-hidden-7620.test.ts
Normal file
73
tests/unit/noauth-autocombo-hidden-7620.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* #7620 — hiding a no-auth-provider model with the EYE icon (Dashboard → Models,
|
||||
* `isHidden: true` written via setModelIsHidden()/mergeModelCompatOverride()) does
|
||||
* remove it from `/v1/models`, but `getNoAuthCandidates()` in
|
||||
* `open-sse/services/autoCombo/virtualFactory.ts` never consults
|
||||
* `getHiddenModelsByProvider()` at all (unlike the credentialed-connection loop a
|
||||
* few lines above it, which does). A hidden no-auth model therefore stays in the
|
||||
* `auto/*` candidate pool and can still be selected, causing a 401 when the
|
||||
* upstream account for that hidden model is no longer valid/allowed.
|
||||
*/
|
||||
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-7620-noauth-hidden-"));
|
||||
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
|
||||
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const core = await import("../../src/lib/db/core.ts");
|
||||
const modelsDb = await import("../../src/lib/db/models.ts");
|
||||
const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFactory.ts");
|
||||
|
||||
async function resetStorage() {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
test.beforeEach(async () => {
|
||||
await resetStorage();
|
||||
});
|
||||
|
||||
test.after(async () => {
|
||||
await resetStorage();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
if (ORIGINAL_DATA_DIR === undefined) {
|
||||
delete process.env.DATA_DIR;
|
||||
} else {
|
||||
process.env.DATA_DIR = ORIGINAL_DATA_DIR;
|
||||
}
|
||||
});
|
||||
|
||||
test("#7620: a no-auth model hidden via the eye icon (isHidden:true) must be ABSENT from the auto-combo candidate pool", async () => {
|
||||
modelsDb.setModelIsHidden("opencode", "mimo-v2.5-free", true);
|
||||
|
||||
const hiddenMap = modelsDb.getHiddenModelsByProvider();
|
||||
assert.equal(
|
||||
hiddenMap.get("opencode")?.has("mimo-v2.5-free"),
|
||||
true,
|
||||
"sanity: getHiddenModelsByProvider() must report opencode/mimo-v2.5-free as hidden"
|
||||
);
|
||||
|
||||
const combo = await virtualFactory.createVirtualAutoCombo(undefined);
|
||||
|
||||
const modelStrings = combo.models.map((m: { model: string }) => m.model);
|
||||
assert.ok(
|
||||
!modelStrings.some((model: string) => model.endsWith("/mimo-v2.5-free")),
|
||||
"BUG #7620: the eye-hidden model 'mimo-v2.5-free' must not appear in the auto-combo " +
|
||||
`candidate pool, but it did. Pool: ${JSON.stringify(modelStrings)}`
|
||||
);
|
||||
});
|
||||
|
||||
test("#7620 baseline: with nothing hidden, opencode/mimo-v2.5-free is present in the pool", async () => {
|
||||
const combo = await virtualFactory.createVirtualAutoCombo(undefined);
|
||||
const modelStrings = combo.models.map((m: { model: string }) => m.model);
|
||||
assert.ok(
|
||||
modelStrings.some((model: string) => model.endsWith("/mimo-v2.5-free")),
|
||||
`baseline: with nothing hidden, mimo-v2.5-free must be present. Pool: ${JSON.stringify(modelStrings)}`
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user