Deploy to Cloudflare Pages / deploy (push) Successful in 30s
- 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
105 lines
4.9 KiB
JavaScript
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)`);
|