Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/agentcompass/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@magpie-community/gateway-agentcompass",
"version": "0.1.3",
"version": "0.1.4",
"description": "Intent, multi-dimensional capability, Model DNA, subscription quota opportunity-cost, and session-affinity routing plugin for Magpie, powered by AgentCompass.",
"type": "module",
"main": "./src/index.js",
Expand Down
10 changes: 7 additions & 3 deletions packages/agentcompass/src/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -1506,9 +1506,13 @@ export function canonicalModel(rawModel, aliases = MODEL_ALIASES) {
if (aliases[clean]) return aliases[clean];
const slashIdx = clean.indexOf("/");
const unprefixed = slashIdx >= 0 ? clean.slice(slashIdx + 1) : clean;
if (aliases[unprefixed]) return aliases[unprefixed];
const lower = unprefixed.toLowerCase();
if (aliases[lower]) return aliases[lower];
// A multi-prefix id (`openrouter/openai/gpt-5-mini`) also resolves by its last segment, as AgentCompass's
// `resolve_canonical_model` does. An unknown id keeps only its first prefix stripped (`openrouter/qwen/foo` ->
// `qwen/foo`), the key quota.js and continuity.js already match on.
const last = clean.slice(clean.lastIndexOf("/") + 1);
for (const name of [unprefixed, unprefixed.toLowerCase(), last, last.toLowerCase()]) {
if (aliases[name]) return aliases[name];
}
return unprefixed;
}

Expand Down
10 changes: 9 additions & 1 deletion packages/agentcompass/test/router.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import test from "node:test";
import { fileURLToPath } from "node:url";

import { burnScale, effortValue, namedRoute, rankCandidates, selectBestRoute } from "../src/allocator.js";
import { CANONICAL_ROUTES, DEFAULT_SCORING_POLICY, EFFORT_CURVES } from "../src/catalog.js";
import { CANONICAL_ROUTES, DEFAULT_SCORING_POLICY, EFFORT_CURVES, canonicalModel } from "../src/catalog.js";
import {
CACHE_COLD_MS,
CHATGPT_CODEX_COLD_MS,
Expand Down Expand Up @@ -2181,6 +2181,14 @@ test("9.7 PR #670 Round 2 Guard: Mainstream real model IDs & trivial single-vari
`Expected claude-opus-4-6:(high|xhigh|max) for permutation [${candidateModels.join(", ")}], got ${auditOut.model}`
);
}

// A multi-prefix id resolves by its last segment; an unknown one keeps only its first prefix stripped
assert.equal(canonicalModel("openrouter/openai/gpt-5-mini"), "gpt-6-luna");
assert.equal(canonicalModel("OpenRouter/OpenAI/GPT-5-Mini"), "gpt-6-luna");
// Alias keys with capitals (`MiniMax-M3`) need the exact-case last-segment lookup
assert.equal(canonicalModel("openrouter/minimax/MiniMax-M3"), "minimax-m3");
assert.equal(canonicalModel("openrouter/qwen/foo"), "qwen/foo");
assert.equal(canonicalModel("qwen/foo"), "foo");
});

test("9.8 PR #670 Round 2 Guard: `options.fetch` alone never enables external scorer unless `allowExternalScorer === true`", async () => {
Expand Down
Loading