From 532143c5f48bc3aa7322c988b789d125427beb50 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 7 Mar 2026 16:35:39 +0900 Subject: [PATCH] feat(delegate-task): use explicit high variant for unspecified-high category MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update DEFAULT_CATEGORIES to use 'openai/gpt-5.4-high' directly instead of separate model + variant - Add helper functions (isExplicitHighModel, getExplicitHighBaseModel) to preserve explicit high models during fuzzy matching - Update category resolver to avoid collapsing explicit high models to base model + variant pair - Update tests to verify explicit high model handling in both background and sync modes - Update documentation examples to reflect new configuration 🤖 Generated with OhMyOpenCode assistance --- docs/guide/agent-model-matching.md | 2 +- docs/reference/configuration.md | 2 +- src/tools/delegate-task/constants.ts | 2 +- src/tools/delegate-task/model-selection.ts | 22 ++++++++++++++++ src/tools/delegate-task/tools.test.ts | 29 ++++++++++++++-------- 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/docs/guide/agent-model-matching.md b/docs/guide/agent-model-matching.md index 1377b6664..7627edd38 100644 --- a/docs/guide/agent-model-matching.md +++ b/docs/guide/agent-model-matching.md @@ -190,7 +190,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch "categories": { "quick": { "model": "opencode/gpt-5-nano" }, "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, - "unspecified-high": { "model": "openai/gpt-5.4", "variant": "high" }, + "unspecified-high": { "model": "openai/gpt-5.4-high" }, "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high", diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 63e7d7689..d742619f9 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -100,7 +100,7 @@ Here's a practical starting configuration: "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, // unspecified-high — complex work - "unspecified-high": { "model": "openai/gpt-5.4", "variant": "high" }, + "unspecified-high": { "model": "openai/gpt-5.4-high" }, // writing — docs/prose "writing": { "model": "google/gemini-3-flash" }, diff --git a/src/tools/delegate-task/constants.ts b/src/tools/delegate-task/constants.ts index 475f9f65c..08fd6ff8e 100644 --- a/src/tools/delegate-task/constants.ts +++ b/src/tools/delegate-task/constants.ts @@ -289,7 +289,7 @@ export const DEFAULT_CATEGORIES: Record = { artistry: { model: "google/gemini-3.1-pro", variant: "high" }, quick: { model: "anthropic/claude-haiku-4-5" }, "unspecified-low": { model: "anthropic/claude-sonnet-4-6" }, - "unspecified-high": { model: "openai/gpt-5.4", variant: "high" }, + "unspecified-high": { model: "openai/gpt-5.4-high" }, writing: { model: "kimi-for-coding/k2p5" }, } diff --git a/src/tools/delegate-task/model-selection.ts b/src/tools/delegate-task/model-selection.ts index e361ed642..f84d96ad1 100644 --- a/src/tools/delegate-task/model-selection.ts +++ b/src/tools/delegate-task/model-selection.ts @@ -3,6 +3,14 @@ import { normalizeModel } from "../../shared/model-normalization" import { fuzzyMatchModel } from "../../shared/model-availability" import { transformModelForProvider } from "../../shared/provider-model-id-transform" +function isExplicitHighModel(model: string): boolean { + return /(?:^|\/)[^/]+-high$/.test(model) +} + +function getExplicitHighBaseModel(model: string): string | null { + return isExplicitHighModel(model) ? model.replace(/-high$/, "") : null +} + export function resolveModelForDelegateTask(input: { userModel?: string @@ -17,6 +25,8 @@ export function resolveModelForDelegateTask(input: { } const categoryDefault = normalizeModel(input.categoryDefaultModel) + const explicitHighBaseModel = categoryDefault ? getExplicitHighBaseModel(categoryDefault) : null + const explicitHighModel = explicitHighBaseModel ? categoryDefault : undefined if (categoryDefault) { if (input.availableModels.size === 0) { return { model: categoryDefault } @@ -26,6 +36,10 @@ export function resolveModelForDelegateTask(input: { const providerHint = parts.length >= 2 ? [parts[0]] : undefined const match = fuzzyMatchModel(categoryDefault, input.availableModels, providerHint) if (match) { + if (isExplicitHighModel(categoryDefault) && match !== categoryDefault) { + return { model: categoryDefault } + } + return { model: match } } } @@ -45,12 +59,20 @@ export function resolveModelForDelegateTask(input: { const fullModel = `${provider}/${entry.model}` const match = fuzzyMatchModel(fullModel, input.availableModels, [provider]) if (match) { + if (explicitHighModel && entry.variant === "high" && match === explicitHighBaseModel) { + return { model: explicitHighModel } + } + return { model: match, variant: entry.variant } } } const crossProviderMatch = fuzzyMatchModel(entry.model, input.availableModels) if (crossProviderMatch) { + if (explicitHighModel && entry.variant === "high" && crossProviderMatch === explicitHighBaseModel) { + return { model: explicitHighModel } + } + return { model: crossProviderMatch, variant: entry.variant } } } diff --git a/src/tools/delegate-task/tools.test.ts b/src/tools/delegate-task/tools.test.ts index 6a89a695f..652c48c45 100644 --- a/src/tools/delegate-task/tools.test.ts +++ b/src/tools/delegate-task/tools.test.ts @@ -96,6 +96,16 @@ describe("sisyphus-task", () => { expect(category.model).toBe("openai/gpt-5.3-codex") expect(category.variant).toBe("medium") }) + + test("unspecified-high category uses explicit high model", () => { + // given + const category = DEFAULT_CATEGORIES["unspecified-high"] + + // when / #then + expect(category).toBeDefined() + expect(category.model).toBe("openai/gpt-5.4-high") + expect(category.variant).toBeUndefined() + }) }) describe("CATEGORY_PROMPT_APPENDS", () => { @@ -981,7 +991,7 @@ describe("sisyphus-task", () => { }) }) - test("DEFAULT_CATEGORIES variant passes to background WITHOUT userCategories", async () => { + test("DEFAULT_CATEGORIES explicit high model passes to background WITHOUT userCategories", async () => { // given - NO userCategories, testing DEFAULT_CATEGORIES only const { createDelegateTask } = require("./tools") let launchInput: any @@ -1026,7 +1036,7 @@ describe("sisyphus-task", () => { abort: new AbortController().signal, } - // when - unspecified-high has variant: "max" in DEFAULT_CATEGORIES + // when - unspecified-high uses the explicit high model in DEFAULT_CATEGORIES await tool.execute( { description: "Test unspecified-high default variant", @@ -1038,15 +1048,14 @@ describe("sisyphus-task", () => { toolContext ) - // then - variant MUST be "max" from DEFAULT_CATEGORIES + // then - the explicit high model should be passed without a separate variant expect(launchInput.model).toEqual({ providerID: "openai", - modelID: "gpt-5.4", - variant: "high", + modelID: "gpt-5.4-high", }) }, { timeout: 20000 }) - test("DEFAULT_CATEGORIES variant passes to sync session.prompt WITHOUT userCategories", async () => { + test("DEFAULT_CATEGORIES explicit high model passes to sync session.prompt WITHOUT userCategories", async () => { // given - NO userCategories, testing DEFAULT_CATEGORIES for sync mode const { createDelegateTask } = require("./tools") let promptBody: any @@ -1087,7 +1096,7 @@ describe("sisyphus-task", () => { abort: new AbortController().signal, } - // when - unspecified-high has variant: "max" in DEFAULT_CATEGORIES + // when - unspecified-high uses the explicit high model in DEFAULT_CATEGORIES await tool.execute( { description: "Test unspecified-high sync variant", @@ -1099,12 +1108,12 @@ describe("sisyphus-task", () => { toolContext ) - // then - variant MUST be "max" from DEFAULT_CATEGORIES (passed as separate field) + // then - the explicit high model should be passed without a separate variant expect(promptBody.model).toEqual({ providerID: "openai", - modelID: "gpt-5.4", + modelID: "gpt-5.4-high", }) - expect(promptBody.variant).toBe("high") + expect(promptBody.variant).toBeUndefined() }, { timeout: 20000 }) })