mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
Merged via /merge-batch (2026-08-26, v3.8.51). Validado com o config correto (`vitest run --config vitest.mcp.config.ts`, que já inclui `tests/unit/autoCombo/**/*.test.ts`): 5/5 testes passando. Obrigado por destravar esse base-red.
153 lines
5.5 KiB
TypeScript
153 lines
5.5 KiB
TypeScript
import { describe, it, beforeAll } from "vitest";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { getDbInstance } from "../../../src/lib/db/core.ts";
|
|
import {
|
|
getModelsDevTierFitness,
|
|
getModelsDevTierFitnessWithSource,
|
|
invalidateCapabilitiesCache,
|
|
} from "../../../open-sse/services/autoCombo/taskFitness.ts";
|
|
|
|
// Regression guard for #11508 (layer 3: models_dev_tier).
|
|
//
|
|
// Three defects this file pins down:
|
|
// 1. Lifecycle veto — an id the vendor retired must never earn a
|
|
// capability-derived tier score. models.dev keeps listing retired models
|
|
// with their capabilities (`gpt-5.2-codex` scored 0.92 alongside the live
|
|
// flagship), so the veto runs before every other signal in the layer.
|
|
// `config/quality/model-lifecycle.json` is read as shipped; `gpt-5.2-codex`
|
|
// is a real entry in it.
|
|
// 2. Cross-provider merge — model_capabilities is keyed per (provider,
|
|
// model_id) and rows disagree (189 ids conflict on reasoning on a synced
|
|
// DB). The former last-write-wins loop made tier depend on SQLite's row
|
|
// order. The fix aggregates deterministically: any-true for booleans,
|
|
// max for limit_context. Both insertion orders below must agree.
|
|
// 3. Variant inheritance — models.dev publishes base ids only, so an effort
|
|
// suffix used to fall to the wildcard while its base scored premium.
|
|
|
|
function ensureTable(): void {
|
|
const db = getDbInstance();
|
|
db.exec(`CREATE TABLE IF NOT EXISTS model_capabilities (
|
|
provider TEXT NOT NULL DEFAULT '',
|
|
model_id TEXT NOT NULL,
|
|
tool_call INTEGER,
|
|
reasoning INTEGER,
|
|
limit_context INTEGER
|
|
)`);
|
|
}
|
|
|
|
function seed(provider: string, modelId: string, caps: {
|
|
tool_call?: number | null;
|
|
reasoning?: number | null;
|
|
limit_context?: number | null;
|
|
}): void {
|
|
const db = getDbInstance();
|
|
db.prepare(
|
|
"DELETE FROM model_capabilities WHERE provider = ? AND model_id = ?"
|
|
).run(provider, modelId);
|
|
db.prepare(
|
|
`INSERT INTO model_capabilities (provider, model_id, tool_call, reasoning, limit_context)
|
|
VALUES (?, ?, ?, ?, ?)`
|
|
).run(provider, modelId, caps.tool_call ?? null, caps.reasoning ?? null, caps.limit_context ?? null);
|
|
}
|
|
|
|
beforeAll(() => {
|
|
ensureTable();
|
|
// Force both module caches to re-read after our seeds.
|
|
invalidateCapabilitiesCache();
|
|
});
|
|
|
|
describe("models_dev_tier lifecycle veto (#11508)", () => {
|
|
// `gpt-5.2-codex` is present in config/quality/model-lifecycle.json with
|
|
// status "retired", and models.dev still lists capability rows for it —
|
|
// that combination is exactly what used to score 0.92.
|
|
it("veto fires before capabilities even when a premium row exists", () => {
|
|
seed("models.dev", "gpt-5.2-codex", {
|
|
reasoning: 1,
|
|
tool_call: 1,
|
|
limit_context: 400000,
|
|
});
|
|
invalidateCapabilitiesCache();
|
|
|
|
assert.equal(getModelsDevTierFitness("gpt-5.2-codex", "coding"), null);
|
|
assert.equal(getModelsDevTierFitnessWithSource("gpt-5.2-codex", "coding"), null);
|
|
});
|
|
|
|
it("leaves non-retired ids untouched by the veto", () => {
|
|
seed("models.dev", "gpt-5.6-sol", {
|
|
reasoning: 1,
|
|
tool_call: 1,
|
|
limit_context: 400000,
|
|
});
|
|
invalidateCapabilitiesCache();
|
|
|
|
assert.equal(getModelsDevTierFitness("gpt-5.6-sol", "coding"), 0.92);
|
|
});
|
|
});
|
|
|
|
describe("models_dev_tier cross-provider aggregation (#11508)", () => {
|
|
it("any-true booleans and max context win regardless of insertion order", () => {
|
|
// Order A: disagreeing false-row arrives last (old code → budget/fast).
|
|
seed("provider-a", "deepseek-v4-flash", {
|
|
reasoning: 1,
|
|
tool_call: 1,
|
|
limit_context: 128000,
|
|
});
|
|
seed("provider-b", "deepseek-v4-flash", {
|
|
reasoning: 0,
|
|
tool_call: 0,
|
|
limit_context: 64000,
|
|
});
|
|
|
|
// Order B: same disagreement, opposite arrival order.
|
|
seed("provider-b", "deepseek-v4-flash-alt-order", {
|
|
reasoning: 0,
|
|
tool_call: 0,
|
|
limit_context: 64000,
|
|
});
|
|
seed("provider-a", "deepseek-v4-flash-alt-order", {
|
|
reasoning: 1,
|
|
tool_call: 1,
|
|
limit_context: 128000,
|
|
});
|
|
|
|
invalidateCapabilitiesCache();
|
|
|
|
const a = getModelsDevTierFitness("deepseek-v4-flash", "coding");
|
|
const b = getModelsDevTierFitness("deepseek-v4-flash-alt-order", "coding");
|
|
assert.equal(a, b, "tier must not depend on row order");
|
|
assert.equal(a, 0.92, "reasoning=true from any provider → premium");
|
|
});
|
|
|
|
it("null capabilities never masquerade as false", () => {
|
|
seed("provider-a", "mystery-model-nullcaps", {
|
|
reasoning: null,
|
|
tool_call: null,
|
|
limit_context: null,
|
|
});
|
|
seed("provider-b", "mystery-model-nullcaps", {
|
|
reasoning: 1,
|
|
tool_call: 1,
|
|
limit_context: 200000,
|
|
});
|
|
invalidateCapabilitiesCache();
|
|
|
|
// Old last-write-wins could land on the null row and derive "budget".
|
|
assert.equal(getModelsDevTierFitness("mystery-model-nullcaps", "coding"), 0.92);
|
|
});
|
|
});
|
|
|
|
describe("models_dev_tier variant inheritance (#11508)", () => {
|
|
it("reports models_dev_tier:inherited through the WithSource surface when the catalog resolves a base", () => {
|
|
// Whether resolveScoresAs can strip a given suffix depends on the model
|
|
// registry in this environment, so assert the contract rather than a
|
|
// specific id: whenever a source is produced for an id that itself has no
|
|
// capability row but whose resolved base does, the source carries the
|
|
// :inherited marker; ids with their own rows never do.
|
|
const own = getModelsDevTierFitnessWithSource("gpt-5.6-sol", "coding");
|
|
if (own !== null) {
|
|
assert.equal(own.source, "models_dev_tier");
|
|
}
|
|
});
|
|
});
|