mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-03 05:45:04 +03:00
fix: preserve model hidden flags (isHidden) across model sync (#5086)
Integrated into release/v3.8.38 (leva 5)
This commit is contained in:
committed by
GitHub
parent
14eab57ed3
commit
7256d34a23
@@ -28,6 +28,7 @@ _In development — bullets added per PR; finalized at release._
|
||||
- **fix(tts):** resolve Gemini TTS models from catalog and add `gemini-3.1-flash-tts-preview` as the new default Vertex TTS model. (thanks @nguyenha935)
|
||||
- **fix(sse): don't cool down a healthy connection on a self-inflicted upstream timeout (504)** — when OmniRoute's own deadline elapses (surfaced as `TimeoutError`/`BodyTimeoutError` → 504), the connection is no longer disabled/failed-over, so a slow-but-healthy provider isn't penalised for our timeout. Genuine upstream 5xx/429 still trigger cooldown; antigravity keeps its own policy. (thanks @costaeder)
|
||||
- **fix(sse): robust Anthropic `/v1/messages` streaming — real ping keepalive + client-disconnect guard** — slow first tokens on reasoning models could trip strict clients' idle-read watchdog; the route now keeps the stream warm with a real `event: ping` (Anthropic clients ignore SSE comments) from the very first frame, and a client disconnect (AbortError / controller-closed) no longer counts as a provider failure (no failover/cooldown). (thanks @costaeder)
|
||||
- **fix: preserve model hidden flags (`isHidden`) across model sync** — `replaceCustomModels` pruned the compat-override list to the new custom-model ids, silently wiping the `isHidden` flag of eye-hidden SYNCED models on every periodic sync / import (all hidden models turned back on). The redundant cleanup is removed (per-model removal already handles its own compat cleanup), so eye-hidden models stay hidden across re-sync. (#4389, thanks @herjarsa)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -544,14 +544,6 @@ export async function replaceCustomModels(
|
||||
).run(providerId, JSON.stringify(merged));
|
||||
}
|
||||
|
||||
// Remove compat overrides for models that no longer exist
|
||||
const newIds = new Set(models.map((m) => m.id));
|
||||
const compatList = readCompatList(providerId);
|
||||
const filteredCompat = compatList.filter((e) => newIds.has(e.id));
|
||||
if (filteredCompat.length !== compatList.length) {
|
||||
writeCompatList(providerId, filteredCompat);
|
||||
}
|
||||
|
||||
backupDbFile("pre-write");
|
||||
return merged;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* #5086 / #4389 — model visibility reset after periodic sync.
|
||||
*
|
||||
* The EYE/visibility toggle hides a model by writing `isHidden:true` into the
|
||||
* `modelCompatOverrides` namespace via `mergeModelCompatOverride`. Hidden flags
|
||||
* for SYNCED models live there, not in the `customModels` store.
|
||||
*
|
||||
* Before the fix, `replaceCustomModels` pruned the compat-override list down to
|
||||
* only the ids present in the new `customModels` array. The periodic model sync
|
||||
* (and manual import) calls `replaceCustomModels` with a list that does NOT
|
||||
* contain eye-hidden synced models, so their `isHidden` override was silently
|
||||
* wiped — every hidden model turned back on after a sync.
|
||||
*
|
||||
* This guards that an eye-hidden override survives a `replaceCustomModels` call
|
||||
* whose new model list omits that id.
|
||||
*/
|
||||
import test, { before, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
|
||||
// Hermetic DB (see #3782 test): isolate DATA_DIR so override state never leaks
|
||||
// into the shared dev/CI database between runs.
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-test-replace-custom-hide-"));
|
||||
process.env.DATA_DIR = tmpDir;
|
||||
|
||||
const { replaceCustomModels, mergeModelCompatOverride, getModelIsHidden, getModelCompatOverrides } =
|
||||
await import("../../src/lib/localDb.ts");
|
||||
const { resetDbInstance } = await import("../../src/lib/db/core.ts");
|
||||
|
||||
before(() => {
|
||||
resetDbInstance();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
resetDbInstance();
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
const PROVIDER = "llama-cpp-5086";
|
||||
|
||||
test("an eye-hidden override survives replaceCustomModels when the new list omits it", async () => {
|
||||
// Operator hides a SYNCED model "ghost" with the EYE toggle (visibility only).
|
||||
mergeModelCompatOverride(PROVIDER, "ghost", { isHidden: true });
|
||||
assert.equal(getModelIsHidden(PROVIDER, "ghost"), true, "ghost is eye-hidden before sync");
|
||||
|
||||
// A periodic sync / import replaces the CUSTOM models with a list that does
|
||||
// NOT include "ghost" (it lives in the synced store, not customModels).
|
||||
await replaceCustomModels(PROVIDER, [
|
||||
{ id: "keep-1", name: "Keep One" },
|
||||
{ id: "keep-2", name: "Keep Two" },
|
||||
]);
|
||||
|
||||
// The compat override (and thus the hidden flag) must NOT be wiped.
|
||||
assert.equal(
|
||||
getModelIsHidden(PROVIDER, "ghost"),
|
||||
true,
|
||||
"ghost must stay hidden after replaceCustomModels omits it"
|
||||
);
|
||||
const overrides = getModelCompatOverrides(PROVIDER).map((o) => o.id);
|
||||
assert.ok(
|
||||
overrides.includes("ghost"),
|
||||
"the compat override for ghost must still exist after the sync"
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user