fix(doctor): respect user-configured agent variant (#1464)

* fix(doctor): respect user-configured agent variant

* fix(doctor): align variant resolution with agent-variant.ts

- Add case-insensitive agent key lookup (matches canonical logic)
- Support category-based variant inheritance (agent.category -> categories[cat].variant)
- Separate getCategoryEffectiveVariant for category-specific resolution
- Addresses Oracle review feedback
This commit is contained in:
YeonGyu-Kim
2026-02-04 11:25:37 +09:00
committed by GitHub
parent b19bc857e3
commit 6a66bfccec
2 changed files with 74 additions and 21 deletions

View File

@@ -28,13 +28,13 @@
"typescript": "^5.7.3",
},
"optionalDependencies": {
"oh-my-opencode-darwin-arm64": "3.2.1",
"oh-my-opencode-darwin-x64": "3.2.1",
"oh-my-opencode-linux-arm64": "3.2.1",
"oh-my-opencode-linux-arm64-musl": "3.2.1",
"oh-my-opencode-linux-x64": "3.2.1",
"oh-my-opencode-linux-x64-musl": "3.2.1",
"oh-my-opencode-windows-x64": "3.2.1",
"oh-my-opencode-darwin-arm64": "3.2.2",
"oh-my-opencode-darwin-x64": "3.2.2",
"oh-my-opencode-linux-arm64": "3.2.2",
"oh-my-opencode-linux-arm64-musl": "3.2.2",
"oh-my-opencode-linux-x64": "3.2.2",
"oh-my-opencode-linux-x64-musl": "3.2.2",
"oh-my-opencode-windows-x64": "3.2.2",
},
},
},
@@ -226,19 +226,19 @@
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
"oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.2.1", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-IvhHRUXTr/g/hJlkKTU2oCdgRl2BDl/Qre31Rukhs4NumlvME6iDmdnm8mM7bTxugfCBkfUUr7QJLxxLhzjdLA=="],
"oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.2.2", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-KyfoWcANfcvpfanrrX+Wc8vH8vr9mvr7dJMHBe2bkvuhdtHnLHOG18hQwLg6jk4HhdoZAeBEmkolOsK2k4XajA=="],
"oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.2.1", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-V2JbAdThAVfhBOcb+wBPZrAI0vBxPPRBdvmAixAxBOFC49CIJUrEFIRBUYFKhSQGHYWrNy8z0zJYoNQm4oQPog=="],
"oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.2.2", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-ajZ1E36Ixwdz6rvSUKUI08M2xOaNIl1ZsdVjknZTrPRtct9xgS+BEFCoSCov9bnV/9DrZD3mlZtO/+FFDbseUg=="],
"oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.2.1", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-SeT8P7Icq5YH/AIaEF28J4q+ifUnOqO2UgMFtdFusr8JLadYFy+6dTdeAuD2uGGToDQ3ZNKuaG+lo84KzEhA5w=="],
"oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.2.2", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-ItJsYfigXcOa8/ejTjopC4qk5BCeYioMQ693kPTpeYHK3ByugTjJk8aamE7bHlVnmrdgWldz91QFzaP82yOAdg=="],
"oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.2.1", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-wJUEVVUn1gyVIFNV4mxWg9cYo1rQdTKUXdGLfiqPiyQhWhZLRfPJ+9qpghvIVv7Dne6rzkbhYWdwdk/tew5RtQ=="],
"oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.2.2", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-/TvjYe/Kb//ZSHnJzgRj0QPKpS5Y2nermVTSaMTGS2btObXQyQWzuphDhsVRu60SVrNLbflHzfuTdqb3avDjyA=="],
"oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.2.1", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-p/XValXi1RRTZV8mEsdStXwZBkyQpgZjB41HLf0VfizPMAKRr6/bhuFZ9BDZFIhcDnLYcGV54MAVEsWms5yC2A=="],
"oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.2.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-Ka5j+tjuQkNnpESVzcTzW5tZMlBhOfP9F12+UaR72cIcwFpSoLMBp84rV6R0vXM0zUcrrN7mPeW66DvQ6A0XQQ=="],
"oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.2.1", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-G7aNMqAMO2P+wUUaaAV8sXymm59cX4G9aVNXKAd/PM6RgFWh2F4HkXkOhOdHKYZzCl1QRhjh672mNillYsvebg=="],
"oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.2.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-ISl0sTNShKCgPFO+rsDqEDsvVHQAMfOSAxO0KuWbHFKaH+KaRV4d3N/ihgxZ2M94CZjJLzZEuln+6kLZ93cvzQ=="],
"oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.2.1", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-pyqTGlNxirKxQgXx9YJBq2y8KN/1oIygVupClmws7dDPj9etI1l8fs/SBEnMsYzMqTlGbLVeJ5+kj9p+yg7YDA=="],
"oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.2.2", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-KeiJLQvJuZ+UYf/+eMsQXvCiHDRPk6tD15lL+qruLvU19va62JqMNvTuOv97732uF19iG0ZMiiVhqIMbSyVPqQ=="],
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],

