Skip to content
Merged
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
38 changes: 37 additions & 1 deletion lib/estimate.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,40 @@ const SPEECH_RATE = {
const SPEECH_DEFAULT_RATE = 0.05; // elevenlabs/flash-v2.5 (the MCP default)
const SOUND_EFFECT_COST = 0.0525;

// Chat models billed $0 — mirrors @blockrun/mcp FREE_CHAT_MODELS
// (src/utils/constants.ts), refreshed 2026-10-20. Membership by id, not
// vendor: cohere/ and poolside/ have $0 models, and not every nvidia/ id is
// guaranteed free. Sources: GET /v1/models billing_mode "free" and the account
// price sheet (blockrun.ai/api/pricing) at $0.
const FREE_CHAT_MODELS = new Set([
"nvidia/gpt-oss-20b", "nvidia/nemotron-3-super-120b", "nvidia/llama-3.2-11b-vision",
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning", "cohere/north-mini-code", "poolside/laguna-xs-2.1",
"nvidia/gpt-oss-120b", "nvidia/nemotron-3-ultra-550b", "nvidia/step-3.7-flash", "nvidia/mistral-nemotron",
"nvidia/nemotron-nano-12b-v2-vl", "nvidia/nemotron-nano-9b-v2", "nvidia/nemotron-3.5-lightning",
"nvidia/muse-glimmer-30b", "nvidia/gemma-4-31b", "nvidia/nemotron-3-super-120b-a12b-free",
"nvidia/qwen3.5-397b-a17b", "nvidia/nemotron-ultra-253b", "nvidia/nemotron-super-49b", "nvidia/deepseek-v3.2",
"nvidia/nemotron-3-nano-omni-nim",
"nvidia/mistral-large-3-675b", "nvidia/qwen3-coder-480b", "nvidia/devstral-2-123b", "nvidia/glm-4.7",
"nvidia/llama-4-maverick", "nvidia/qwen3-next-80b-a3b-instruct", "nvidia/qwen3.5-122b-a10b",
"nvidia/seed-oss-36b", "nvidia/mistral-small-4-119b",
]);
// nvidia/deepseek-v4-pro and nvidia/deepseek-v4-flash are NOT here: the
// gateways retired both (unknown-model 400; blockrun#848 and its follow-up).
//
// Bare spellings the gateway also accepts. A free id whose bare name belongs
// to a PAID model must be listed here and excluded, so the paid model wins
// the spelling (MCP FREE_SHADOWED_BY_PAID). Empty since the nvidia DeepSeek
// mirror was retired; bare "deepseek-v4-pro" is the paid
// deepseek/deepseek-v4-pro ($1.32/$3.96) and is not in the free set at all.
const FREE_SHADOWED_BY_PAID = new Set([]);
const FREE_CHAT_BARE = new Set(
[...FREE_CHAT_MODELS].filter((id) => !FREE_SHADOWED_BY_PAID.has(id)).map((id) => id.slice(id.indexOf("/") + 1)),
);
function isFreeChatModel(model) {
const id = String(model || "").trim();
return FREE_CHAT_MODELS.has(id) || (!id.includes("/") && FREE_CHAT_BARE.has(id));
}

// Whether `size` is in `model`'s large tier (see IMAGE_LARGE_THRESHOLD /
// IMAGE_LARGE_MIN_DIM). Unparseable sizes price at the base.
function isLargerThanBase(model, size) {
Expand Down Expand Up @@ -147,7 +181,9 @@ function estimate(toolName, input = {}) {
return { usd: paid ? 0.001 : 0, label: `price · ${cat || "crypto"}${paid ? "" : " (free)"}` };
}
case "chat": {
const free = input.mode === "free" || /^nvidia\//.test(input.model || "");
// An explicit model wins over mode, as in the MCP: mode is ignored when
// model is set.
const free = input.model ? isFreeChatModel(input.model) : input.mode === "free";
return { usd: free ? 0 : 0.005, label: `chat${free ? " (free tier)" : ""}` };
}
// Wallet + models are always free; data tools (if a fuller profile is used)
Expand Down