Skip to content

Commit 59fb9e5

Browse files
committed
refactor: unify lazy import loaders
1 parent 2dcc13d commit 59fb9e5

66 files changed

Lines changed: 642 additions & 616 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/agents/agent-command.ts

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
2323
import { applyVerboseOverride } from "../sessions/level-overrides.js";
2424
import { applyModelOverrideToSessionEntry } from "../sessions/model-overrides.js";
2525
import { resolveSendPolicy } from "../sessions/send-policy.js";
26+
import { createLazyImportLoader } from "../shared/lazy-promise.js";
2627
import { normalizeOptionalString } from "../shared/string-coerce.js";
2728
import { sanitizeForLog } from "../terminal/ansi.js";
2829
import { createTrajectoryRuntimeRecorder } from "../trajectory/runtime.js";
@@ -87,95 +88,106 @@ type SkillsFilterRuntime = typeof import("./skills/filter.js");
8788
type SkillsRefreshStateRuntime = typeof import("./skills/refresh-state.js");
8889
type SkillsRemoteRuntime = typeof import("../infra/skills-remote.js");
8990

90-
let attemptExecutionRuntimePromise: Promise<AttemptExecutionRuntime> | undefined;
91-
let acpManagerRuntimePromise: Promise<AcpManagerRuntime> | undefined;
92-
let acpPolicyRuntimePromise: Promise<AcpPolicyRuntime> | undefined;
93-
let acpRuntimeErrorsRuntimePromise: Promise<AcpRuntimeErrorsRuntime> | undefined;
94-
let acpSessionIdentifiersRuntimePromise: Promise<AcpSessionIdentifiersRuntime> | undefined;
95-
let deliveryRuntimePromise: Promise<DeliveryRuntime> | undefined;
96-
let sessionStoreRuntimePromise: Promise<SessionStoreRuntime> | undefined;
97-
let cliCompactionRuntimePromise: Promise<CliCompactionRuntime> | undefined;
98-
let transcriptResolveRuntimePromise: Promise<TranscriptResolveRuntime> | undefined;
99-
let cliDepsRuntimePromise: Promise<CliDepsRuntime> | undefined;
100-
let execDefaultsRuntimePromise: Promise<ExecDefaultsRuntime> | undefined;
101-
let skillsRuntimePromise: Promise<SkillsRuntime> | undefined;
102-
let skillsFilterRuntimePromise: Promise<SkillsFilterRuntime> | undefined;
103-
let skillsRefreshStateRuntimePromise: Promise<SkillsRefreshStateRuntime> | undefined;
104-
let skillsRemoteRuntimePromise: Promise<SkillsRemoteRuntime> | undefined;
91+
const attemptExecutionRuntimeLoader = createLazyImportLoader<AttemptExecutionRuntime>(
92+
() => import("./command/attempt-execution.runtime.js"),
93+
);
94+
const acpManagerRuntimeLoader = createLazyImportLoader<AcpManagerRuntime>(
95+
() => import("../acp/control-plane/manager.js"),
96+
);
97+
const acpPolicyRuntimeLoader = createLazyImportLoader<AcpPolicyRuntime>(
98+
() => import("../acp/policy.js"),
99+
);
100+
const acpRuntimeErrorsRuntimeLoader = createLazyImportLoader<AcpRuntimeErrorsRuntime>(
101+
() => import("../acp/runtime/errors.js"),
102+
);
103+
const acpSessionIdentifiersRuntimeLoader = createLazyImportLoader<AcpSessionIdentifiersRuntime>(
104+
() => import("../acp/runtime/session-identifiers.js"),
105+
);
106+
const deliveryRuntimeLoader = createLazyImportLoader<DeliveryRuntime>(
107+
() => import("./command/delivery.runtime.js"),
108+
);
109+
const sessionStoreRuntimeLoader = createLazyImportLoader<SessionStoreRuntime>(
110+
() => import("./command/session-store.runtime.js"),
111+
);
112+
const cliCompactionRuntimeLoader = createLazyImportLoader<CliCompactionRuntime>(
113+
() => import("./command/cli-compaction.js"),
114+
);
115+
const transcriptResolveRuntimeLoader = createLazyImportLoader<TranscriptResolveRuntime>(
116+
() => import("../config/sessions/transcript-resolve.runtime.js"),
117+
);
118+
const cliDepsRuntimeLoader = createLazyImportLoader<CliDepsRuntime>(() => import("../cli/deps.js"));
119+
const execDefaultsRuntimeLoader = createLazyImportLoader<ExecDefaultsRuntime>(
120+
() => import("./exec-defaults.js"),
121+
);
122+
const skillsRuntimeLoader = createLazyImportLoader<SkillsRuntime>(() => import("./skills.js"));
123+
const skillsFilterRuntimeLoader = createLazyImportLoader<SkillsFilterRuntime>(
124+
() => import("./skills/filter.js"),
125+
);
126+
const skillsRefreshStateRuntimeLoader = createLazyImportLoader<SkillsRefreshStateRuntime>(
127+
() => import("./skills/refresh-state.js"),
128+
);
129+
const skillsRemoteRuntimeLoader = createLazyImportLoader<SkillsRemoteRuntime>(
130+
() => import("../infra/skills-remote.js"),
131+
);
105132

