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:
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user