diff --git a/open-sse/config/freeModelCatalog.data.ts b/open-sse/config/freeModelCatalog.data.ts index 38c17abf2d..7b3ad6946f 100644 --- a/open-sse/config/freeModelCatalog.data.ts +++ b/open-sse/config/freeModelCatalog.data.ts @@ -16,7 +16,7 @@ import type { FreeModelBudget } from "./freeModelCatalog.ts"; * rewrites file timestamps on every deploy, which would report a months-old * catalog as "updated today". Bump this whenever the entries below change. */ -export const FREE_CATALOG_CURATED_AT = "2026-08-18"; +export const FREE_CATALOG_CURATED_AT = "2026-08-20"; export const FREE_MODEL_BUDGETS: FreeModelBudget[] = [ { provider: "chatgpt-web", modelId: "gpt-5.6-luna-free", displayName: "GPT-5.6 Luna (Free)", monthlyTokens: 0, creditTokens: 0, freeType: "recurring-uncapped", poolKey: "chatgpt-web-free", tos: "caution" }, @@ -318,6 +318,7 @@ export const FREE_MODEL_BUDGETS: FreeModelBudget[] = [ { provider: "opencode-zen", modelId: "opencode/north-mini-code-free", displayName: "North Mini Code (free)", monthlyTokens: 0, creditTokens: 0, freeType: "recurring-uncapped", poolKey: "opencode-zen-free", tos: "caution" }, { provider: "opencode-zen", modelId: "opencode/nemotron-3-ultra-free", displayName: "Nemotron 3 Ultra (free)", monthlyTokens: 0, creditTokens: 0, freeType: "recurring-uncapped", poolKey: "opencode-zen-free", tos: "caution" }, { provider: "openrouter", modelId: "auto", displayName: "Auto (Best Available)", monthlyTokens: 1200000, creditTokens: 0, freeType: "recurring-daily", poolKey: "openrouter-free", tos: "caution" }, + { provider: "openrouter", modelId: "stealth/ox-alpha", displayName: "Stealth Ox Alpha (free)", monthlyTokens: 0, creditTokens: 0, freeType: "recurring-daily", poolKey: "openrouter-free", tos: "caution" }, { provider: "pollinations", modelId: "openai", displayName: "OpenAI (Pollinations)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "pollinations", tos: "caution" }, { provider: "pollinations", modelId: "openai-fast", displayName: "OpenAI Fast (Pollinations)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "pollinations", tos: "caution" }, { provider: "pollinations", modelId: "openai-large", displayName: "OpenAI Large (Pollinations)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "pollinations", tos: "caution" }, diff --git a/tests/unit/free-model-catalog-ox-alpha.test.ts b/tests/unit/free-model-catalog-ox-alpha.test.ts new file mode 100644 index 0000000000..00a551ab0f --- /dev/null +++ b/tests/unit/free-model-catalog-ox-alpha.test.ts @@ -0,0 +1,16 @@ +// Regression: stealth/ox-alpha (Stealth Ox Alpha, free 0/0 pricing, 1M context) must +// stay in the openrouter free roster — the /v1/models synced-row filter drops +// pricing metadata, so roster presence is what keeps this model visible under +// hidePaidModels (see #6328). +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { FREE_MODEL_BUDGETS } from "../../open-sse/config/freeModelCatalog.data.ts"; + +test("openrouter free roster includes stealth/ox-alpha", () => { + const entry = FREE_MODEL_BUDGETS.find( + (m) => m.provider === "openrouter" && m.modelId === "stealth/ox-alpha" + ); + assert.ok(entry, "stealth/ox-alpha must be in the openrouter free roster"); + assert.equal(entry!.poolKey, "openrouter-free"); + assert.equal(entry!.monthlyTokens, 0, "must not inflate the shared free-pool budget"); +});