From 47d1ad7bb900065ef5a1b0b26fc23474d62f8b93 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 16 Mar 2026 13:53:28 +0900 Subject: [PATCH] fix(plugin): persist ultrawork variant on same-model override and normalize Claude model IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-openagent) --- .../claude-model-mapper.test.ts | 4 ++++ .../claude-code-agent-loader/claude-model-mapper.ts | 11 ++++++++++- src/plugin/ultrawork-model-override.ts | 8 ++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/features/claude-code-agent-loader/claude-model-mapper.test.ts b/src/features/claude-code-agent-loader/claude-model-mapper.test.ts index e0a9ec638..b5f1983a9 100644 --- a/src/features/claude-code-agent-loader/claude-model-mapper.test.ts +++ b/src/features/claude-code-agent-loader/claude-model-mapper.test.ts @@ -75,6 +75,10 @@ describe("mapClaudeModelToOpenCode", () => { expect(mapClaudeModelToOpenCode("anthropic/claude-sonnet-4-6")).toEqual({ providerID: "anthropic", modelID: "claude-sonnet-4-6" }) }) + it("#when called with anthropic/claude-3.5-sonnet #then normalizes dots before splitting into object format", () => { + expect(mapClaudeModelToOpenCode("anthropic/claude-3.5-sonnet")).toEqual({ providerID: "anthropic", modelID: "claude-3-5-sonnet" }) + }) + it("#when called with openai/gpt-5.2 #then splits into object format", () => { expect(mapClaudeModelToOpenCode("openai/gpt-5.2")).toEqual({ providerID: "openai", modelID: "gpt-5.2" }) }) diff --git a/src/features/claude-code-agent-loader/claude-model-mapper.ts b/src/features/claude-code-agent-loader/claude-model-mapper.ts index bee1be6f9..736a5f303 100644 --- a/src/features/claude-code-agent-loader/claude-model-mapper.ts +++ b/src/features/claude-code-agent-loader/claude-model-mapper.ts @@ -20,7 +20,16 @@ function mapClaudeModelString(model: string | undefined): string | undefined { const aliasResult = CLAUDE_CODE_ALIAS_MAP.get(trimmed.toLowerCase()) if (aliasResult) return aliasResult - if (trimmed.includes("/")) return trimmed + if (trimmed.includes("/")) { + const [providerID, ...modelParts] = trimmed.split("/") + const modelID = modelParts.join("/") + + if (providerID.length === 0 || modelID.length === 0) return trimmed + + return modelID.startsWith("claude-") + ? `${providerID}/${normalizeModelID(modelID)}` + : trimmed + } const normalized = normalizeModelID(trimmed) diff --git a/src/plugin/ultrawork-model-override.ts b/src/plugin/ultrawork-model-override.ts index 55d90c066..282c86142 100644 --- a/src/plugin/ultrawork-model-override.ts +++ b/src/plugin/ultrawork-model-override.ts @@ -110,12 +110,16 @@ function applyResolvedUltraworkOverride(args: { if (!override.providerID || !override.modelID) return const targetModel = { providerID: override.providerID, modelID: override.modelID } + const messageId = output.message["id"] as string | undefined if (isSameModel(output.message.model, targetModel)) { + if (validatedVariant && messageId) { + scheduleDeferredModelOverride(messageId, targetModel, validatedVariant) + log(`[ultrawork-model-override] Persist validated variant for active model: ${override.modelID}`) + return + } log(`[ultrawork-model-override] Skip override; target model already active: ${override.modelID}`) return } - - const messageId = output.message["id"] as string | undefined if (!messageId) { log("[ultrawork-model-override] No message ID found, falling back to direct mutation") output.message.model = targetModel