From 29caab9d0d5613064bc3f357cd9c20f7bb8033fd Mon Sep 17 00:00:00 2001 From: Chris Estreich Date: Mon, 23 Feb 2026 23:13:26 -0800 Subject: [PATCH] feat: warm Roo models on CLI startup (#11722) When the CLI is configured with the Roo provider, proactively fetch and warm the model list during activation so that model information is available before the first prompt is sent. The warmup has a 10s timeout and failures are logged only in debug mode so they never block normal operation. Co-authored-by: Claude Opus 4.6 --- apps/cli/src/commands/cli/run.ts | 65 ++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/apps/cli/src/commands/cli/run.ts b/apps/cli/src/commands/cli/run.ts index b72e4e7283..8c9d82d903 100644 --- a/apps/cli/src/commands/cli/run.ts +++ b/apps/cli/src/commands/cli/run.ts @@ -21,6 +21,7 @@ import { JsonEventEmitter } from "@/agent/json-event-emitter.js" import { createClient } from "@/lib/sdk/index.js" import { loadToken, loadSettings } from "@/lib/storage/index.js" +import { isRecord } from "@/lib/utils/guards.js" import { getEnvVarName, getApiKeyFromEnv } from "@/lib/utils/provider.js" import { runOnboarding } from "@/lib/utils/onboarding.js" import { getDefaultExtensionPath } from "@/lib/utils/extension.js" @@ -30,6 +31,60 @@ import { ExtensionHost, ExtensionHostOptions } from "@/agent/index.js" import { runStdinStreamMode } from "./stdin-stream.js" const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const ROO_MODEL_WARMUP_TIMEOUT_MS = 10_000 + +async function warmRooModels(host: ExtensionHost): Promise { + await new Promise((resolve, reject) => { + let settled = false + + const cleanup = () => { + clearTimeout(timeoutId) + host.off("extensionWebviewMessage", onMessage) + } + + const finish = (fn: () => void) => { + if (settled) return + settled = true + cleanup() + fn() + } + + const onMessage = (message: unknown) => { + if (!isRecord(message)) { + return + } + + if (message.type !== "singleRouterModelFetchResponse") { + return + } + + const values = isRecord(message.values) ? message.values : undefined + + if (values?.provider !== "roo") { + return + } + + if (message.success === false) { + const errorMessage = + typeof message.error === "string" && message.error.length > 0 + ? message.error + : "failed to refresh Roo models" + + finish(() => reject(new Error(errorMessage))) + return + } + + finish(() => resolve()) + } + + const timeoutId = setTimeout(() => { + finish(() => reject(new Error(`timed out waiting for Roo models after ${ROO_MODEL_WARMUP_TIMEOUT_MS}ms`))) + }, ROO_MODEL_WARMUP_TIMEOUT_MS) + + host.on("extensionWebviewMessage", onMessage) + host.sendToExtension({ type: "requestRooModels" }) + }) +} export async function run(promptArg: string | undefined, flagOptions: FlagOptions) { setLogger({ @@ -295,6 +350,16 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption try { await host.activate() + if (extensionHostOptions.provider === "roo") { + try { + await warmRooModels(host) + } catch (warmupError) { + if (flagOptions.debug) { + const message = warmupError instanceof Error ? warmupError.message : String(warmupError) + console.error(`[CLI] Warning: Roo model warmup failed: ${message}`) + } + } + } if (jsonEmitter) { jsonEmitter.attachToClient(host.client)