scripts/cost.js
#!/usr/bin/env node
// cost.js — estimates extraction cost per model / whole catalogue from the
// interview token budgets, using pricing from scripts/models.js.
import { MODELS, PILOT_MODELS, findModel, estimateCost } from "./models.js";
import { parseArgs, fmtUsd } from "./lib.js";
// Standard-depth interview budgets (tokens per model, before reasoning inflation):
// ~73 cells x ~6 turns x ~2K input avg, ~400K base output.
const BUDGETS = {
minimal: { in: 300_000, out: 150_000 },
standard: { in: 1_000_000, out: 400_000 },
deep: { in: 2_500_000, out: 1_000_000 },
};
const { args } = parseArgs(process.argv.slice(2), {
model: { takes: "value", default: null },
all: { takes: "none", default: false },
pilot: { takes: "none", default: false },
depth: { takes: "value", default: "standard" },
input_m: { takes: "value", default: null },
output_m: { takes: "value", default: null },
});
const budget = BUDGETS[args.depth] || BUDGETS.standard;
const inTok = args.input_m ? parseFloat(args.input_m) * 1e6 : budget.in;
const outTok = args.output_m ? parseFloat(args.output_m) * 1e6 : budget.out;
function perModel(m) {
const out = m.reasoning ? outTok * (m.reasoning_out_mult || 2) : outTok;
return { cost: estimateCost(m, inTok, out), out };
}
if (args.model) {
const m = findModel(args.model);
if (!m) { console.error(`unknown model ${args.model}`); process.exit(1); }
const { cost, out } = perModel(m);
console.log(`${m.id}`);
console.log(` depth=${args.depth} in=${(inTok / 1e6).toFixed(2)}M out≈${(out / 1e6).toFixed(2)}M${m.reasoning ? ` (x${m.reasoning_out_mult} reasoning)` : ""}`);
console.log(` estimated cost: ${fmtUsd(cost)}`);
console.log(` in=$${m.in.toFixed(3)}/M out=$${m.out.toFixed(3)}/M${m.cached_in ? ` cached-in=$${m.cached_in.toFixed(3)}/M` : ""}${m.paid_billing ? " [paid billing required]" : ""}`);
process.exit(0);
}
const list = args.pilot ? PILOT_MODELS.map(findModel) : MODELS;
console.log(`Extraction cost estimate — depth=${args.depth}, in=${(inTok / 1e6).toFixed(2)}M tokens, out=${(outTok / 1e6).toFixed(2)}M base output (reasoning models inflated)`);
console.log("");
let total = 0;
for (const m of list) {
const { cost, out } = perModel(m);
total += cost;
console.log(
` ${m.id.padEnd(48)} ${fmtUsd(cost).padStart(8)} out≈${(out / 1e6).toFixed(1)}M${m.reasoning ? " (reasoning)" : " "}${m.paid_billing ? " [paid billing]" : ""}`
);
}
console.log("-".repeat(90));
console.log(` ${args.pilot ? "PILOT TOTAL" : "FULL CATALOGUE TOTAL"} (${list.length} models)`.padEnd(58) + fmtUsd(total).padStart(8));
console.log(`\nNote: free allocation is 10,000 Neurons/day (~$0.11/day) — negligible at this scale.`);