refactor(migration): auto-upgrade claude-opus-4-5 and 4-6 to claude-opus-4-7

MODEL_VERSION_MAP now chains the legacy claude-opus-4-5 entry straight
to claude-opus-4-7 and adds an explicit claude-opus-4-6 to 4-7 bump
path, letting existing user configs upgrade on next load without an
intermediate 4-6 stop.

MODEL_TO_CATEGORY_MAP picks up claude-opus-4-7 as the canonical
unspecified-high model (prior 4-6 entry is covered by the chained
version map above, so legacy hardcoded configs still resolve).

Migration tests rewritten to reflect the chained 4-5 to 4-7 behavior
and the new 4-6 to 4-7 bump path, including the sidecar-union
scenario.
This commit is contained in:
YeonGyu-Kim
2026-04-17 14:52:02 +09:00
parent def44338ff
commit 4ca4c06698
6 changed files with 40 additions and 39 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ export const MODEL_TO_CATEGORY_MAP: Record<string, string> = {
"google/gemini-3-flash": "writing",
"openai/gpt-5.4": "ultrabrain",
"anthropic/claude-haiku-4-5": "quick",
"anthropic/claude-opus-4-6": "unspecified-high",
"anthropic/claude-opus-4-7": "unspecified-high",
"anthropic/claude-sonnet-4-6": "unspecified-low",
}
@@ -8,7 +8,7 @@ import { migrateConfigFile } from "./config-migration"
import { getSidecarPath } from "./migrations-sidecar"
const createdDirectories: string[] = []
const MIGRATION_KEY = "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6"
const MIGRATION_KEY = "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7"
function createWorkdir(): string {
const workdir = mkdtempSync(join(tmpdir(), "omo-config-migration-"))
@@ -46,13 +46,13 @@ describe("migrateConfigFile sidecar write ordering", () => {
expect(needsWrite).toBe(true)
expect(rawConfig._migrations).toBeUndefined()
expect((rawConfig.agents as Record<string, Record<string, unknown>>).prometheus.model).toBe(
"anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-7",
)
const persistedConfig = JSON.parse(readFileSync(configPath, "utf-8")) as Record<string, unknown>
expect(persistedConfig._migrations).toBeUndefined()
expect((persistedConfig.agents as Record<string, Record<string, unknown>>).prometheus.model).toBe(
"anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-7",
)
const sidecar = JSON.parse(readFileSync(getSidecarPath(configPath), "utf-8")) as {
@@ -87,7 +87,7 @@ describe("migrateConfigFile sidecar write ordering", () => {
expect(retriedNeedsWrite).toBe(true)
expect(retriedConfig._migrations).toBeUndefined()
expect((retriedConfig.agents as Record<string, Record<string, unknown>>).prometheus.model).toBe(
"anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-7",
)
expect(existsSync(getSidecarPath(configPath))).toBe(true)
})
@@ -108,13 +108,13 @@ describe("migrateConfigFile sidecar write ordering", () => {
expect(needsWrite).toBe(true)
expect(rawConfig._migrations).toEqual([MIGRATION_KEY])
expect((rawConfig.agents as Record<string, Record<string, unknown>>).prometheus.model).toBe(
"anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-7",
)
const persistedConfig = JSON.parse(readFileSync(configPath, "utf-8")) as Record<string, unknown>
expect(persistedConfig._migrations).toEqual([MIGRATION_KEY])
expect((persistedConfig.agents as Record<string, Record<string, unknown>>).prometheus.model).toBe(
"anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-7",
)
expect(statSync(getSidecarPath(configPath)).isDirectory()).toBe(true)
})
@@ -42,7 +42,7 @@ describe("migrations sidecar", () => {
JSON.stringify({
appliedMigrations: [
"model-version:openai/gpt-5.3-codex->openai/gpt-5.4",
"model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6",
"model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7",
],
}),
)
@@ -51,7 +51,7 @@ describe("migrations sidecar", () => {
expect(applied.size).toBe(2)
expect(applied.has("model-version:openai/gpt-5.3-codex->openai/gpt-5.4")).toBe(true)
expect(applied.has("model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6")).toBe(true)
expect(applied.has("model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7")).toBe(true)
})
test("returns an empty set on malformed JSON instead of throwing", () => {
@@ -134,7 +134,7 @@ describe("migrations sidecar", () => {
const configPath = join(workdir, "oh-my-openagent.jsonc")
const original = new Set([
"model-version:openai/gpt-5.3-codex->openai/gpt-5.4",
"model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6",
"model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7",
])
writeAppliedMigrations(configPath, original)
+1 -1
View File
@@ -22,7 +22,7 @@ import { writeFileAtomically } from "../write-file-atomically"
* {
* "appliedMigrations": [
* "model-version:openai/gpt-5.3-codex->openai/gpt-5.4",
* "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6"
* "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7"
* ]
* }
*/
+2 -1
View File
@@ -6,7 +6,8 @@
* Keys are full "provider/model" strings. Only openai and anthropic entries needed.
*/
export const MODEL_VERSION_MAP: Record<string, string> = {
"anthropic/claude-opus-4-5": "anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-5": "anthropic/claude-opus-4-7",
"anthropic/claude-opus-4-6": "anthropic/claude-opus-4-7",
"anthropic/claude-sonnet-4-5": "anthropic/claude-sonnet-4-6",
"openai/gpt-5.3-codex": "openai/gpt-5.4",
}