refactor: unify lazy module loaders

This commit is contained in:
Peter Steinberger
2026-05-02 10:15:16 +01:00
parent 4407c317f3
commit db06fcd990
39 changed files with 408 additions and 264 deletions

View File

@@ -1,6 +1,7 @@
import type { Mock } from "vitest"; import type { Mock } from "vitest";
import { vi } from "vitest"; import { vi } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { createTestRuntime } from "./test-runtime-config-helpers.js"; import { createTestRuntime } from "./test-runtime-config-helpers.js";
type ReplaceConfigFileResult = Awaited< type ReplaceConfigFileResult = Awaited<
@@ -44,11 +45,12 @@ vi.mock("./agents.command-shared.js", () => ({
export const runtime = createTestRuntime(); export const runtime = createTestRuntime();
let agentsBindCommandModulePromise: Promise<typeof import("./agents.commands.bind.js")> | undefined; const agentsBindCommandModuleLoader = createLazyImportLoader(
() => import("./agents.commands.bind.js"),
);
export async function loadFreshAgentsBindCommandModuleForTest() { export async function loadFreshAgentsBindCommandModuleForTest() {
agentsBindCommandModulePromise ??= import("./agents.commands.bind.js"); return await agentsBindCommandModuleLoader.load();
return await agentsBindCommandModulePromise;
} }
export function resetAgentsBindTestHarness(): void { export function resetAgentsBindTestHarness(): void {

View File

@@ -6,7 +6,7 @@ import { normalizeChannelId as normalizeBundledChannelId } from "../channels/reg
import { isRouteBinding, listRouteBindings } from "../config/bindings.js"; import { isRouteBinding, listRouteBindings } from "../config/bindings.js";
import type { AgentRouteBinding } from "../config/types.js"; import type { AgentRouteBinding } from "../config/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { OpenClawConfig } from "../config/types.openclaw.js";
import { listManifestChannelContributionIds } from "../plugins/manifest-channel-contributions.js"; import { listManifestChannelContributionIds } from "../plugins/manifest-contribution-ids.js";
import { DEFAULT_ACCOUNT_ID, normalizeAgentId } from "../routing/session-key.js"; import { DEFAULT_ACCOUNT_ID, normalizeAgentId } from "../routing/session-key.js";
import { normalizeOptionalString } from "../shared/string-coerce.js"; import { normalizeOptionalString } from "../shared/string-coerce.js";
import { normalizeStringEntries } from "../shared/string-normalization.js"; import { normalizeStringEntries } from "../shared/string-normalization.js";

View File

@@ -6,6 +6,7 @@ import type { AgentRouteBinding } from "../config/types.js";
import { normalizeAgentId } from "../routing/session-key.js"; import { normalizeAgentId } from "../routing/session-key.js";
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js"; import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
import { defaultRuntime } from "../runtime.js"; import { defaultRuntime } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { describeBinding } from "./agents.binding-format.js"; import { describeBinding } from "./agents.binding-format.js";
import { requireValidConfig, requireValidConfigFileSnapshot } from "./agents.command-shared.js"; import { requireValidConfig, requireValidConfigFileSnapshot } from "./agents.command-shared.js";
@@ -29,11 +30,12 @@ type AgentsUnbindOptions = {
json?: boolean; json?: boolean;
}; };
let agentBindingsModulePromise: Promise<AgentBindingsModule> | undefined; const agentBindingsModuleLoader = createLazyImportLoader<AgentBindingsModule>(
() => import("./agents.bindings.js"),
);
function loadAgentBindingsModule(): Promise<AgentBindingsModule> { function loadAgentBindingsModule(): Promise<AgentBindingsModule> {
agentBindingsModulePromise ??= import("./agents.bindings.js"); return agentBindingsModuleLoader.load();
return agentBindingsModulePromise;
} }
function resolveAgentId( function resolveAgentId(

View File

@@ -5,15 +5,17 @@ import {
type BackupCreateResult, type BackupCreateResult,
} from "../infra/backup-create.js"; } from "../infra/backup-create.js";
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js"; import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
export type { BackupCreateOptions, BackupCreateResult } from "../infra/backup-create.js"; export type { BackupCreateOptions, BackupCreateResult } from "../infra/backup-create.js";
type BackupVerifyRuntime = typeof import("./backup-verify.js"); type BackupVerifyRuntime = typeof import("./backup-verify.js");
let backupVerifyRuntimePromise: Promise<BackupVerifyRuntime> | undefined; const backupVerifyRuntimeLoader = createLazyImportLoader<BackupVerifyRuntime>(
() => import("./backup-verify.js"),
);
function loadBackupVerifyRuntime(): Promise<BackupVerifyRuntime> { function loadBackupVerifyRuntime(): Promise<BackupVerifyRuntime> {
backupVerifyRuntimePromise ??= import("./backup-verify.js"); return backupVerifyRuntimeLoader.load();
return backupVerifyRuntimePromise;
} }
export async function backupCreateCommand( export async function backupCreateCommand(

View File

@@ -8,7 +8,7 @@ import type { ChannelMeta } from "../../channels/plugins/types.public.js";
import { isStaticallyChannelConfigured } from "../../config/channel-configured-shared.js"; import { isStaticallyChannelConfigured } from "../../config/channel-configured-shared.js";
import { applyPluginAutoEnable } from "../../config/plugin-auto-enable.js"; import { applyPluginAutoEnable } from "../../config/plugin-auto-enable.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { listManifestChannelContributionIds } from "../../plugins/manifest-channel-contributions.js"; import { listManifestChannelContributionIds } from "../../plugins/manifest-contribution-ids.js";
import type { ChannelChoice } from "../onboard-types.js"; import type { ChannelChoice } from "../onboard-types.js";
import { import {
listSetupDiscoveryChannelPluginCatalogEntries, listSetupDiscoveryChannelPluginCatalogEntries,

View File

@@ -11,6 +11,7 @@ import { refreshPluginRegistryAfterConfigMutation } from "../../cli/plugins-regi
import type { OpenClawConfig } from "../../config/config.js"; import type { OpenClawConfig } from "../../config/config.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js";
import { defaultRuntime, type RuntimeEnv } from "../../runtime.js"; import { defaultRuntime, type RuntimeEnv } from "../../runtime.js";
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js"; import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
import { createClackPrompter } from "../../wizard/clack-prompter.js"; import { createClackPrompter } from "../../wizard/clack-prompter.js";
import { applyAgentBindings, describeBinding } from "../agents.bindings.js"; import { applyAgentBindings, describeBinding } from "../agents.bindings.js";
@@ -22,17 +23,19 @@ import { requireValidConfigFileSnapshot, shouldUseWizard } from "./shared.js";
type ChannelSetupPluginInstallModule = typeof import("../channel-setup/plugin-install.js"); type ChannelSetupPluginInstallModule = typeof import("../channel-setup/plugin-install.js");
type OnboardChannelsModule = typeof import("../onboard-channels.js"); type OnboardChannelsModule = typeof import("../onboard-channels.js");
let channelSetupPluginInstallPromise: Promise<ChannelSetupPluginInstallModule> | undefined; const channelSetupPluginInstallLoader = createLazyImportLoader<ChannelSetupPluginInstallModule>(
let onboardChannelsPromise: Promise<OnboardChannelsModule> | undefined; () => import("../channel-setup/plugin-install.js"),
);
const onboardChannelsLoader = createLazyImportLoader<OnboardChannelsModule>(
() => import("../onboard-channels.js"),
);
function loadChannelSetupPluginInstall(): Promise<ChannelSetupPluginInstallModule> { function loadChannelSetupPluginInstall(): Promise<ChannelSetupPluginInstallModule> {
channelSetupPluginInstallPromise ??= import("../channel-setup/plugin-install.js"); return channelSetupPluginInstallLoader.load();
return channelSetupPluginInstallPromise;
} }
function loadOnboardChannels(): Promise<OnboardChannelsModule> { function loadOnboardChannels(): Promise<OnboardChannelsModule> {
onboardChannelsPromise ??= import("../onboard-channels.js"); return onboardChannelsLoader.load();
return onboardChannelsPromise;
} }
export type ChannelsAddOptions = { export type ChannelsAddOptions = {

View File

@@ -3,7 +3,7 @@ import { normalizeChannelId as normalizeBundledChannelId } from "../../channels/
import { getResolvedLoggerSettings } from "../../logging.js"; import { getResolvedLoggerSettings } from "../../logging.js";
import { resolveLogFile } from "../../logging/log-tail.js"; import { resolveLogFile } from "../../logging/log-tail.js";
import { parseLogLine } from "../../logging/parse-log-line.js"; import { parseLogLine } from "../../logging/parse-log-line.js";
import { listManifestChannelContributionIds } from "../../plugins/manifest-channel-contributions.js"; import { listManifestChannelContributionIds } from "../../plugins/manifest-contribution-ids.js";
import { defaultRuntime, type RuntimeEnv, writeRuntimeJson } from "../../runtime.js"; import { defaultRuntime, type RuntimeEnv, writeRuntimeJson } from "../../runtime.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js"; import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
import { theme } from "../../terminal/theme.js"; import { theme } from "../../terminal/theme.js";

View File

@@ -12,6 +12,7 @@ import { ensureControlUiAssetsBuilt } from "../infra/control-ui-assets.js";
import { resolvePluginContributionOwners } from "../plugins/plugin-registry.js"; import { resolvePluginContributionOwners } from "../plugins/plugin-registry.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js"; import { defaultRuntime } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { normalizeOptionalString } from "../shared/string-coerce.js"; import { normalizeOptionalString } from "../shared/string-coerce.js";
import { note } from "../terminal/note.js"; import { note } from "../terminal/note.js";
import { isPlainObject, resolveUserPath } from "../utils.js"; import { isPlainObject, resolveUserPath } from "../utils.js";
@@ -56,11 +57,12 @@ type SetupPluginConfigModule = typeof import("../wizard/setup.plugin-config.js")
const GATEWAY_HINT_PROBE_TIMEOUT_MS = 300; const GATEWAY_HINT_PROBE_TIMEOUT_MS = 300;
let setupPluginConfigModulePromise: Promise<SetupPluginConfigModule> | undefined; const setupPluginConfigModuleLoader = createLazyImportLoader<SetupPluginConfigModule>(
() => import("../wizard/setup.plugin-config.js"),
);
function loadSetupPluginConfigModule(): Promise<SetupPluginConfigModule> { function loadSetupPluginConfigModule(): Promise<SetupPluginConfigModule> {
setupPluginConfigModulePromise ??= import("../wizard/setup.plugin-config.js"); return setupPluginConfigModuleLoader.load();
return setupPluginConfigModulePromise;
} }
function mergeWizardConfigOntoLatest(current: unknown, base: unknown, next: unknown): unknown { function mergeWizardConfigOntoLatest(current: unknown, base: unknown, next: unknown): unknown {

View File

@@ -1,5 +1,5 @@
import { mergeMissing } from "../../../config/legacy.shared.js"; import { mergeMissing } from "../../../config/legacy.shared.js";
import { loadPluginMetadataSnapshot } from "../../../plugins/plugin-metadata-snapshot.js"; import { loadManifestMetadataSnapshot } from "../../../plugins/manifest-contract-eligibility.js";
import { import {
cloneRecord, cloneRecord,
ensureRecord, ensureRecord,
@@ -17,7 +17,7 @@ const LEGACY_GLOBAL_WEB_SEARCH_PROVIDER_ID = "brave";
function getBundledLegacyWebSearchOwners(): ReadonlyMap<string, string> { function getBundledLegacyWebSearchOwners(): ReadonlyMap<string, string> {
const owners = new Map<string, string>(); const owners = new Map<string, string>();
for (const plugin of loadPluginMetadataSnapshot({ config: {}, env: process.env }).plugins) { for (const plugin of loadManifestMetadataSnapshot({ config: {}, env: process.env }).plugins) {
if (plugin.origin !== "bundled") { if (plugin.origin !== "bundled") {
continue; continue;
} }

View File

@@ -6,7 +6,7 @@ import { installPluginFromNpmSpec } from "../../../plugins/install.js";
import { loadInstalledPluginIndexInstallRecords } from "../../../plugins/installed-plugin-index-records.js"; import { loadInstalledPluginIndexInstallRecords } from "../../../plugins/installed-plugin-index-records.js";
import { writePersistedInstalledPluginIndexInstallRecords } from "../../../plugins/installed-plugin-index-records.js"; import { writePersistedInstalledPluginIndexInstallRecords } from "../../../plugins/installed-plugin-index-records.js";
import { buildNpmResolutionInstallFields } from "../../../plugins/installs.js"; import { buildNpmResolutionInstallFields } from "../../../plugins/installs.js";
import { loadPluginMetadataSnapshot } from "../../../plugins/plugin-metadata-snapshot.js"; import { loadManifestMetadataSnapshot } from "../../../plugins/manifest-contract-eligibility.js";
import { resolveProviderInstallCatalogEntries } from "../../../plugins/provider-install-catalog.js"; import { resolveProviderInstallCatalogEntries } from "../../../plugins/provider-install-catalog.js";
import { updateNpmInstalledPlugins } from "../../../plugins/update.js"; import { updateNpmInstalledPlugins } from "../../../plugins/update.js";
import { asObjectRecord } from "./object.js"; import { asObjectRecord } from "./object.js";
@@ -154,7 +154,7 @@ export async function repairMissingConfiguredPluginInstalls(params: {
}): Promise<{ changes: string[]; warnings: string[] }> { }): Promise<{ changes: string[]; warnings: string[] }> {
const env = params.env ?? process.env; const env = params.env ?? process.env;
const knownIds = new Set( const knownIds = new Set(
loadPluginMetadataSnapshot({ loadManifestMetadataSnapshot({
config: params.cfg, config: params.cfg,
env, env,
}).plugins.map((plugin) => plugin.id), }).plugins.map((plugin) => plugin.id),

View File

@@ -1,8 +1,8 @@
import { normalizeToolName } from "../../../agents/tool-policy-shared.js"; import { normalizeToolName } from "../../../agents/tool-policy-shared.js";
import type { OpenClawConfig } from "../../../config/types.openclaw.js"; import type { OpenClawConfig } from "../../../config/types.openclaw.js";
import { normalizePluginId } from "../../../plugins/config-state.js"; import { normalizePluginId } from "../../../plugins/config-state.js";
import { loadManifestMetadataSnapshot } from "../../../plugins/manifest-contract-eligibility.js";
import type { PluginManifestRegistry } from "../../../plugins/manifest-registry.js"; import type { PluginManifestRegistry } from "../../../plugins/manifest-registry.js";
import { loadPluginMetadataSnapshot } from "../../../plugins/plugin-metadata-snapshot.js";
type ToolAllowlistSource = { type ToolAllowlistSource = {
label: string; label: string;
@@ -147,7 +147,7 @@ export function collectPluginToolAllowlistWarnings(params: {
const registry = const registry =
params.manifestRegistry ?? params.manifestRegistry ??
loadPluginMetadataSnapshot({ loadManifestMetadataSnapshot({
config: params.cfg, config: params.cfg,
env: params.env ?? process.env, env: params.env ?? process.env,
}).manifestRegistry; }).manifestRegistry;

View File

@@ -3,14 +3,16 @@ import { isToolAllowedByPolicies } from "../../../agents/tool-policy-match.js";
import { mergeAlsoAllowPolicy, resolveToolProfilePolicy } from "../../../agents/tool-policy.js"; import { mergeAlsoAllowPolicy, resolveToolProfilePolicy } from "../../../agents/tool-policy.js";
import type { OpenClawConfig } from "../../../config/types.openclaw.js"; import type { OpenClawConfig } from "../../../config/types.openclaw.js";
import type { AgentToolsConfig, ToolsConfig } from "../../../config/types.tools.js"; import type { AgentToolsConfig, ToolsConfig } from "../../../config/types.tools.js";
import { createLazyImportLoader } from "../../../shared/lazy-promise.js";
type ChannelDoctorModule = typeof import("./channel-doctor.js"); type ChannelDoctorModule = typeof import("./channel-doctor.js");
let channelDoctorModulePromise: Promise<ChannelDoctorModule> | undefined; const channelDoctorModuleLoader = createLazyImportLoader<ChannelDoctorModule>(
() => import("./channel-doctor.js"),
);
function loadChannelDoctorModule(): Promise<ChannelDoctorModule> { function loadChannelDoctorModule(): Promise<ChannelDoctorModule> {
channelDoctorModulePromise ??= import("./channel-doctor.js"); return channelDoctorModuleLoader.load();
return channelDoctorModulePromise;
} }
function hasRecord(value: unknown): value is Record<string, unknown> { function hasRecord(value: unknown): value is Record<string, unknown> {

View File

@@ -3,7 +3,7 @@ import { CHANNEL_IDS } from "../../../channels/ids.js";
import type { OpenClawConfig } from "../../../config/types.openclaw.js"; import type { OpenClawConfig } from "../../../config/types.openclaw.js";
import { normalizePluginId } from "../../../plugins/config-state.js"; import { normalizePluginId } from "../../../plugins/config-state.js";
import { loadInstalledPluginIndexInstallRecordsSync } from "../../../plugins/installed-plugin-index-records.js"; import { loadInstalledPluginIndexInstallRecordsSync } from "../../../plugins/installed-plugin-index-records.js";
import { loadPluginMetadataSnapshot } from "../../../plugins/plugin-metadata-snapshot.js"; import { loadManifestMetadataSnapshot } from "../../../plugins/manifest-contract-eligibility.js";
import { sanitizeForLog } from "../../../terminal/ansi.js"; import { sanitizeForLog } from "../../../terminal/ansi.js";
import { asObjectRecord } from "./object.js"; import { asObjectRecord } from "./object.js";
@@ -29,7 +29,7 @@ function collectPluginRegistryState(
env?: NodeJS.ProcessEnv, env?: NodeJS.ProcessEnv,
): StalePluginRegistryState { ): StalePluginRegistryState {
const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg)); const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg));
const registry = loadPluginMetadataSnapshot({ const registry = loadManifestMetadataSnapshot({
config: cfg, config: cfg,
workspaceDir: workspaceDir ?? undefined, workspaceDir: workspaceDir ?? undefined,
env: env ?? process.env, env: env ?? process.env,

View File

@@ -2,6 +2,7 @@ import { withProgress } from "../cli/progress.js";
import { readBestEffortConfig, resolveGatewayPort } from "../config/config.js"; import { readBestEffortConfig, resolveGatewayPort } from "../config/config.js";
import { resolveWideAreaDiscoveryDomain } from "../infra/widearea-dns.js"; import { resolveWideAreaDiscoveryDomain } from "../infra/widearea-dns.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { isRich } from "../terminal/theme.js"; import { isRich } from "../terminal/theme.js";
import { inferSshTargetFromRemoteUrl, resolveSshTarget } from "./gateway-status/discovery.js"; import { inferSshTargetFromRemoteUrl, resolveSshTarget } from "./gateway-status/discovery.js";
import { import {
@@ -18,23 +19,20 @@ import {
} from "./gateway-status/output.js"; } from "./gateway-status/output.js";
import { runGatewayStatusProbePass } from "./gateway-status/probe-run.js"; import { runGatewayStatusProbePass } from "./gateway-status/probe-run.js";
let sshConfigModulePromise: Promise<typeof import("../infra/ssh-config.js")> | undefined; const sshConfigModuleLoader = createLazyImportLoader(() => import("../infra/ssh-config.js"));
let sshTunnelModulePromise: Promise<typeof import("../infra/ssh-tunnel.js")> | undefined; const sshTunnelModuleLoader = createLazyImportLoader(() => import("../infra/ssh-tunnel.js"));
let gatewayTlsModulePromise: Promise<typeof import("../infra/tls/gateway.js")> | undefined; const gatewayTlsModuleLoader = createLazyImportLoader(() => import("../infra/tls/gateway.js"));
function loadSshConfigModule() { function loadSshConfigModule() {
sshConfigModulePromise ??= import("../infra/ssh-config.js"); return sshConfigModuleLoader.load();
return sshConfigModulePromise;
} }
function loadSshTunnelModule() { function loadSshTunnelModule() {
sshTunnelModulePromise ??= import("../infra/ssh-tunnel.js"); return sshTunnelModuleLoader.load();
return sshTunnelModulePromise;
} }
function loadGatewayTlsModule() { function loadGatewayTlsModule() {
gatewayTlsModulePromise ??= import("../infra/tls/gateway.js"); return gatewayTlsModuleLoader.load();
return gatewayTlsModulePromise;
} }
export async function gatewayStatusCommand( export async function gatewayStatusCommand(

View File

@@ -23,6 +23,7 @@ import { getActivePluginRegistry } from "../plugins/runtime.js";
import { buildChannelAccountBindings, resolvePreferredAccountId } from "../routing/bindings.js"; import { buildChannelAccountBindings, resolvePreferredAccountId } from "../routing/bindings.js";
import { normalizeAgentId } from "../routing/session-key.js"; import { normalizeAgentId } from "../routing/session-key.js";
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js"; import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { asNullableRecord } from "../shared/record-coerce.js"; import { asNullableRecord } from "../shared/record-coerce.js";
import { styleHealthChannelLine } from "../terminal/health-style.js"; import { styleHealthChannelLine } from "../terminal/health-style.js";
import { isRich } from "../terminal/theme.js"; import { isRich } from "../terminal/theme.js";
@@ -48,11 +49,12 @@ const DEFAULT_TIMEOUT_MS = 10_000;
type ConfigModule = typeof import("../config/config.js"); type ConfigModule = typeof import("../config/config.js");
let configModulePromise: Promise<ConfigModule> | undefined; const configModuleLoader = createLazyImportLoader<ConfigModule>(
() => import("../config/config.js"),
);
function loadConfigModule(): Promise<ConfigModule> { function loadConfigModule(): Promise<ConfigModule> {
configModulePromise ??= import("../config/config.js"); return configModuleLoader.load();
return configModulePromise;
} }
const debugHealth = (...args: unknown[]) => { const debugHealth = (...args: unknown[]) => {

View File

@@ -2,6 +2,7 @@ import type { Api, Model } from "@mariozechner/pi-ai";
import type { ModelRegistry } from "@mariozechner/pi-coding-agent"; import type { ModelRegistry } from "@mariozechner/pi-coding-agent";
import { parseModelRef } from "../../agents/model-selection.js"; import { parseModelRef } from "../../agents/model-selection.js";
import type { RuntimeEnv } from "../../runtime.js"; import type { RuntimeEnv } from "../../runtime.js";
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js"; import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
import { createModelListAuthIndex } from "./list.auth-index.js"; import { createModelListAuthIndex } from "./list.auth-index.js";
import { resolveConfiguredEntries } from "./list.configured.js"; import { resolveConfiguredEntries } from "./list.configured.js";
@@ -17,23 +18,26 @@ type RegistryLoadModule = typeof import("./list.registry-load.js");
type RowSourcesModule = typeof import("./list.row-sources.js"); type RowSourcesModule = typeof import("./list.row-sources.js");
type SourcePlanModule = typeof import("./list.source-plan.js"); type SourcePlanModule = typeof import("./list.source-plan.js");
let registryLoadModulePromise: Promise<RegistryLoadModule> | undefined; const registryLoadModuleLoader = createLazyImportLoader<RegistryLoadModule>(
let rowSourcesModulePromise: Promise<RowSourcesModule> | undefined; () => import("./list.registry-load.js"),
let sourcePlanModulePromise: Promise<SourcePlanModule> | undefined; );
const rowSourcesModuleLoader = createLazyImportLoader<RowSourcesModule>(
() => import("./list.row-sources.js"),
);
const sourcePlanModuleLoader = createLazyImportLoader<SourcePlanModule>(
() => import("./list.source-plan.js"),
);
function loadRegistryLoadModule(): Promise<RegistryLoadModule> { function loadRegistryLoadModule(): Promise<RegistryLoadModule> {
registryLoadModulePromise ??= import("./list.registry-load.js"); return registryLoadModuleLoader.load();
return registryLoadModulePromise;
} }
function loadRowSourcesModule(): Promise<RowSourcesModule> { function loadRowSourcesModule(): Promise<RowSourcesModule> {
rowSourcesModulePromise ??= import("./list.row-sources.js"); return rowSourcesModuleLoader.load();
return rowSourcesModulePromise;
} }
function loadSourcePlanModule(): Promise<SourcePlanModule> { function loadSourcePlanModule(): Promise<SourcePlanModule> {
sourcePlanModulePromise ??= import("./list.source-plan.js"); return sourcePlanModuleLoader.load();
return sourcePlanModulePromise;
} }
export async function modelsListCommand( export async function modelsListCommand(

View File

@@ -4,8 +4,8 @@ import {
planManifestModelCatalogRows, planManifestModelCatalogRows,
} from "../../model-catalog/index.js"; } from "../../model-catalog/index.js";
import type { NormalizedModelCatalogRow } from "../../model-catalog/index.js"; import type { NormalizedModelCatalogRow } from "../../model-catalog/index.js";
import { loadManifestMetadataSnapshot } from "../../plugins/manifest-contract-eligibility.js";
import type { PluginManifestRegistry } from "../../plugins/manifest-registry.js"; import type { PluginManifestRegistry } from "../../plugins/manifest-registry.js";
import { loadPluginMetadataSnapshot } from "../../plugins/plugin-metadata-snapshot.js";
import { import {
getPluginRecord, getPluginRecord,
isPluginEnabled, isPluginEnabled,
@@ -98,7 +98,7 @@ function loadManifestCatalogRowsForList(params: {
? normalizeModelCatalogProviderId(params.providerFilter) ? normalizeModelCatalogProviderId(params.providerFilter)
: undefined; : undefined;
const mode = params.mode ?? "static-authoritative"; const mode = params.mode ?? "static-authoritative";
const snapshot = loadPluginMetadataSnapshot({ const snapshot = loadManifestMetadataSnapshot({
config: params.cfg, config: params.cfg,
env: params.env ?? process.env, env: params.env ?? process.env,
}); });

View File

@@ -28,16 +28,18 @@ import {
import type { OpenClawConfig } from "../../config/types.openclaw.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { coerceSecretRef, normalizeSecretInputString } from "../../config/types.secrets.js"; import { coerceSecretRef, normalizeSecretInputString } from "../../config/types.secrets.js";
import { type SecretRefResolveCache, resolveSecretRefString } from "../../secrets/resolve.js"; import { type SecretRefResolveCache, resolveSecretRefString } from "../../secrets/resolve.js";
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
import { redactSecrets } from "../status-all/format.js"; import { redactSecrets } from "../status-all/format.js";
import { DEFAULT_PROVIDER, formatMs } from "./shared.js"; import { DEFAULT_PROVIDER, formatMs } from "./shared.js";
const PROBE_PROMPT = "Reply with OK. Do not use tools."; const PROBE_PROMPT = "Reply with OK. Do not use tools.";
let embeddedRunnerModulePromise: Promise<typeof import("../../agents/pi-embedded.js")> | undefined; const embeddedRunnerModuleLoader = createLazyImportLoader(
() => import("../../agents/pi-embedded.js"),
);
function loadEmbeddedRunnerModule() { function loadEmbeddedRunnerModule() {
embeddedRunnerModulePromise ??= import("../../agents/pi-embedded.js"); return embeddedRunnerModuleLoader.load();
return embeddedRunnerModulePromise;
} }
export type AuthProbeStatus = export type AuthProbeStatus =

View File

@@ -9,6 +9,7 @@ import { normalizeProviderId } from "../../agents/provider-id.js";
import type { ModelDefinitionConfig, ModelProviderConfig } from "../../config/types.models.js"; import type { ModelDefinitionConfig, ModelProviderConfig } from "../../config/types.models.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { NormalizedModelCatalogRow } from "../../model-catalog/index.js"; import type { NormalizedModelCatalogRow } from "../../model-catalog/index.js";
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
import type { ModelListAuthIndex } from "./list.auth-index.js"; import type { ModelListAuthIndex } from "./list.auth-index.js";
import type { ListRowModel } from "./list.model-row.js"; import type { ListRowModel } from "./list.model-row.js";
import { toModelRow } from "./list.model-row.js"; import { toModelRow } from "./list.model-row.js";
@@ -36,23 +37,26 @@ export type RowBuilderContext = {
skipRuntimeModelSuppression?: boolean; skipRuntimeModelSuppression?: boolean;
}; };
let modelCatalogModulePromise: Promise<ModelCatalogModule> | undefined; const modelCatalogModuleLoader = createLazyImportLoader<ModelCatalogModule>(
let modelResolverModulePromise: Promise<ModelResolverModule> | undefined; () => import("../../agents/model-catalog.js"),
let providerCatalogModulePromise: Promise<ProviderCatalogModule> | undefined; );
const modelResolverModuleLoader = createLazyImportLoader<ModelResolverModule>(
() => import("../../agents/pi-embedded-runner/model.js"),
);
const providerCatalogModuleLoader = createLazyImportLoader<ProviderCatalogModule>(
() => import("./list.provider-catalog.js"),
);
function loadModelCatalogModule(): Promise<ModelCatalogModule> { function loadModelCatalogModule(): Promise<ModelCatalogModule> {
modelCatalogModulePromise ??= import("../../agents/model-catalog.js"); return modelCatalogModuleLoader.load();
return modelCatalogModulePromise;
} }
function loadModelResolverModule(): Promise<ModelResolverModule> { function loadModelResolverModule(): Promise<ModelResolverModule> {
modelResolverModulePromise ??= import("../../agents/pi-embedded-runner/model.js"); return modelResolverModuleLoader.load();
return modelResolverModulePromise;
} }
function loadProviderCatalogModule(): Promise<ProviderCatalogModule> { function loadProviderCatalogModule(): Promise<ProviderCatalogModule> {
providerCatalogModulePromise ??= import("./list.provider-catalog.js"); return providerCatalogModuleLoader.load();
return providerCatalogModulePromise;
} }
function matchesRowFilter(filter: RowFilter, model: { provider: string; baseUrl?: string }) { function matchesRowFilter(filter: RowFilter, model: { provider: string; baseUrl?: string }) {

View File

@@ -42,6 +42,7 @@ import type { ProviderSyntheticAuthResult } from "../../plugins/provider-externa
import { resolveProviderSyntheticAuthWithPlugin } from "../../plugins/provider-runtime.js"; import { resolveProviderSyntheticAuthWithPlugin } from "../../plugins/provider-runtime.js";
import { resolveRuntimeSyntheticAuthProviderRefs } from "../../plugins/synthetic-auth.runtime.js"; import { resolveRuntimeSyntheticAuthProviderRefs } from "../../plugins/synthetic-auth.runtime.js";
import { type RuntimeEnv, writeRuntimeJson } from "../../runtime.js"; import { type RuntimeEnv, writeRuntimeJson } from "../../runtime.js";
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js"; import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { colorize, theme } from "../../terminal/theme.js"; import { colorize, theme } from "../../terminal/theme.js";
import { shortenHomePath } from "../../utils.js"; import { shortenHomePath } from "../../utils.js";
@@ -61,10 +62,18 @@ type ProgressRuntime = typeof import("../../cli/progress.js");
type TerminalTableRuntime = typeof import("../../terminal/table.js"); type TerminalTableRuntime = typeof import("../../terminal/table.js");
type ListProbeRuntime = typeof import("./list.probe.js"); type ListProbeRuntime = typeof import("./list.probe.js");
let providerUsageRuntimePromise: Promise<ProviderUsageRuntime> | undefined; const providerUsageRuntimeLoader = createLazyImportLoader<ProviderUsageRuntime>(
let progressRuntimePromise: Promise<ProgressRuntime> | undefined; () => import("../../infra/provider-usage.js"),
let terminalTableRuntimePromise: Promise<TerminalTableRuntime> | undefined; );
let listProbeRuntimePromise: Promise<ListProbeRuntime> | undefined; const progressRuntimeLoader = createLazyImportLoader<ProgressRuntime>(
() => import("../../cli/progress.js"),
);
const terminalTableRuntimeLoader = createLazyImportLoader<TerminalTableRuntime>(
() => import("../../terminal/table.js"),
);
const listProbeRuntimeLoader = createLazyImportLoader<ListProbeRuntime>(
() => import("./list.probe.js"),
);
const DISPLAY_MODEL_PARSE_OPTIONS = { allowPluginNormalization: false } as const; const DISPLAY_MODEL_PARSE_OPTIONS = { allowPluginNormalization: false } as const;
@@ -77,23 +86,19 @@ type StatusSyntheticAuth = {
}; };
function loadProviderUsageRuntime(): Promise<ProviderUsageRuntime> { function loadProviderUsageRuntime(): Promise<ProviderUsageRuntime> {
providerUsageRuntimePromise ??= import("../../infra/provider-usage.js"); return providerUsageRuntimeLoader.load();
return providerUsageRuntimePromise;
} }
function loadProgressRuntime(): Promise<ProgressRuntime> { function loadProgressRuntime(): Promise<ProgressRuntime> {
progressRuntimePromise ??= import("../../cli/progress.js"); return progressRuntimeLoader.load();
return progressRuntimePromise;
} }
function loadTerminalTableRuntime(): Promise<TerminalTableRuntime> { function loadTerminalTableRuntime(): Promise<TerminalTableRuntime> {
terminalTableRuntimePromise ??= import("../../terminal/table.js"); return terminalTableRuntimeLoader.load();
return terminalTableRuntimePromise;
} }
function loadListProbeRuntime(): Promise<ListProbeRuntime> { function loadListProbeRuntime(): Promise<ListProbeRuntime> {
listProbeRuntimePromise ??= import("./list.probe.js"); return listProbeRuntimeLoader.load();
return listProbeRuntimePromise;
} }
function resolveProviderConfigForStatus( function resolveProviderConfigForStatus(

View File

@@ -5,6 +5,7 @@ import { loadSessionStore, resolveSessionTotalTokens } from "../config/sessions.
import { info } from "../globals.js"; import { info } from "../globals.js";
import { parseAgentSessionKey } from "../routing/session-key.js"; import { parseAgentSessionKey } from "../routing/session-key.js";
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js"; import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { isRich, theme } from "../terminal/theme.js"; import { isRich, theme } from "../terminal/theme.js";
import { resolveSessionStoreTargetsOrExit } from "./session-store-targets.js"; import { resolveSessionStoreTargetsOrExit } from "./session-store-targets.js";
import { import {
@@ -33,7 +34,7 @@ type SessionRow = SessionDisplayRow & {
const AGENT_PAD = 10; const AGENT_PAD = 10;
const KIND_PAD = 6; const KIND_PAD = 6;
const TOKENS_PAD = 20; const TOKENS_PAD = 20;
let contextLookupRuntimePromise: Promise<typeof import("../agents/context.js")> | null = null; const contextLookupRuntimeLoader = createLazyImportLoader(() => import("../agents/context.js"));
const formatKTokens = (value: number) => `${(value / 1000).toFixed(value >= 10_000 ? 0 : 1)}k`; const formatKTokens = (value: number) => `${(value / 1000).toFixed(value >= 10_000 ? 0 : 1)}k`;
@@ -72,8 +73,7 @@ const formatTokensCell = (
}; };
async function lookupContextTokensForDisplay(model: string): Promise<number | undefined> { async function lookupContextTokensForDisplay(model: string): Promise<number | undefined> {
contextLookupRuntimePromise ??= import("../agents/context.js"); const { lookupContextTokens } = await contextLookupRuntimeLoader.load();
const { lookupContextTokens } = await contextLookupRuntimePromise;
return lookupContextTokens(model, { allowAsyncLoad: false }); return lookupContextTokens(model, { allowAsyncLoad: false });
} }

View File

@@ -5,6 +5,7 @@ import type { OptionalBootstrapFileName } from "../config/types.agent-defaults.j
import type { OpenClawConfig } from "../config/types.js"; import type { OpenClawConfig } from "../config/types.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js"; import { defaultRuntime } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { shortenHomePath } from "../utils.js"; import { shortenHomePath } from "../utils.js";
import { safeParseWithSchema } from "../utils/zod-parse.js"; import { safeParseWithSchema } from "../utils/zod-parse.js";
@@ -41,23 +42,26 @@ type AgentWorkspaceModule = typeof import("../agents/workspace.js");
type ConfigIOModule = typeof import("../config/config.js"); type ConfigIOModule = typeof import("../config/config.js");
type ConfigLoggingModule = typeof import("../config/logging.js"); type ConfigLoggingModule = typeof import("../config/logging.js");
let agentWorkspaceModulePromise: Promise<AgentWorkspaceModule> | undefined; const agentWorkspaceModuleLoader = createLazyImportLoader<AgentWorkspaceModule>(
let configIOModulePromise: Promise<ConfigIOModule> | undefined; () => import("../agents/workspace.js"),
let configLoggingModulePromise: Promise<ConfigLoggingModule> | undefined; );
const configIOModuleLoader = createLazyImportLoader<ConfigIOModule>(
() => import("../config/config.js"),
);
const configLoggingModuleLoader = createLazyImportLoader<ConfigLoggingModule>(
() => import("../config/logging.js"),
);
function loadAgentWorkspaceModule(): Promise<AgentWorkspaceModule> { function loadAgentWorkspaceModule(): Promise<AgentWorkspaceModule> {
agentWorkspaceModulePromise ??= import("../agents/workspace.js"); return agentWorkspaceModuleLoader.load();
return agentWorkspaceModulePromise;
} }
function loadConfigIOModule(): Promise<ConfigIOModule> { function loadConfigIOModule(): Promise<ConfigIOModule> {
configIOModulePromise ??= import("../config/config.js"); return configIOModuleLoader.load();
return configIOModulePromise;
} }
function loadConfigLoggingModule(): Promise<ConfigLoggingModule> { function loadConfigLoggingModule(): Promise<ConfigLoggingModule> {
configLoggingModulePromise ??= import("../config/logging.js"); return configLoggingModuleLoader.load();
return configLoggingModulePromise;
} }
async function createDefaultConfigIO(): Promise<ConfigIO> { async function createDefaultConfigIO(): Promise<ConfigIO> {

View File

@@ -1,26 +1,26 @@
import { resolveReadOnlyChannelPluginsForConfig } from "../channels/plugins/read-only.js"; import { resolveReadOnlyChannelPluginsForConfig } from "../channels/plugins/read-only.js";
import type { OpenClawConfig } from "../config/types.js"; import type { OpenClawConfig } from "../config/types.js";
import type { HeartbeatEventPayload } from "../infra/heartbeat-events.js"; import type { HeartbeatEventPayload } from "../infra/heartbeat-events.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import type { HealthSummary } from "./health.js"; import type { HealthSummary } from "./health.js";
import { getDaemonStatusSummary, getNodeDaemonStatusSummary } from "./status.daemon.js"; import { getDaemonStatusSummary, getNodeDaemonStatusSummary } from "./status.daemon.js";
let providerUsagePromise: Promise<typeof import("../infra/provider-usage.js")> | undefined; const providerUsageLoader = createLazyImportLoader(() => import("../infra/provider-usage.js"));
let securityAuditModulePromise: Promise<typeof import("../security/audit.runtime.js")> | undefined; const securityAuditModuleLoader = createLazyImportLoader(
let gatewayCallModulePromise: Promise<typeof import("../gateway/call.js")> | undefined; () => import("../security/audit.runtime.js"),
);
const gatewayCallModuleLoader = createLazyImportLoader(() => import("../gateway/call.js"));
function loadProviderUsage() { function loadProviderUsage() {
providerUsagePromise ??= import("../infra/provider-usage.js"); return providerUsageLoader.load();
return providerUsagePromise;
} }
function loadSecurityAuditModule() { function loadSecurityAuditModule() {
securityAuditModulePromise ??= import("../security/audit.runtime.js"); return securityAuditModuleLoader.load();
return securityAuditModulePromise;
} }
function loadGatewayCallModule() { function loadGatewayCallModule() {
gatewayCallModulePromise ??= import("../gateway/call.js"); return gatewayCallModuleLoader.load();
return gatewayCallModulePromise;
} }
export async function resolveStatusSecurityAudit(params: { export async function resolveStatusSecurityAudit(params: {

View File

@@ -6,6 +6,7 @@ import {
type ConnectPairingRequiredReason, type ConnectPairingRequiredReason,
} from "../gateway/protocol/connect-error-details.js"; } from "../gateway/protocol/connect-error-details.js";
import { type RuntimeEnv } from "../runtime.js"; import { type RuntimeEnv } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { sanitizeTerminalText } from "../terminal/safe-text.js"; import { sanitizeTerminalText } from "../terminal/safe-text.js";
import { runStatusJsonCommand } from "./status-json-command.ts"; import { runStatusJsonCommand } from "./status-json-command.ts";
import { buildStatusOverviewSurfaceFromScan } from "./status-overview-surface.ts"; import { buildStatusOverviewSurfaceFromScan } from "./status-overview-surface.ts";
@@ -20,47 +21,41 @@ import { buildStatusCommandReportData } from "./status.command-report-data.ts";
import { buildStatusCommandReportLines } from "./status.command-report.ts"; import { buildStatusCommandReportLines } from "./status.command-report.ts";
import { logGatewayConnectionDetails } from "./status.gateway-connection.ts"; import { logGatewayConnectionDetails } from "./status.gateway-connection.ts";
let statusScanModulePromise: Promise<typeof import("./status.scan.js")> | undefined; const statusScanModuleLoader = createLazyImportLoader(() => import("./status.scan.js"));
let statusScanFastJsonModulePromise: const statusScanFastJsonModuleLoader = createLazyImportLoader(
| Promise<typeof import("./status.scan.fast-json.js")> () => import("./status.scan.fast-json.js"),
| undefined; );
let statusAllModulePromise: Promise<typeof import("./status-all.js")> | undefined; const statusAllModuleLoader = createLazyImportLoader(() => import("./status-all.js"));
let statusCommandTextRuntimePromise: const statusCommandTextRuntimeLoader = createLazyImportLoader(
| Promise<typeof import("./status.command.text-runtime.js")> () => import("./status.command.text-runtime.js"),
| undefined; );
let statusGatewayConnectionRuntimePromise: const statusGatewayConnectionRuntimeLoader = createLazyImportLoader(
| Promise<typeof import("./status.gateway-connection.runtime.js")> () => import("./status.gateway-connection.runtime.js"),
| undefined; );
let statusNodeModeModulePromise: Promise<typeof import("./status.node-mode.js")> | undefined; const statusNodeModeModuleLoader = createLazyImportLoader(() => import("./status.node-mode.js"));
function loadStatusScanModule() { function loadStatusScanModule() {
statusScanModulePromise ??= import("./status.scan.js"); return statusScanModuleLoader.load();
return statusScanModulePromise;
} }
function loadStatusScanFastJsonModule() { function loadStatusScanFastJsonModule() {
statusScanFastJsonModulePromise ??= import("./status.scan.fast-json.js"); return statusScanFastJsonModuleLoader.load();
return statusScanFastJsonModulePromise;
} }
function loadStatusAllModule() { function loadStatusAllModule() {
statusAllModulePromise ??= import("./status-all.js"); return statusAllModuleLoader.load();
return statusAllModulePromise;
} }
function loadStatusCommandTextRuntime() { function loadStatusCommandTextRuntime() {
statusCommandTextRuntimePromise ??= import("./status.command.text-runtime.js"); return statusCommandTextRuntimeLoader.load();
return statusCommandTextRuntimePromise;
} }
function loadStatusGatewayConnectionRuntime() { function loadStatusGatewayConnectionRuntime() {
statusGatewayConnectionRuntimePromise ??= import("./status.gateway-connection.runtime.js"); return statusGatewayConnectionRuntimeLoader.load();
return statusGatewayConnectionRuntimePromise;
} }
function loadStatusNodeModeModule() { function loadStatusNodeModeModule() {
statusNodeModeModulePromise ??= import("./status.node-mode.js"); return statusNodeModeModuleLoader.load();
return statusNodeModeModulePromise;
} }
export function resolvePairingRecoveryContext(params: { export function resolvePairingRecoveryContext(params: {

View File

@@ -3,6 +3,7 @@ import path from "node:path";
import { resolveMemorySearchConfig } from "../agents/memory-search.js"; import { resolveMemorySearchConfig } from "../agents/memory-search.js";
import { resolveStateDir } from "../config/paths.js"; import { resolveStateDir } from "../config/paths.js";
import type { OpenClawConfig } from "../config/types.js"; import type { OpenClawConfig } from "../config/types.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import type { getAgentLocalStatuses as getAgentLocalStatusesFn } from "./status.agent-local.js"; import type { getAgentLocalStatuses as getAgentLocalStatusesFn } from "./status.agent-local.js";
import { import {
resolveSharedMemoryStatusSnapshot, resolveSharedMemoryStatusSnapshot,
@@ -10,13 +11,12 @@ import {
type MemoryStatusSnapshot, type MemoryStatusSnapshot,
} from "./status.scan.shared.js"; } from "./status.scan.shared.js";
let statusScanDepsRuntimeModulePromise: const statusScanDepsRuntimeModuleLoader = createLazyImportLoader(
| Promise<typeof import("./status.scan.deps.runtime.js")> () => import("./status.scan.deps.runtime.js"),
| undefined; );
function loadStatusScanDepsRuntimeModule() { function loadStatusScanDepsRuntimeModule() {
statusScanDepsRuntimeModulePromise ??= import("./status.scan.deps.runtime.js"); return statusScanDepsRuntimeModuleLoader.load();
return statusScanDepsRuntimeModulePromise;
} }
export function resolveDefaultMemoryStorePath(agentId: string): string { export function resolveDefaultMemoryStorePath(agentId: string): string {

View File

@@ -4,6 +4,7 @@ import { resolveOsSummary } from "../infra/os-summary.js";
import type { UpdateCheckResult } from "../infra/update-check.js"; import type { UpdateCheckResult } from "../infra/update-check.js";
import { hasConfiguredChannelsForReadOnlyScope } from "../plugins/channel-plugin-ids.js"; import { hasConfiguredChannelsForReadOnlyScope } from "../plugins/channel-plugin-ids.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import type { buildChannelsTable as buildChannelsTableFn } from "./status-all/channels.js"; import type { buildChannelsTable as buildChannelsTableFn } from "./status-all/channels.js";
import type { getAgentLocalStatuses as getAgentLocalStatusesFn } from "./status.agent-local.js"; import type { getAgentLocalStatuses as getAgentLocalStatusesFn } from "./status.agent-local.js";
import { import {
@@ -13,65 +14,60 @@ import {
import { loadStatusScanCommandConfig } from "./status.scan.config-shared.js"; import { loadStatusScanCommandConfig } from "./status.scan.config-shared.js";
import type { GatewayProbeSnapshot } from "./status.scan.shared.js"; import type { GatewayProbeSnapshot } from "./status.scan.shared.js";
let statusScanDepsRuntimeModulePromise: const statusScanDepsRuntimeModuleLoader = createLazyImportLoader(
| Promise<typeof import("./status.scan.deps.runtime.js")> () => import("./status.scan.deps.runtime.js"),
| undefined; );
let statusAgentLocalModulePromise: Promise<typeof import("./status.agent-local.js")> | undefined; const statusAgentLocalModuleLoader = createLazyImportLoader(
let statusUpdateModulePromise: Promise<typeof import("./status.update.js")> | undefined; () => import("./status.agent-local.js"),
let statusScanRuntimeModulePromise: Promise<typeof import("./status.scan.runtime.js")> | undefined; );
let gatewayCallModulePromise: Promise<typeof import("../gateway/call.js")> | undefined; const statusUpdateModuleLoader = createLazyImportLoader(() => import("./status.update.js"));
let statusSummaryModulePromise: Promise<typeof import("./status.summary.js")> | undefined; const statusScanRuntimeModuleLoader = createLazyImportLoader(
let configModulePromise: Promise<typeof import("../config/config.js")> | undefined; () => import("./status.scan.runtime.js"),
let commandConfigResolutionModulePromise: );
| Promise<typeof import("../cli/command-config-resolution.js")> const gatewayCallModuleLoader = createLazyImportLoader(() => import("../gateway/call.js"));
| undefined; const statusSummaryModuleLoader = createLazyImportLoader(() => import("./status.summary.js"));
let commandSecretTargetsModulePromise: const configModuleLoader = createLazyImportLoader(() => import("../config/config.js"));
| Promise<typeof import("../cli/command-secret-targets.js")> const commandConfigResolutionModuleLoader = createLazyImportLoader(
| undefined; () => import("../cli/command-config-resolution.js"),
);
const commandSecretTargetsModuleLoader = createLazyImportLoader(
() => import("../cli/command-secret-targets.js"),
);
function loadStatusScanDepsRuntimeModule() { function loadStatusScanDepsRuntimeModule() {
statusScanDepsRuntimeModulePromise ??= import("./status.scan.deps.runtime.js"); return statusScanDepsRuntimeModuleLoader.load();
return statusScanDepsRuntimeModulePromise;
} }
function loadStatusAgentLocalModule() { function loadStatusAgentLocalModule() {
statusAgentLocalModulePromise ??= import("./status.agent-local.js"); return statusAgentLocalModuleLoader.load();
return statusAgentLocalModulePromise;
} }
function loadStatusUpdateModule() { function loadStatusUpdateModule() {
statusUpdateModulePromise ??= import("./status.update.js"); return statusUpdateModuleLoader.load();
return statusUpdateModulePromise;
} }
function loadStatusScanRuntimeModule() { function loadStatusScanRuntimeModule() {
statusScanRuntimeModulePromise ??= import("./status.scan.runtime.js"); return statusScanRuntimeModuleLoader.load();
return statusScanRuntimeModulePromise;
} }
function loadGatewayCallModule() { function loadGatewayCallModule() {
gatewayCallModulePromise ??= import("../gateway/call.js"); return gatewayCallModuleLoader.load();
return gatewayCallModulePromise;
} }
function loadStatusSummaryModule() { function loadStatusSummaryModule() {
statusSummaryModulePromise ??= import("./status.summary.js"); return statusSummaryModuleLoader.load();
return statusSummaryModulePromise;
} }
function loadConfigModule() { function loadConfigModule() {
configModulePromise ??= import("../config/config.js"); return configModuleLoader.load();
return configModulePromise;
} }
function loadCommandConfigResolutionModule() { function loadCommandConfigResolutionModule() {
commandConfigResolutionModulePromise ??= import("../cli/command-config-resolution.js"); return commandConfigResolutionModuleLoader.load();
return commandConfigResolutionModulePromise;
} }
function loadCommandSecretTargetsModule() { function loadCommandSecretTargetsModule() {
commandSecretTargetsModulePromise ??= import("../cli/command-secret-targets.js"); return commandSecretTargetsModuleLoader.load();
return commandSecretTargetsModulePromise;
} }
async function resolveStatusChannelsStatus(params: { async function resolveStatusChannelsStatus(params: {

View File

@@ -7,6 +7,7 @@ import type { GatewayProbeResult, probeGateway as probeGatewayFn } from "../gate
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import type { MemoryProviderStatus } from "../memory-host-sdk/engine-storage.js"; import type { MemoryProviderStatus } from "../memory-host-sdk/engine-storage.js";
import { defaultSlotIdForKey } from "../plugins/slots.js"; import { defaultSlotIdForKey } from "../plugins/slots.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { isLoopbackIpAddress } from "../shared/net/ip.js"; import { isLoopbackIpAddress } from "../shared/net/ip.js";
import { import {
normalizeOptionalLowercaseString, normalizeOptionalLowercaseString,
@@ -16,23 +17,20 @@ import { pickGatewaySelfPresence } from "./gateway-presence.js";
import { isProbeReachable } from "./gateway-status/helpers.js"; import { isProbeReachable } from "./gateway-status/helpers.js";
export { pickGatewaySelfPresence } from "./gateway-presence.js"; export { pickGatewaySelfPresence } from "./gateway-presence.js";
let gatewayProbeModulePromise: Promise<typeof import("./status.gateway-probe.js")> | undefined; const gatewayProbeModuleLoader = createLazyImportLoader(() => import("./status.gateway-probe.js"));
let probeGatewayModulePromise: Promise<typeof import("../gateway/probe.js")> | undefined; const probeGatewayModuleLoader = createLazyImportLoader(() => import("../gateway/probe.js"));
let gatewayCallModulePromise: Promise<typeof import("../gateway/call.js")> | undefined; const gatewayCallModuleLoader = createLazyImportLoader(() => import("../gateway/call.js"));
function loadGatewayProbeModule() { function loadGatewayProbeModule() {
gatewayProbeModulePromise ??= import("./status.gateway-probe.js"); return gatewayProbeModuleLoader.load();
return gatewayProbeModulePromise;
} }
function loadProbeGatewayModule() { function loadProbeGatewayModule() {
probeGatewayModulePromise ??= import("../gateway/probe.js"); return probeGatewayModuleLoader.load();
return probeGatewayModulePromise;
} }
function loadGatewayCallModule() { function loadGatewayCallModule() {
gatewayCallModulePromise ??= import("../gateway/call.js"); return gatewayCallModuleLoader.load();
return gatewayCallModulePromise;
} }
export type MemoryStatusSnapshot = MemoryProviderStatus & { export type MemoryStatusSnapshot = MemoryProviderStatus & {

View File

@@ -11,24 +11,25 @@ import { resolveHeartbeatSummaryForAgent } from "../infra/heartbeat-summary.js";
import { peekSystemEvents } from "../infra/system-events.js"; import { peekSystemEvents } from "../infra/system-events.js";
import { hasConfiguredChannelsForReadOnlyScope } from "../plugins/channel-plugin-ids.js"; import { hasConfiguredChannelsForReadOnlyScope } from "../plugins/channel-plugin-ids.js";
import { parseAgentSessionKey } from "../routing/session-key.js"; import { parseAgentSessionKey } from "../routing/session-key.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { createLazyRuntimeSurface } from "../shared/lazy-runtime.js"; import { createLazyRuntimeSurface } from "../shared/lazy-runtime.js";
import { resolveRuntimeServiceVersion } from "../version.js"; import { resolveRuntimeServiceVersion } from "../version.js";
import type { HeartbeatStatus, SessionStatus, StatusSummary } from "./status.types.js"; import type { HeartbeatStatus, SessionStatus, StatusSummary } from "./status.types.js";
let channelSummaryModulePromise: Promise<typeof import("../infra/channel-summary.js")> | undefined; const channelSummaryModuleLoader = createLazyImportLoader(
let linkChannelModulePromise: Promise<typeof import("./status.link-channel.js")> | undefined; () => import("../infra/channel-summary.js"),
let taskRegistryMaintenanceModulePromise: );
| Promise<typeof import("../tasks/task-registry.maintenance.js")> const linkChannelModuleLoader = createLazyImportLoader(() => import("./status.link-channel.js"));
| undefined; const taskRegistryMaintenanceModuleLoader = createLazyImportLoader(
() => import("../tasks/task-registry.maintenance.js"),
);
function loadChannelSummaryModule() { function loadChannelSummaryModule() {
channelSummaryModulePromise ??= import("../infra/channel-summary.js"); return channelSummaryModuleLoader.load();
return channelSummaryModulePromise;
} }
function loadLinkChannelModule() { function loadLinkChannelModule() {
linkChannelModulePromise ??= import("./status.link-channel.js"); return linkChannelModuleLoader.load();
return linkChannelModulePromise;
} }
const loadStatusSummaryRuntimeModule = createLazyRuntimeSurface( const loadStatusSummaryRuntimeModule = createLazyRuntimeSurface(
@@ -37,8 +38,7 @@ const loadStatusSummaryRuntimeModule = createLazyRuntimeSurface(
); );
function loadTaskRegistryMaintenanceModule() { function loadTaskRegistryMaintenanceModule() {
taskRegistryMaintenanceModulePromise ??= import("../tasks/task-registry.maintenance.js"); return taskRegistryMaintenanceModuleLoader.load();
return taskRegistryMaintenanceModulePromise;
} }
const buildFlags = (entry?: SessionEntry): string[] => { const buildFlags = (entry?: SessionEntry): string[] => {

View File

@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js"; import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
import { runExec } from "../process/exec.js"; import { runExec } from "../process/exec.js";
import { createLazyPromiseLoader } from "../shared/lazy-promise.js";
export type ImageMetadata = { export type ImageMetadata = {
width: number; width: number;
@@ -54,8 +55,6 @@ function prefersSips(): boolean {
); );
} }
let mediaAttachmentImageOpsPromise: Promise<MediaAttachmentImageOps> | null = null;
function isMediaAttachmentImageOps(value: unknown): value is MediaAttachmentImageOps { function isMediaAttachmentImageOps(value: unknown): value is MediaAttachmentImageOps {
if (!value || typeof value !== "object") { if (!value || typeof value !== "object") {
return false; return false;
@@ -71,30 +70,24 @@ function isMediaAttachmentImageOps(value: unknown): value is MediaAttachmentImag
); );
} }
async function loadMediaAttachmentImageOps(): Promise<MediaAttachmentImageOps> { const mediaAttachmentImageOpsLoader = createLazyPromiseLoader(async () => {
if (!mediaAttachmentImageOpsPromise) { const { loadBundledPluginPublicArtifactModuleSync } =
mediaAttachmentImageOpsPromise = Promise.resolve() await import("../plugins/public-surface-loader.js");
.then(async () => { const mod = loadBundledPluginPublicArtifactModuleSync<MediaAttachmentImageOpsModule>({
const { loadBundledPluginPublicArtifactModuleSync } = dirName: MEDIA_UNDERSTANDING_CORE_PLUGIN_ID,
await import("../plugins/public-surface-loader.js"); artifactBasename: MEDIA_UNDERSTANDING_CORE_IMAGE_OPS_ARTIFACT,
const mod = loadBundledPluginPublicArtifactModuleSync<MediaAttachmentImageOpsModule>({ });
dirName: MEDIA_UNDERSTANDING_CORE_PLUGIN_ID, const ops = mod.createMediaAttachmentImageOps?.({
artifactBasename: MEDIA_UNDERSTANDING_CORE_IMAGE_OPS_ARTIFACT, maxInputPixels: MAX_IMAGE_INPUT_PIXELS,
}); });
const ops = mod.createMediaAttachmentImageOps?.({ if (!isMediaAttachmentImageOps(ops)) {
maxInputPixels: MAX_IMAGE_INPUT_PIXELS, throw new Error("Media understanding core did not expose image ops");
});
if (!isMediaAttachmentImageOps(ops)) {
throw new Error("Media understanding core did not expose image ops");
}
return ops;
})
.catch((err) => {
mediaAttachmentImageOpsPromise = null;
throw err;
});
} }
return await mediaAttachmentImageOpsPromise; return ops;
});
async function loadMediaAttachmentImageOps(): Promise<MediaAttachmentImageOps> {
return await mediaAttachmentImageOpsLoader.load();
} }
function isPositiveImageDimension(value: number): boolean { function isPositiveImageDimension(value: number): boolean {

View File

@@ -1,4 +1,5 @@
import path from "node:path"; import path from "node:path";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { type MediaKind, mediaKindFromMime } from "./constants.js"; import { type MediaKind, mediaKindFromMime } from "./constants.js";
/** @internal */ /** @internal */
@@ -66,7 +67,7 @@ const AUDIO_FILE_EXTENSIONS = new Set([
".wav", ".wav",
]); ]);
let fileTypeModulePromise: Promise<typeof import("file-type")> | undefined; const fileTypeModuleLoader = createLazyImportLoader(() => import("file-type"));
export function normalizeMimeType(mime?: string | null): string | undefined { export function normalizeMimeType(mime?: string | null): string | undefined {
if (!mime) { if (!mime) {
@@ -89,8 +90,7 @@ async function sniffMime(buffer?: Buffer): Promise<string | undefined> {
return undefined; return undefined;
} }
try { try {
fileTypeModulePromise ??= import("file-type"); const { fileTypeFromBuffer } = await fileTypeModuleLoader.load();
const { fileTypeFromBuffer } = await fileTypeModulePromise;
const type = await fileTypeFromBuffer(sliceMimeSniffBuffer(buffer)); const type = await fileTypeFromBuffer(sliceMimeSniffBuffer(buffer));
if (type?.mime) { if (type?.mime) {
return type.mime; return type.mime;

View File

@@ -1,14 +1,14 @@
import type QRCode from "qrcode"; import type QRCode from "qrcode";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
type QrCodeRuntime = typeof QRCode; type QrCodeRuntime = typeof QRCode;
let qrCodeRuntimePromise: Promise<QrCodeRuntime> | null = null; const qrCodeRuntimeLoader = createLazyImportLoader<QrCodeRuntime>(() =>
import("qrcode").then((mod) => mod.default ?? mod),
);
export async function loadQrCodeRuntime(): Promise<QrCodeRuntime> { export async function loadQrCodeRuntime(): Promise<QrCodeRuntime> {
if (!qrCodeRuntimePromise) { return await qrCodeRuntimeLoader.load();
qrCodeRuntimePromise = import("qrcode").then((mod) => mod.default ?? mod);
}
return await qrCodeRuntimePromise;
} }
export function normalizeQrText(text: string): string { export function normalizeQrText(text: string): string {

View File

@@ -17,6 +17,7 @@ import {
createSafeNpmInstallEnv, createSafeNpmInstallEnv,
} from "../infra/safe-package-install.js"; } from "../infra/safe-package-install.js";
import { runCommandWithTimeout } from "../process/exec.js"; import { runCommandWithTimeout } from "../process/exec.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { normalizeOptionalString } from "../shared/string-coerce.js"; import { normalizeOptionalString } from "../shared/string-coerce.js";
import { resolveUserPath } from "../utils.js"; import { resolveUserPath } from "../utils.js";
import { import {
@@ -38,11 +39,10 @@ import { linkOpenClawPeerDependencies } from "./plugin-peer-link.js";
export { resolvePluginInstallDir } from "./install-paths.js"; export { resolvePluginInstallDir } from "./install-paths.js";
let pluginInstallRuntimePromise: Promise<typeof import("./install.runtime.js")> | undefined; const pluginInstallRuntimeLoader = createLazyImportLoader(() => import("./install.runtime.js"));
async function loadPluginInstallRuntime() { async function loadPluginInstallRuntime() {
pluginInstallRuntimePromise ??= import("./install.runtime.js"); return await pluginInstallRuntimeLoader.load();
return pluginInstallRuntimePromise;
} }
type PluginInstallLogger = { type PluginInstallLogger = {

View File

@@ -1,26 +0,0 @@
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { listPluginContributionIds, loadPluginRegistrySnapshot } from "./plugin-registry.js";
export function listManifestChannelContributionIds(
params: {
config?: OpenClawConfig;
workspaceDir?: string;
env?: NodeJS.ProcessEnv;
includeDisabled?: boolean;
} = {},
): readonly string[] {
const env = params.env ?? process.env;
const index = loadPluginRegistrySnapshot({
config: params.config,
workspaceDir: params.workspaceDir,
env,
});
return listPluginContributionIds({
index,
contribution: "channels",
config: params.config,
workspaceDir: params.workspaceDir,
env,
includeDisabled: params.includeDisabled,
});
}

View File

@@ -0,0 +1,54 @@
import {
listPluginContributionIds,
loadPluginRegistrySnapshot,
type LoadPluginRegistryParams,
type PluginRegistryContributionKey,
type PluginRegistrySnapshot,
} from "./plugin-registry.js";
export type ListManifestContributionIdsParams = LoadPluginRegistryParams & {
contribution: PluginRegistryContributionKey;
index?: PluginRegistrySnapshot;
includeDisabled?: boolean;
};
export function listManifestContributionIds(
params: ListManifestContributionIdsParams,
): readonly string[] {
const env = params.env ?? process.env;
const index =
params.index ??
loadPluginRegistrySnapshot({
config: params.config,
workspaceDir: params.workspaceDir,
env,
candidates: params.candidates,
preferPersisted: params.preferPersisted,
});
return listPluginContributionIds({
index,
contribution: params.contribution,
config: params.config,
workspaceDir: params.workspaceDir,
env,
includeDisabled: params.includeDisabled,
});
}
export function listManifestChannelContributionIds(
params: Omit<ListManifestContributionIdsParams, "contribution"> = {},
): readonly string[] {
return listManifestContributionIds({
...params,
contribution: "channels",
});
}
export function listManifestProviderContributionIds(
params: Omit<ListManifestContributionIdsParams, "contribution"> = {},
): readonly string[] {
return listManifestContributionIds({
...params,
contribution: "providers",
});
}

View File

@@ -9,17 +9,17 @@ import {
isValidFileSecretRefId, isValidFileSecretRefId,
resolveDefaultSecretProviderAlias, resolveDefaultSecretProviderAlias,
} from "../secrets/ref-contract.js"; } from "../secrets/ref-contract.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { import {
normalizeOptionalString, normalizeOptionalString,
normalizeStringifiedOptionalString, normalizeStringifiedOptionalString,
} from "../shared/string-coerce.js"; } from "../shared/string-coerce.js";
import type { WizardPrompter } from "../wizard/prompts.js"; import type { WizardPrompter } from "../wizard/prompts.js";
let secretResolvePromise: Promise<typeof import("../secrets/resolve.js")> | undefined; const secretResolveLoader = createLazyImportLoader(() => import("../secrets/resolve.js"));
function loadSecretResolve() { function loadSecretResolve() {
secretResolvePromise ??= import("../secrets/resolve.js"); return secretResolveLoader.load();
return secretResolvePromise;
} }
const ENV_SOURCE_LABEL_RE = /(?:^|:\s)([A-Z][A-Z0-9_]*)$/; const ENV_SOURCE_LABEL_RE = /(?:^|:\s)([A-Z][A-Z0-9_]*)$/;

View File

@@ -1,22 +1,20 @@
import { normalizeProviderId } from "../agents/model-selection.js"; import { normalizeProviderId } from "../agents/model-selection.js";
import type { ModelProviderConfig } from "../config/types.js"; import type { ModelProviderConfig } from "../config/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { listManifestProviderContributionIds } from "./manifest-contribution-ids.js";
import type { PluginMetadataRegistryView } from "./plugin-metadata-snapshot.types.js"; import type { PluginMetadataRegistryView } from "./plugin-metadata-snapshot.types.js";
import { import { type LoadPluginRegistryParams, type PluginRegistrySnapshot } from "./plugin-registry.js";
listPluginContributionIds,
loadPluginRegistrySnapshot,
type LoadPluginRegistryParams,
type PluginRegistrySnapshot,
} from "./plugin-registry.js";
import type { ProviderDiscoveryOrder, ProviderPlugin } from "./types.js"; import type { ProviderDiscoveryOrder, ProviderPlugin } from "./types.js";
const DISCOVERY_ORDER: readonly ProviderDiscoveryOrder[] = ["simple", "profile", "paired", "late"]; const DISCOVERY_ORDER: readonly ProviderDiscoveryOrder[] = ["simple", "profile", "paired", "late"];
const DANGEROUS_PROVIDER_KEYS = new Set(["__proto__", "prototype", "constructor"]); const DANGEROUS_PROVIDER_KEYS = new Set(["__proto__", "prototype", "constructor"]);
let providerRuntimePromise: Promise<typeof import("./provider-discovery.runtime.js")> | undefined; const providerRuntimeLoader = createLazyImportLoader(
() => import("./provider-discovery.runtime.js"),
);
function loadProviderRuntime() { function loadProviderRuntime() {
providerRuntimePromise ??= import("./provider-discovery.runtime.js"); return providerRuntimeLoader.load();
return providerRuntimePromise;
} }
function resolveProviderCatalogHook(provider: ProviderPlugin) { function resolveProviderCatalogHook(provider: ProviderPlugin) {
@@ -62,13 +60,11 @@ export function resolveInstalledPluginProviderContributionIds(
params.candidates && params.preferPersisted === undefined params.candidates && params.preferPersisted === undefined
? { ...params, preferPersisted: false } ? { ...params, preferPersisted: false }
: params; : params;
const index = params.index ?? loadPluginRegistrySnapshot(registryParams);
return sortedValues( return sortedValues(
listPluginContributionIds({ listManifestProviderContributionIds({
index, ...registryParams,
contribution: "providers", index: params.index,
includeDisabled: params.includeDisabled, includeDisabled: params.includeDisabled,
config: params.config,
}), }),
); );
} }

View File

@@ -1,3 +1,5 @@
import { createLazyImportLoader } from "../shared/lazy-promise.js";
type ProviderRuntimeModule = typeof import("./provider-runtime.js"); type ProviderRuntimeModule = typeof import("./provider-runtime.js");
type AugmentModelCatalogWithProviderPlugins = type AugmentModelCatalogWithProviderPlugins =
@@ -12,13 +14,14 @@ type PrepareProviderRuntimeAuth = ProviderRuntimeModule["prepareProviderRuntimeA
type RefreshProviderOAuthCredentialWithPlugin = type RefreshProviderOAuthCredentialWithPlugin =
ProviderRuntimeModule["refreshProviderOAuthCredentialWithPlugin"]; ProviderRuntimeModule["refreshProviderOAuthCredentialWithPlugin"];
let providerRuntimePromise: Promise<ProviderRuntimeModule> | undefined; const providerRuntimeLoader = createLazyImportLoader<ProviderRuntimeModule>(
() => import("./provider-runtime.js"),
);
async function loadProviderRuntime(): Promise<ProviderRuntimeModule> { async function loadProviderRuntime(): Promise<ProviderRuntimeModule> {
// Keep the heavy provider runtime behind an actual async boundary so callers // Keep the heavy provider runtime behind an actual async boundary so callers
// can import this wrapper eagerly without collapsing the lazy chunk. // can import this wrapper eagerly without collapsing the lazy chunk.
providerRuntimePromise ??= import("./provider-runtime.js"); return await providerRuntimeLoader.load();
return providerRuntimePromise;
} }
export async function augmentModelCatalogWithProviderPlugins( export async function augmentModelCatalogWithProviderPlugins(

View File

@@ -0,0 +1,59 @@
import { describe, expect, it, vi } from "vitest";
import { createLazyImportLoader, createLazyPromiseLoader } from "./lazy-promise.js";
describe("createLazyPromiseLoader", () => {
it("dedupes concurrent loads and reuses the resolved value", async () => {
let calls = 0;
const loader = createLazyPromiseLoader(async () => `loaded-${++calls}`);
await expect(Promise.all([loader.load(), loader.load()])).resolves.toEqual([
"loaded-1",
"loaded-1",
]);
await expect(loader.load()).resolves.toBe("loaded-1");
expect(calls).toBe(1);
});
it("evicts rejected loads by default so retries can recover", async () => {
let calls = 0;
const loader = createLazyPromiseLoader(async () => {
calls += 1;
if (calls === 1) {
throw new Error("transient");
}
return "recovered";
});
await expect(loader.load()).rejects.toThrow("transient");
await expect(loader.load()).resolves.toBe("recovered");
expect(calls).toBe(2);
});
it("can keep rejected loads when requested", async () => {
const load = vi.fn(async () => {
throw new Error("sticky");
});
const loader = createLazyPromiseLoader(load, { cacheRejections: true });
await expect(loader.load()).rejects.toThrow("sticky");
await expect(loader.load()).rejects.toThrow("sticky");
expect(load).toHaveBeenCalledOnce();
});
it("clears cached values", async () => {
let calls = 0;
const loader = createLazyPromiseLoader(() => `loaded-${++calls}`);
await expect(loader.load()).resolves.toBe("loaded-1");
loader.clear();
await expect(loader.load()).resolves.toBe("loaded-2");
});
});
describe("createLazyImportLoader", () => {
it("wraps import-shaped loaders", async () => {
const loader = createLazyImportLoader(async () => ({ value: "module" }));
await expect(loader.load()).resolves.toEqual({ value: "module" });
});
});

View File

@@ -0,0 +1,44 @@
export type LazyPromiseLoader<T> = {
load(): Promise<T>;
clear(): void;
};
export type LazyPromiseLoaderOptions = {
cacheRejections?: boolean;
};
export function createLazyPromiseLoader<T>(
load: () => T | Promise<T>,
options: LazyPromiseLoaderOptions = {},
): LazyPromiseLoader<T> {
let promise: Promise<T> | undefined;
const createPromise = (): Promise<T> => {
const loaded = Promise.resolve().then(load);
if (options.cacheRejections !== true) {
void loaded.catch(() => {
if (promise === loaded) {
promise = undefined;
}
});
}
return loaded;
};
return {
async load(): Promise<T> {
promise ??= createPromise();
return await promise;
},
clear(): void {
promise = undefined;
},
};
}
export function createLazyImportLoader<T>(
load: () => Promise<T>,
options?: LazyPromiseLoaderOptions,
): LazyPromiseLoader<T> {
return createLazyPromiseLoader(load, options);
}