From de7d72db271645c3dfef9d667d4b822bcc34cfbc Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 31 Mar 2026 17:03:42 -0700 Subject: [PATCH] fix: honor category-derived model overrides in call_omo_agent --- src/tools/call-omo-agent/tools.test.ts | 54 ++++++++++++++++++++++++++ src/tools/call-omo-agent/tools.ts | 18 +++++++++ 2 files changed, 72 insertions(+) diff --git a/src/tools/call-omo-agent/tools.test.ts b/src/tools/call-omo-agent/tools.test.ts index 45038a2b6..56893ee7c 100644 --- a/src/tools/call-omo-agent/tools.test.ts +++ b/src/tools/call-omo-agent/tools.test.ts @@ -265,6 +265,60 @@ describe("createCallOmoAgent", () => { }) }) + test("forwards category-derived model override to background executor", async () => { + //#given + const launch = mock((_input: { model?: { providerID: string; modelID: string } }) => Promise.resolve({ + id: "task-category-model", + sessionID: "sub-session", + description: "Test task", + agent: "explore", + status: "pending", + })) + const managerWithLaunch = { + launch, + getTask: mock(() => undefined), + } + const toolDef = createCallOmoAgent( + mockCtx, + managerWithLaunch, + [], + { + explore: { + category: "research", + }, + }, + { + research: { + model: "openai/gpt-5.4", + }, + }, + ) + const executeFunc = toolDef.execute as Function + + //#when + await executeFunc( + { + description: "Test category model override", + prompt: "Test prompt", + subagent_type: "explore", + run_in_background: true, + }, + { sessionID: "test", messageID: "msg", agent: "test", abort: new AbortController().signal } + ) + + //#then + const firstLaunchCall = launch.mock.calls[0] + if (firstLaunchCall === undefined) { + throw new Error("Expected launch to be called") + } + + const [launchArgs] = firstLaunchCall + expect(launchArgs.model).toEqual({ + providerID: "openai", + modelID: "gpt-5.4", + }) + }) + test("should return a tool error when sync spawn depth validation fails", async () => { //#given reserveSubagentSpawnMock.mockRejectedValueOnce(new Error("Subagent spawn blocked: child depth 4 exceeds background_task.maxDepth=3.")) diff --git a/src/tools/call-omo-agent/tools.ts b/src/tools/call-omo-agent/tools.ts index 13388f062..9b62ef7e3 100644 --- a/src/tools/call-omo-agent/tools.ts +++ b/src/tools/call-omo-agent/tools.ts @@ -27,6 +27,12 @@ function resolveModelAndFallbackChain(args: { ?? (agentOverrides ? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === agentConfigKey)?.[1] : undefined) + const agentCategoryModel = agentOverride?.category + ? userCategories?.[agentOverride.category]?.model + : undefined + const agentCategoryVariant = agentOverride?.category + ? userCategories?.[agentOverride.category]?.variant + : undefined let model: DelegatedModelConfig | undefined if (agentOverride?.model) { @@ -39,6 +45,18 @@ function resolveModelAndFallbackChain(args: { variant: agentOverride.variant, }) } + } else if (agentCategoryModel) { + const normalized = normalizeModelFormat(agentCategoryModel) + if (normalized) { + const variantToUse = agentOverride?.variant ?? agentCategoryVariant + model = variantToUse ? { ...normalized, variant: variantToUse } : normalized + log("[call_omo_agent] Resolved model override from agent category", { + agent: subagentType, + category: agentOverride?.category, + model: agentCategoryModel, + variant: variantToUse, + }) + } } const normalizedFallbackModels = normalizeFallbackModels(