From cc740a0b7b2c21dd3b77533c613a9ca97d0ea579 Mon Sep 17 00:00:00 2001 From: cte Date: Mon, 23 Feb 2026 23:09:45 -0800 Subject: [PATCH] feat: warm Roo models on CLI startup 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 b72e4e72834..8c9d82d9036 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)