From 1b2482dcb8d5c1cb9eac077fcd362f086efc1a79 Mon Sep 17 00:00:00 2001 From: jelveh Date: Sun, 26 Jul 2026 12:15:56 -0700 Subject: [PATCH] Keep the ai-chat model-map build inside the server lifecycle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit onServerStart fired #buildModelMap without awaiting or tracking it, so the network fetches it does (notably Ollama auto-discovery, which is enabled by default and doomed on any machine without a local Ollama) kept running after server.shutdown() resolved. In vitest that let the provider's console.error land during worker teardown, which surfaces as "Closing rpc while onUserConsoleLog was pending" — the unhandled error that intermittently fails CI (last seen attributed to WispController.test.ts). A rejection in the detached chain would also have been an unhandled rejection. Track the promise, catch and log rejections, and await it from onServerShutdown so no provider I/O or logging outlives the server. Also disable Ollama auto-discovery in setupTestServer's defaults — every test server was firing a pointless model-list fetch at localhost. --- .../drivers/ai-chat/ChatCompletionDriver.ts | 14 +++++++++++++- src/backend/testUtil.ts | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/backend/drivers/ai-chat/ChatCompletionDriver.ts b/src/backend/drivers/ai-chat/ChatCompletionDriver.ts index 90ebc3f8b..1c834b7c9 100644 --- a/src/backend/drivers/ai-chat/ChatCompletionDriver.ts +++ b/src/backend/drivers/ai-chat/ChatCompletionDriver.ts @@ -216,10 +216,22 @@ export class ChatCompletionDriver extends PuterDriver { #providers: Record = {}; #modelIdMap: Record = {}; + #modelMapReady: Promise = Promise.resolve(); override onServerStart() { this.#registerProviders(); - this.#buildModelMap(); + // Not awaited — providers fetch model lists over the network and + // boot must not block on their latency. Shutdown awaits the + // tracked promise so provider I/O (and its error logging) never + // outlives the server; a rejection here must not become an + // unhandled one. + this.#modelMapReady = this.#buildModelMap().catch((e) => { + console.error('Failed to build ai-chat model map:', e); + }); + } + + override async onServerShutdown() { + await this.#modelMapReady; } // -- Interface methods ------------------------------------------- diff --git a/src/backend/testUtil.ts b/src/backend/testUtil.ts index a6cf752f2..7373e488d 100644 --- a/src/backend/testUtil.ts +++ b/src/backend/testUtil.ts @@ -153,6 +153,9 @@ export const setupTestServer = async ( no_devwatch: true, no_browser_launch: true, import_ts_extensions: true, + // No local-Ollama auto-discovery: every test server would + // otherwise fire a doomed model-list fetch at localhost. + providers: { ollama: { enabled: false } }, }), configOverrides ?? {}, ) as IConfig;