fix: resolve deadlock in config handler during plugin initialization (#1304)

* fix: resolve deadlock in config handler during plugin initialization

The config handler and createBuiltinAgents were calling fetchAvailableModels
with client, which triggers client.provider.list() API call to OpenCode server.
This caused a deadlock because:
- Plugin initialization waits for server response
- Server waits for plugin init to complete before handling requests

Now using cache-only mode by passing undefined instead of client.
If cache is unavailable, the fallback chain will use the first model.

Fixes #1301

* test: add regression tests for deadlock prevention in fetchAvailableModels

Add tests to ensure fetchAvailableModels is called with undefined client
during plugin initialization. This prevents regression on issue #1301.

- config-handler.test.ts: verify config handler does not pass client
- utils.test.ts: verify createBuiltinAgents does not pass client

* test: restore spies in utils.test.ts to prevent test pollution

Add mockRestore() calls for all spies created in test cases to ensure proper cleanup between tests and prevent state leakage.

* test: restore fetchAvailableModels spy

---------

Co-authored-by: robin <robin@watcha.com>
Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
This commit is contained in:
Kwanghyun Moon
2026-01-31 12:46:05 +09:00
committed by GitHub
parent 839a4c5316
commit b405494808
4 changed files with 147 additions and 56 deletions
+6 -3
View File
@@ -180,9 +180,12 @@ export async function createBuiltinAgents(
uiSelectedModel?: string
): Promise<Record<string, AgentConfig>> {
const connectedProviders = readConnectedProvidersCache()
const availableModels = client
? await fetchAvailableModels(client, { connectedProviders: connectedProviders ?? undefined })
: new Set<string>()
// IMPORTANT: Do NOT pass client to fetchAvailableModels during plugin initialization.
// This function is called from config handler, and calling client API causes deadlock.
// See: https://github.com/code-yeongyu/oh-my-opencode/issues/1301
const availableModels = await fetchAvailableModels(undefined, {
connectedProviders: connectedProviders ?? undefined,
})
const result: Record<string, AgentConfig> = {}
const availableAgents: AvailableAgent[] = []