diff --git a/extensions/acpx/register.runtime.ts b/extensions/acpx/register.runtime.ts index 85958b3cb0c..bd44f8b8adf 100644 --- a/extensions/acpx/register.runtime.ts +++ b/extensions/acpx/register.runtime.ts @@ -9,6 +9,7 @@ import { type AcpRuntime, } from "openclaw/plugin-sdk/acp-runtime-backend"; import type { OpenClawPluginService, OpenClawPluginServiceContext } from "openclaw/plugin-sdk/core"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { createLazyAcpRuntimeProxy } from "./src/runtime-proxy.js"; const ACPX_BACKEND_ID = "acpx"; @@ -26,12 +27,7 @@ type DeferredServiceState = { startPromise: Promise | null; }; -let serviceModulePromise: Promise | null = null; - -function loadServiceModule(): Promise { - serviceModulePromise ??= import("./src/service.js"); - return serviceModulePromise; -} +const loadServiceModule = createLazyRuntimeModule(() => import("./src/service.js")); async function startRealService(state: DeferredServiceState): Promise { if (state.realRuntime) { diff --git a/extensions/acpx/src/service.ts b/extensions/acpx/src/service.ts index 94510ccc369..a12db4dac21 100644 --- a/extensions/acpx/src/service.ts +++ b/extensions/acpx/src/service.ts @@ -7,6 +7,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { inspect } from "node:util"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime"; import type { OpenKeyedStoreOptions, @@ -58,9 +59,6 @@ const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE"; const SKIP_RUNTIME_PROBE_ENV = "OPENCLAW_SKIP_ACPX_RUNTIME_PROBE"; const ACPX_BACKEND_ID = "acpx"; -type AcpxRuntimeModule = typeof import("./runtime.js"); -let runtimeModulePromise: Promise | null = null; - type AcpxRuntimeFactoryParams = { pluginConfig: ResolvedAcpxPluginConfig; gatewayInstanceId: string; @@ -76,10 +74,7 @@ type CreateAcpxRuntimeServiceParams = { processCleanupDeps?: AcpxProcessCleanupDeps; }; -function loadRuntimeModule(): Promise { - runtimeModulePromise ??= import("./runtime.js"); - return runtimeModulePromise; -} +const loadRuntimeModule = createLazyRuntimeModule(() => import("./runtime.js")); /** Convert ACPX timeout seconds into timer-safe milliseconds. */ export function resolveAcpxTimerTimeoutMs(timeoutSeconds: number | undefined): number | undefined { diff --git a/extensions/anthropic-vertex/api.ts b/extensions/anthropic-vertex/api.ts index 5b37cb90dbf..b3c3f9c533d 100644 --- a/extensions/anthropic-vertex/api.ts +++ b/extensions/anthropic-vertex/api.ts @@ -3,6 +3,7 @@ * and lazy stream factories without eagerly importing the Vertex SDK runtime. */ import type { StreamFn } from "openclaw/plugin-sdk/agent-core"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import type { AnthropicVertexStreamDeps } from "./stream-runtime.js"; export { @@ -21,12 +22,7 @@ export { import { buildAnthropicVertexProvider } from "./provider-catalog.js"; import { hasAnthropicVertexAvailableAuth } from "./region.js"; -let streamRuntimeModulePromise: Promise | null = null; - -const loadStreamRuntimeModule = async () => { - streamRuntimeModulePromise ??= import("./stream-runtime.js"); - return await streamRuntimeModulePromise; -}; +const loadStreamRuntimeModule = createLazyRuntimeModule(() => import("./stream-runtime.js")); /** Merge an implicit Anthropic Vertex provider with explicit user config. */ export function mergeImplicitAnthropicVertexProvider(params: { diff --git a/extensions/bonjour/src/advertiser.ts b/extensions/bonjour/src/advertiser.ts index fd3549c5989..a9ef1a9165c 100644 --- a/extensions/bonjour/src/advertiser.ts +++ b/extensions/bonjour/src/advertiser.ts @@ -6,6 +6,7 @@ import type { ChildProcess } from "node:child_process"; import fs from "node:fs"; import { createRequire } from "node:module"; import os from "node:os"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; import { isTruthyEnvValue } from "openclaw/plugin-sdk/runtime-env"; import { classifyCiaoProcessError, type CiaoProcessErrorClassification } from "./ciao.js"; @@ -113,14 +114,10 @@ const defaultLogger = { const CIAO_MODULE_ID = "@homebridge/ciao"; const CIAO_WINDOWS_SHELL_COMMANDS = new Set(['arp -a | findstr /C:"---"']); -let ciaoModulePromise: Promise | null = null; let ciaoExecHidePatchDepth = 0; let restoreCiaoExecHidePatchOnce: (() => void) | null = null; -async function loadCiaoModule(): Promise { - ciaoModulePromise ??= import(CIAO_MODULE_ID) as Promise; - return ciaoModulePromise; -} +const loadCiaoModule = createLazyRuntimeModule(() => import(CIAO_MODULE_ID) as Promise); function readBonjourDisableOverride(): boolean | null { const raw = process.env.OPENCLAW_DISABLE_BONJOUR; diff --git a/extensions/brave/src/brave-web-search-provider.ts b/extensions/brave/src/brave-web-search-provider.ts index 5fa52bc7df5..cb9548299d7 100644 --- a/extensions/brave/src/brave-web-search-provider.ts +++ b/extensions/brave/src/brave-web-search-provider.ts @@ -3,6 +3,7 @@ * lazy-loads HTTP execution only when a search is run. */ import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-runtime"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import type { SearchConfigRecord, WebSearchProviderPlugin, @@ -15,14 +16,9 @@ import { import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { buildBraveWebSearchProviderBase } from "../web-search-shared.js"; -type BraveWebSearchRuntime = typeof import("./brave-web-search-provider.runtime.js"); - -let braveWebSearchRuntimePromise: Promise | undefined; - -function loadBraveWebSearchRuntime(): Promise { - braveWebSearchRuntimePromise ??= import("./brave-web-search-provider.runtime.js"); - return braveWebSearchRuntimePromise; -} +const loadBraveWebSearchRuntime = createLazyRuntimeModule( + () => import("./brave-web-search-provider.runtime.js"), +); const BraveSearchSchema = { type: "object", diff --git a/extensions/browser/plugin-registration.ts b/extensions/browser/plugin-registration.ts index 96d4823e74d..c88820d0b27 100644 --- a/extensions/browser/plugin-registration.ts +++ b/extensions/browser/plugin-registration.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; /** * Browser plugin registration helpers. This file keeps registration lazy while * advertising Browser tools, services, node-host commands, and audits. @@ -19,14 +20,9 @@ import { BrowserToolSchema } from "./src/browser-tool.schema.js"; const EAGER_BROWSER_CONTROL_SERVICE_ENV = "OPENCLAW_EAGER_BROWSER_CONTROL_SERVER"; -let browserRegistrationRuntimeModulePromise: Promise< - typeof import("./register.runtime.js") -> | null = null; - -const loadBrowserRegistrationRuntimeModule = async () => { - browserRegistrationRuntimeModulePromise ??= import("./register.runtime.js"); - return await browserRegistrationRuntimeModulePromise; -}; +const loadBrowserRegistrationRuntimeModule = createLazyRuntimeModule( + () => import("./register.runtime.js"), +); function isTruthyEnvValue(value: string | undefined): boolean { return /^(?:1|true|yes|on)$/iu.test(value?.trim() ?? ""); diff --git a/extensions/browser/src/browser/server-context.remote-profile-tab-ops.test-helpers.ts b/extensions/browser/src/browser/server-context.remote-profile-tab-ops.test-helpers.ts index 9568a96e20f..cc2a57d6c50 100644 --- a/extensions/browser/src/browser/server-context.remote-profile-tab-ops.test-helpers.ts +++ b/extensions/browser/src/browser/server-context.remote-profile-tab-ops.test-helpers.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; /** * Lazy-loaded dependency bundle for remote-profile tab operation tests. */ @@ -19,11 +20,9 @@ export type RemoteProfileTestDeps = { originalFetch: typeof import("./server-context.remote-tab-ops.harness.js").originalFetch; }; -let remoteProfileTestDepsPromise: Promise | undefined; - /** Loads remote-profile tab operation dependencies after Chrome mocks are installed. */ -export async function loadRemoteProfileTestDeps(): Promise { - remoteProfileTestDepsPromise ??= (async () => { +const loadRemoteProfileTestDepsOnce = createLazyRuntimeModule(() => + (async () => { await import("./server-context.chrome-test-harness.js"); const cdpModule = await import("./cdp.js"); const chromeModule = await import("./chrome.js"); @@ -53,9 +52,10 @@ export async function loadRemoteProfileTestDeps(): Promise ({ })), })); -let browserServerModulePromise: Promise | undefined; - -async function loadBrowserServerModule() { - browserServerModulePromise ??= import("../server.js"); - return await browserServerModulePromise; -} +const loadBrowserServerModule = createLazyRuntimeModule(() => import("../server.js")); /** Starts the Browser control server from the mocked config module. */ export async function startBrowserControlServerFromConfig() { diff --git a/extensions/canvas/index.ts b/extensions/canvas/index.ts index 19b4932b656..bcbbfe06fc4 100644 --- a/extensions/canvas/index.ts +++ b/extensions/canvas/index.ts @@ -5,6 +5,7 @@ import type { IncomingMessage, ServerResponse } from "node:http"; import type { Duplex } from "node:stream"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { definePluginEntry, type AnyAgentTool } from "openclaw/plugin-sdk/plugin-entry"; import { canvasConfigSchema, isCanvasHostEnabled } from "./src/config.js"; import { A2UI_PATH, CANVAS_HOST_PATH, CANVAS_WS_PATH } from "./src/host/a2ui-shared.js"; @@ -25,16 +26,14 @@ function createLazyCanvasTool(params: { config?: OpenClawConfig; workspaceDir?: string; }): AnyAgentTool { - let toolPromise: Promise | undefined; - const loadTool = async () => { - toolPromise ??= import("./src/tool.js").then(({ createCanvasTool }) => + const loadTool = createLazyRuntimeModule(() => + import("./src/tool.js").then(({ createCanvasTool }) => createCanvasTool({ config: params.config, workspaceDir: params.workspaceDir, }), - ); - return await toolPromise; - }; + ), + ); return { label: "Canvas", name: "canvas", @@ -56,28 +55,22 @@ export default definePluginEntry({ }, register(api) { if (isCanvasHostEnabled(api.config)) { - let httpRouteHandlerPromise: - | Promise< - ReturnType<(typeof import("./src/http-route.js"))["createCanvasHttpRouteHandler"]> - > - | undefined; - const loadHttpRouteHandler = async () => { - httpRouteHandlerPromise ??= import("./src/http-route.js").then( - ({ createCanvasHttpRouteHandler }) => - createCanvasHttpRouteHandler({ - config: api.config, - pluginConfig: api.pluginConfig, - runtime: { - log: (...args) => api.logger.info(args.map(String).join(" ")), - error: (...args) => api.logger.error(args.map(String).join(" ")), - exit: (code) => { - throw new Error(`canvas host requested process exit ${code}`); - }, + const httpRouteHandlerLoader = createLazyRuntimeModule(() => + import("./src/http-route.js").then(({ createCanvasHttpRouteHandler }) => + createCanvasHttpRouteHandler({ + config: api.config, + pluginConfig: api.pluginConfig, + runtime: { + log: (...args) => api.logger.info(args.map(String).join(" ")), + error: (...args) => api.logger.error(args.map(String).join(" ")), + exit: (code) => { + throw new Error(`canvas host requested process exit ${code}`); }, - }), - ); - return await httpRouteHandlerPromise; - }; + }, + }), + ), + ); + const loadHttpRouteHandler = httpRouteHandlerLoader; const handleHttpRequest = async (req: IncomingMessage, res: ServerResponse) => await (await loadHttpRouteHandler()).handleHttpRequest(req, res); const handleUpgrade = async (req: IncomingMessage, socket: Duplex, head: Buffer) => @@ -109,18 +102,17 @@ export default definePluginEntry({ id: "canvas-host", start: () => {}, stop: async () => { - const httpRouteHandler = httpRouteHandlerPromise ? await httpRouteHandlerPromise : null; + const httpRouteHandler = await httpRouteHandlerLoader.peek(); await httpRouteHandler?.close(); }, }); - let resolveCanvasHttpPathToLocalPathPromise: - | Promise<(typeof import("./src/documents.js"))["resolveCanvasHttpPathToLocalPath"]> - | undefined; - api.registerHostedMediaResolver(async (mediaUrl) => { - resolveCanvasHttpPathToLocalPathPromise ??= import("./src/documents.js").then( + const loadResolveCanvasHttpPathToLocalPath = createLazyRuntimeModule(() => + import("./src/documents.js").then( ({ resolveCanvasHttpPathToLocalPath }) => resolveCanvasHttpPathToLocalPath, - ); - return (await resolveCanvasHttpPathToLocalPathPromise)(mediaUrl); + ), + ); + api.registerHostedMediaResolver(async (mediaUrl) => { + return (await loadResolveCanvasHttpPathToLocalPath())(mediaUrl); }); } api.registerNodeInvokePolicy({ diff --git a/extensions/codex/src/app-server/client-factory.ts b/extensions/codex/src/app-server/client-factory.ts index 8a474cf0c9f..127fae10c22 100644 --- a/extensions/codex/src/app-server/client-factory.ts +++ b/extensions/codex/src/app-server/client-factory.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; /** * Lazy factories for shared and leased Codex app-server clients. */ @@ -22,12 +23,7 @@ export type CodexAppServerClientFactory = ( }, ) => Promise; -let sharedClientModulePromise: Promise | null = null; - -const loadSharedClientModule = async () => { - sharedClientModulePromise ??= import("./shared-client.js"); - return await sharedClientModulePromise; -}; +const loadSharedClientModule = createLazyRuntimeModule(() => import("./shared-client.js")); /** Returns a leased shared client so startup can release ownership explicitly. */ export const defaultLeasedCodexAppServerClientFactory: CodexAppServerClientFactory = ( diff --git a/extensions/codex/src/web-search-provider.ts b/extensions/codex/src/web-search-provider.ts index 943b7312934..6e50d138610 100644 --- a/extensions/codex/src/web-search-provider.ts +++ b/extensions/codex/src/web-search-provider.ts @@ -1,16 +1,12 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime"; import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-contract"; import type { CodexAppServerClientFactory } from "./app-server/client-factory.js"; import { createCodexWebSearchProviderBase } from "./web-search-provider.shared.js"; -type CodexWebSearchRuntime = typeof import("./web-search-provider.runtime.js"); - -let codexWebSearchRuntimePromise: Promise | undefined; - -function loadCodexWebSearchRuntime(): Promise { - codexWebSearchRuntimePromise ??= import("./web-search-provider.runtime.js"); - return codexWebSearchRuntimePromise; -} +const loadCodexWebSearchRuntime = createLazyRuntimeModule( + () => import("./web-search-provider.runtime.js"), +); const CodexWebSearchSchema = { type: "object", diff --git a/extensions/duckduckgo/src/ddg-search-provider.ts b/extensions/duckduckgo/src/ddg-search-provider.ts index 9b05daa6dfc..df0b4157cd8 100644 --- a/extensions/duckduckgo/src/ddg-search-provider.ts +++ b/extensions/duckduckgo/src/ddg-search-provider.ts @@ -1,16 +1,10 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Duckduckgo provider module implements model/runtime integration. import { readPositiveIntegerParam, readStringParam } from "openclaw/plugin-sdk/param-readers"; import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-contract"; import { createDuckDuckGoWebSearchProviderBase } from "./ddg-search-provider.shared.js"; -type DuckDuckGoClientModule = typeof import("./ddg-client.js"); - -let duckDuckGoClientModulePromise: Promise | undefined; - -function loadDuckDuckGoClientModule(): Promise { - duckDuckGoClientModulePromise ??= import("./ddg-client.js"); - return duckDuckGoClientModulePromise; -} +const loadDuckDuckGoClientModule = createLazyRuntimeModule(() => import("./ddg-client.js")); const DuckDuckGoSearchSchema = { type: "object", diff --git a/extensions/exa/src/exa-web-search-provider.ts b/extensions/exa/src/exa-web-search-provider.ts index e72ddda2078..195a75c3f3d 100644 --- a/extensions/exa/src/exa-web-search-provider.ts +++ b/extensions/exa/src/exa-web-search-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Exa provider module implements model/runtime integration. import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-contract"; import { createExaWebSearchProviderBase } from "./exa-web-search-provider.shared.js"; @@ -6,14 +7,9 @@ const EXA_SEARCH_TYPES = ["auto", "neural", "fast", "deep", "deep-reasoning", "i const EXA_FRESHNESS_VALUES = ["day", "week", "month", "year"] as const; const EXA_MAX_SEARCH_COUNT = 100; -type ExaWebSearchRuntime = typeof import("./exa-web-search-provider.runtime.js"); - -let exaWebSearchRuntimePromise: Promise | undefined; - -function loadExaWebSearchRuntime(): Promise { - exaWebSearchRuntimePromise ??= import("./exa-web-search-provider.runtime.js"); - return exaWebSearchRuntimePromise; -} +const loadExaWebSearchRuntime = createLazyRuntimeModule( + () => import("./exa-web-search-provider.runtime.js"), +); const ExaSearchSchema = { type: "object", diff --git a/extensions/firecrawl/src/firecrawl-search-provider.ts b/extensions/firecrawl/src/firecrawl-search-provider.ts index 52b8b336d6e..520eadf1ef8 100644 --- a/extensions/firecrawl/src/firecrawl-search-provider.ts +++ b/extensions/firecrawl/src/firecrawl-search-provider.ts @@ -1,16 +1,10 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Firecrawl provider module implements model/runtime integration. import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers"; import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-contract"; import { buildFirecrawlWebSearchProviderBase } from "../web-search-shared.js"; -type FirecrawlClientModule = typeof import("./firecrawl-client.js"); - -let firecrawlClientModulePromise: Promise | undefined; - -function loadFirecrawlClientModule(): Promise { - firecrawlClientModulePromise ??= import("./firecrawl-client.js"); - return firecrawlClientModulePromise; -} +const loadFirecrawlClientModule = createLazyRuntimeModule(() => import("./firecrawl-client.js")); const GenericFirecrawlSearchSchema = { type: "object", diff --git a/extensions/google/gemini-cli-provider.ts b/extensions/google/gemini-cli-provider.ts index 1950479e578..5b03b74e4dc 100644 --- a/extensions/google/gemini-cli-provider.ts +++ b/extensions/google/gemini-cli-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Google provider module implements model/runtime integration. import type { OpenClawPluginApi, @@ -22,12 +23,7 @@ const ENV_VARS = [ "GEMINI_CLI_OAUTH_CLIENT_SECRET", ] as const; -let oauthRuntimeModulePromise: Promise | null = null; - -const loadOauthRuntimeModule = async () => { - oauthRuntimeModulePromise ??= import("./oauth.runtime.js"); - return await oauthRuntimeModulePromise; -}; +const loadOauthRuntimeModule = createLazyRuntimeModule(() => import("./oauth.runtime.js")); async function fetchGeminiCliUsage(ctx: ProviderFetchUsageSnapshotContext) { return await fetchGeminiUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn, PROVIDER_ID); diff --git a/extensions/google/src/gemini-web-search-provider.ts b/extensions/google/src/gemini-web-search-provider.ts index 1cba040ef9b..9f9b2f8a223 100644 --- a/extensions/google/src/gemini-web-search-provider.ts +++ b/extensions/google/src/gemini-web-search-provider.ts @@ -1,5 +1,6 @@ // Google provider module implements model/runtime integration. import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { createWebSearchProviderContractFields, mergeScopedSearchConfig, @@ -17,14 +18,9 @@ import { const GEMINI_CREDENTIAL_PATH = "plugins.entries.google.config.webSearch.apiKey"; const GOOGLE_PROVIDER_CREDENTIAL_PATH = "models.providers.google.apiKey"; -type GeminiWebSearchRuntime = typeof import("./gemini-web-search-provider.runtime.js"); - -let geminiWebSearchRuntimePromise: Promise | undefined; - -function loadGeminiWebSearchRuntime(): Promise { - geminiWebSearchRuntimePromise ??= import("./gemini-web-search-provider.runtime.js"); - return geminiWebSearchRuntimePromise; -} +const loadGeminiWebSearchRuntime = createLazyRuntimeModule( + () => import("./gemini-web-search-provider.runtime.js"), +); const GEMINI_TOOL_PARAMETERS = { type: "object", diff --git a/extensions/memory-core/index.ts b/extensions/memory-core/index.ts index 6f32caa06c1..2ad6f3c8c1b 100644 --- a/extensions/memory-core/index.ts +++ b/extensions/memory-core/index.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Memory Core plugin entrypoint registers its OpenClaw integration. import { jsonResult, @@ -20,7 +21,6 @@ import { buildMemoryFlushPlan } from "./src/flush-plan.js"; import { buildPromptSection } from "./src/prompt-section.js"; type MemoryToolsModule = typeof import("./src/tools.js"); -type RuntimeProviderModule = typeof import("./src/runtime-provider.js"); type MemoryToolOptions = { config?: OpenClawConfig; @@ -31,18 +31,11 @@ type MemoryToolOptions = { oneShotCliRun?: boolean; }; -let memoryToolsModulePromise: Promise | undefined; -let runtimeProviderModulePromise: Promise | undefined; +const loadMemoryToolsModule = createLazyRuntimeModule(() => import("./src/tools.js")); -function loadMemoryToolsModule(): Promise { - memoryToolsModulePromise ??= import("./src/tools.js"); - return memoryToolsModulePromise; -} - -function loadRuntimeProviderModule(): Promise { - runtimeProviderModulePromise ??= import("./src/runtime-provider.js"); - return runtimeProviderModulePromise; -} +const loadRuntimeProviderModule = createLazyRuntimeModule( + () => import("./src/runtime-provider.js"), +); function getToolConfig(options: MemoryToolOptions): OpenClawConfig | undefined { return options.getConfig?.() ?? options.config; diff --git a/extensions/memory-core/src/cli.ts b/extensions/memory-core/src/cli.ts index a98be07c536..2306adbda28 100644 --- a/extensions/memory-core/src/cli.ts +++ b/extensions/memory-core/src/cli.ts @@ -1,5 +1,6 @@ // Memory Core plugin module implements cli behavior. import type { Command } from "commander"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { formatDocsLink, formatHelpExamples, @@ -23,14 +24,7 @@ import { DEFAULT_PROMOTION_MIN_UNIQUE_QUERIES, } from "./short-term-promotion.js"; -type MemoryCliRuntime = typeof import("./cli.runtime.js"); - -let memoryCliRuntimePromise: Promise | null = null; - -async function loadMemoryCliRuntime(): Promise { - memoryCliRuntimePromise ??= import("./cli.runtime.js"); - return await memoryCliRuntimePromise; -} +const loadMemoryCliRuntime = createLazyRuntimeModule(() => import("./cli.runtime.js")); const DECIMAL_NUMBER_RE = /^[+-]?(?:\d+(?:\.\d+)?|\.\d+)$/; diff --git a/extensions/memory-core/src/memory/search-manager.ts b/extensions/memory-core/src/memory/search-manager.ts index c7d6e305ae5..1a1e61f7903 100644 --- a/extensions/memory-core/src/memory/search-manager.ts +++ b/extensions/memory-core/src/memory/search-manager.ts @@ -2,6 +2,7 @@ import { createHash } from "node:crypto"; // Memory Core plugin module implements search manager behavior. import fs from "node:fs/promises"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { createSubsystemLogger, resolveAgentContextLimits, @@ -112,18 +113,10 @@ const { pendingQmdManagerCreates: PENDING_QMD_MANAGER_CREATES, qmdManagerOpenFailures: QMD_MANAGER_OPEN_FAILURES, } = getMemorySearchManagerCacheStore(); -let managerRuntimePromise: Promise | null = null; -let qmdManagerModulePromise: Promise | null = null; +const managerRuntimeLoader = createLazyRuntimeModule(() => import("../../manager-runtime.js")); +const loadManagerRuntime = managerRuntimeLoader; -function loadManagerRuntime() { - managerRuntimePromise ??= import("../../manager-runtime.js"); - return managerRuntimePromise; -} - -function loadQmdManagerModule() { - qmdManagerModulePromise ??= import("./qmd-manager.js"); - return qmdManagerModulePromise; -} +const loadQmdManagerModule = createLazyRuntimeModule(() => import("./qmd-manager.js")); export type MemorySearchManagerResult = { manager: Maybe; @@ -522,7 +515,7 @@ export async function closeAllMemorySearchManagers(): Promise { log.warn(`failed to close qmd memory manager: ${String(err)}`); } } - if (managerRuntimePromise !== null) { + if (managerRuntimeLoader.peek()) { const { closeAllMemoryIndexManagers } = await loadManagerRuntime(); await closeAllMemoryIndexManagers(); } @@ -548,7 +541,7 @@ export async function closeMemorySearchManager(params: { log.warn(`failed to close qmd memory manager for agent ${normalizedAgentId}: ${String(err)}`); } } - if (managerRuntimePromise !== null) { + if (managerRuntimeLoader.peek()) { const { closeMemoryIndexManagersForAgent } = await loadManagerRuntime(); await closeMemoryIndexManagersForAgent({ cfg: params.cfg, agentId: normalizedAgentId }); } diff --git a/extensions/memory-core/src/memory/test-manager-helpers.ts b/extensions/memory-core/src/memory/test-manager-helpers.ts index cd5729fdd00..ca753d7871a 100644 --- a/extensions/memory-core/src/memory/test-manager-helpers.ts +++ b/extensions/memory-core/src/memory/test-manager-helpers.ts @@ -1,22 +1,15 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Memory Core helper module supports test manager helpers behavior. import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core-host-engine-foundation"; import type { MemoryIndexManager } from "./index.js"; -type MemoryIndexModule = typeof import("./index.js"); +const ensureEmbeddingMocksLoaded = createLazyRuntimeModule(() => + import("./embedding.test-mocks.js").then(() => undefined), +); -let ensureEmbeddingMocksLoadedPromise: Promise | null = null; -let getMemorySearchManagerPromise: Promise | null = - null; - -async function ensureEmbeddingMocksLoaded(): Promise { - ensureEmbeddingMocksLoadedPromise ??= import("./embedding.test-mocks.js").then(() => undefined); - await ensureEmbeddingMocksLoadedPromise; -} - -async function loadGetMemorySearchManager(): Promise { - getMemorySearchManagerPromise ??= import("./index.js").then((mod) => mod.getMemorySearchManager); - return await getMemorySearchManagerPromise; -} +const loadGetMemorySearchManager = createLazyRuntimeModule(() => + import("./index.js").then((mod) => mod.getMemorySearchManager), +); export async function getRequiredMemoryIndexManager(params: { cfg: OpenClawConfig; diff --git a/extensions/memory-core/src/tools.shared.ts b/extensions/memory-core/src/tools.shared.ts index 67175836cae..d526a8c5bd5 100644 --- a/extensions/memory-core/src/tools.shared.ts +++ b/extensions/memory-core/src/tools.shared.ts @@ -1,5 +1,6 @@ // Memory Core plugin module implements tools.shared behavior. import { optionalFiniteNumberSchema, stringEnum } from "openclaw/plugin-sdk/channel-actions"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { listMemoryCorpusSupplements, resolveMemorySearchConfig, @@ -10,8 +11,6 @@ import { } from "openclaw/plugin-sdk/memory-core-host-runtime-core"; import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; import { Type } from "typebox"; - -type MemoryToolRuntime = typeof import("./tools.runtime.js"); type MemorySearchManagerResult = Awaited< ReturnType<(typeof import("./memory/index.js"))["getMemorySearchManager"]> >; @@ -23,12 +22,7 @@ type MemoryToolOptions = { oneShotCliRun?: boolean; }; -let memoryToolRuntimePromise: Promise | null = null; - -export async function loadMemoryToolRuntime(): Promise { - memoryToolRuntimePromise ??= import("./tools.runtime.js"); - return await memoryToolRuntimePromise; -} +export const loadMemoryToolRuntime = createLazyRuntimeModule(() => import("./tools.runtime.js")); export const MemorySearchSchema = Type.Object({ query: Type.String(), diff --git a/extensions/memory-lancedb/index.ts b/extensions/memory-lancedb/index.ts index 1ec101e9861..af2a3d5c796 100644 --- a/extensions/memory-lancedb/index.ts +++ b/extensions/memory-lancedb/index.ts @@ -16,6 +16,7 @@ import { } from "openclaw/plugin-sdk/channel-actions"; import { BUNDLED_CHAT_CHANNEL_ENVELOPE_PREFIXES } from "openclaw/plugin-sdk/chat-channel-ids"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import type { MemoryEmbeddingProvider } from "openclaw/plugin-sdk/memory-core-host-engine-embeddings"; import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints"; import { @@ -78,33 +79,13 @@ type OpenAiEmbeddingClient = { options: { body: unknown; timeout?: number; maxRetries?: number }, ): Promise; }; - -let openAiModulePromise: Promise | undefined; -function loadOpenAiModule(): Promise { - openAiModulePromise ??= import("openai"); - return openAiModulePromise; -} - -let memoryEmbeddingProviderModulePromise: - | Promise - | undefined; -function loadMemoryEmbeddingProviderModule(): Promise< - typeof import("openclaw/plugin-sdk/memory-core-host-engine-embeddings") -> { - memoryEmbeddingProviderModulePromise ??= - import("openclaw/plugin-sdk/memory-core-host-engine-embeddings"); - return memoryEmbeddingProviderModulePromise; -} - -let memoryHostCoreModulePromise: - | Promise - | undefined; -function loadMemoryHostCoreModule(): Promise< - typeof import("openclaw/plugin-sdk/memory-host-core") -> { - memoryHostCoreModulePromise ??= import("openclaw/plugin-sdk/memory-host-core"); - return memoryHostCoreModulePromise; -} +const loadOpenAiModule = createLazyRuntimeModule(() => import("openai")); +const loadMemoryEmbeddingProviderModule = createLazyRuntimeModule( + () => import("openclaw/plugin-sdk/memory-core-host-engine-embeddings"), +); +const loadMemoryHostCoreModule = createLazyRuntimeModule( + () => import("openclaw/plugin-sdk/memory-host-core"), +); function extractUserTextContent(message: unknown): string[] { const msgObj = asRecord(message); diff --git a/extensions/minimax/src/minimax-web-search-provider.ts b/extensions/minimax/src/minimax-web-search-provider.ts index 21765d583a3..69bcbdd218f 100644 --- a/extensions/minimax/src/minimax-web-search-provider.ts +++ b/extensions/minimax/src/minimax-web-search-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Minimax provider module implements model/runtime integration. import { createWebSearchProviderContractFields, @@ -12,14 +13,9 @@ const MINIMAX_TOKEN_PLAN_ENV_VARS = [ ] as const; const MINIMAX_WEB_SEARCH_ENV_VARS = [...MINIMAX_TOKEN_PLAN_ENV_VARS, "MINIMAX_API_KEY"] as const; -type MiniMaxWebSearchRuntime = typeof import("./minimax-web-search-provider.runtime.js"); - -let miniMaxWebSearchRuntimePromise: Promise | undefined; - -function loadMiniMaxWebSearchRuntime(): Promise { - miniMaxWebSearchRuntimePromise ??= import("./minimax-web-search-provider.runtime.js"); - return miniMaxWebSearchRuntimePromise; -} +const loadMiniMaxWebSearchRuntime = createLazyRuntimeModule( + () => import("./minimax-web-search-provider.runtime.js"), +); const MiniMaxSearchSchema = { type: "object", diff --git a/extensions/moonshot/src/kimi-web-search-provider.ts b/extensions/moonshot/src/kimi-web-search-provider.ts index dc5e1587de6..f1259b018fc 100644 --- a/extensions/moonshot/src/kimi-web-search-provider.ts +++ b/extensions/moonshot/src/kimi-web-search-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Moonshot provider module implements model/runtime integration. import { createWebSearchProviderContractFields, @@ -6,14 +7,10 @@ import { } from "openclaw/plugin-sdk/provider-web-search-config-contract"; const KIMI_CREDENTIAL_PATH = "plugins.entries.moonshot.config.webSearch.apiKey"; -type KimiWebSearchProviderRuntime = typeof import("./kimi-web-search-provider.runtime.js"); -let kimiWebSearchProviderRuntimePromise: Promise | undefined; - -function loadKimiWebSearchProviderRuntime(): Promise { - kimiWebSearchProviderRuntimePromise ??= import("./kimi-web-search-provider.runtime.js"); - return kimiWebSearchProviderRuntimePromise; -} +const loadKimiWebSearchProviderRuntime = createLazyRuntimeModule( + () => import("./kimi-web-search-provider.runtime.js"), +); const KimiSearchSchema = { type: "object", diff --git a/extensions/openai/openai-chatgpt-oauth-flow.runtime.ts b/extensions/openai/openai-chatgpt-oauth-flow.runtime.ts index df8dce69a3c..e5314f35246 100644 --- a/extensions/openai/openai-chatgpt-oauth-flow.runtime.ts +++ b/extensions/openai/openai-chatgpt-oauth-flow.runtime.ts @@ -5,6 +5,7 @@ * It is only intended for CLI use, not browser environments. */ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { parseOAuthAuthorizationInput, resolveOAuthTokenExpiresAt, @@ -56,7 +57,12 @@ type TokenRequestOptions = { timeoutMs?: number; }; -let nodeOAuthRuntimePromise: Promise | null = null; +const loadNodeOAuthModules = createLazyRuntimeModule(() => + Promise.all([import("node:crypto"), import("node:http")]).then(([cryptoModule, httpModule]) => ({ + randomBytes: cryptoModule.randomBytes, + http: httpModule, + })), +); function loadNodeOAuthRuntime(): Promise { if (typeof process === "undefined" || (!process.versions?.node && !process.versions?.bun)) { @@ -64,13 +70,7 @@ function loadNodeOAuthRuntime(): Promise { new Error("OpenAI Codex OAuth is only available in Node.js environments"), ); } - nodeOAuthRuntimePromise ??= Promise.all([import("node:crypto"), import("node:http")]).then( - ([cryptoModule, httpModule]) => ({ - randomBytes: cryptoModule.randomBytes, - http: httpModule, - }), - ); - return nodeOAuthRuntimePromise; + return loadNodeOAuthModules(); } function resolveCallbackHost(env: NodeJS.ProcessEnv = process.env): string { diff --git a/extensions/parallel/src/parallel-free-web-search-provider.ts b/extensions/parallel/src/parallel-free-web-search-provider.ts index b9370a0ea0f..1a073cfd199 100644 --- a/extensions/parallel/src/parallel-free-web-search-provider.ts +++ b/extensions/parallel/src/parallel-free-web-search-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-contract"; import { createParallelFreeWebSearchProviderBase } from "./parallel-free-web-search-provider.shared.js"; import { PARALLEL_FREE_SESSION_ID_MAX_LENGTH } from "./parallel-search-normalize.js"; @@ -18,14 +19,9 @@ const ParallelFreeSearchSchema = { }, } satisfies Record; -type ParallelFreeWebSearchRuntime = typeof import("./parallel-free-web-search-provider.runtime.js"); - -let parallelFreeWebSearchRuntimePromise: Promise | undefined; - -function loadParallelFreeWebSearchRuntime(): Promise { - parallelFreeWebSearchRuntimePromise ??= import("./parallel-free-web-search-provider.runtime.js"); - return parallelFreeWebSearchRuntimePromise; -} +const loadParallelFreeWebSearchRuntime = createLazyRuntimeModule( + () => import("./parallel-free-web-search-provider.runtime.js"), +); export function createParallelFreeWebSearchProvider(): WebSearchProviderPlugin { return { diff --git a/extensions/parallel/src/parallel-web-search-provider.ts b/extensions/parallel/src/parallel-web-search-provider.ts index 13fe704a8d5..aeee2c3fb42 100644 --- a/extensions/parallel/src/parallel-web-search-provider.ts +++ b/extensions/parallel/src/parallel-web-search-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-contract"; import { createParallelWebSearchProviderBase } from "./parallel-web-search-provider.shared.js"; @@ -8,14 +9,9 @@ const PARALLEL_MAX_OBJECTIVE_CHARS = 5000; const PARALLEL_MAX_SESSION_ID_CHARS = 1000; const PARALLEL_MAX_CLIENT_MODEL_CHARS = 100; -type ParallelWebSearchRuntime = typeof import("./parallel-web-search-provider.runtime.js"); - -let parallelWebSearchRuntimePromise: Promise | undefined; - -function loadParallelWebSearchRuntime(): Promise { - parallelWebSearchRuntimePromise ??= import("./parallel-web-search-provider.runtime.js"); - return parallelWebSearchRuntimePromise; -} +const loadParallelWebSearchRuntime = createLazyRuntimeModule( + () => import("./parallel-web-search-provider.runtime.js"), +); // Mirrors Parallel's recommended search tool schema: // https://docs.parallel.ai/search/best-practices#search-tool-definition diff --git a/extensions/perplexity/src/perplexity-web-search-provider.ts b/extensions/perplexity/src/perplexity-web-search-provider.ts index 8133f87e96a..b181e51dd21 100644 --- a/extensions/perplexity/src/perplexity-web-search-provider.ts +++ b/extensions/perplexity/src/perplexity-web-search-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Perplexity provider module implements model/runtime integration. import { mergeScopedSearchConfig, @@ -11,14 +12,9 @@ import { resolvePerplexityWebSearchRuntimeMetadata, } from "./perplexity-web-search-provider.shared.js"; -type PerplexityWebSearchRuntime = typeof import("./perplexity-web-search-provider.runtime.js"); - -let perplexityWebSearchRuntimePromise: Promise | undefined; - -function loadPerplexityWebSearchRuntime(): Promise { - perplexityWebSearchRuntimePromise ??= import("./perplexity-web-search-provider.runtime.js"); - return perplexityWebSearchRuntimePromise; -} +const loadPerplexityWebSearchRuntime = createLazyRuntimeModule( + () => import("./perplexity-web-search-provider.runtime.js"), +); function createPerplexityParameters(transport?: string): Record { const properties: Record = { diff --git a/extensions/policy/src/doctor/register.ts b/extensions/policy/src/doctor/register.ts index f08715fec5a..d0c0fbec6f4 100644 --- a/extensions/policy/src/doctor/register.ts +++ b/extensions/policy/src/doctor/register.ts @@ -8,6 +8,7 @@ import { type HealthCheckContext, type HealthFinding, } from "openclaw/plugin-sdk/health"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { normalizeAgentId } from "openclaw/plugin-sdk/routing"; import { isRecord, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime"; import { @@ -25,12 +26,7 @@ import { } from "../policy-state.js"; import { POLICY_TOOL_GROUPS } from "../tool-policy-conformance.js"; -let fsPromisesModulePromise: Promise | null = null; - -const loadFsPromisesModule = async () => { - fsPromisesModulePromise ??= import("node:fs/promises"); - return await fsPromisesModulePromise; -}; +const loadFsPromisesModule = createLazyRuntimeModule(() => import("node:fs/promises")); import { createPolicyDoctorChecks } from "./checks.js"; import { diff --git a/extensions/qa-lab/src/cli.ts b/extensions/qa-lab/src/cli.ts index c1277074b99..5bf3c6e9d22 100644 --- a/extensions/qa-lab/src/cli.ts +++ b/extensions/qa-lab/src/cli.ts @@ -1,5 +1,6 @@ // Qa Lab plugin module implements cli behavior. import type { Command } from "commander"; +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime"; import { collectString } from "./cli-options.js"; import type { @@ -21,8 +22,6 @@ import { import type { QaProviderMode, QaProviderModeInput } from "./run-config.js"; import { hasQaScenarioPack } from "./scenario-catalog.js"; -type QaLabCliRuntime = typeof import("./cli.runtime.js"); - type QaScenarioRunCliOptions = { repoRoot?: QaSuiteCommandOptions["repoRoot"]; outputDir?: QaSuiteCommandOptions["outputDir"]; @@ -83,12 +82,7 @@ type QaSuiteCliOptions = QaScenarioRunCliOptions & { runtimeParityTier?: QaSuiteCommandOptions["runtimeParityTier"]; }; -let qaLabCliRuntimePromise: Promise | null = null; - -async function loadQaLabCliRuntime(): Promise { - qaLabCliRuntimePromise ??= import("./cli.runtime.js"); - return await qaLabCliRuntimePromise; -} +const loadQaLabCliRuntime = createLazyRuntimeModule(() => import("./cli.runtime.js")); function invalidQaCliArgument(message: string): Error & { code: string; exitCode: number } { const error = new Error(message) as Error & { code: string; exitCode: number }; diff --git a/extensions/searxng/src/searxng-search-provider.ts b/extensions/searxng/src/searxng-search-provider.ts index 7a4f6e017ea..61c2b9df609 100644 --- a/extensions/searxng/src/searxng-search-provider.ts +++ b/extensions/searxng/src/searxng-search-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Searxng provider module implements model/runtime integration. import { readPositiveIntegerParam, readStringParam } from "openclaw/plugin-sdk/param-readers"; import { @@ -7,14 +8,7 @@ import { const SEARXNG_CREDENTIAL_PATH = "plugins.entries.searxng.config.webSearch.baseUrl"; -type SearxngClientModule = typeof import("./searxng-client.js"); - -let searxngClientModulePromise: Promise | undefined; - -function loadSearxngClientModule(): Promise { - searxngClientModulePromise ??= import("./searxng-client.js"); - return searxngClientModulePromise; -} +const loadSearxngClientModule = createLazyRuntimeModule(() => import("./searxng-client.js")); const SearxngSearchSchema = { type: "object", diff --git a/extensions/tavily/src/tavily-search-provider.ts b/extensions/tavily/src/tavily-search-provider.ts index ad8bf1e9a7d..5785ce07bd5 100644 --- a/extensions/tavily/src/tavily-search-provider.ts +++ b/extensions/tavily/src/tavily-search-provider.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Tavily provider module implements model/runtime integration. import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers"; import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-contract"; @@ -7,14 +8,7 @@ import { TAVILY_GENERIC_SEARCH_SCHEMA, } from "../web-search-shared.js"; -type TavilyClientModule = typeof import("./tavily-client.js"); - -let tavilyClientModulePromise: Promise | undefined; - -function loadTavilyClientModule(): Promise { - tavilyClientModulePromise ??= import("./tavily-client.js"); - return tavilyClientModulePromise; -} +const loadTavilyClientModule = createLazyRuntimeModule(() => import("./tavily-client.js")); export function createTavilyWebSearchProvider(): WebSearchProviderPlugin { return { diff --git a/extensions/tavily/web-search-contract-api.ts b/extensions/tavily/web-search-contract-api.ts index 34845eaef4f..aff998a270b 100644 --- a/extensions/tavily/web-search-contract-api.ts +++ b/extensions/tavily/web-search-contract-api.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Tavily API module exposes the plugin public contract. import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-config-contract"; import { @@ -6,14 +7,9 @@ import { TAVILY_GENERIC_SEARCH_SCHEMA, } from "./web-search-shared.js"; -type TavilySearchProviderModule = typeof import("./src/tavily-search-provider.js"); - -let tavilySearchProviderModulePromise: Promise | undefined; - -function loadTavilySearchProviderModule(): Promise { - tavilySearchProviderModulePromise ??= import("./src/tavily-search-provider.js"); - return tavilySearchProviderModulePromise; -} +const loadTavilySearchProviderModule = createLazyRuntimeModule( + () => import("./src/tavily-search-provider.js"), +); export function createTavilyWebSearchProvider(): WebSearchProviderPlugin { return { diff --git a/extensions/xai/index.ts b/extensions/xai/index.ts index a8ea0d68bc9..e4849f7214b 100644 --- a/extensions/xai/index.ts +++ b/extensions/xai/index.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Xai plugin entrypoint registers its OpenClaw integration. import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry"; import { OPENAI_COMPATIBLE_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared"; @@ -48,25 +49,14 @@ import { } from "./xai-oauth.js"; const PROVIDER_ID = "xai"; -type CodeExecutionModule = typeof import("./code-execution.js"); -type XSearchModule = typeof import("./x-search.js"); const XAI_CREDIT_OR_SPENDING_LIMIT_RE = /\b(?:used all available credits|monthly spending limit|purchase more credits|raise your spending limit)\b/i; const XAI_RATE_LIMIT_RE = /\b(?:rate limit exceeded|too many requests)\b/i; -let codeExecutionModulePromise: Promise | undefined; -let xSearchModulePromise: Promise | undefined; +const loadCodeExecutionModule = createLazyRuntimeModule(() => import("./code-execution.js")); -function loadCodeExecutionModule(): Promise { - codeExecutionModulePromise ??= import("./code-execution.js"); - return codeExecutionModulePromise; -} - -function loadXSearchModule(): Promise { - xSearchModulePromise ??= import("./x-search.js"); - return xSearchModulePromise; -} +const loadXSearchModule = createLazyRuntimeModule(() => import("./x-search.js")); function classifyXaiFailoverReason(errorMessage: string) { if (XAI_CREDIT_OR_SPENDING_LIMIT_RE.test(errorMessage)) { diff --git a/extensions/xai/web-search.ts b/extensions/xai/web-search.ts index 5fa13defa88..8d7b2af7f51 100644 --- a/extensions/xai/web-search.ts +++ b/extensions/xai/web-search.ts @@ -1,3 +1,4 @@ +import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime"; // Xai plugin module implements web search behavior. import type { WebSearchProviderPlugin, @@ -5,14 +6,9 @@ import type { } from "openclaw/plugin-sdk/provider-web-search-config-contract"; import { buildXaiWebSearchProviderBase } from "./web-search-provider-shared.js"; -type XaiWebSearchProviderRuntime = typeof import("./src/web-search-provider.runtime.js"); - -let xaiWebSearchProviderRuntimePromise: Promise | undefined; - -function loadXaiWebSearchProviderRuntime(): Promise { - xaiWebSearchProviderRuntimePromise ??= import("./src/web-search-provider.runtime.js"); - return xaiWebSearchProviderRuntimePromise; -} +const loadXaiWebSearchProviderRuntime = createLazyRuntimeModule( + () => import("./src/web-search-provider.runtime.js"), +); const GenericXaiSearchSchema = { type: "object",