Files
OpenCodeGoEvals/scripts/build-models-md.mjs
T
devadmin 4e5a13f7b6
Deploy to Cloudflare Pages / deploy (push) Successful in 30s
Automate the evaluation on a weekly schedule
- scripts/sync-catalog.mjs: rebuilds the Go catalogue from models.dev and benchmark
  scores from Artificial Analysis, and records what changed in snapshot.json
- scripts/build-models-md.mjs: regenerates MODELS.md from the data layers
- scripts/notify-new-models.mjs: files an issue when a new model needs a write-up
- weekly-eval.yml: cron every Monday 05:23 UTC -> refresh -> commit -> Pages deploy
- site now renders every model in the catalogue (33) with a data-snapshot stamp;
  auto-added models are flagged 'no write-up' until described
- replaced scripts/refresh-evals.mjs with the wider sync script
2026-10-21 17:06:51 +00:00

105 lines
4.9 KiB
JavaScript

#!/usr/bin/env node
// Regenerates MODELS.md from the three data layers.
//
// node scripts/build-models-md.mjs
//
// site/assets/catalog.js auto — catalogue metadata
// site/assets/evals.js auto — benchmark scores
// site/assets/data.js hand — descriptions and targeting
import { writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const { CATALOG, SNAPSHOT } = await import(resolve(ROOT, "site/assets/catalog.js"));
const { RAW } = await import(resolve(ROOT, "site/assets/evals.js"));
const { GO_MODELS, FREE_NOTES } = await import(resolve(ROOT, "site/assets/data.js"));
const DESC = Object.fromEntries(GO_MODELS.map((m) => [m.id, m]));
const SCORE = Object.fromEntries(RAW.map((m) => [m.id, m]));
const fmtCtx = (c) => (c ? `${(c / 1e6).toFixed(c % 1e6 ? 2 : 0)}M` : "n/a");
let md = `# OpenCode Go — what each model is for
Short, practical notes on every model in the OpenCode Go catalogue: what each one is targeted for
(agentic work, coding, data analysis, image understanding, deep research, high-volume chores),
what it costs, and what to watch out for.
Evaluated scores come from Artificial Analysis (single consistent harness) plus vendor model cards.
Catalogue metadata comes from models.dev's OpenCode Go provider. Data snapshot: **${(SNAPSHOT.generated || "").slice(0, 10)}**.
The interactive version with the full task matrix lives at \`site/index.html\`.
> No model in the Go catalogue generates images. Every Go model is text-output; several accept image,
> video, PDF or audio as **input**.
## Quick picks
| If you need… | Use |
|---|---|
| The strongest model overall, for hard agentic + coding work | Gemini 4 Argon Contributor |
| The best value per token for everyday coding agents | DeepSeek V4.1 Flash |
| Zero-cost exploration (limited time) | MiniMax M3.1 Flash Free, Beam Free, LongCat 2.5 Preview Free |
| Long-horizon agent runs with multimodal input | Muse Spark 1.3 Contributor, MiMo-V2.6-Pro |
| Repo-scale code changes | Kimi K2.7 Code, GLM-5.3, Qwen3.8 Max |
| Spreadsheets / data analysis deliverables | Kimi K3, Qwen3.8 Max |
| Reading screenshots, charts and documents | Qwen3.8 Flash, GLM-5.3-Flash, MiniMax M3 |
| High-volume, latency-sensitive work | Claude Haiku 5.5, GPT-6 Luna, MiMo-V2.5 |
## The catalogue
`;
const sorted = CATALOG.slice().sort((a, b) => {
const ia = SCORE[a.id]?.ii ?? -1;
const ib = SCORE[b.id]?.ii ?? -1;
return ib - ia;
});
for (const m of sorted) {
const d = DESC[m.id];
const s = SCORE[m.id];
md += `### ${m.name}\n\n`;
md += `**${m.lab || "undisclosed"}** · released ${m.released || "?"} · $${m.price.in} in / $${m.price.out} out per 1M tokens`;
md += m.free ? " · **free tier (limited time)**" : "";
md += ` · ${fmtCtx(m.ctx)} context · ${m.modalities}\n\n`;
if (d?.best?.length) md += `Targeted for: **${d.best.join(", ")}**\n\n`;
if (d?.blurb) md += `${d.blurb}\n\n`;
else md += `${m.description || "_No description published._"}\n\n`;
if (d?.target) md += `${d.target}\n\n`;
else md += "_No hand-written write-up yet._\n\n";
if (s?.ii !== null && s?.ii !== undefined) {
md += `*Evaluated:* Intelligence Index ${s.ii}`;
const extra = [
s.fc != null ? `FrontierCode ${s.fc}` : null,
s.tb21 != null ? `TB2.1 ${s.tb21}` : s.tb40 != null ? `TB4.0 ${s.tb40}` : null,
s.auto != null ? `AutomationBench ${s.auto}` : null,
s.gpqa != null ? `GPQA ${s.gpqa}` : null,
s.hle != null ? `HLE ${s.hle}` : null,
s.lcr != null ? `LCR ${s.lcr}` : null,
s.mmmu != null ? `MMMU-Pro ${s.mmmu}` : null
].filter(Boolean);
if (extra.length) md += " · " + extra.join(" · ");
md += "\n\n";
} else {
md += "*Evaluated:* no public third-party evaluation published yet.\n\n";
}
if (d?.caveats?.length) md += `**Caveats**\n\n${d.caveats.map((c) => `- ${c}`).join("\n")}\n\n`;
}
md += `## Free models outside the Go plan\n\n`;
for (const f of FREE_NOTES) {
md += `### ${f.name} (${f.lab})\n\n`;
md += `*Where:* ${f.where}\n\n${f.target}\n\n_${f.note}_\n\n`;
}
md += `## Sources\n\n`;
md += `- [OpenCode Go docs](https://opencode.ai/docs/go) — pricing, allowances, privacy and retention per model\n`;
md += `- [models.dev](https://models.dev) — OpenCode Go catalogue metadata (pricing, context, modalities)\n`;
md += `- [OpenCode Data](https://opencode.ai/data) — usage, retention, market share\n`;
md += `- [Artificial Analysis](https://artificialanalysis.ai) — benchmark scores and the Intelligence Index\n`;
md += `- Vendor announcements: Google (Gemini 4 Argon), Reflection AI (Beam), Meituan (LongCat), MiniMax, xAI (Grok 4.7), StepFun (Step 5), Qwen, Zhipu, Moonshot, DeepSeek, Xiaomi, Tencent\n`;
writeFileSync(resolve(ROOT, "MODELS.md"), md);
console.log(`wrote MODELS.md (${md.length} bytes, ${sorted.length} models)`);