Compare commits

...

1 Commits

Author SHA1 Message Date
Kit Langton 51b17967f2 chore(core): compress models snapshot 2026-08-14 13:43:21 -04:00
5 changed files with 36 additions and 12 deletions
+3 -1
View File
@@ -65,8 +65,10 @@ const appArchive = await buildAppArchive(Script.channel)
// text that ships inside the bundle. // text that ships inside the bundle.
async function assertTextImportsInlined(bundlePath: string) { async function assertTextImportsInlined(bundlePath: string) {
const bundle = await readFile(bundlePath, "utf8") const bundle = await readFile(bundlePath, "utf8")
const snapshotMarker = (await readFile("../core/src/models-dev/snapshot.gz.base64.txt", "utf8")).slice(0, 64)
const markers = [ const markers = [
{ marker: '"zhipuai"', source: "models-dev snapshot" }, { marker: snapshotMarker, source: "compressed models-dev snapshot" },
{ marker: '"zhipuai"', source: "uncompressed models-dev snapshot", forbidden: true },
{ marker: "/assets/snapshot", source: "models-dev snapshot inlined as asset URL", forbidden: true }, { marker: "/assets/snapshot", source: "models-dev snapshot inlined as asset URL", forbidden: true },
{ marker: '="/assets/', source: "text import inlined as asset URL", forbidden: true }, { marker: '="/assets/', source: "text import inlined as asset URL", forbidden: true },
] ]
@@ -20,5 +20,9 @@ if (typeof parsed !== "object" || parsed === null || Object.keys(parsed).length
process.exit(1) process.exit(1)
} }
const target = new URL("../src/models-dev/snapshot.txt", import.meta.url) const target = new URL("../src/models-dev/snapshot.txt", import.meta.url)
await Bun.write(target, text) const compressed = new URL("../src/models-dev/snapshot.gz.base64.txt", import.meta.url)
console.log(`Wrote ${Object.keys(parsed).length} providers (${text.length} bytes) to ${Bun.fileURLToPath(target)}`) const gzip = Bun.gzipSync(text, { level: 9 })
await Promise.all([Bun.write(target, text), Bun.write(compressed, gzip.toBase64())])
console.log(
`Wrote ${Object.keys(parsed).length} providers (${text.length} bytes, ${gzip.length} bytes gzip) to ${Bun.fileURLToPath(target)}`,
)
+15 -8
View File
@@ -11,7 +11,7 @@ import { httpClient } from "@opencode-ai/util/effect/app-node-platform"
import { Model } from "./model.js" import { Model } from "./model.js"
import { Provider } from "./provider.js" import { Provider } from "./provider.js"
import { KV } from "./kv.js" import { KV } from "./kv.js"
import snapshotText from "./models-dev/snapshot.txt" with { type: "text" } import snapshotGzip from "./models-dev/snapshot.gz.base64.txt" with { type: "text" }
export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"]) export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"])
export type CatalogModelStatus = typeof CatalogModelStatus.Type export type CatalogModelStatus = typeof CatalogModelStatus.Type
@@ -544,17 +544,24 @@ const Cache = Schema.Struct({
}) })
const defaultSource = "https://models.opencode.ai" const defaultSource = "https://models.opencode.ai"
// Bundled snapshot of https://models.opencode.ai/api.json, committed at // Bundled snapshot of https://models.opencode.ai/api.json, refreshed via
// packages/core/src/models-dev/snapshot.txt and refreshed via // `bun run script/update-models-snapshot.ts`. Decompressed, decoded, and
// `bun run script/update-models-snapshot.ts`. Decoded and normalized once per // normalized once per isolate: one isolate can host many runtimes (Cloudflare
// isolate: the snapshot is a multi-MB module-level constant and one isolate can // colocates Durable Object instances), so per-runtime work would multiply the
// host many runtimes (Cloudflare colocates Durable Object instances), so // cost.
// per-runtime decoding would multiply the cost.
let bundledCache: readonly Snapshot[] | undefined let bundledCache: readonly Snapshot[] | undefined
const bundledSnapshot = Effect.suspend(() => const bundledSnapshot = Effect.suspend(() =>
bundledCache bundledCache
? Effect.succeed(bundledCache) ? Effect.succeed(bundledCache)
: decodeCatalog(snapshotText).pipe( : Schema.decodeUnknownEffect(Schema.Uint8ArrayFromBase64)(snapshotGzip).pipe(
Effect.flatMap((bytes) =>
Effect.promise(() =>
new Response(
new Blob([Uint8Array.from(bytes)]).stream().pipeThrough(new DecompressionStream("gzip")),
).text(),
),
),
Effect.flatMap(decodeCatalog),
Effect.map((catalog) => { Effect.map((catalog) => {
bundledCache = normalize(catalog) bundledCache = normalize(catalog)
return bundledCache return bundledCache
File diff suppressed because one or more lines are too long
+11 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import { Money } from "@opencode-ai/schema/money" import { Money } from "@opencode-ai/schema/money"
import { Effect, Layer, Ref } from "effect" import { Effect, Layer, Ref, Schema } from "effect"
import { HttpClient, HttpClientResponse } from "effect/unstable/http" import { HttpClient, HttpClientResponse } from "effect/unstable/http"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { LayerNodePlatform } from "@opencode-ai/util/effect/app-node-platform" import { LayerNodePlatform } from "@opencode-ai/util/effect/app-node-platform"
@@ -13,6 +13,16 @@ import { it } from "./lib/effect"
const cacheKey = "models-dev:catalog" const cacheKey = "models-dev:catalog"
test("compressed snapshot matches the reviewable source", async () => {
const source = await Bun.file(new URL("../src/models-dev/snapshot.txt", import.meta.url)).text()
const encoded = await Bun.file(new URL("../src/models-dev/snapshot.gz.base64.txt", import.meta.url)).text()
const bytes = Schema.decodeUnknownSync(Schema.Uint8ArrayFromBase64)(encoded)
const restored = await new Response(
new Blob([Uint8Array.from(bytes)]).stream().pipeThrough(new DecompressionStream("gzip")),
).text()
expect(restored).toBe(source)
})
test("normalizes permissive interleaved values to compatibility", () => { test("normalizes permissive interleaved values to compatibility", () => {
expect(Model.compatibility("reasoning_text")).toEqual({ reasoningField: "reasoning_text" }) expect(Model.compatibility("reasoning_text")).toEqual({ reasoningField: "reasoning_text" })
expect(Model.compatibility({ field: "vendor_reasoning" })).toEqual({ reasoningField: "vendor_reasoning" }) expect(Model.compatibility({ field: "vendor_reasoning" })).toEqual({ reasoningField: "vendor_reasoning" })