From d32caf3d8722e642ae5f660c9585b4020df0e815 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 29 May 2026 19:08:55 +0900 Subject: [PATCH] test(delegate-task): isolate model availability fixtures Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/category-resolver.ts | 2 +- src/tools/delegate-task/executor-types.ts | 5 ++ src/tools/delegate-task/subagent-resolver.ts | 2 +- .../subagent-resolver.test.ts | 50 +++++++++++++------ 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/tools/delegate-task/category-resolver.ts b/src/tools/delegate-task/category-resolver.ts index f45d2452f..679f41559 100644 --- a/src/tools/delegate-task/category-resolver.ts +++ b/src/tools/delegate-task/category-resolver.ts @@ -82,7 +82,7 @@ export async function resolveCategoryExecution( } } - const availableModels = await getAvailableModelsForDelegateTask(client) + const availableModels = executorCtx.availableModelsOverride ?? await getAvailableModelsForDelegateTask(client) const resolved = resolveCategoryConfig(categoryName, { userCategories, diff --git a/src/tools/delegate-task/executor-types.ts b/src/tools/delegate-task/executor-types.ts index 7efc08370..f310ef5a9 100644 --- a/src/tools/delegate-task/executor-types.ts +++ b/src/tools/delegate-task/executor-types.ts @@ -13,6 +13,11 @@ export interface ExecutorContext { browserProvider?: BrowserAutomationProvider agentOverrides?: AgentOverrides sisyphusAgentConfig?: SisyphusAgentConfig + /** + * Test hook: bypass global model cache reads with an explicit available model set. + * This keeps resolver tests isolated from Bun's process-wide module cache. + */ + availableModelsOverride?: Set modelFallbackControllerAccessor?: ModelFallbackControllerAccessor onSyncSessionCreated?: (event: { sessionID: string; parentID: string; title: string }) => Promise syncPollTimeoutMs?: number diff --git a/src/tools/delegate-task/subagent-resolver.ts b/src/tools/delegate-task/subagent-resolver.ts index 3d2fd92bb..36bc67a54 100644 --- a/src/tools/delegate-task/subagent-resolver.ts +++ b/src/tools/delegate-task/subagent-resolver.ts @@ -191,7 +191,7 @@ Create the work plan directly - that's your job as the planning agent.`, ?? agentCategoryConfig?.fallback_models ) - const availableModels = await getAvailableModelsForDelegateTask(client) + const availableModels = executorCtx.availableModelsOverride ?? await getAvailableModelsForDelegateTask(client) if (agentOverride?.model || agentCategoryModel || agentRequirement || matchedAgent.model) { diff --git a/src/tools/delegate-task/zauc-mocks-subagent-resolver/subagent-resolver.test.ts b/src/tools/delegate-task/zauc-mocks-subagent-resolver/subagent-resolver.test.ts index 1c632e072..d0417530d 100644 --- a/src/tools/delegate-task/zauc-mocks-subagent-resolver/subagent-resolver.test.ts +++ b/src/tools/delegate-task/zauc-mocks-subagent-resolver/subagent-resolver.test.ts @@ -1,8 +1,9 @@ /// -import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test" +import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test" import type { DelegateTaskArgs } from "../types" import type { ExecutorContext } from "../executor-types" +import * as connectedProvidersCache from "../../../shared/connected-providers-cache" type SubagentResolverModule = typeof import("../subagent-resolver") @@ -30,6 +31,36 @@ type ClaudeCodeAgentRecord = Record< const loadUserAgentsMock = mock((): ClaudeCodeAgentRecord => ({})) const loadProjectAgentsMock = mock((_directory?: string): ClaudeCodeAgentRecord => ({})) +function getAvailableModelsOverride(): Set | undefined { + const providerModelsCache = readProviderModelsCacheMock() + if (providerModelsCache === null) { + return undefined + } + + const connectedProviders = new Set(providerModelsCache.connected) + const availableModels = new Set() + for (const [providerID, models] of Object.entries(providerModelsCache.models)) { + if (!connectedProviders.has(providerID)) { + continue + } + for (const modelID of models) { + availableModels.add(`${providerID}/${modelID}`) + } + } + return availableModels +} + +function mockConnectedProvidersCache(): void { + spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockImplementation(readConnectedProvidersCacheMock) + spyOn(connectedProvidersCache, "readProviderModelsCache").mockImplementation(readProviderModelsCacheMock) + spyOn(connectedProvidersCache, "hasConnectedProvidersCache").mockImplementation( + () => readConnectedProvidersCacheMock() !== null, + ) + spyOn(connectedProvidersCache, "hasProviderModelsCache").mockImplementation( + () => readProviderModelsCacheMock() !== null, + ) +} + async function importFreshSubagentResolverModule(): Promise { return await import(`../subagent-resolver?test=${Date.now()}-${Math.random()}`) } @@ -59,6 +90,7 @@ function createExecutorContext( client, manager: {} as ExecutorContext["manager"], directory: "/tmp/test", + availableModelsOverride: getAvailableModelsOverride(), ...overrides, } } @@ -80,13 +112,7 @@ describe("resolveSubagentExecution", () => { mock.module("../../../shared/logger", () => ({ log: logMock, })) - mock.module("../../../shared/connected-providers-cache", () => ({ - readConnectedProvidersCache: readConnectedProvidersCacheMock, - readProviderModelsCache: readProviderModelsCacheMock, - hasConnectedProvidersCache: () => readConnectedProvidersCacheMock() !== null, - hasProviderModelsCache: () => readProviderModelsCacheMock() !== null, - _resetMemCacheForTesting: () => {}, - })) + mockConnectedProvidersCache() mock.module("../../../features/claude-code-agent-loader/loader", () => ({ loadUserAgents: loadUserAgentsMock, loadProjectAgents: loadProjectAgentsMock, @@ -1320,13 +1346,7 @@ describe("resolveSubagentExecution - agent name sanitization", () => { mock.module("../../../shared/logger", () => ({ log: logMock, })) - mock.module("../../../shared/connected-providers-cache", () => ({ - readConnectedProvidersCache: readConnectedProvidersCacheMock, - readProviderModelsCache: readProviderModelsCacheMock, - hasConnectedProvidersCache: () => readConnectedProvidersCacheMock() !== null, - hasProviderModelsCache: () => readProviderModelsCacheMock() !== null, - _resetMemCacheForTesting: () => {}, - })) + mockConnectedProvidersCache() mock.module("../../../features/claude-code-agent-loader/loader", () => ({ loadUserAgents: loadUserAgentsMock, loadProjectAgents: loadProjectAgentsMock,