106133
function loadAttemptExecutionRuntime(): Promise<AttemptExecutionRuntime> {
107-
attemptExecutionRuntimePromise ??= import("./command/attempt-execution.runtime.js");
108-
return attemptExecutionRuntimePromise;
134+
return attemptExecutionRuntimeLoader.load();
109135
}
110136

111137
function loadAcpManagerRuntime(): Promise<AcpManagerRuntime> {
112-
acpManagerRuntimePromise ??= import("../acp/control-plane/manager.js");
113-
return acpManagerRuntimePromise;
138+
return acpManagerRuntimeLoader.load();
114139
}
115140

116141
function loadAcpPolicyRuntime(): Promise<AcpPolicyRuntime> {
117-
acpPolicyRuntimePromise ??= import("../acp/policy.js");
118-
return acpPolicyRuntimePromise;
142+
return acpPolicyRuntimeLoader.load();
119143
}
120144

121145
function loadAcpRuntimeErrorsRuntime(): Promise<AcpRuntimeErrorsRuntime> {
122-
acpRuntimeErrorsRuntimePromise ??= import("../acp/runtime/errors.js");
123-
return acpRuntimeErrorsRuntimePromise;
146+
return acpRuntimeErrorsRuntimeLoader.load();
124147
}
125148

126149
function loadAcpSessionIdentifiersRuntime(): Promise<AcpSessionIdentifiersRuntime> {
127-
acpSessionIdentifiersRuntimePromise ??= import("../acp/runtime/session-identifiers.js");
128-
return acpSessionIdentifiersRuntimePromise;
150+
return acpSessionIdentifiersRuntimeLoader.load();
129151
}
130152

131153
function loadDeliveryRuntime(): Promise<DeliveryRuntime> {
132-
deliveryRuntimePromise ??= import("./command/delivery.runtime.js");
133-
return deliveryRuntimePromise;
154+
return deliveryRuntimeLoader.load();
134155
}
135156

136157
function loadSessionStoreRuntime(): Promise<SessionStoreRuntime> {
137-
sessionStoreRuntimePromise ??= import("./command/session-store.runtime.js");
138-
return sessionStoreRuntimePromise;
158+
return sessionStoreRuntimeLoader.load();
139159
}
140160

141161
function loadCliCompactionRuntime(): Promise<CliCompactionRuntime> {
142-
cliCompactionRuntimePromise ??= import("./command/cli-compaction.js");
143-
return cliCompactionRuntimePromise;
162+
return cliCompactionRuntimeLoader.load();
144163
}
145164

146165
function loadTranscriptResolveRuntime(): Promise<TranscriptResolveRuntime> {
147-
transcriptResolveRuntimePromise ??= import("../config/sessions/transcript-resolve.runtime.js");
148-
return transcriptResolveRuntimePromise;
166+
return transcriptResolveRuntimeLoader.load();
149167
}
150168

151169
function loadCliDepsRuntime(): Promise<CliDepsRuntime> {
152-
cliDepsRuntimePromise ??= import("../cli/deps.js");
153-
return cliDepsRuntimePromise;
170+
return cliDepsRuntimeLoader.load();
154171
}
155172

156173
function loadExecDefaultsRuntime(): Promise<ExecDefaultsRuntime> {
157-
execDefaultsRuntimePromise ??= import("./exec-defaults.js");
158-
return execDefaultsRuntimePromise;
174+
return execDefaultsRuntimeLoader.load();
159175
}
160176

161177
function loadSkillsRuntime(): Promise<SkillsRuntime> {
162-
skillsRuntimePromise ??= import("./skills.js");
163-
return skillsRuntimePromise;
178+
return skillsRuntimeLoader.load();
164179
}
165180

