diff --git a/packages/model-core/src/model-capabilities-bundled-snapshot.test.ts b/packages/model-core/src/model-capabilities-bundled-snapshot.test.ts index 9fa742a87..95289f6d2 100644 --- a/packages/model-core/src/model-capabilities-bundled-snapshot.test.ts +++ b/packages/model-core/src/model-capabilities-bundled-snapshot.test.ts @@ -1,11 +1,12 @@ import { describe, expect, test } from "bun:test" import { getBundledModelCapabilitiesSnapshot, getModelCapabilities } from "./model-capabilities" +import bundledModelCapabilitiesSnapshotJson from "./generated/model-capabilities.generated.json" describe("bundled model capabilities snapshot", () => { test("keeps GPT-4.1 OpenAI variants marked as supporting tool calls", () => { // given - const bundledSnapshot = getBundledModelCapabilitiesSnapshot() + const bundledSnapshot = getBundledModelCapabilitiesSnapshot(bundledModelCapabilitiesSnapshotJson) const modelIDs = [ "openai/gpt-4.1", "openai/gpt-4.1-mini", diff --git a/packages/model-core/src/model-capabilities.test.ts b/packages/model-core/src/model-capabilities.test.ts index 8483f7f56..46e5477fe 100644 --- a/packages/model-core/src/model-capabilities.test.ts +++ b/packages/model-core/src/model-capabilities.test.ts @@ -2,6 +2,7 @@ import type { ModelCapabilitiesSnapshot } from "./model-capabilities" import { afterEach, describe, expect, test, spyOn } from "bun:test" import * as connectedProvidersCache from "./connected-providers-cache" import { getModelCapabilities, getBundledModelCapabilitiesSnapshot } from "./model-capabilities" +import bundledModelCapabilitiesSnapshotJson from "./generated/model-capabilities.generated.json" import { AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS } from "./model-requirements" describe("getModelCapabilities", () => { @@ -402,7 +403,7 @@ describe("getModelCapabilities", () => { }) test("keeps every built-in OmO requirement model snapshot-backed", () => { - const bundledSnapshot = getBundledModelCapabilitiesSnapshot() + const bundledSnapshot = getBundledModelCapabilitiesSnapshot(bundledModelCapabilitiesSnapshotJson) const requirementModels = new Set() for (const requirement of Object.values(AGENT_MODEL_REQUIREMENTS)) { diff --git a/packages/model-core/src/model-capabilities/bundled-snapshot.ts b/packages/model-core/src/model-capabilities/bundled-snapshot.ts index 97e86e1b7..157de6cf1 100644 --- a/packages/model-core/src/model-capabilities/bundled-snapshot.ts +++ b/packages/model-core/src/model-capabilities/bundled-snapshot.ts @@ -1,24 +1,14 @@ -import bundledModelCapabilitiesSnapshotJson from "../../../../src/generated/model-capabilities.generated.json" - import { SUPPLEMENTAL_MODEL_CAPABILITIES } from "./supplemental-entries" import type { ModelCapabilitiesSnapshot } from "./types" -function normalizeSnapshot( - snapshot: ModelCapabilitiesSnapshot | typeof bundledModelCapabilitiesSnapshotJson, +export function getBundledModelCapabilitiesSnapshot( + snapshotJson: ModelCapabilitiesSnapshot, ): ModelCapabilitiesSnapshot { - return snapshot as ModelCapabilitiesSnapshot -} - -const normalizedBundledSnapshot = normalizeSnapshot(bundledModelCapabilitiesSnapshotJson) - -const bundledModelCapabilitiesSnapshot: ModelCapabilitiesSnapshot = { - ...normalizedBundledSnapshot, - models: { - ...normalizedBundledSnapshot.models, - ...SUPPLEMENTAL_MODEL_CAPABILITIES, - }, -} - -export function getBundledModelCapabilitiesSnapshot(): ModelCapabilitiesSnapshot { - return bundledModelCapabilitiesSnapshot + return { + ...snapshotJson, + models: { + ...snapshotJson.models, + ...SUPPLEMENTAL_MODEL_CAPABILITIES, + }, + } } diff --git a/packages/model-core/src/model-capabilities/get-model-capabilities.ts b/packages/model-core/src/model-capabilities/get-model-capabilities.ts index c13c5bf16..8bbf2e9da 100644 --- a/packages/model-core/src/model-capabilities/get-model-capabilities.ts +++ b/packages/model-core/src/model-capabilities/get-model-capabilities.ts @@ -1,8 +1,6 @@ import { resolveModelIDAlias } from "../model-capability-aliases" import { detectHeuristicModelFamily } from "../model-capability-heuristics" -import type { ProviderCache } from "../provider-cache" -import { getBundledModelCapabilitiesSnapshot } from "./bundled-snapshot" import { readRuntimeModel, readRuntimeModelLimitOutput, @@ -38,9 +36,9 @@ export function getModelCapabilities(input: GetModelCapabilitiesInput): ModelCap input.runtimeModel ?? input.providerCache?.findProviderModelMetadata(input.providerID, input.modelID), ) const runtimeSnapshot = input.runtimeSnapshot - const bundledSnapshot = input.bundledSnapshot ?? getBundledModelCapabilitiesSnapshot() + const bundledSnapshot = input.bundledSnapshot const snapshotEntry = runtimeSnapshot?.models?.[canonicalization.canonicalModelID] - ?? bundledSnapshot.models[canonicalization.canonicalModelID] + ?? bundledSnapshot?.models?.[canonicalization.canonicalModelID] const heuristicFamily = detectHeuristicModelFamily(canonicalization.canonicalModelID) const runtimeVariants = readRuntimeModelVariants(runtimeModel) @@ -55,7 +53,7 @@ export function getModelCapabilities(input: GetModelCapabilitiesInput): ModelCap const snapshotSource: ModelCapabilitiesDiagnostics["snapshot"]["source"] = runtimeSnapshot?.models?.[canonicalization.canonicalModelID] ? "runtime-snapshot" - : bundledSnapshot.models[canonicalization.canonicalModelID] + : bundledSnapshot?.models?.[canonicalization.canonicalModelID] ? "bundled-snapshot" : "none" const familySource: ModelCapabilitiesDiagnostics["family"]["source"] = diff --git a/packages/model-core/src/model-capability-guardrails.test.ts b/packages/model-core/src/model-capability-guardrails.test.ts index 3c818850a..e53e65db6 100644 --- a/packages/model-core/src/model-capability-guardrails.test.ts +++ b/packages/model-core/src/model-capability-guardrails.test.ts @@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test" import type { ModelCapabilitiesSnapshot } from "./model-capabilities" import { getBundledModelCapabilitiesSnapshot } from "./model-capabilities" +import bundledModelCapabilitiesSnapshotJson from "./generated/model-capabilities.generated.json" import { collectModelCapabilityGuardrailIssues, getBuiltInRequirementModelIDs, @@ -9,7 +10,9 @@ import { describe("model-capability-guardrails", () => { test("keeps the current alias registry and built-in requirements aligned with the bundled snapshot", () => { - const issues = collectModelCapabilityGuardrailIssues() + const issues = collectModelCapabilityGuardrailIssues({ + snapshot: getBundledModelCapabilitiesSnapshot(bundledModelCapabilitiesSnapshotJson), + }) expect(issues).toEqual([]) }) @@ -25,7 +28,7 @@ describe("model-capability-guardrails", () => { }) test("flags exact aliases whose canonical target disappears from the snapshot", () => { - const bundledSnapshot = getBundledModelCapabilitiesSnapshot() + const bundledSnapshot = getBundledModelCapabilitiesSnapshot(bundledModelCapabilitiesSnapshotJson) const brokenSnapshot: ModelCapabilitiesSnapshot = { ...bundledSnapshot, models: Object.fromEntries( @@ -48,7 +51,7 @@ describe("model-capability-guardrails", () => { }) test("flags pattern aliases when models.dev gains a canonical entry for the alias itself", () => { - const bundledSnapshot = getBundledModelCapabilitiesSnapshot() + const bundledSnapshot = getBundledModelCapabilitiesSnapshot(bundledModelCapabilitiesSnapshotJson) const aliasCollisionSnapshot: ModelCapabilitiesSnapshot = { ...bundledSnapshot, models: { @@ -76,7 +79,7 @@ describe("model-capability-guardrails", () => { }) test("flags exact aliases when models.dev gains a canonical entry for the alias itself", () => { - const bundledSnapshot = getBundledModelCapabilitiesSnapshot() + const bundledSnapshot = getBundledModelCapabilitiesSnapshot(bundledModelCapabilitiesSnapshotJson) const aliasCollisionSnapshot: ModelCapabilitiesSnapshot = { ...bundledSnapshot, models: { @@ -105,6 +108,7 @@ describe("model-capability-guardrails", () => { test("flags built-in requirement models that rely on aliases instead of canonical IDs", () => { const issues = collectModelCapabilityGuardrailIssues({ + snapshot: getBundledModelCapabilitiesSnapshot(bundledModelCapabilitiesSnapshotJson), requirementModelIDs: ["gemini-3.1-pro-high"], }) diff --git a/packages/model-core/src/model-capability-guardrails.ts b/packages/model-core/src/model-capability-guardrails.ts index b1c74feae..985cdff62 100644 --- a/packages/model-core/src/model-capability-guardrails.ts +++ b/packages/model-core/src/model-capability-guardrails.ts @@ -1,5 +1,4 @@ import type { ModelCapabilitiesSnapshot } from "./model-capabilities" -import { getBundledModelCapabilitiesSnapshot } from "./model-capabilities" import { getExactModelIDAliasRules, getPatternModelIDAliasRules, @@ -45,6 +44,7 @@ export type ModelCapabilityGuardrailIssue = type CollectModelCapabilityGuardrailIssuesInput = { snapshot?: ModelCapabilitiesSnapshot + loadBundledSnapshot?: () => ModelCapabilitiesSnapshot requirementModelIDs?: Iterable } @@ -73,7 +73,10 @@ export function getBuiltInRequirementModelIDs(): string[] { export function collectModelCapabilityGuardrailIssues( input: CollectModelCapabilityGuardrailIssuesInput = {}, ): ModelCapabilityGuardrailIssue[] { - const snapshot = input.snapshot ?? getBundledModelCapabilitiesSnapshot() + const snapshot = input.snapshot ?? input.loadBundledSnapshot?.() + if (!snapshot) { + return [] + } const snapshotModelIDs = new Set( Object.keys(snapshot.models).map((modelID) => normalizeLookupModelID(modelID)), ) diff --git a/src/shared/model-capabilities/index.ts b/src/shared/model-capabilities/index.ts index 203e056c6..6a1560792 100644 --- a/src/shared/model-capabilities/index.ts +++ b/src/shared/model-capabilities/index.ts @@ -1,15 +1,25 @@ import { - getBundledModelCapabilitiesSnapshot, - getModelCapabilities as getModelCapabilitiesFromCore, + getBundledModelCapabilitiesSnapshot, + getModelCapabilities as getModelCapabilitiesFromCore, } from "@oh-my-opencode/model-core" import type { GetModelCapabilitiesInput, ModelCapabilities } from "@oh-my-opencode/model-core" import * as connectedProvidersCache from "../connected-providers-cache" +import bundledModelCapabilitiesSnapshotJson from "../../generated/model-capabilities.generated.json" -export { getBundledModelCapabilitiesSnapshot } +export function getBundledModelCapabilitiesSnapshotForRuntime() { + return getBundledModelCapabilitiesSnapshot(bundledModelCapabilitiesSnapshotJson) +} + +export function getBundledModelCapabilitiesSnapshotForShared(): ReturnType { + return getBundledModelCapabilitiesSnapshotForRuntime() +} + +export { getBundledModelCapabilitiesSnapshotForShared as getBundledModelCapabilitiesSnapshot } export function getModelCapabilities(input: GetModelCapabilitiesInput): ModelCapabilities { return getModelCapabilitiesFromCore({ ...input, + bundledSnapshot: input.bundledSnapshot ?? getBundledModelCapabilitiesSnapshotForRuntime(), providerCache: input.providerCache ?? connectedProvidersCache, }) } diff --git a/src/shared/model-capability-guardrails.ts b/src/shared/model-capability-guardrails.ts index b67f99582..ce8d31934 100644 --- a/src/shared/model-capability-guardrails.ts +++ b/src/shared/model-capability-guardrails.ts @@ -1,5 +1,22 @@ -export type { ModelCapabilityGuardrailIssue } from "@oh-my-opencode/model-core" -export { - getBuiltInRequirementModelIDs, - collectModelCapabilityGuardrailIssues, +import { + collectModelCapabilityGuardrailIssues as collectModelCapabilityGuardrailIssuesFromCore, + getBuiltInRequirementModelIDs, } from "@oh-my-opencode/model-core" +import type { + ModelCapabilityGuardrailIssue, + ModelCapabilitiesSnapshot, +} from "@oh-my-opencode/model-core" +import { getBundledModelCapabilitiesSnapshotForRuntime } from "./model-capabilities" + +export { getBuiltInRequirementModelIDs } +export type { ModelCapabilityGuardrailIssue } + +export function collectModelCapabilityGuardrailIssues(input: { + snapshot?: ModelCapabilitiesSnapshot + requirementModelIDs?: Iterable +} = {}): ModelCapabilityGuardrailIssue[] { + return collectModelCapabilityGuardrailIssuesFromCore({ + ...input, + snapshot: input.snapshot ?? getBundledModelCapabilitiesSnapshotForRuntime(), + }) +}