Files
oh-my-opencode/src/shared/model-capability-aliases.ts
T
YeonGyu-Kim 5478bab457 refactor(models): preserve legacy claude-opus-4-6 aliases and category mapping
Addresses review feedback on #3486:

1. claude-thinking-legacy-alias now matches both claude-opus-4-6-thinking
   and claude-opus-4-7-thinking, canonicalizing both to claude-opus-4-7.
   The previous diff retargeted the regex to 4-7 only, which dropped
   backward compatibility for users still pinned to the 4-6 thinking
   suffix.

2. MODEL_TO_CATEGORY_MAP keeps the claude-opus-4-6 to unspecified-high
   entry alongside the new 4-7 entry. The map is order-independent from
   MODEL_VERSION_MAP, so preserving the 4-6 key avoids relying on a
   specific migration ordering for legacy agent configs.

3. Fix stale 'Claude Opus 4.6' labels and BDD test comments that the
   sed-based bump missed.
2026-04-17 15:35:11 +09:00

109 lines
3.2 KiB
TypeScript

export type ExactAliasRule = {
aliasModelID: string
ruleID: string
canonicalModelID: string
rationale: string
}
export type PatternAliasRule = {
ruleID: string
description: string
match: (normalizedModelID: string) => boolean
canonicalize: (normalizedModelID: string) => string
}
export type ModelIDAliasResolution = {
requestedModelID: string
canonicalModelID: string
source: "canonical" | "exact-alias" | "pattern-alias"
ruleID?: string
}
const EXACT_ALIAS_RULES: ReadonlyArray<ExactAliasRule> = [
{
aliasModelID: "gemini-3-pro-high",
ruleID: "gemini-3-pro-tier-alias",
canonicalModelID: "gemini-3-pro-preview",
rationale: "Legacy Gemini 3 tier suffixes still need to land on the canonical preview model.",
},
{
aliasModelID: "gemini-3-pro-low",
ruleID: "gemini-3-pro-tier-alias",
canonicalModelID: "gemini-3-pro-preview",
rationale: "Legacy Gemini 3 tier suffixes still need to land on the canonical preview model.",
},
]
const EXACT_ALIAS_RULES_BY_MODEL: ReadonlyMap<string, ExactAliasRule> = new Map(
EXACT_ALIAS_RULES.map((rule) => [rule.aliasModelID, rule]),
)
const PATTERN_ALIAS_RULES: ReadonlyArray<PatternAliasRule> = [
{
ruleID: "claude-thinking-legacy-alias",
description: "Normalizes legacy Claude Opus thinking suffixes (4-6, 4-7) to the canonical snapshot ID.",
match: (normalizedModelID) => /^claude-opus-4-(?:6|7)-thinking$/.test(normalizedModelID),
canonicalize: () => "claude-opus-4-7",
},
{
ruleID: "gemini-3.1-pro-tier-alias",
description: "Normalizes Gemini 3.1 Pro tier suffixes to the canonical snapshot ID.",
match: (normalizedModelID) => /^gemini-3\.1-pro-(?:high|low)$/.test(normalizedModelID),
canonicalize: () => "gemini-3.1-pro",
},
]
function normalizeLookupModelID(modelID: string): string {
return modelID.trim().toLowerCase()
}
function stripProviderPrefixForAliasLookup(normalizedModelID: string): string {
const slashIndex = normalizedModelID.indexOf("/")
if (slashIndex <= 0 || slashIndex === normalizedModelID.length - 1) {
return normalizedModelID
}
return normalizedModelID.slice(slashIndex + 1)
}
export function resolveModelIDAlias(modelID: string): ModelIDAliasResolution {
const requestedModelID = normalizeLookupModelID(modelID)
const aliasLookupModelID = stripProviderPrefixForAliasLookup(requestedModelID)
const exactRule = EXACT_ALIAS_RULES_BY_MODEL.get(aliasLookupModelID)
if (exactRule) {
return {
requestedModelID,
canonicalModelID: exactRule.canonicalModelID,
source: "exact-alias",
ruleID: exactRule.ruleID,
}
}
for (const rule of PATTERN_ALIAS_RULES) {
if (!rule.match(aliasLookupModelID)) {
continue
}
return {
requestedModelID,
canonicalModelID: rule.canonicalize(aliasLookupModelID),
source: "pattern-alias",
ruleID: rule.ruleID,
}
}
return {
requestedModelID,
canonicalModelID: aliasLookupModelID,
source: "canonical",
}
}
export function getExactModelIDAliasRules(): ReadonlyArray<ExactAliasRule> {
return EXACT_ALIAS_RULES
}
export function getPatternModelIDAliasRules(): ReadonlyArray<PatternAliasRule> {
return PATTERN_ALIAS_RULES
}