summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2026-01-24 12:26:57 -0500
committerDax Raad <[email protected]>2026-01-24 12:27:13 -0500
commite3c1861a3ee315e1c81bd7f0aee5e3c9faf7af83 (patch)
treee8a476295af4a877ee462794f481a1e99e206a53
parentd9eebba90ed6028f2367ea09f753696ee93b2366 (diff)
downloadopencode-e3c1861a3ee315e1c81bd7f0aee5e3c9faf7af83.tar.gz
opencode-e3c1861a3ee315e1c81bd7f0aee5e3c9faf7af83.zip
get rid of models.dev macro
-rw-r--r--packages/opencode/.gitignore1
-rwxr-xr-xpackages/opencode/script/build.ts8
-rw-r--r--packages/opencode/src/flag/flag.ts1
-rw-r--r--packages/opencode/src/global/index.ts4
-rw-r--r--packages/opencode/src/provider/models-macro.ts14
-rw-r--r--packages/opencode/src/provider/models.ts52
-rw-r--r--packages/opencode/test/preload.ts11
7 files changed, 48 insertions, 43 deletions
diff --git a/packages/opencode/.gitignore b/packages/opencode/.gitignore
index e057ca61f..69643b7af 100644
--- a/packages/opencode/.gitignore
+++ b/packages/opencode/.gitignore
@@ -2,3 +2,4 @@ research
dist
gen
app.log
+src/provider/models-snapshot.ts
diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts
index cb88db2c4..e25a3c5f5 100755
--- a/packages/opencode/script/build.ts
+++ b/packages/opencode/script/build.ts
@@ -15,6 +15,14 @@ process.chdir(dir)
import pkg from "../package.json"
import { Script } from "@opencode-ai/script"
+// Fetch and generate models.dev snapshot
+const modelsData = await fetch(`https://models.dev/api.json`).then((x) => x.text())
+await Bun.write(
+ path.join(dir, "src/provider/models-snapshot.ts"),
+ `// Auto-generated by build.ts - do not edit\nexport const snapshot = ${modelsData} as const\n`,
+)
+console.log("Generated models-snapshot.ts")
+
const singleFlag = process.argv.includes("--single")
const baselineFlag = process.argv.includes("--baseline")
const skipInstall = process.argv.includes("--skip-install")
diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts
index d106c2d86..0274dcc82 100644
--- a/packages/opencode/src/flag/flag.ts
+++ b/packages/opencode/src/flag/flag.ts
@@ -46,6 +46,7 @@ export namespace Flag {
export const OPENCODE_EXPERIMENTAL_LSP_TOOL = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_LSP_TOOL")
export const OPENCODE_DISABLE_FILETIME_CHECK = truthy("OPENCODE_DISABLE_FILETIME_CHECK")
export const OPENCODE_EXPERIMENTAL_PLAN_MODE = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_PLAN_MODE")
+ export const OPENCODE_MODELS_URL = process.env["OPENCODE_MODELS_URL"]
function number(key: string) {
const value = process.env[key]
diff --git a/packages/opencode/src/global/index.ts b/packages/opencode/src/global/index.ts
index 25595abcd..d3011b415 100644
--- a/packages/opencode/src/global/index.ts
+++ b/packages/opencode/src/global/index.ts
@@ -22,10 +22,6 @@ export namespace Global {
cache,
config,
state,
- // Allow overriding models.dev URL for offline deployments
- get modelsDevUrl() {
- return process.env.OPENCODE_MODELS_URL || "https://models.dev"
- },
}
}
diff --git a/packages/opencode/src/provider/models-macro.ts b/packages/opencode/src/provider/models-macro.ts
deleted file mode 100644
index e8fd353c9..000000000
--- a/packages/opencode/src/provider/models-macro.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Global } from "../global"
-
-export async function data() {
- const path = Bun.env.MODELS_DEV_API_JSON
- if (path) {
- const file = Bun.file(path)
- if (await file.exists()) {
- return await file.text()
- }
- }
- const url = Global.Path.modelsDevUrl
- const json = await fetch(`${url}/api.json`).then((x) => x.text())
- return json
-}
diff --git a/packages/opencode/src/provider/models.ts b/packages/opencode/src/provider/models.ts
index 1f7b74081..68eac37f2 100644
--- a/packages/opencode/src/provider/models.ts
+++ b/packages/opencode/src/provider/models.ts
@@ -2,9 +2,16 @@ import { Global } from "../global"
import { Log } from "../util/log"
import path from "path"
import z from "zod"
-import { data } from "./models-macro" with { type: "macro" }
import { Installation } from "../installation"
import { Flag } from "../flag/flag"
+import { lazy } from "@/util/lazy"
+
+// Try to import bundled snapshot (generated at build time)
+// Falls back to undefined in dev mode when snapshot doesn't exist
+/* @ts-ignore */
+const SNAPSHOT = await import("./models-snapshot")
+ .then((m) => m.snapshot as Record<string, unknown>)
+ .catch(() => undefined)
export namespace ModelsDev {
const log = Log.create({ service: "models.dev" })
@@ -76,18 +83,24 @@ export namespace ModelsDev {
export type Provider = z.infer<typeof Provider>
- export async function get() {
- refresh()
+ function url() {
+ return Flag.OPENCODE_MODELS_URL || "https://models.dev"
+ }
+
+ export const Data = lazy(async () => {
const file = Bun.file(filepath)
const result = await file.json().catch(() => {})
- if (result) return result as Record<string, Provider>
- if (typeof data === "function") {
- const json = await data()
- return JSON.parse(json) as Record<string, Provider>
- }
- const url = Global.Path.modelsDevUrl
- const json = await fetch(`${url}/api.json`).then((x) => x.text())
- return JSON.parse(json) as Record<string, Provider>
+ if (result) return result
+ if (SNAPSHOT) return SNAPSHOT
+ if (Flag.OPENCODE_DISABLE_MODELS_FETCH) return {}
+ const json = await fetch(`${url()}/api.json`).then((x) => x.text())
+ return JSON.parse(json)
+ })
+
+ export async function get() {
+ refresh()
+ const result = await Data()
+ return result as Record<string, Provider>
}
export async function refresh() {
@@ -96,8 +109,7 @@ export namespace ModelsDev {
log.info("refreshing", {
file,
})
- const url = Global.Path.modelsDevUrl
- const result = await fetch(`${url}/api.json`, {
+ const result = await fetch(`${url()}/api.json`, {
headers: {
"User-Agent": Installation.USER_AGENT,
},
@@ -107,8 +119,18 @@ export namespace ModelsDev {
error: e,
})
})
- if (result && result.ok) await Bun.write(file, await result.text())
+ if (result && result.ok) {
+ await Bun.write(file, await result.text())
+ ModelsDev.Data.reset()
+ }
}
}
-setInterval(() => ModelsDev.refresh(), 60 * 1000 * 60).unref()
+if (!Flag.OPENCODE_DISABLE_MODELS_FETCH) {
+ setInterval(
+ async () => {
+ await ModelsDev.refresh()
+ },
+ 60 * 1000 * 60,
+ ).unref()
+}
diff --git a/packages/opencode/test/preload.ts b/packages/opencode/test/preload.ts
index 819166c94..1cb777862 100644
--- a/packages/opencode/test/preload.ts
+++ b/packages/opencode/test/preload.ts
@@ -5,7 +5,6 @@ import path from "path"
import fs from "fs/promises"
import fsSync from "fs"
import { afterAll } from "bun:test"
-const { Global } = await import("../src/global")
const dir = path.join(os.tmpdir(), "opencode-test-data-" + process.pid)
await fs.mkdir(dir, { recursive: true })
@@ -23,18 +22,10 @@ process.env["XDG_CACHE_HOME"] = path.join(dir, "cache")
process.env["XDG_CONFIG_HOME"] = path.join(dir, "config")
process.env["XDG_STATE_HOME"] = path.join(dir, "state")
-// Pre-fetch models.json so tests don't need the macro fallback
-// Also write the cache version file to prevent global/index.ts from clearing the cache
+// Write the cache version file to prevent global/index.ts from clearing the cache
const cacheDir = path.join(dir, "cache", "opencode")
await fs.mkdir(cacheDir, { recursive: true })
await fs.writeFile(path.join(cacheDir, "version"), "14")
-const url = Global.Path.modelsDevUrl
-const response = await fetch(`${url}/api.json`)
-if (response.ok) {
- await fs.writeFile(path.join(cacheDir, "models.json"), await response.text())
-}
-// Disable models.dev refresh to avoid race conditions during tests
-process.env["OPENCODE_DISABLE_MODELS_FETCH"] = "true"
// Clear provider env vars to ensure clean test state
delete process.env["ANTHROPIC_API_KEY"]