From 75b65c2a352cfbfee6322dfcc7274f13bbb7325c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 23 Mar 2026 09:23:30 +0000 Subject: [PATCH] fix: restore provider runtime lazy boundary --- src/agents/auth-profiles/doctor.ts | 11 +--- src/agents/auth-profiles/oauth.ts | 17 ++---- src/agents/model-auth.ts | 2 +- src/agents/model-catalog.ts | 12 +---- src/plugins/provider-runtime.runtime.ts | 72 ++++++++++++++++++++++--- 5 files changed, 73 insertions(+), 41 deletions(-) diff --git a/src/agents/auth-profiles/doctor.ts b/src/agents/auth-profiles/doctor.ts index e2ce1a7efca..51fb5ed93f3 100644 --- a/src/agents/auth-profiles/doctor.ts +++ b/src/agents/auth-profiles/doctor.ts @@ -1,16 +1,8 @@ import type { OpenClawConfig } from "../../config/config.js"; +import { buildProviderAuthDoctorHintWithPlugin } from "../../plugins/provider-runtime.runtime.js"; import { normalizeProviderId } from "../model-selection.js"; import type { AuthProfileStore } from "./types.js"; -let providerRuntimePromise: - | Promise - | undefined; - -function loadProviderRuntime() { - providerRuntimePromise ??= import("../../plugins/provider-runtime.runtime.js"); - return providerRuntimePromise; -} - export async function formatAuthDoctorHint(params: { cfg?: OpenClawConfig; store: AuthProfileStore; @@ -18,7 +10,6 @@ export async function formatAuthDoctorHint(params: { profileId?: string; }): Promise { const normalizedProvider = normalizeProviderId(params.provider); - const { buildProviderAuthDoctorHintWithPlugin } = await loadProviderRuntime(); const pluginHint = await buildProviderAuthDoctorHintWithPlugin({ provider: normalizedProvider, context: { diff --git a/src/agents/auth-profiles/oauth.ts b/src/agents/auth-profiles/oauth.ts index 35b88000133..2faba1a552e 100644 --- a/src/agents/auth-profiles/oauth.ts +++ b/src/agents/auth-profiles/oauth.ts @@ -7,6 +7,10 @@ import { import { loadConfig, type OpenClawConfig } from "../../config/config.js"; import { coerceSecretRef } from "../../config/types.secrets.js"; import { withFileLock } from "../../infra/file-lock.js"; +import { + formatProviderAuthProfileApiKeyWithPlugin, + refreshProviderOAuthCredentialWithPlugin, +} from "../../plugins/provider-runtime.runtime.js"; import { resolveSecretRefString, type SecretRefResolveCache } from "../../secrets/resolve.js"; import { refreshChutesTokens } from "../chutes-oauth.js"; import { AUTH_STORE_LOCK_OPTIONS, log } from "./constants.js"; @@ -39,15 +43,6 @@ function listOAuthProviderIds(): string[] { const OAUTH_PROVIDER_IDS = new Set(listOAuthProviderIds()); -let providerRuntimePromise: - | Promise - | undefined; - -function loadProviderRuntime() { - providerRuntimePromise ??= import("../../plugins/provider-runtime.runtime.js"); - return providerRuntimePromise; -} - const isOAuthProvider = (provider: string): provider is OAuthProvider => OAUTH_PROVIDER_IDS.has(provider); @@ -86,8 +81,7 @@ function isProfileConfigCompatible(params: { } async function buildOAuthApiKey(provider: string, credentials: OAuthCredential): Promise { - const { formatProviderAuthProfileApiKeyWithPlugin } = await loadProviderRuntime(); - const formatted = formatProviderAuthProfileApiKeyWithPlugin({ + const formatted = await formatProviderAuthProfileApiKeyWithPlugin({ provider, context: credentials, }); @@ -185,7 +179,6 @@ async function refreshOAuthTokenWithLock(params: { }; } - const { refreshProviderOAuthCredentialWithPlugin } = await loadProviderRuntime(); const pluginRefreshed = await refreshProviderOAuthCredentialWithPlugin({ provider: cred.provider, context: cred, diff --git a/src/agents/model-auth.ts b/src/agents/model-auth.ts index c811b9b2999..98906e5b1e2 100644 --- a/src/agents/model-auth.ts +++ b/src/agents/model-auth.ts @@ -369,7 +369,7 @@ export async function resolveApiKeyForProvider(params: { }) : undefined; if (owningPluginIds?.length) { - const pluginMissingAuthMessage = buildProviderMissingAuthMessageWithPlugin({ + const pluginMissingAuthMessage = await buildProviderMissingAuthMessageWithPlugin({ provider, config: cfg, context: { diff --git a/src/agents/model-catalog.ts b/src/agents/model-catalog.ts index 4306da76660..cd8ea846916 100644 --- a/src/agents/model-catalog.ts +++ b/src/agents/model-catalog.ts @@ -1,5 +1,6 @@ import { type OpenClawConfig, loadConfig } from "../config/config.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; +import { augmentModelCatalogWithProviderPlugins } from "../plugins/provider-runtime.runtime.js"; import { resolveOpenClawAgentDir } from "./agent-paths.js"; import { ensureOpenClawModelsJson } from "./models-config.js"; @@ -31,9 +32,6 @@ let modelCatalogPromise: Promise | null = null; let hasLoggedModelCatalogError = false; const defaultImportPiSdk = () => import("./pi-model-discovery-runtime.js"); let importPiSdk = defaultImportPiSdk; -let providerRuntimePromise: - | Promise - | undefined; let modelSuppressionPromise: Promise | undefined; const NON_PI_NATIVE_MODEL_PROVIDERS = new Set(["kilocode"]); @@ -42,11 +40,6 @@ function shouldLogModelCatalogTiming(): boolean { return process.env.OPENCLAW_DEBUG_INGRESS_TIMING === "1"; } -function loadProviderRuntime() { - providerRuntimePromise ??= import("../plugins/provider-runtime.runtime.js"); - return providerRuntimePromise; -} - function loadModelSuppression() { modelSuppressionPromise ??= import("./model-suppression.runtime.js"); return modelSuppressionPromise; @@ -187,8 +180,7 @@ export async function loadModelCatalog(params?: { const piSdk = await importPiSdk(); logStage("pi-sdk-imported"); const agentDir = resolveOpenClawAgentDir(); - const [{ shouldSuppressBuiltInModel }, { augmentModelCatalogWithProviderPlugins }] = - await Promise.all([loadModelSuppression(), loadProviderRuntime()]); + const { shouldSuppressBuiltInModel } = await loadModelSuppression(); logStage("catalog-deps-ready"); const { join } = await import("node:path"); const authStorage = piSdk.discoverAuthStorage(agentDir); diff --git a/src/plugins/provider-runtime.runtime.ts b/src/plugins/provider-runtime.runtime.ts index 005e5f63ec3..c8675f38ed1 100644 --- a/src/plugins/provider-runtime.runtime.ts +++ b/src/plugins/provider-runtime.runtime.ts @@ -1,8 +1,64 @@ -export { - augmentModelCatalogWithProviderPlugins, - buildProviderAuthDoctorHintWithPlugin, - buildProviderMissingAuthMessageWithPlugin, - formatProviderAuthProfileApiKeyWithPlugin, - prepareProviderRuntimeAuth, - refreshProviderOAuthCredentialWithPlugin, -} from "./provider-runtime.js"; +type ProviderRuntimeModule = typeof import("./provider-runtime.js"); + +type AugmentModelCatalogWithProviderPlugins = + ProviderRuntimeModule["augmentModelCatalogWithProviderPlugins"]; +type BuildProviderAuthDoctorHintWithPlugin = + ProviderRuntimeModule["buildProviderAuthDoctorHintWithPlugin"]; +type BuildProviderMissingAuthMessageWithPlugin = + ProviderRuntimeModule["buildProviderMissingAuthMessageWithPlugin"]; +type FormatProviderAuthProfileApiKeyWithPlugin = + ProviderRuntimeModule["formatProviderAuthProfileApiKeyWithPlugin"]; +type PrepareProviderRuntimeAuth = ProviderRuntimeModule["prepareProviderRuntimeAuth"]; +type RefreshProviderOAuthCredentialWithPlugin = + ProviderRuntimeModule["refreshProviderOAuthCredentialWithPlugin"]; + +let providerRuntimePromise: Promise | undefined; + +async function loadProviderRuntime(): Promise { + // Keep the heavy provider runtime behind an actual async boundary so callers + // can import this wrapper eagerly without collapsing the lazy chunk. + providerRuntimePromise ??= import("./provider-runtime.js"); + return providerRuntimePromise; +} + +export async function augmentModelCatalogWithProviderPlugins( + ...args: Parameters +): Promise>> { + const runtime = await loadProviderRuntime(); + return runtime.augmentModelCatalogWithProviderPlugins(...args); +} + +export async function buildProviderAuthDoctorHintWithPlugin( + ...args: Parameters +): Promise>> { + const runtime = await loadProviderRuntime(); + return runtime.buildProviderAuthDoctorHintWithPlugin(...args); +} + +export async function buildProviderMissingAuthMessageWithPlugin( + ...args: Parameters +): Promise>> { + const runtime = await loadProviderRuntime(); + return runtime.buildProviderMissingAuthMessageWithPlugin(...args); +} + +export async function formatProviderAuthProfileApiKeyWithPlugin( + ...args: Parameters +): Promise>> { + const runtime = await loadProviderRuntime(); + return runtime.formatProviderAuthProfileApiKeyWithPlugin(...args); +} + +export async function prepareProviderRuntimeAuth( + ...args: Parameters +): Promise>> { + const runtime = await loadProviderRuntime(); + return runtime.prepareProviderRuntimeAuth(...args); +} + +export async function refreshProviderOAuthCredentialWithPlugin( + ...args: Parameters +): Promise>> { + const runtime = await loadProviderRuntime(); + return runtime.refreshProviderOAuthCredentialWithPlugin(...args); +}