View File

@@ -69,8 +69,8 @@ export interface ModelResolutionInfo {
}
interface OmoConfig {
agents?: Record<string, { model?: string }>
categories?: Record<string, { model?: string }>
agents?: Record<string, { model?: string; variant?: string; category?: string }>
categories?: Record<string, { model?: string; variant?: string }>
}
function loadConfig(): OmoConfig | null {
@@ -182,7 +182,44 @@ function formatModelWithVariant(model: string, variant?: string): string {
return variant ? `${model} (${variant})` : model
}
function getEffectiveVariant(requirement: ModelRequirement): string | undefined {
function getAgentOverride(
agentName: string,
config: OmoConfig,
): { variant?: string; category?: string } | undefined {
const agentOverrides = config.agents
if (!agentOverrides) return undefined
// Direct lookup first, then case-insensitive lookup (matches agent-variant.ts)
return (
agentOverrides[agentName] ??
Object.entries(agentOverrides).find(
([key]) => key.toLowerCase() === agentName.toLowerCase()
)?.[1]
)
}
function getEffectiveVariant(
name: string,
requirement: ModelRequirement,
config: OmoConfig,
): string | undefined {
const agentOverride = getAgentOverride(name, config)
// Priority 1: Agent's direct variant override
if (agentOverride?.variant) {
return agentOverride.variant
}
// Priority 2: Agent's category -> category's variant (matches agent-variant.ts)
const categoryName = agentOverride?.category
if (categoryName) {
const categoryVariant = config.categories?.[categoryName]?.variant
if (categoryVariant) {
return categoryVariant
}
}
// Priority 3: Fall back to requirement's fallback chain
const firstEntry = requirement.fallbackChain[0]
return firstEntry?.variant ?? requirement.variant
}
@@ -193,7 +230,20 @@ interface AvailableModelsInfo {
cacheExists: boolean
}
function buildDetailsArray(info: ModelResolutionInfo, available: AvailableModelsInfo): string[] {
function getCategoryEffectiveVariant(
categoryName: string,
requirement: ModelRequirement,
config: OmoConfig,
): string | undefined {
const categoryVariant = config.categories?.[categoryName]?.variant
if (categoryVariant) {
return categoryVariant
}
const firstEntry = requirement.fallbackChain[0]
return firstEntry?.variant ?? requirement.variant
}
function buildDetailsArray(info: ModelResolutionInfo, available: AvailableModelsInfo, config: OmoConfig): string[] {
const details: string[] = []
details.push("═══ Available Models (from cache) ═══")
@@ -215,14 +265,17 @@ function buildDetailsArray(info: ModelResolutionInfo, available: AvailableModels
details.push("Agents:")
for (const agent of info.agents) {
const marker = agent.userOverride ? "●" : "○"
const display = formatModelWithVariant(agent.effectiveModel, getEffectiveVariant(agent.requirement))
const display = formatModelWithVariant(agent.effectiveModel, getEffectiveVariant(agent.name, agent.requirement, config))
details.push(` ${marker} ${agent.name}: ${display}`)
}
details.push("")
details.push("Categories:")
for (const category of info.categories) {
const marker = category.userOverride ? "●" : "○"
const display = formatModelWithVariant(category.effectiveModel, getEffectiveVariant(category.requirement))
const display = formatModelWithVariant(
category.effectiveModel,
getCategoryEffectiveVariant(category.name, category.requirement, config)
)
details.push(` ${marker} ${category.name}: ${display}`)
}
details.push("")
@@ -249,7 +302,7 @@ export async function checkModelResolution(): Promise<CheckResult> {
name: CHECK_NAMES[CHECK_IDS.MODEL_RESOLUTION],
status: available.cacheExists ? "pass" : "warn",
message: `${agentCount} agents, ${categoryCount} categories${overrideNote}${cacheNote}`,
details: buildDetailsArray(info, available),
details: buildDetailsArray(info, available, config),
}
}