166181
function loadSkillsFilterRuntime(): Promise<SkillsFilterRuntime> {
167-
skillsFilterRuntimePromise ??= import("./skills/filter.js");
168-
return skillsFilterRuntimePromise;
182+
return skillsFilterRuntimeLoader.load();
169183
}
170184

171185
function loadSkillsRefreshStateRuntime(): Promise<SkillsRefreshStateRuntime> {
172-
skillsRefreshStateRuntimePromise ??= import("./skills/refresh-state.js");
173-
return skillsRefreshStateRuntimePromise;
186+
return skillsRefreshStateRuntimeLoader.load();
174187
}
175188

176189
function loadSkillsRemoteRuntime(): Promise<SkillsRemoteRuntime> {
177-
skillsRemoteRuntimePromise ??= import("../infra/skills-remote.js");
178-
return skillsRemoteRuntimePromise;
190+
return skillsRemoteRuntimeLoader.load();
179191
}
180192

181193
async function resolveAgentCommandDeps(deps: CliDeps | undefined): Promise<CliDeps> {

src/agents/auth-profiles/session-override.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import type { SessionEntry } from "../../config/sessions/types.js";
22
import type { OpenClawConfig } from "../../config/types.openclaw.js";
3+
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
34
import { resolveAuthProfileOrder } from "../auth-profiles/order.js";
45
import { ensureAuthProfileStore, hasAnyAuthProfileStoreSource } from "../auth-profiles/store.js";
56
import { isProfileInCooldown } from "../auth-profiles/usage.js";
67
import { resolveProviderIdForAuth } from "../provider-auth-aliases.js";
78

8-
let sessionStoreRuntimePromise:
9-
| Promise<typeof import("../../config/sessions/store.runtime.js")>
10-
| undefined;
9+
const sessionStoreRuntimeLoader = createLazyImportLoader(
10+
() => import("../../config/sessions/store.runtime.js"),
11+
);
1112

1213
function loadSessionStoreRuntime() {
13-
sessionStoreRuntimePromise ??= import("../../config/sessions/store.runtime.js");
14-
return sessionStoreRuntimePromise;
14+
return sessionStoreRuntimeLoader.load();
1515
}
1616

1717
function isProfileForProvider(params: {

src/agents/bash-tools.exec.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from "../infra/shell-env.js";
1919
import { logInfo } from "../logger.js";
2020
import { parseAgentSessionKey, resolveAgentIdFromSessionKey } from "../routing/session-key.js";
21+
import { createLazyImportLoader } from "../shared/lazy-promise.js";
2122
import {
2223
normalizeLowercaseStringOrEmpty,
2324
normalizeOptionalLowercaseString,
@@ -127,11 +128,12 @@ function getNodeErrorCode(error: unknown): string | undefined {
127128

128129
type FsSafeModule = typeof import("../infra/fs-safe.js");
129130

130-
let fsSafeModulePromise: Promise<FsSafeModule> | undefined;
131+
const fsSafeModuleLoader = createLazyImportLoader<FsSafeModule>(
132+
() => import("../infra/fs-safe.js"),
133+
);
131134

132135
async function loadFsSafeModule(): Promise<FsSafeModule> {
133-
fsSafeModulePromise ??= import("../infra/fs-safe.js");
134-
return await fsSafeModulePromise;
136+
return await fsSafeModuleLoader.load();
135137
}
136138

137139
function shouldSkipScriptPreflightPathError(

src/agents/command/session-store.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
updateSessionStore,
66
} from "../../config/sessions.js";
77
import type { OpenClawConfig } from "../../config/types.openclaw.js";
8+
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
89
import { normalizeOptionalString } from "../../shared/string-coerce.js";
910
import { clearCliSession, setCliSessionBinding, setCliSessionId } from "../cli-session.js";
1011
import { DEFAULT_CONTEXT_TOKENS } from "../defaults.js";
@@ -13,17 +14,15 @@ import { deriveSessionTotalTokens, hasNonzeroUsage } from "../usage.js";
1314

1415
type RunResult = Awaited<ReturnType<(typeof import("../pi-embedded.js"))["runEmbeddedPiAgent"]>>;
1516

16-
let usageFormatModulePromise: Promise<typeof import("../../utils/usage-format.js")> | undefined;
17-
let contextModulePromise: Promise<typeof import("../context.js")> | undefined;
17+
const usageFormatModuleLoader = createLazyImportLoader(() => import("../../utils/usage-format.js"));
18+
const contextModuleLoader = createLazyImportLoader(() => import("../context.js"));
1819

1920
async function getUsageFormatModule() {
20-
usageFormatModulePromise ??= import("../../utils/usage-format.js");
21-
return await usageFormatModulePromise;
21+
return await usageFormatModuleLoader.load();
2222
}
2323

2424
async function getContextModule() {
25-
contextModulePromise ??= import("../context.js");
26-
return await contextModulePromise;
25+
return await contextModuleLoader.load();
2726
}
2827

2928
function resolveNonNegativeNumber(value: number | undefined): number | undefined {

src/agents/context-runtime-state.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { OpenClawConfig } from "../config/types.openclaw.js";
2+
import { createLazyImportLoader, type LazyPromiseLoader } from "../shared/lazy-promise.js";
23
import { MODEL_CONTEXT_TOKEN_CACHE } from "./context-cache.js";
34

45
const CONTEXT_WINDOW_RUNTIME_STATE_KEY = Symbol.for("openclaw.contextWindowRuntimeState");
@@ -8,7 +9,7 @@ type ContextWindowRuntimeState = {
89
configuredConfig: OpenClawConfig | undefined;
910
configLoadFailures: number;
1011
nextConfigLoadAttemptAtMs: number;
11-
modelsConfigRuntimePromise: Promise<typeof import("./models-config.runtime.js")> | undefined;
12+
modelsConfigRuntimeLoader: LazyPromiseLoader<typeof import("./models-config.runtime.js")>;
1213
};
1314

1415
export const CONTEXT_WINDOW_RUNTIME_STATE = (() => {
@@ -21,7 +22,7 @@ export const CONTEXT_WINDOW_RUNTIME_STATE = (() => {
2122
configuredConfig: undefined,
2223
configLoadFailures: 0,
2324
nextConfigLoadAttemptAtMs: 0,
24-
modelsConfigRuntimePromise: undefined,
25+
modelsConfigRuntimeLoader: createLazyImportLoader(() => import("./models-config.runtime.js")),
2526
};
2627
}
2728
return globalState[CONTEXT_WINDOW_RUNTIME_STATE_KEY];
@@ -32,6 +33,6 @@ export function resetContextWindowCacheForTest(): void {
3233
CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig = undefined;
3334
CONTEXT_WINDOW_RUNTIME_STATE.configLoadFailures = 0;
3435
CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs = 0;
35-
CONTEXT_WINDOW_RUNTIME_STATE.modelsConfigRuntimePromise = undefined;
36+
CONTEXT_WINDOW_RUNTIME_STATE.modelsConfigRuntimeLoader.clear();
3637
MODEL_CONTEXT_TOKEN_CACHE.clear();
3738
}

src/agents/context.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ export function applyConfiguredContextWindows(params: {
101101
}
102102

103103
function loadModelsConfigRuntime() {
104-
CONTEXT_WINDOW_RUNTIME_STATE.modelsConfigRuntimePromise ??= import("./models-config.runtime.js");
105-
return CONTEXT_WINDOW_RUNTIME_STATE.modelsConfigRuntimePromise;
104+
return CONTEXT_WINDOW_RUNTIME_STATE.modelsConfigRuntimeLoader.load();
106105
}
107106

108107
function isLikelyOpenClawCliProcess(argv: string[] = process.argv): boolean {

src/agents/harness/tool-result-middleware.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
AgentToolResultMiddlewareEvent,
66
OpenClawAgentToolResult,
77
} from "../../plugins/agent-tool-result-middleware-types.js";
8+
import { createLazyPromiseLoader } from "../../shared/lazy-promise.js";
89
import { truncateUtf16Safe } from "../../utils.js";
910

1011
const log = createSubsystemLogger("agents/harness");
@@ -125,18 +126,18 @@ export function createAgentToolResultMiddlewareRunner(
125126
) {
126127
const middlewareContext = { ...ctx, harness: ctx.harness ?? ctx.runtime };
127128
let resolvedHandlers = handlers;
128-
let resolvedHandlersPromise: Promise<AgentToolResultMiddleware[]> | undefined;
129+
const resolvedHandlersLoader = createLazyPromiseLoader(async () => {
130+
const { loadAgentToolResultMiddlewaresForRuntime } =
131+
await import("../../plugins/agent-tool-result-middleware-loader.js");
132+
return loadAgentToolResultMiddlewaresForRuntime({
133+
runtime: ctx.runtime,
134+
});
135+
});
129136
const resolveHandlers = async (): Promise<AgentToolResultMiddleware[]> => {
130137
if (resolvedHandlers) {
131138
return resolvedHandlers;
132139
}
133-
resolvedHandlersPromise ??= import("../../plugins/agent-tool-result-middleware-loader.js").then(
134-
({ loadAgentToolResultMiddlewaresForRuntime }) =>
135-
loadAgentToolResultMiddlewaresForRuntime({
136-
runtime: ctx.runtime,
137-
}),
138-
);
139-
resolvedHandlers = await resolvedHandlersPromise;
140+
resolvedHandlers = await resolvedHandlersLoader.load();
140141
return resolvedHandlers;
141142
};
142143
return {

src/agents/model-catalog.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { getCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-meta
77
import { isManifestPluginAvailableForControlPlane } from "../plugins/manifest-contract-eligibility.js";
88
import { loadPluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
99
import { augmentModelCatalogWithProviderPlugins } from "../plugins/provider-runtime.runtime.js";
10+
import { createLazyImportLoader } from "../shared/lazy-promise.js";
1011
import {
1112
normalizeLowercaseStringOrEmpty,
1213
normalizeOptionalString,
@@ -52,15 +53,16 @@ let modelCatalogPromise: Promise<ModelCatalogEntry[]> | null = null;
5253
let hasLoggedModelCatalogError = false;
5354
const defaultImportPiSdk = () => import("./pi-model-discovery-runtime.js");
5455
let importPiSdk = defaultImportPiSdk;
55-
let modelSuppressionPromise: Promise<typeof import("./model-suppression.runtime.js")> | undefined;
56+
const modelSuppressionLoader = createLazyImportLoader(
57+
() => import("./model-suppression.runtime.js"),
58+
);
5659

5760
function shouldLogModelCatalogTiming(): boolean {
5861
return process.env.OPENCLAW_DEBUG_INGRESS_TIMING === "1";
5962
}
6063

6164
function loadModelSuppression() {
62-
modelSuppressionPromise ??= import("./model-suppression.runtime.js");
63-
return modelSuppressionPromise;
65+
return modelSuppressionLoader.load();
6466
}
6567

6668
export function resetModelCatalogCache() {

src/agents/model-fallback.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
import type { OpenClawConfig } from "../config/types.openclaw.js";
66
import { formatErrorMessage } from "../infra/errors.js";
77
import { createSubsystemLogger } from "../logging/subsystem.js";
8+
import { createLazyImportLoader } from "../shared/lazy-promise.js";
89
import { normalizeOptionalString } from "../shared/string-coerce.js";
910
import { sanitizeForLog } from "../terminal/ansi.js";
1011
import { externalCliDiscoveryForProviders } from "./auth-profiles/external-cli-discovery.js";
@@ -181,11 +182,12 @@ type ModelFallbackRunResult<T> = {
181182

182183
type ModelFallbackAuthRuntime = typeof import("./model-fallback-auth.runtime.js");
183184

184-
let modelFallbackAuthRuntimePromise: Promise<ModelFallbackAuthRuntime> | undefined;
185+
const modelFallbackAuthRuntimeLoader = createLazyImportLoader<ModelFallbackAuthRuntime>(
186+
() => import("./model-fallback-auth.runtime.js"),
187+
);
185188

186189
async function loadModelFallbackAuthRuntime() {
187-
modelFallbackAuthRuntimePromise ??= import("./model-fallback-auth.runtime.js");
188-
return await modelFallbackAuthRuntimePromise;
190+
return await modelFallbackAuthRuntimeLoader.load();
189191
}
190192

191193
function buildFallbackSuccess<T>(params: {

src/agents/pi-embedded-runner/compact.runtime.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
12
import type { CompactEmbeddedPiSessionDirect } from "./compact.runtime.types.js";
23

3-
let compactRuntimePromise: Promise<typeof import("./compact.js")> | null = null;
4+
const compactRuntimeLoader = createLazyImportLoader(() => import("./compact.js"));
45

56
function loadCompactRuntime() {
6-
compactRuntimePromise ??= import("./compact.js");
7-
return compactRuntimePromise;
7+
return compactRuntimeLoader.load();
88
}
99

1010
export async function compactEmbeddedPiSessionDirect(

0 commit comments

Comments
 (0)