Files
oh-my-opencode/packages/model-core/src/context-limit-resolver.test.ts
YeonGyu-Kim edaa95fec0 refactor(model-core): host snapshot fetcher, suggestion parser, and context-limit resolver
Move three pure helpers from src/shared/ into @oh-my-opencode/model-core so the package can stand alone without depending on plugin internals:

- buildModelCapabilitiesSnapshotFromModelsDev + fetchModelCapabilitiesSnapshot (models.dev normalization)
- parseModelSuggestion (cross-provider ProviderModelNotFoundError suggestion extraction)
- resolveActualContextLimit (Anthropic GA 1M context override)

Split provider-model-id-transform into two variants exposed by model-core:

- transformModelForProvider keeps the runtime dash to dot Anthropic rewrite used by the SDK
- transformModelForProviderDisplay preserves hyphenated Anthropic IDs so the installer writes registry-compatible model strings, fixing the ProviderModelNotFoundError fresh installs hit when the dotted form leaks into the config

src/shared/* and src/cli/provider-model-id-transform.ts collapse to re-export shims that point at the new core modules. Stale src/shared/{known-variants,model-capability-aliases,model-capability-guardrails,model-capability-heuristics}.ts re-export files plus the duplicated context-limit-resolver test are removed in favor of the canonical model-core copies.

Tests: bun test packages/model-core src/shared/model-capabilities-cache.test.ts src/cli/provider-model-id-transform.test.ts
2026-05-21 16:19:38 +09:00

93 lines
3.0 KiB
TypeScript

import process from "node:process"
import { afterEach, describe, expect, it } from "bun:test"
import { resolveActualContextLimit } from "./context-limit-resolver"
const ANTHROPIC_CONTEXT_ENV_KEY = "ANTHROPIC_1M_CONTEXT"
const VERTEX_CONTEXT_ENV_KEY = "VERTEX_ANTHROPIC_1M_CONTEXT"
const originalAnthropicContextEnv = process.env[ANTHROPIC_CONTEXT_ENV_KEY]
const originalVertexContextEnv = process.env[VERTEX_CONTEXT_ENV_KEY]
function restoreContextLimitEnv(): void {
if (originalAnthropicContextEnv === undefined) {
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
} else {
process.env[ANTHROPIC_CONTEXT_ENV_KEY] = originalAnthropicContextEnv
}
if (originalVertexContextEnv === undefined) {
delete process.env[VERTEX_CONTEXT_ENV_KEY]
} else {
process.env[VERTEX_CONTEXT_ENV_KEY] = originalVertexContextEnv
}
}
describe("resolveActualContextLimit", () => {
afterEach(() => {
restoreContextLimitEnv()
})
it("returns cached limit for non-Anthropic providers", () => {
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("openai/gpt-5", 400_000)
const actualLimit = resolveActualContextLimit("openai", "gpt-5", {
anthropicContext1MEnabled: false,
modelContextLimitsCache,
})
expect(actualLimit).toBe(400_000)
})
it("returns GA 1M for Anthropic 4.6/4.7 models without explicit 1M mode", () => {
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
delete process.env[VERTEX_CONTEXT_ENV_KEY]
const actualLimit = resolveActualContextLimit("anthropic", "claude-sonnet-4-6", {
anthropicContext1MEnabled: false,
})
expect(actualLimit).toBe(1_000_000)
})
it("uses cached limit for GA Anthropic models when cache exists", () => {
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
delete process.env[VERTEX_CONTEXT_ENV_KEY]
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("anthropic/claude-opus-4-7", 700_000)
const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4-7", {
anthropicContext1MEnabled: false,
modelContextLimitsCache,
})
expect(actualLimit).toBe(700_000)
})
it("returns 1M when ANTHROPIC_1M_CONTEXT=true regardless of model", () => {
process.env[ANTHROPIC_CONTEXT_ENV_KEY] = "true"
delete process.env[VERTEX_CONTEXT_ENV_KEY]
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("anthropic/claude-sonnet-4-5", 200_000)
const actualLimit = resolveActualContextLimit("anthropic", "claude-sonnet-4-5", {
anthropicContext1MEnabled: false,
modelContextLimitsCache,
})
expect(actualLimit).toBe(1_000_000)
})
it("returns 1M when VERTEX_ANTHROPIC_1M_CONTEXT=true for Anthropic aliases", () => {
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
process.env[VERTEX_CONTEXT_ENV_KEY] = "true"
const actualLimit = resolveActualContextLimit("google-vertex-anthropic", "claude-sonnet-4-5", {
anthropicContext1MEnabled: false,
})
expect(actualLimit).toBe(1_000_000)
})
})