From 4bbc55bb02069432367068fd1f3e4f7121178f32 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 20 Feb 2026 17:47:21 +0900 Subject: [PATCH] fix(variant): respect TUI variant and enforce max in ultrawork mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - keyword-detector: always set variant to 'max' when ultrawork/ulw keyword detected - chat-message: remove variant resolution logic to passthrough TUI variant unchanged - Tests updated to reflect new behavior 🤖 Generated with OhMyOpenCode assistance --- src/hooks/keyword-detector/hook.ts | 4 +-- src/hooks/keyword-detector/index.test.ts | 8 ++--- src/plugin/chat-message.test.ts | 42 ++++++++++++------------ src/plugin/chat-message.ts | 27 +-------------- 4 files changed, 27 insertions(+), 54 deletions(-) diff --git a/src/hooks/keyword-detector/hook.ts b/src/hooks/keyword-detector/hook.ts index c6b7e9dfb..d55a73c37 100644 --- a/src/hooks/keyword-detector/hook.ts +++ b/src/hooks/keyword-detector/hook.ts @@ -74,9 +74,7 @@ export function createKeywordDetectorHook(ctx: PluginInput, _collector?: Context if (hasUltrawork) { log(`[keyword-detector] Ultrawork mode activated`, { sessionID: input.sessionID }) - if (output.message.variant === undefined) { - output.message.variant = "max" - } + output.message.variant = "max" ctx.client.tui .showToast({ diff --git a/src/hooks/keyword-detector/index.test.ts b/src/hooks/keyword-detector/index.test.ts index 558f103de..182b6afae 100644 --- a/src/hooks/keyword-detector/index.test.ts +++ b/src/hooks/keyword-detector/index.test.ts @@ -219,8 +219,8 @@ describe("keyword-detector session filtering", () => { expect(toastCalls).toContain("Ultrawork Mode Activated") }) - test("should not override existing variant", async () => { - // given - main session set with pre-existing variant + test("should override existing variant when ultrawork keyword is used", async () => { + // given - main session set with pre-existing variant from TUI setMainSession("main-123") const toastCalls: string[] = [] @@ -236,8 +236,8 @@ describe("keyword-detector session filtering", () => { output ) - // then - existing variant should remain - expect(output.message.variant).toBe("low") + // then - ultrawork should override TUI variant to max + expect(output.message.variant).toBe("max") expect(toastCalls).toContain("Ultrawork Mode Activated") }) }) diff --git a/src/plugin/chat-message.test.ts b/src/plugin/chat-message.test.ts index 4b5108add..8cebd6b43 100644 --- a/src/plugin/chat-message.test.ts +++ b/src/plugin/chat-message.test.ts @@ -45,9 +45,9 @@ function createMockOutput(variant?: string): ChatMessageHandlerOutput { return { message, parts: [] } } -describe("createChatMessageHandler - first message variant", () => { - test("first message: sets variant from fallback chain when user has no selection", async () => { - //#given - first message, no user-selected variant, hephaestus with medium in chain +describe("createChatMessageHandler - TUI variant passthrough", () => { + test("first message: does not override TUI variant when user has no selection", async () => { + //#given - first message, no user-selected variant const args = createMockHandlerArgs({ shouldOverride: true }) const handler = createChatMessageHandler(args) const input = createMockInput("hephaestus", { providerID: "openai", modelID: "gpt-5.3-codex" }) @@ -56,8 +56,8 @@ describe("createChatMessageHandler - first message variant", () => { //#when await handler(input, output) - //#then - should set variant from fallback chain - expect(output.message["variant"]).toBeDefined() + //#then - TUI sent undefined, should stay undefined (no config override) + expect(output.message["variant"]).toBeUndefined() }) test("first message: preserves user-selected variant when already set", async () => { @@ -70,25 +70,11 @@ describe("createChatMessageHandler - first message variant", () => { //#when await handler(input, output) - //#then - user's xhigh must be preserved, not overwritten to "medium" + //#then - user's xhigh must be preserved expect(output.message["variant"]).toBe("xhigh") }) - test("first message: preserves user-selected 'high' variant", async () => { - //#given - user selected "high" variant - const args = createMockHandlerArgs({ shouldOverride: true }) - const handler = createChatMessageHandler(args) - const input = createMockInput("hephaestus", { providerID: "openai", modelID: "gpt-5.3-codex" }) - const output = createMockOutput("high") - - //#when - await handler(input, output) - - //#then - expect(output.message["variant"]).toBe("high") - }) - - test("subsequent message: does not override existing variant", async () => { + test("subsequent message: preserves TUI variant", async () => { //#given - not first message, variant already set const args = createMockHandlerArgs({ shouldOverride: false }) const handler = createChatMessageHandler(args) @@ -102,6 +88,20 @@ describe("createChatMessageHandler - first message variant", () => { expect(output.message["variant"]).toBe("xhigh") }) + test("subsequent message: does not inject variant when TUI sends none", async () => { + //#given - not first message, no variant from TUI + const args = createMockHandlerArgs({ shouldOverride: false }) + const handler = createChatMessageHandler(args) + const input = createMockInput("hephaestus", { providerID: "openai", modelID: "gpt-5.3-codex" }) + const output = createMockOutput() // no variant + + //#when + await handler(input, output) + + //#then - should stay undefined, not auto-resolved from config + expect(output.message["variant"]).toBeUndefined() + }) + test("first message: marks gate as applied regardless of variant presence", async () => { //#given - first message with user-selected variant const args = createMockHandlerArgs({ shouldOverride: true }) diff --git a/src/plugin/chat-message.ts b/src/plugin/chat-message.ts index cc296a7d6..f035c99a5 100644 --- a/src/plugin/chat-message.ts +++ b/src/plugin/chat-message.ts @@ -1,15 +1,8 @@ import type { OhMyOpenCodeConfig } from "../config" import type { PluginContext } from "./types" -import { - applyAgentVariant, - resolveAgentVariant, - resolveVariantForModel, -} from "../shared/agent-variant" import { hasConnectedProvidersCache } from "../shared" -import { - setSessionAgent, -} from "../features/claude-code-session-state" +import { setSessionAgent } from "../features/claude-code-session-state" import { applyUltraworkModelOverrideOnMessage } from "./ultrawork-model-override" import type { CreatedHooks } from "../create-hooks" @@ -57,25 +50,7 @@ export function createChatMessageHandler(args: { const message = output.message if (firstMessageVariantGate.shouldOverride(input.sessionID)) { - if (message["variant"] === undefined) { - const variant = - input.model && input.agent - ? resolveVariantForModel(pluginConfig, input.agent, input.model) - : resolveAgentVariant(pluginConfig, input.agent) - if (variant !== undefined) { - message["variant"] = variant - } - } firstMessageVariantGate.markApplied(input.sessionID) - } else { - if (input.model && input.agent && message["variant"] === undefined) { - const variant = resolveVariantForModel(pluginConfig, input.agent, input.model) - if (variant !== undefined) { - message["variant"] = variant - } - } else { - applyAgentVariant(pluginConfig, input.agent, message) - } } await hooks.stopContinuationGuard?.["chat.message"]?.(input)