mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
reverseModelsDevProviders() only matched MODELS_DEV_PROVIDER_MAP entries by the canonical OmniRoute provider id, but the map's RHS for the OAuth CLI providers (codex/claude) only lists their alias (cx/cc), never the canonical id itself. Since the models.dev sync job writes model_capabilities rows under openai/cx and anthropic/cc (never codex/claude), and the auto-combo gate canonicalizes a codex/... or claude/... target's provider to "codex"/"claude" before the lookup, the synced capability row was unreachable for those two providers. Also probe the provider's alias (via the already-imported PROVIDER_ID_TO_ALIAS) when scanning the map, so a canonical id like "codex"/"claude" still matches entries keyed only by their alias. Co-authored-by: ikelvingo <im.kelvinwong@gmail.com>
This commit is contained in:
committed by
GitHub
parent
61277813b2
commit
6cad24eec0
@@ -0,0 +1 @@
|
||||
- fix(api): reach synced model_capabilities rows for canonical provider ids that only appear as an alias in MODELS_DEV_PROVIDER_MAP, e.g. codex/claude (#8429)
|
||||
@@ -281,9 +281,21 @@ function reverseModelsDevProviders(provider: string): string[] {
|
||||
// models.dev may store capabilities under a different OmniRoute provider id
|
||||
// that also maps from the same upstream models.dev provider. Build reverse
|
||||
// candidates from MODELS_DEV_PROVIDER_MAP (e.g. openai ↔ cx).
|
||||
//
|
||||
// MODELS_DEV_PROVIDER_MAP's RHS is inconsistent: most providers list their
|
||||
// canonical id directly, but the OAuth CLI providers (codex/claude) only
|
||||
// list their alias (cx/cc), never the canonical id. Also probe the
|
||||
// provider's alias so a canonical id like "codex"/"claude" still matches
|
||||
// the map entries keyed only by "cx"/"cc" (#8429).
|
||||
const out = new Set<string>();
|
||||
const providerAlias = PROVIDER_ID_TO_ALIAS[provider] || provider;
|
||||
for (const [modelsDevId, omniIds] of Object.entries(MODELS_DEV_PROVIDER_MAP)) {
|
||||
if (omniIds.includes(provider) || modelsDevId === provider) {
|
||||
if (
|
||||
omniIds.includes(provider) ||
|
||||
omniIds.includes(providerAlias) ||
|
||||
modelsDevId === provider ||
|
||||
modelsDevId === providerAlias
|
||||
) {
|
||||
out.add(modelsDevId);
|
||||
for (const id of omniIds) out.add(id);
|
||||
}
|
||||
|
||||
74
tests/unit/repro-8429-capability-canonicalization.test.ts
Normal file
74
tests/unit/repro-8429-capability-canonicalization.test.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
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-repro-8429-"));
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const core = await import("../../src/lib/db/core.ts");
|
||||
const modelsDevSync = await import("../../src/lib/modelsDevSync.ts");
|
||||
const modelCapabilities = await import("../../src/lib/modelCapabilities.ts");
|
||||
|
||||
function buildCapability(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
tool_call: null, reasoning: null, attachment: null, structured_output: null,
|
||||
temperature: null, modalities_input: "[]", modalities_output: "[]",
|
||||
knowledge_cutoff: null, release_date: null, last_updated: null, status: null,
|
||||
family: null, open_weights: null, limit_context: null, limit_input: null,
|
||||
limit_output: null, interleaved_field: null, ...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function resetStorage() {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
test.beforeEach(() => { resetStorage(); });
|
||||
test.after(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("#8429: synced model_capabilities row written under models.dev mapping is unreachable via the canonical 'codex' provider id", () => {
|
||||
modelsDevSync.saveModelsDevCapabilities({
|
||||
openai: { "gpt-6-codex-preview": buildCapability({ tool_call: false }) },
|
||||
cx: { "gpt-6-codex-preview": buildCapability({ tool_call: false }) },
|
||||
});
|
||||
const viaAlias = modelsDevSync.getSyncedCapability("cx", "gpt-6-codex-preview");
|
||||
assert.equal(viaAlias?.tool_call, false, "row must exist under the alias 'cx'");
|
||||
|
||||
const resolved = modelCapabilities.getResolvedModelCapabilities({
|
||||
provider: "codex",
|
||||
model: "gpt-6-codex-preview",
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
resolved.supportsTools,
|
||||
false,
|
||||
`expected synced tool_call=false to be resolved for provider "codex" (it was ${resolved.supportsTools})`
|
||||
);
|
||||
});
|
||||
|
||||
test("#8429: synced model_capabilities row is unreachable via the canonical 'claude' provider id (same class, alias 'cc')", () => {
|
||||
modelsDevSync.saveModelsDevCapabilities({
|
||||
anthropic: { "claude-preview-9-9": buildCapability({ tool_call: false }) },
|
||||
cc: { "claude-preview-9-9": buildCapability({ tool_call: false }) },
|
||||
});
|
||||
const viaAlias = modelsDevSync.getSyncedCapability("cc", "claude-preview-9-9");
|
||||
assert.equal(viaAlias?.tool_call, false, "row must exist under the alias 'cc'");
|
||||
|
||||
const resolved = modelCapabilities.getResolvedModelCapabilities({
|
||||
provider: "claude",
|
||||
model: "claude-preview-9-9",
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
resolved.supportsTools,
|
||||
false,
|
||||
`expected synced tool_call=false to be resolved for provider "claude" (it was ${resolved.supportsTools})`
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user