diff --git a/changelog.d/fixes/11861-nous-hermes-405b-label.md b/changelog.d/fixes/11861-nous-hermes-405b-label.md new file mode 100644 index 0000000000..c34eb40120 --- /dev/null +++ b/changelog.d/fixes/11861-nous-hermes-405b-label.md @@ -0,0 +1 @@ +- **fix(config):** Nous Research's `Hermes-4-405B` model now displays as "Hermes 4 405B (Nous Research)" in both the provider registry and the free-model catalog, instead of the mislabelled "Hermes 4 7B" ([#11861](https://github.com/diegosouzapw/OmniRoute/issues/11861)) — thanks @Karan825 diff --git a/open-sse/config/freeModelCatalog.data.ts b/open-sse/config/freeModelCatalog.data.ts index 1403e27f06..163b82bc84 100644 --- a/open-sse/config/freeModelCatalog.data.ts +++ b/open-sse/config/freeModelCatalog.data.ts @@ -268,7 +268,7 @@ export const FREE_MODEL_BUDGETS: FreeModelBudget[] = [ { provider: "muse-spark-web", modelId: "muse-spark-contemplating", displayName: "Muse Spark Contemplating", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "muse-spark-web", tos: "avoid" }, { provider: "nebius", modelId: "meta-llama/Llama-3.3-70B-Instruct", displayName: "Llama 3.3 70B Instruct", monthlyTokens: 0, creditTokens: 1000000, freeType: "one-time-initial", poolKey: "nebius", tos: "caution" }, { provider: "nlpcloud", modelId: "llama-3-8b-instruct", displayName: "Llama 3 8B", monthlyTokens: 0, creditTokens: 0, freeType: "recurring-monthly", poolKey: "nlpcloud", tos: "avoid" }, - { provider: "nous-research", modelId: "Hermes-4-405B", displayName: "Hermes 4 7B (Nous Research)", monthlyTokens: 0, creditTokens: 0, freeType: "recurring-credit", poolKey: "nous-research", tos: "ambiguous" }, + { provider: "nous-research", modelId: "Hermes-4-405B", displayName: "Hermes 4 405B (Nous Research)", monthlyTokens: 0, creditTokens: 0, freeType: "recurring-credit", poolKey: "nous-research", tos: "ambiguous" }, { provider: "nous-research", modelId: "Hermes-4-70B", displayName: "Hermes 4 70B (Nous Research)", monthlyTokens: 0, creditTokens: 0, freeType: "recurring-credit", poolKey: "nous-research", tos: "ambiguous" }, { provider: "novita", modelId: "ai-ai/llama-3.1-8b-instruct", displayName: "Llama 3.1 8B", monthlyTokens: 0, creditTokens: 500000, freeType: "one-time-initial", poolKey: "novita", tos: "caution" }, { provider: "nscale", modelId: "moonshotai/Kimi-K2.5", displayName: "moonshotai/Kimi-K2.5", monthlyTokens: 0, creditTokens: 5000000, freeType: "one-time-initial", poolKey: "nscale", tos: "caution" }, diff --git a/open-sse/config/providers/registry/nous-research/index.ts b/open-sse/config/providers/registry/nous-research/index.ts index aaa61ac5ac..e118dbcae7 100644 --- a/open-sse/config/providers/registry/nous-research/index.ts +++ b/open-sse/config/providers/registry/nous-research/index.ts @@ -9,7 +9,7 @@ export const nous_researchProvider: RegistryEntry = { authType: "apikey", authHeader: "bearer", models: [ - { id: "Hermes-4-405B", name: "Hermes 4 7B (Nous Research)" }, + { id: "Hermes-4-405B", name: "Hermes 4 405B (Nous Research)" }, { id: "Hermes-4-70B", name: "Hermes 4 70B (Nous Research)" }, ], }; diff --git a/tests/unit/nous-research-model-labels-11861.test.ts b/tests/unit/nous-research-model-labels-11861.test.ts new file mode 100644 index 0000000000..61751682db --- /dev/null +++ b/tests/unit/nous-research-model-labels-11861.test.ts @@ -0,0 +1,67 @@ +/** + * Regression test for #11861 — Nous Research registry mislabels Hermes-4-405B as "7B" + * + * `open-sse/config/providers/registry/nous-research/index.ts` displayed the 405B-parameter + * model with the copy-pasted name "Hermes 4 7B (Nous Research)". The `id` and `name` fields + * must agree on the model's parameter size for every model this provider ships. + */ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { REGISTRY as providerRegistry } from "../../open-sse/config/providerRegistry.ts"; +import { FREE_MODEL_BUDGETS } from "../../open-sse/config/freeModelCatalog.ts"; + +/** Extracts a parameter-size token like "405B" or "70B" from a string, if present. */ +function extractParamSize(value: string): string | null { + const match = value.match(/(\d+(?:\.\d+)?[BM])\b/i); + return match ? match[1].toUpperCase() : null; +} + +test("nous-research model display names match their id's parameter size", () => { + const entry = providerRegistry["nous-research"]; + assert.ok(entry, "providerRegistry['nous-research'] must be defined"); + assert.ok(entry.models.length > 0, "nous-research must ship at least one model"); + + for (const model of entry.models) { + const idSize = extractParamSize(model.id); + assert.ok(idSize, `nous-research model id "${model.id}" must encode a parameter size`); + + const nameSize = extractParamSize(model.name); + assert.ok( + nameSize, + `nous-research model "${model.id}" display name "${model.name}" must encode a parameter size` + ); + + assert.equal( + nameSize, + idSize, + `nous-research model "${model.id}" display name "${model.name}" advertises ${nameSize} ` + + `but the id says ${idSize}` + ); + } +}); + +test("nous-research Hermes-4-405B is labelled 405B (Nous Research)", () => { + const entry = providerRegistry["nous-research"]; + const model = entry.models.find((m) => m.id === "Hermes-4-405B"); + assert.ok(model, "Hermes-4-405B must be registered"); + assert.equal(model.name, "Hermes 4 405B (Nous Research)"); +}); + +test("nous-research free-model catalog display names match their modelId's parameter size", () => { + const rows = FREE_MODEL_BUDGETS.filter((model) => model.provider === "nous-research"); + assert.ok(rows.length > 0, "FREE_MODEL_BUDGETS must list nous-research models"); + + for (const row of rows) { + const idSize = extractParamSize(row.modelId); + assert.ok(idSize, `nous-research free-catalog modelId "${row.modelId}" must encode a size`); + + const nameSize = extractParamSize(row.displayName); + assert.equal( + nameSize, + idSize, + `nous-research free-catalog "${row.modelId}" displayName "${row.displayName}" advertises ` + + `${nameSize} but the modelId says ${idSize}` + ); + } +});