mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
refactor(shared): consolidate core leaf lazy loaders (#99278)
This commit is contained in:
@@ -24,23 +24,19 @@ import {
|
||||
POSIX_SHELL_WRAPPERS,
|
||||
resolveShellWrapperTransportArgv,
|
||||
} from "../infra/shell-wrapper-resolution.js";
|
||||
import { createLazyPromise } from "../shared/lazy-runtime.js";
|
||||
import {
|
||||
DEFAULT_APPROVAL_REQUEST_TIMEOUT_MS,
|
||||
DEFAULT_APPROVAL_TIMEOUT_MS,
|
||||
} from "./bash-tools.exec-runtime.js";
|
||||
import { callGatewayTool } from "./tools/gateway.js";
|
||||
|
||||
type ExecApprovalCommandSpansRuntime =
|
||||
typeof import("./bash-tools.exec-approval-request.runtime.js");
|
||||
|
||||
let execApprovalCommandSpansRuntimePromise: Promise<ExecApprovalCommandSpansRuntime> | null = null;
|
||||
const POSIX_COMMAND_HIGHLIGHT_SHELLS: ReadonlySet<string> = POSIX_SHELL_WRAPPERS;
|
||||
|
||||
function loadExecApprovalCommandSpansRuntime(): Promise<ExecApprovalCommandSpansRuntime> {
|
||||
execApprovalCommandSpansRuntimePromise ??=
|
||||
import("./bash-tools.exec-approval-request.runtime.js");
|
||||
return execApprovalCommandSpansRuntimePromise;
|
||||
}
|
||||
const loadExecApprovalCommandSpansRuntime = createLazyPromise(
|
||||
() => import("./bash-tools.exec-approval-request.runtime.js"),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
|
||||
/** Gateway payload fields used to register or wait for an exec approval decision. */
|
||||
type RequestExecApprovalDecisionParams = {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { isRecord } from "@openclaw/normalization-core/record-coerce";
|
||||
import { uniqueValues } from "@openclaw/normalization-core/string-normalization";
|
||||
import { Type } from "typebox";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { createLazyPromiseLoader } from "../shared/lazy-runtime.js";
|
||||
import { resolveAgentConfig } from "./agent-scope-config.js";
|
||||
import type { HookContext } from "./agent-tools.before-tool-call.js";
|
||||
import {
|
||||
@@ -151,7 +152,9 @@ type CodeModeWorkerResult =
|
||||
const activeRuns = new Map<string, CodeModeRunState>();
|
||||
const resumingRunIds = new Set<string>();
|
||||
let activeRunReservations = 0;
|
||||
let typescriptRuntimePromise: Promise<typeof import("typescript")> | null = null;
|
||||
const typescriptRuntimeLoader = createLazyPromiseLoader(() => import("typescript"), {
|
||||
cacheRejections: true,
|
||||
});
|
||||
let typescriptRuntimeForTest: typeof import("typescript") | null = null;
|
||||
|
||||
function normalizeCodeModeRawConfig(value: unknown): Record<string, unknown> | undefined {
|
||||
@@ -438,8 +441,7 @@ async function loadTypeScriptRuntime(): Promise<typeof import("typescript")> {
|
||||
if (typescriptRuntimeForTest) {
|
||||
return typescriptRuntimeForTest;
|
||||
}
|
||||
typescriptRuntimePromise ??= import("typescript");
|
||||
return await typescriptRuntimePromise;
|
||||
return await typescriptRuntimeLoader.load();
|
||||
}
|
||||
|
||||
async function prepareSource(input: {
|
||||
@@ -1274,7 +1276,8 @@ export const testing = {
|
||||
runCodeModeWorker,
|
||||
resolveCodeModeWorkerUrl,
|
||||
resolveCodeModeConfig,
|
||||
getTypescriptRuntimePromise: () => typescriptRuntimePromise,
|
||||
getTypescriptRuntimePromise: (): Promise<typeof import("typescript")> | null =>
|
||||
typescriptRuntimeLoader.peek() ?? null,
|
||||
setTypescriptRuntimeForTest: (runtime: typeof import("typescript") | null) => {
|
||||
typescriptRuntimeForTest = runtime;
|
||||
},
|
||||
|
||||
@@ -19,6 +19,7 @@ import type {
|
||||
import { formatErrorMessage } from "../../../infra/errors.js";
|
||||
import type { Model } from "../../../llm/types.js";
|
||||
import type { PluginMetadataSnapshot } from "../../../plugins/plugin-metadata-snapshot.js";
|
||||
import { createLazyPromise } from "../../../shared/lazy-runtime.js";
|
||||
import type { EmbeddedContextFile } from "../../embedded-agent-helpers.js";
|
||||
import type {
|
||||
MessagingToolSend,
|
||||
@@ -924,18 +925,15 @@ function createCompletedAssistantStream(): TestAgentStream {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let runEmbeddedAttemptPromise:
|
||||
| Promise<typeof import("./attempt.js").runEmbeddedAttempt>
|
||||
| undefined;
|
||||
const ATTEMPT_SPAWN_WORKSPACE_TEST_SPECIFIER = "./attempt.ts?spawn-workspace-test";
|
||||
|
||||
async function loadRunEmbeddedAttempt() {
|
||||
runEmbeddedAttemptPromise ??= (
|
||||
import(ATTEMPT_SPAWN_WORKSPACE_TEST_SPECIFIER) as Promise<typeof import("./attempt.js")>
|
||||
).then((mod) => mod.runEmbeddedAttempt);
|
||||
return await runEmbeddedAttemptPromise;
|
||||
}
|
||||
const loadRunEmbeddedAttempt = createLazyPromise(
|
||||
() =>
|
||||
(import(ATTEMPT_SPAWN_WORKSPACE_TEST_SPECIFIER) as Promise<typeof import("./attempt.js")>).then(
|
||||
(mod) => mod.runEmbeddedAttempt,
|
||||
),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
|
||||
export async function preloadRunEmbeddedAttemptForTests(): Promise<void> {
|
||||
await loadRunEmbeddedAttempt();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Commander registration for device pairing and auth-token commands.
|
||||
import type { Command } from "commander";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { applyParentDefaultHelpAction } from "./program/parent-default-help.js";
|
||||
|
||||
type DevicesRpcOpts = {
|
||||
@@ -18,14 +19,8 @@ type DevicesRpcOpts = {
|
||||
|
||||
const DEFAULT_DEVICES_TIMEOUT_MS = 10_000;
|
||||
|
||||
type DevicesRuntimeModule = typeof import("./devices-cli.runtime.js");
|
||||
|
||||
let devicesRuntimePromise: Promise<DevicesRuntimeModule> | undefined;
|
||||
|
||||
function loadDevicesRuntime(): Promise<DevicesRuntimeModule> {
|
||||
// Keep device-pairing crypto/table dependencies out of root help startup.
|
||||
return (devicesRuntimePromise ??= import("./devices-cli.runtime.js"));
|
||||
}
|
||||
// Keep device-pairing crypto/table dependencies out of root help startup.
|
||||
const loadDevicesRuntime = createLazyRuntimeModule(() => import("./devices-cli.runtime.js"));
|
||||
|
||||
const devicesCallOpts = (cmd: Command, defaults?: { timeoutMs?: number }) =>
|
||||
cmd
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { Command } from "commander";
|
||||
import { formatDocsLink } from "../../../packages/terminal-core/src/links.js";
|
||||
import { theme } from "../../../packages/terminal-core/src/theme.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
import { hasExplicitOptions } from "../command-options.js";
|
||||
import { formatHelpExamples } from "../help-format.js";
|
||||
import { collectOption } from "./helpers.js";
|
||||
@@ -14,11 +15,9 @@ type AgentsListModule = typeof import("../../commands/agents.commands.list.js");
|
||||
type CliUtilsModule = typeof import("../cli-utils.js");
|
||||
type RuntimeModule = typeof import("../../runtime.js");
|
||||
|
||||
let agentsBindModulePromise: Promise<AgentsBindModule> | undefined;
|
||||
|
||||
function loadAgentsBindModule(): Promise<AgentsBindModule> {
|
||||
return (agentsBindModulePromise ??= import("../../commands/agents.commands.bind.js"));
|
||||
}
|
||||
const loadAgentsBindModule = createLazyRuntimeModule(
|
||||
() => import("../../commands/agents.commands.bind.js"),
|
||||
);
|
||||
|
||||
async function loadAgentsAddCommand(): Promise<AgentsAddModule["agentsAddCommand"]> {
|
||||
return (await import("../../commands/agents.commands.add.js")).agentsAddCommand;
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
scopeLegacySessionKeyToAgent,
|
||||
} from "../routing/session-key.js";
|
||||
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
|
||||
import { createLazyPromiseLoader } from "../shared/lazy-runtime.js";
|
||||
import { normalizeMessageChannel } from "../utils/message-channel-normalize.js";
|
||||
|
||||
type AgentGatewayResult = {
|
||||
@@ -104,9 +105,7 @@ type AgentGatewayCallIdentity = Pick<
|
||||
Parameters<typeof callGateway>[0],
|
||||
"clientName" | "mode" | "scopes"
|
||||
>;
|
||||
type EmbeddedAgentCommandModule = typeof import("./agent.js");
|
||||
type AgentSessionModule = typeof import("./agent/session.js");
|
||||
type RuntimeConfigModule = typeof import("../config/io.js");
|
||||
type AgentSessionModuleLoader = () => Promise<AgentSessionModule>;
|
||||
|
||||
const AGENT_CLI_SIGNALS: readonly AgentCliSignal[] = ["SIGINT", "SIGTERM"];
|
||||
@@ -118,53 +117,50 @@ const AGENT_CLI_SIGNAL_EXIT_CODES: Record<AgentCliSignal, number> = {
|
||||
};
|
||||
const MESSAGE_FILE_DECODER = new TextDecoder("utf-8", { fatal: true });
|
||||
|
||||
let embeddedAgentCommandPromise: Promise<EmbeddedAgentCommandModule["agentCommand"]> | undefined;
|
||||
let agentSessionModulePromise: Promise<AgentSessionModule> | undefined;
|
||||
let runtimeConfigModulePromise: Promise<RuntimeConfigModule> | undefined;
|
||||
let replyPayloadModulePromise:
|
||||
| Promise<typeof import("openclaw/plugin-sdk/reply-payload")>
|
||||
| undefined;
|
||||
const defaultAgentSessionModuleLoader: AgentSessionModuleLoader = () =>
|
||||
import("./agent/session.js");
|
||||
let agentSessionModuleLoader: AgentSessionModuleLoader = defaultAgentSessionModuleLoader;
|
||||
const embeddedAgentCommandLoader = createLazyPromiseLoader(
|
||||
() => import("./agent.js").then((module) => module.agentCommand),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
const agentSessionModuleCache = createLazyPromiseLoader(() => agentSessionModuleLoader(), {
|
||||
cacheRejections: true,
|
||||
});
|
||||
const runtimeConfigModuleLoader = createLazyPromiseLoader(() => import("../config/io.js"), {
|
||||
cacheRejections: true,
|
||||
});
|
||||
const replyPayloadModuleLoader = createLazyPromiseLoader(
|
||||
() => import("openclaw/plugin-sdk/reply-payload"),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
let gatewayAbortRetryDelaysMsForTests: readonly number[] | undefined;
|
||||
|
||||
function resolveGatewayAbortRetryDelaysMs(): readonly number[] {
|
||||
return gatewayAbortRetryDelaysMsForTests ?? GATEWAY_ABORT_RETRY_DELAYS_MS;
|
||||
}
|
||||
|
||||
function loadEmbeddedAgentCommand(): Promise<EmbeddedAgentCommandModule["agentCommand"]> {
|
||||
embeddedAgentCommandPromise ??= import("./agent.js").then((module) => module.agentCommand);
|
||||
return embeddedAgentCommandPromise;
|
||||
}
|
||||
|
||||
function loadAgentSessionModule(): Promise<AgentSessionModule> {
|
||||
agentSessionModulePromise ??= agentSessionModuleLoader();
|
||||
return agentSessionModulePromise;
|
||||
}
|
||||
const loadEmbeddedAgentCommand = embeddedAgentCommandLoader.load;
|
||||
const loadAgentSessionModule = agentSessionModuleCache.load;
|
||||
|
||||
async function loadRuntimeConfig(): Promise<OpenClawConfig> {
|
||||
runtimeConfigModulePromise ??= import("../config/io.js");
|
||||
const { getRuntimeConfig } = await runtimeConfigModulePromise;
|
||||
const { getRuntimeConfig } = await runtimeConfigModuleLoader.load();
|
||||
return getRuntimeConfig();
|
||||
}
|
||||
|
||||
function loadReplyPayloadModule() {
|
||||
replyPayloadModulePromise ??= import("openclaw/plugin-sdk/reply-payload");
|
||||
return replyPayloadModulePromise;
|
||||
}
|
||||
const loadReplyPayloadModule = replyPayloadModuleLoader.load;
|
||||
|
||||
/** Test-only hooks for resetting lazy imports and shortening retry timing. */
|
||||
export const agentViaGatewayTesting = {
|
||||
resetLazyImportsForTests(): void {
|
||||
embeddedAgentCommandPromise = undefined;
|
||||
agentSessionModulePromise = undefined;
|
||||
runtimeConfigModulePromise = undefined;
|
||||
replyPayloadModulePromise = undefined;
|
||||
embeddedAgentCommandLoader.clear();
|
||||
agentSessionModuleCache.clear();
|
||||
runtimeConfigModuleLoader.clear();
|
||||
replyPayloadModuleLoader.clear();
|
||||
agentSessionModuleLoader = defaultAgentSessionModuleLoader;
|
||||
},
|
||||
setAgentSessionModuleLoaderForTests(loader: AgentSessionModuleLoader): void {
|
||||
agentSessionModulePromise = undefined;
|
||||
agentSessionModuleCache.clear();
|
||||
agentSessionModuleLoader = loader;
|
||||
},
|
||||
resolveGatewayAgentTimeoutMs,
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
import { collectPluginConfigAssignments } from "../secrets/runtime-config-collectors-plugins.js";
|
||||
import { createResolverContext } from "../secrets/runtime-shared.js";
|
||||
import { discoverConfigSecretTargets } from "../secrets/target-registry.js";
|
||||
import { createLazyPromise } from "../shared/lazy-runtime.js";
|
||||
import {
|
||||
emitDaemonInstallRuntimeWarning,
|
||||
resolveDaemonInstallRuntimeInputs,
|
||||
@@ -60,13 +61,6 @@ type GatewayInstallPlan = {
|
||||
environmentValueSources?: Record<string, GatewayServiceEnvironmentValueSource | undefined>;
|
||||
};
|
||||
|
||||
let daemonInstallAuthProfileSourceRuntimePromise:
|
||||
| Promise<typeof import("./daemon-install-auth-profiles-source.runtime.js")>
|
||||
| undefined;
|
||||
let daemonInstallAuthProfileStoreRuntimePromise:
|
||||
| Promise<typeof import("./daemon-install-auth-profiles-store.runtime.js")>
|
||||
| undefined;
|
||||
|
||||
const NON_PERSISTED_CONFIG_SECRET_ENV_TARGET_IDS = new Set([
|
||||
"gateway.auth.password",
|
||||
"gateway.auth.token",
|
||||
@@ -83,17 +77,15 @@ function isBlockedExecSecretRefPassEnvKey(key: string): boolean {
|
||||
return !EXEC_SECRET_REF_PASS_ENV_ALLOWED_OVERRIDE_ONLY_KEYS.has(key.toUpperCase());
|
||||
}
|
||||
|
||||
function loadDaemonInstallAuthProfileSourceRuntime() {
|
||||
daemonInstallAuthProfileSourceRuntimePromise ??=
|
||||
import("./daemon-install-auth-profiles-source.runtime.js");
|
||||
return daemonInstallAuthProfileSourceRuntimePromise;
|
||||
}
|
||||
const loadDaemonInstallAuthProfileSourceRuntime = createLazyPromise(
|
||||
() => import("./daemon-install-auth-profiles-source.runtime.js"),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
|
||||
function loadDaemonInstallAuthProfileStoreRuntime() {
|
||||
daemonInstallAuthProfileStoreRuntimePromise ??=
|
||||
import("./daemon-install-auth-profiles-store.runtime.js");
|
||||
return daemonInstallAuthProfileStoreRuntimePromise;
|
||||
}
|
||||
const loadDaemonInstallAuthProfileStoreRuntime = createLazyPromise(
|
||||
() => import("./daemon-install-auth-profiles-store.runtime.js"),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
|
||||
async function resolveAuthProfileStoreForServiceEnv(
|
||||
authStore: AuthProfileStore | undefined,
|
||||
|
||||
@@ -11,26 +11,17 @@ import { formatConfigIssueLines } from "../config/issue-format.js";
|
||||
import type { ConfigFileSnapshot, LegacyConfigIssue } from "../config/types.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { isTruthyEnvValue } from "../infra/env.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { resolveHomeDir } from "../utils.js";
|
||||
import { noteIncludeConfinementWarning } from "./doctor-config-analysis.js";
|
||||
import { findDoctorLegacyConfigIssues } from "./doctor/shared/legacy-config-issues.js";
|
||||
import { resolveStateMigrationConfigInput } from "./doctor/shared/legacy-config-state-migration-input.js";
|
||||
|
||||
type DoctorStateMigrationsModule = typeof import("./doctor-state-migrations.js");
|
||||
type DoctorCronModule = typeof import("./doctor/cron/index.js");
|
||||
const loadDoctorStateMigrations = createLazyRuntimeModule(
|
||||
() => import("./doctor-state-migrations.js"),
|
||||
);
|
||||
|
||||
let doctorStateMigrationsPromise: Promise<DoctorStateMigrationsModule> | null = null;
|
||||
let doctorCronPromise: Promise<DoctorCronModule> | null = null;
|
||||
|
||||
function loadDoctorStateMigrations(): Promise<DoctorStateMigrationsModule> {
|
||||
doctorStateMigrationsPromise ??= import("./doctor-state-migrations.js");
|
||||
return doctorStateMigrationsPromise;
|
||||
}
|
||||
|
||||
function loadDoctorCron(): Promise<DoctorCronModule> {
|
||||
doctorCronPromise ??= import("./doctor/cron/index.js");
|
||||
return doctorCronPromise;
|
||||
}
|
||||
const loadDoctorCron = createLazyRuntimeModule(() => import("./doctor/cron/index.js"));
|
||||
|
||||
async function maybeMigrateLegacyConfig(): Promise<string[]> {
|
||||
const changes: string[] = [];
|
||||
|
||||
@@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url";
|
||||
import { sortUniqueStrings } from "@openclaw/normalization-core/string-normalization";
|
||||
import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js";
|
||||
import { replaceFileAtomicSync } from "../infra/replace-file.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import type { ConfigSchemaResponse } from "./schema.js";
|
||||
import { schemaHasChildren } from "./schema.shared.js";
|
||||
|
||||
@@ -91,8 +92,6 @@ const DEFAULT_CHANNEL_OUTPUT = "docs/.generated/config-baseline.channel.json";
|
||||
const DEFAULT_PLUGIN_OUTPUT = "docs/.generated/config-baseline.plugin.json";
|
||||
const DEFAULT_HASH_OUTPUT = "docs/.generated/config-baseline.sha256";
|
||||
let cachedConfigDocBaselinePromise: Promise<ConfigDocBaseline> | null = null;
|
||||
let cachedDocBaselineRuntimePromise: Promise<typeof import("./doc-baseline.runtime.js")> | null =
|
||||
null;
|
||||
const uiHintIndexCache = new WeakMap<
|
||||
ConfigSchemaResponse["uiHints"],
|
||||
Map<
|
||||
@@ -123,10 +122,7 @@ function resolveRepoRoot(): string {
|
||||
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
}
|
||||
|
||||
async function loadDocBaselineRuntime() {
|
||||
cachedDocBaselineRuntimePromise ??= import("./doc-baseline.runtime.js");
|
||||
return await cachedDocBaselineRuntimePromise;
|
||||
}
|
||||
const loadDocBaselineRuntime = createLazyRuntimeModule(() => import("./doc-baseline.runtime.js"));
|
||||
|
||||
function normalizeBaselinePath(rawPath: string): string {
|
||||
return rawPath
|
||||
|
||||
@@ -20,6 +20,7 @@ import type {
|
||||
SessionTranscriptUpdate,
|
||||
SessionTranscriptUpdateTarget,
|
||||
} from "../../sessions/transcript-events.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
import type { OpenClawConfig } from "../types.openclaw.js";
|
||||
import { formatSessionArchiveTimestamp } from "./artifacts.js";
|
||||
import { extractGeneratedTranscriptSessionId } from "./generated-transcript-session-id.js";
|
||||
@@ -441,14 +442,9 @@ type SessionEntryRetirement = {
|
||||
key: string;
|
||||
};
|
||||
|
||||
let sessionArchiveRuntimePromise: Promise<
|
||||
typeof import("../../gateway/session-archive.runtime.js")
|
||||
> | null = null;
|
||||
|
||||
function loadSessionArchiveRuntime() {
|
||||
sessionArchiveRuntimePromise ??= import("../../gateway/session-archive.runtime.js");
|
||||
return sessionArchiveRuntimePromise;
|
||||
}
|
||||
const loadSessionArchiveRuntime = createLazyRuntimeModule(
|
||||
() => import("../../gateway/session-archive.runtime.js"),
|
||||
);
|
||||
|
||||
export type SessionEntryPatchOptions = {
|
||||
/** Entry to synthesize when a patch operation is allowed to create. */
|
||||
|
||||
@@ -7,6 +7,7 @@ import { resolveStoredSessionOwnerAgentId } from "../../gateway/session-store-ke
|
||||
import { writeTextAtomic } from "../../infra/json-files.js";
|
||||
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
import {
|
||||
deliveryContextFromChannelRoute,
|
||||
deliveryContextFromSession,
|
||||
@@ -115,26 +116,18 @@ export type SessionEntryPatchProjectionResult<TFailure extends SessionEntryPatch
|
||||
{ ok: true; entry: SessionEntry } | TFailure;
|
||||
|
||||
const log = createSubsystemLogger("sessions/store");
|
||||
let sessionArchiveRuntimePromise: Promise<
|
||||
typeof import("../../gateway/session-archive.runtime.js")
|
||||
> | null = null;
|
||||
let trajectoryCleanupRuntimePromise: Promise<typeof import("../../trajectory/cleanup.js")> | null =
|
||||
null;
|
||||
const writerStoreFileStats = new WeakMap<
|
||||
Record<string, SessionEntry>,
|
||||
ReturnType<typeof getFileStatSnapshot> | null
|
||||
>();
|
||||
|
||||
function loadSessionArchiveRuntime() {
|
||||
// Archive cleanup is a cold maintenance path, so keep it lazy to avoid gateway import cycles.
|
||||
sessionArchiveRuntimePromise ??= import("../../gateway/session-archive.runtime.js");
|
||||
return sessionArchiveRuntimePromise;
|
||||
}
|
||||
const loadSessionArchiveRuntime = createLazyRuntimeModule(
|
||||
() => import("../../gateway/session-archive.runtime.js"),
|
||||
);
|
||||
|
||||
function loadTrajectoryCleanupRuntime() {
|
||||
trajectoryCleanupRuntimePromise ??= import("../../trajectory/cleanup.js");
|
||||
return trajectoryCleanupRuntimePromise;
|
||||
}
|
||||
const loadTrajectoryCleanupRuntime = createLazyRuntimeModule(
|
||||
() => import("../../trajectory/cleanup.js"),
|
||||
);
|
||||
|
||||
function removeThreadFromDeliveryContext(context?: DeliveryContext): DeliveryContext | undefined {
|
||||
if (!context || context.threadId == null) {
|
||||
|
||||
@@ -3,19 +3,14 @@ import { intro as clackIntro, outro as clackOutro } from "@clack/prompts";
|
||||
import { stylePromptTitle } from "../../packages/terminal-core/src/prompt-style.js";
|
||||
import type { DoctorOptions } from "../commands/doctor-prompter.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import type { DoctorHealthFlowContext } from "./doctor-health-contributions.js";
|
||||
|
||||
// Interactive doctor entrypoint; lazy imports keep normal CLI startup light.
|
||||
const intro = (message: string) => clackIntro(stylePromptTitle(message) ?? message);
|
||||
const outro = (message: string) => clackOutro(stylePromptTitle(message) ?? message);
|
||||
|
||||
type ConfigModule = typeof import("../config/config.js");
|
||||
|
||||
let configModulePromise: Promise<ConfigModule> | undefined;
|
||||
|
||||
function loadConfigModule(): Promise<ConfigModule> {
|
||||
return (configModulePromise ??= import("../config/config.js"));
|
||||
}
|
||||
const loadConfigModule = createLazyRuntimeModule(() => import("../config/config.js"));
|
||||
|
||||
/** Runs the full interactive doctor flow against the provided or default runtime. */
|
||||
export async function doctorCommand(runtime?: RuntimeEnv, options: DoctorOptions = {}) {
|
||||
|
||||
@@ -13,15 +13,11 @@ import {
|
||||
} from "../plugins/install-security-scan.js";
|
||||
import { PLUGIN_MANIFEST_FILENAME } from "../plugins/manifest.js";
|
||||
import type { InstallPolicySource } from "../security/install-policy.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { CONFIG_DIR, resolveUserPath } from "../utils.js";
|
||||
import { parseFrontmatter } from "./frontmatter.js";
|
||||
|
||||
let hookInstallRuntimePromise: Promise<typeof import("./install.runtime.js")> | undefined;
|
||||
|
||||
async function loadHookInstallRuntime() {
|
||||
hookInstallRuntimePromise ??= import("./install.runtime.js");
|
||||
return hookInstallRuntimePromise;
|
||||
}
|
||||
const loadHookInstallRuntime = createLazyRuntimeModule(() => import("./install.runtime.js"));
|
||||
|
||||
/** Logger contract used by hook install and update operations. */
|
||||
export type HookInstallLogger = {
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
resolveBackupPlanFromDisk,
|
||||
} from "../commands/backup-shared.js";
|
||||
import { isPathWithin } from "../commands/cleanup-utils.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { resolveOpenClawStateSqlitePath } from "../state/openclaw-state-db.paths.js";
|
||||
import { resolveHomeDir, resolveUserPath } from "../utils.js";
|
||||
import { resolveRuntimeServiceVersion } from "../version.js";
|
||||
@@ -22,14 +23,7 @@ import { isVolatileBackupPath } from "./backup-volatile-filter.js";
|
||||
import { writeJson } from "./json-files.js";
|
||||
import { requireNodeSqlite } from "./node-sqlite.js";
|
||||
|
||||
type TarRuntime = typeof import("tar");
|
||||
|
||||
let tarRuntimePromise: Promise<TarRuntime> | undefined;
|
||||
|
||||
function loadTarRuntime(): Promise<TarRuntime> {
|
||||
tarRuntimePromise ??= import("tar");
|
||||
return tarRuntimePromise;
|
||||
}
|
||||
const loadTarRuntime = createLazyRuntimeModule(() => import("tar"));
|
||||
|
||||
type BackupLinkCacheKey = `${number}:${number}`;
|
||||
|
||||
|
||||
+9
-5
@@ -1,18 +1,22 @@
|
||||
// Normalizes env flag values and logs env warnings lazily.
|
||||
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
|
||||
import type { SubsystemLogger } from "../logging/subsystem.js";
|
||||
import { createLazyPromise } from "../shared/lazy-runtime.js";
|
||||
|
||||
let log: SubsystemLogger | null = null;
|
||||
let logPromise: Promise<SubsystemLogger> | null = null;
|
||||
const loadLog = createLazyPromise(
|
||||
() =>
|
||||
import("../logging/subsystem.js").then(({ createSubsystemLogger }) =>
|
||||
createSubsystemLogger("env"),
|
||||
),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
const loggedEnv = new Set<string>();
|
||||
const ENV_NORMALIZATION_KEY_GROUPS = [["ZAI_API_KEY", "Z_AI_API_KEY"]] as const;
|
||||
|
||||
async function getLog(): Promise<SubsystemLogger> {
|
||||
if (!log) {
|
||||
logPromise ??= import("../logging/subsystem.js").then(({ createSubsystemLogger }) =>
|
||||
createSubsystemLogger("env"),
|
||||
);
|
||||
log = await logPromise;
|
||||
log = await loadLog();
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
buildPluginApprovalResolvedReplyPayload,
|
||||
} from "../plugin-sdk/approval-renderers.js";
|
||||
import { channelRouteDedupeKey } from "../plugin-sdk/channel-route.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import {
|
||||
isDeliverableMessageChannel,
|
||||
normalizeMessageChannel,
|
||||
@@ -142,14 +143,10 @@ type ExecApprovalForwarderDeps = {
|
||||
|
||||
const DEFAULT_MODE = "session" as const;
|
||||
const SYNTHETIC_APPROVAL_REQUEST_ID = "__approval-routing__";
|
||||
let execApprovalForwarderRuntimePromise: Promise<
|
||||
typeof import("./exec-approval-forwarder.runtime.js")
|
||||
> | null = null;
|
||||
|
||||
function loadExecApprovalForwarderRuntime() {
|
||||
execApprovalForwarderRuntimePromise ??= import("./exec-approval-forwarder.runtime.js");
|
||||
return execApprovalForwarderRuntimePromise;
|
||||
}
|
||||
const loadExecApprovalForwarderRuntime = createLazyRuntimeModule(
|
||||
() => import("./exec-approval-forwarder.runtime.js"),
|
||||
);
|
||||
|
||||
function normalizeMode(mode?: ExecApprovalForwardingConfig["mode"]) {
|
||||
return mode ?? DEFAULT_MODE;
|
||||
|
||||
@@ -106,6 +106,7 @@ import {
|
||||
toAgentStoreSessionKey,
|
||||
} from "../routing/session-key.js";
|
||||
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { escapeRegExp } from "../utils.js";
|
||||
import { MAX_SAFE_TIMEOUT_DELAY_MS, resolveSafeTimeoutDelayMs } from "../utils/timer-delay.js";
|
||||
import { loadOrCreateDeviceIdentity } from "./device-identity.js";
|
||||
@@ -172,13 +173,10 @@ export type HeartbeatDeps = OutboundSendDeps &
|
||||
};
|
||||
|
||||
const log = createSubsystemLogger("gateway/heartbeat");
|
||||
let heartbeatRunnerRuntimePromise: Promise<typeof import("./heartbeat-runner.runtime.js")> | null =
|
||||
null;
|
||||
|
||||
function loadHeartbeatRunnerRuntime() {
|
||||
heartbeatRunnerRuntimePromise ??= import("./heartbeat-runner.runtime.js");
|
||||
return heartbeatRunnerRuntimePromise;
|
||||
}
|
||||
const loadHeartbeatRunnerRuntime = createLazyRuntimeModule(
|
||||
() => import("./heartbeat-runner.runtime.js"),
|
||||
);
|
||||
|
||||
const HEARTBEAT_ALWAYS_BUSY_LANES = [CommandLane.Cron, CommandLane.CronNested] as const;
|
||||
const DEFAULT_HEARTBEAT_TIMEOUT_SECONDS = 10 * 60;
|
||||
|
||||
@@ -41,6 +41,7 @@ import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import type { OutboundMediaAccess } from "../../media/load-options.js";
|
||||
import { resolveAgentScopedOutboundMediaAccess } from "../../media/read-capability.js";
|
||||
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
import { diagnosticErrorCategory } from "../diagnostic-error-metadata.js";
|
||||
import {
|
||||
emitInternalDiagnosticEvent as emitDiagnosticEvent,
|
||||
@@ -123,25 +124,16 @@ export type OutboundDurableDeliverySupport =
|
||||
};
|
||||
|
||||
const log = createSubsystemLogger("outbound/deliver");
|
||||
let transcriptRuntimePromise:
|
||||
| Promise<typeof import("../../config/sessions/transcript.runtime.js")>
|
||||
| undefined;
|
||||
|
||||
async function loadTranscriptRuntime() {
|
||||
// Transcript writes are optional side effects; keep this lazy for import-only
|
||||
// delivery policy checks and tests.
|
||||
transcriptRuntimePromise ??= import("../../config/sessions/transcript.runtime.js");
|
||||
return await transcriptRuntimePromise;
|
||||
}
|
||||
// Transcript writes are optional side effects; keep this lazy for import-only
|
||||
// delivery policy checks and tests.
|
||||
const loadTranscriptRuntime = createLazyRuntimeModule(
|
||||
() => import("../../config/sessions/transcript.runtime.js"),
|
||||
);
|
||||
|
||||
let channelBootstrapRuntimePromise:
|
||||
| Promise<typeof import("./channel-bootstrap.runtime.js")>
|
||||
| undefined;
|
||||
|
||||
async function loadChannelBootstrapRuntime() {
|
||||
channelBootstrapRuntimePromise ??= import("./channel-bootstrap.runtime.js");
|
||||
return await channelBootstrapRuntimePromise;
|
||||
}
|
||||
const loadChannelBootstrapRuntime = createLazyRuntimeModule(
|
||||
() => import("./channel-bootstrap.runtime.js"),
|
||||
);
|
||||
|
||||
type ChannelHandler = {
|
||||
chunker: ChannelOutboundAdapter["chunker"] | null;
|
||||
|
||||
@@ -42,6 +42,7 @@ import { extractToolPayload } from "../../plugin-sdk/tool-payload.js";
|
||||
import { hasPollCreationParams } from "../../poll-params.js";
|
||||
import { resolvePollMaxSelections } from "../../polls.js";
|
||||
import { resolveFirstBoundAccountId } from "../../routing/bound-account-read.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
import { stripUnsupportedCitationControlMarkers } from "../../shared/text/citation-control-markers.js";
|
||||
import { stripFormattedReasoningMessage } from "../../shared/text/formatted-reasoning-message.js";
|
||||
import { parseInlineDirectives } from "../../utils/directive-tags.js";
|
||||
@@ -104,16 +105,11 @@ export type MessageActionRunnerGateway = {
|
||||
mode: GatewayClientMode;
|
||||
};
|
||||
|
||||
let messageActionGatewayRuntimePromise: Promise<
|
||||
typeof import("./message.gateway.runtime.js")
|
||||
> | null = null;
|
||||
|
||||
function loadMessageActionGatewayRuntime() {
|
||||
// Gateway runtime is only needed for remote message action dispatch or
|
||||
// idempotency keys; keep normal in-process actions import-light.
|
||||
messageActionGatewayRuntimePromise ??= import("./message.gateway.runtime.js");
|
||||
return messageActionGatewayRuntimePromise;
|
||||
}
|
||||
// Gateway runtime is only needed for remote message action dispatch or
|
||||
// idempotency keys; keep normal in-process actions import-light.
|
||||
const loadMessageActionGatewayRuntime = createLazyRuntimeModule(
|
||||
() => import("./message.gateway.runtime.js"),
|
||||
);
|
||||
|
||||
export type RunMessageActionParams = {
|
||||
cfg: OpenClawConfig;
|
||||
|
||||
@@ -5,15 +5,13 @@ import { resolveStorePath } from "../../config/sessions.js";
|
||||
import { loadSessionEntry } from "../../config/sessions/session-accessor.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { TtsAutoMode } from "../../config/types.tts.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
import { shouldAttemptTtsPayload } from "../../tts/tts-config.js";
|
||||
|
||||
let ttsRuntimePromise: Promise<typeof import("../../tts/tts.runtime.js")> | null = null;
|
||||
|
||||
function loadMessageActionTtsRuntime() {
|
||||
// Keep the TTS runtime lazy so ordinary message sends do not pay the provider import cost.
|
||||
ttsRuntimePromise ??= import("../../tts/tts.runtime.js");
|
||||
return ttsRuntimePromise;
|
||||
}
|
||||
// Keep the TTS runtime lazy so ordinary message sends do not pay the provider import cost.
|
||||
const loadMessageActionTtsRuntime = createLazyRuntimeModule(
|
||||
() => import("../../tts/tts.runtime.js"),
|
||||
);
|
||||
|
||||
/** Reads the session-level TTS auto mode for a message-action send. */
|
||||
export function resolveMessageActionSessionTtsAuto(params: {
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { OutboundMediaAccess } from "../../media/load-options.js";
|
||||
import type { PollInput } from "../../polls.js";
|
||||
import { normalizePollInput } from "../../polls.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
import { resolveOutboundChannelPlugin } from "./channel-resolution.js";
|
||||
import { resolveMessageChannelSelection } from "./channel-selection.js";
|
||||
import {
|
||||
@@ -29,23 +30,17 @@ import {
|
||||
import { buildOutboundSessionContext } from "./session-context.js";
|
||||
import { resolveOutboundTarget } from "./targets.js";
|
||||
|
||||
let messageConfigRuntimePromise: Promise<typeof import("./message.config.runtime.js")> | null =
|
||||
null;
|
||||
let messageGatewayRuntimePromise: Promise<typeof import("./message.gateway.runtime.js")> | null =
|
||||
null;
|
||||
const SEND_BUFFER_MEDIA_URL = "buffer://message-send/attachment";
|
||||
|
||||
function loadMessageConfigRuntime() {
|
||||
// Keep config/runtime loading lazy so importing message helpers does not
|
||||
// bootstrap plugin registries or gateway clients.
|
||||
messageConfigRuntimePromise ??= import("./message.config.runtime.js");
|
||||
return messageConfigRuntimePromise;
|
||||
}
|
||||
const loadMessageConfigRuntime = createLazyRuntimeModule(
|
||||
() => import("./message.config.runtime.js"),
|
||||
);
|
||||
|
||||
function loadMessageGatewayRuntime() {
|
||||
messageGatewayRuntimePromise ??= import("./message.gateway.runtime.js");
|
||||
return messageGatewayRuntimePromise;
|
||||
}
|
||||
// Keep config/runtime loading lazy so importing message helpers does not
|
||||
// bootstrap plugin registries or gateway clients.
|
||||
const loadMessageGatewayRuntime = createLazyRuntimeModule(
|
||||
() => import("./message.gateway.runtime.js"),
|
||||
);
|
||||
|
||||
export type MessageGatewayOptions = OutboundMessageGatewayOptionsInput;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
import path from "node:path";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { createAsyncLock, tryReadJson, writeJson } from "./json-files.js";
|
||||
|
||||
// --- Types ---
|
||||
@@ -44,14 +45,9 @@ const withLock = createAsyncLock();
|
||||
type WebPushRuntime = typeof import("web-push");
|
||||
type WebPushRuntimeModule = WebPushRuntime & { default?: WebPushRuntime };
|
||||
|
||||
let webPushRuntimePromise: Promise<WebPushRuntime> | undefined;
|
||||
|
||||
async function loadWebPushRuntime(): Promise<WebPushRuntime> {
|
||||
webPushRuntimePromise ??= import("web-push").then(
|
||||
(mod: WebPushRuntimeModule) => mod.default ?? mod,
|
||||
);
|
||||
return await webPushRuntimePromise;
|
||||
}
|
||||
const loadWebPushRuntime = createLazyRuntimeModule(() =>
|
||||
import("web-push").then((mod: WebPushRuntimeModule) => mod.default ?? mod),
|
||||
);
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { SessionMaintenanceWarning } from "../config/sessions/store-mainten
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { createLazyPromiseLoader } from "../shared/lazy-runtime.js";
|
||||
import { deliveryContextFromSession } from "../utils/delivery-context.shared.js";
|
||||
import { isDeliverableMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
|
||||
import { buildOutboundSessionContext } from "./outbound/session-context.js";
|
||||
@@ -19,21 +20,21 @@ type WarningParams = {
|
||||
|
||||
const warnedContexts = new Map<string, string>();
|
||||
const log = createSubsystemLogger("session-maintenance-warning");
|
||||
let messageRuntimePromise: Promise<typeof import("../channels/message/runtime.js")> | null = null;
|
||||
const messageRuntimeLoader = createLazyPromiseLoader(
|
||||
() => import("../channels/message/runtime.js"),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
|
||||
function resetSessionMaintenanceWarningForTests() {
|
||||
warnedContexts.clear();
|
||||
messageRuntimePromise = null;
|
||||
messageRuntimeLoader.clear();
|
||||
}
|
||||
|
||||
export const testing = {
|
||||
resetSessionMaintenanceWarningForTests,
|
||||
} as const;
|
||||
|
||||
function loadDeliverRuntime() {
|
||||
messageRuntimePromise ??= import("../channels/message/runtime.js");
|
||||
return messageRuntimePromise;
|
||||
}
|
||||
const loadDeliverRuntime = messageRuntimeLoader.load;
|
||||
|
||||
function shouldSendWarning(): boolean {
|
||||
return process.env.NODE_ENV !== "test";
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
type DiagnosticPhaseSnapshot,
|
||||
type DiagnosticLivenessWarningReason,
|
||||
} from "../infra/diagnostic-events.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { emitDiagnosticMemorySample, resetDiagnosticMemoryForTest } from "./diagnostic-memory.js";
|
||||
import {
|
||||
getCurrentDiagnosticPhase,
|
||||
@@ -65,6 +66,7 @@ import {
|
||||
startDiagnosticStabilityRecorder,
|
||||
stopDiagnosticStabilityRecorder,
|
||||
} from "./diagnostic-stability.js";
|
||||
|
||||
export { diagnosticLogger, logLaneDequeue, logLaneEnqueue } from "./diagnostic-runtime.js";
|
||||
|
||||
const webhookStats = {
|
||||
@@ -84,12 +86,9 @@ const DEFAULT_LIVENESS_EVENT_LOOP_DELAY_WARN_MS = 1_000;
|
||||
const DEFAULT_LIVENESS_EVENT_LOOP_UTILIZATION_WARN = 0.95;
|
||||
const DEFAULT_LIVENESS_CPU_CORE_RATIO_WARN = 0.9;
|
||||
const DEFAULT_LIVENESS_WARN_COOLDOWN_MS = 120_000;
|
||||
let commandPollBackoffRuntimePromise: Promise<
|
||||
typeof import("../agents/command-poll-backoff.runtime.js")
|
||||
> | null = null;
|
||||
let stuckSessionRecoveryRuntimePromise: Promise<
|
||||
typeof import("./diagnostic-stuck-session-recovery.runtime.js")
|
||||
> | null = null;
|
||||
const loadStuckSessionRecoveryRuntime = createLazyRuntimeModule(
|
||||
() => import("./diagnostic-stuck-session-recovery.runtime.js"),
|
||||
);
|
||||
|
||||
type EmitDiagnosticMemorySample = typeof emitDiagnosticMemorySample;
|
||||
type EventLoopDelayMonitor = ReturnType<typeof monitorEventLoopDelay>;
|
||||
@@ -153,16 +152,14 @@ let lastDiagnosticLivenessEventLoopUtilization: EventLoopUtilization | null = nu
|
||||
let lastDiagnosticLivenessEventAt = 0;
|
||||
let lastDiagnosticLivenessWarnAt = 0;
|
||||
|
||||
function loadCommandPollBackoffRuntime() {
|
||||
commandPollBackoffRuntimePromise ??= import("../agents/command-poll-backoff.runtime.js");
|
||||
return commandPollBackoffRuntimePromise;
|
||||
}
|
||||
const loadCommandPollBackoffRuntime = createLazyRuntimeModule(
|
||||
() => import("../agents/command-poll-backoff.runtime.js"),
|
||||
);
|
||||
|
||||
async function recoverStuckSession(
|
||||
params: StuckSessionRecoveryRequest,
|
||||
): Promise<StuckSessionRecoveryOutcome> {
|
||||
stuckSessionRecoveryRuntimePromise ??= import("./diagnostic-stuck-session-recovery.runtime.js");
|
||||
return stuckSessionRecoveryRuntimePromise
|
||||
return loadStuckSessionRecoveryRuntime()
|
||||
.then(({ recoverStuckDiagnosticSession }) => recoverStuckDiagnosticSession(params))
|
||||
.catch((err: unknown) => {
|
||||
diag.warn(`stuck session recovery unavailable: ${String(err)}`);
|
||||
|
||||
@@ -4,16 +4,12 @@ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/st
|
||||
import type { MsgContext } from "../auto-reply/templating.js";
|
||||
import type { OpenClawConfig } from "../config/types.js";
|
||||
import { logVerbose, shouldLogVerbose } from "../globals.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { isDeliverableMessageChannel } from "../utils/message-channel.js";
|
||||
|
||||
let messageRuntimePromise: Promise<typeof import("../channels/message/runtime.js")> | null = null;
|
||||
|
||||
function loadMessageRuntime() {
|
||||
// The message runtime is heavy and only needed when echo delivery actually
|
||||
// proceeds to a deliverable channel.
|
||||
messageRuntimePromise ??= import("../channels/message/runtime.js");
|
||||
return messageRuntimePromise;
|
||||
}
|
||||
// The message runtime is heavy and only needed when echo delivery actually
|
||||
// proceeds to a deliverable channel.
|
||||
const loadMessageRuntime = createLazyRuntimeModule(() => import("../channels/message/runtime.js"));
|
||||
|
||||
/** Default operator-visible transcript echo format for preflight audio transcription. */
|
||||
export const DEFAULT_ECHO_TRANSCRIPT_FORMAT = '📝 "{transcript}"';
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
import { resolveOfficialExternalPluginRepairHint } from "../plugins/official-external-plugin-repair-hints.js";
|
||||
import { runExec } from "../process/exec.js";
|
||||
import { providerOperationRetryConfig } from "../provider-runtime/operation-retry.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { MediaAttachmentCache } from "./attachments.js";
|
||||
import {
|
||||
CLI_OUTPUT_MAX_BUFFER,
|
||||
@@ -65,20 +66,7 @@ import type {
|
||||
} from "./types.js";
|
||||
|
||||
type ProviderRegistry = Map<string, MediaUnderstandingProvider>;
|
||||
type ResolveApiKeyForProvider = typeof import("../agents/model-auth.js").resolveApiKeyForProvider;
|
||||
type RequireApiKey = typeof import("../agents/model-auth.js").requireApiKey;
|
||||
type IsProviderAuthError = typeof import("../agents/model-auth.js").isProviderAuthError;
|
||||
|
||||
let cachedModelAuth: {
|
||||
resolveApiKeyForProvider: ResolveApiKeyForProvider;
|
||||
requireApiKey: RequireApiKey;
|
||||
isProviderAuthError: IsProviderAuthError;
|
||||
} | null = null;
|
||||
|
||||
async function loadModelAuth() {
|
||||
cachedModelAuth ??= await import("../agents/model-auth.js");
|
||||
return cachedModelAuth;
|
||||
}
|
||||
const loadModelAuth = createLazyRuntimeModule(async () => await import("../agents/model-auth.js"));
|
||||
|
||||
function resolveLiteralProviderApiKey(params: {
|
||||
cfg: OpenClawConfig;
|
||||
|
||||
@@ -15,6 +15,9 @@ import {
|
||||
normalizeStringEntries,
|
||||
uniqueStrings,
|
||||
} from "@openclaw/normalization-core/string-normalization";
|
||||
import type { ActiveMediaModel } from "../../packages/media-understanding-common/src/active-model.js";
|
||||
import { isMediaUnderstandingSkipError } from "../../packages/media-understanding-common/src/errors.js";
|
||||
import { providerSupportsCapability } from "../../packages/media-understanding-common/src/provider-supports.js";
|
||||
import { isMinimaxVlmModel, isMinimaxVlmProvider } from "../agents/minimax-vlm.js";
|
||||
import {
|
||||
buildModelAliasIndex,
|
||||
@@ -38,9 +41,7 @@ import { logWarn } from "../logger.js";
|
||||
import { resolveChannelInboundAttachmentRoots } from "../media/channel-inbound-roots.js";
|
||||
import { getDefaultMediaLocalRoots } from "../media/local-roots.js";
|
||||
import { runExec } from "../process/exec.js";
|
||||
import type { ActiveMediaModel } from "../../packages/media-understanding-common/src/active-model.js";
|
||||
import { isMediaUnderstandingSkipError } from "../../packages/media-understanding-common/src/errors.js";
|
||||
import { providerSupportsCapability } from "../../packages/media-understanding-common/src/provider-supports.js";
|
||||
import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "../shared/lazy-runtime.js";
|
||||
import { MediaAttachmentCache, selectAttachments } from "./attachments.js";
|
||||
import { fileExists } from "./fs.js";
|
||||
import { resolveOpenAiAudioAuthModelApi } from "./openai-audio-api.js";
|
||||
@@ -64,12 +65,11 @@ import type {
|
||||
MediaUnderstandingOutput,
|
||||
MediaUnderstandingProvider,
|
||||
} from "./types.js";
|
||||
|
||||
export { createMediaAttachmentCache, normalizeMediaAttachments } from "./runner.attachments.js";
|
||||
export type { ActiveMediaModel } from "../../packages/media-understanding-common/src/active-model.js";
|
||||
|
||||
type ProviderRegistry = Map<string, MediaUnderstandingProvider>;
|
||||
type HasAvailableAuthForProvider =
|
||||
typeof import("../agents/model-auth.js").hasAvailableAuthForProvider;
|
||||
type ModelCatalogApi = typeof import("../agents/model-catalog.js");
|
||||
type ModelCatalog = Awaited<ReturnType<ModelCatalogApi["loadModelCatalog"]>>;
|
||||
|
||||
@@ -78,13 +78,14 @@ export type RunCapabilityResult = {
|
||||
decision: MediaUnderstandingDecision;
|
||||
};
|
||||
|
||||
let cachedHasAvailableAuthForProvider: HasAvailableAuthForProvider | null = null;
|
||||
let cachedModelCatalogApi: ModelCatalogApi | null = null;
|
||||
const loadHasAvailableAuthForProvider = createLazyRuntimeNamedExport(
|
||||
() => import("../agents/model-auth.js"),
|
||||
"hasAvailableAuthForProvider",
|
||||
);
|
||||
|
||||
async function loadModelCatalogApi(): Promise<ModelCatalogApi> {
|
||||
cachedModelCatalogApi ??= await import("../agents/model-catalog.js");
|
||||
return cachedModelCatalogApi;
|
||||
}
|
||||
const loadModelCatalogApi = createLazyRuntimeModule(
|
||||
async () => await import("../agents/model-catalog.js"),
|
||||
);
|
||||
|
||||
function resolveLiteralProviderApiKey(
|
||||
cfg: OpenClawConfig | undefined,
|
||||
@@ -107,9 +108,8 @@ async function hasProviderAuthAvailable(params: {
|
||||
if (resolveLiteralProviderApiKey(params.cfg, params.provider)) {
|
||||
return true;
|
||||
}
|
||||
cachedHasAvailableAuthForProvider ??= (await import("../agents/model-auth.js"))
|
||||
.hasAvailableAuthForProvider;
|
||||
return await cachedHasAvailableAuthForProvider({
|
||||
const hasAvailableAuthForProvider = await loadHasAvailableAuthForProvider();
|
||||
return await hasAvailableAuthForProvider({
|
||||
...params,
|
||||
modelApi: resolveOpenAiAudioAuthModelApi({
|
||||
capability: params.capability,
|
||||
|
||||
@@ -10,6 +10,7 @@ import { withEnv, withEnvAsync } from "openclaw/plugin-sdk/test-env";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { AssistantMessage, Model } from "../../llm/types.js";
|
||||
import { resolveWorkspacePackagePublicModuleUrl } from "../../plugin-sdk/test-helpers/public-surface-loader.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
|
||||
type TtsRuntimeModule = typeof import("openclaw/plugin-sdk/tts-runtime");
|
||||
type TtsCoreModule = typeof import("openclaw/plugin-sdk/speech-core");
|
||||
@@ -21,9 +22,7 @@ const speechCoreRuntimeApiModuleId = resolveWorkspacePackagePublicModuleUrl({
|
||||
});
|
||||
|
||||
let ttsRuntime: TtsRuntimeModule;
|
||||
let ttsRuntimePromise: Promise<TtsRuntimeModule> | null = null;
|
||||
let ttsRuntimeInitialized = false;
|
||||
let ttsCorePromise: Promise<TtsCoreModule> | null = null;
|
||||
let completeSimple: typeof import("openclaw/plugin-sdk/llm").completeSimple;
|
||||
let prepareSimpleCompletionModelMock: SummarizeTextDeps["prepareSimpleCompletionModel"];
|
||||
let requireApiKeyMock: SummarizeTextDeps["requireApiKey"];
|
||||
@@ -413,15 +412,11 @@ function buildTestGoogleSpeechProvider(): SpeechProviderPlugin {
|
||||
};
|
||||
}
|
||||
|
||||
async function loadTtsRuntime(): Promise<TtsRuntimeModule> {
|
||||
ttsRuntimePromise ??= import(speechCoreRuntimeApiModuleId) as Promise<TtsRuntimeModule>;
|
||||
return await ttsRuntimePromise;
|
||||
}
|
||||
const loadTtsRuntime = createLazyRuntimeModule(
|
||||
() => import(speechCoreRuntimeApiModuleId) as Promise<TtsRuntimeModule>,
|
||||
);
|
||||
|
||||
async function loadTtsCore(): Promise<TtsCoreModule> {
|
||||
ttsCorePromise ??= import("openclaw/plugin-sdk/speech-core");
|
||||
return await ttsCorePromise;
|
||||
}
|
||||
const loadTtsCore = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/speech-core"));
|
||||
|
||||
function createPrepareSimpleCompletionModelMock(): SummarizeTextDeps["prepareSimpleCompletionModel"] {
|
||||
return vi.fn(async ({ provider, modelId }) => ({
|
||||
|
||||
@@ -14,6 +14,7 @@ import { extractDeliveryInfo } from "../config/sessions/delivery-info.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { resolveAgentIdFromSessionKey } from "../routing/session-key.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { isDeliverableMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
|
||||
import type {
|
||||
PluginAttachmentChannelHints,
|
||||
@@ -31,17 +32,10 @@ export const attachmentProbeFs = {
|
||||
const MAX_ATTACHMENT_FILES = 10;
|
||||
|
||||
type SendMessage = typeof import("../infra/outbound/message.js").sendMessage;
|
||||
let sendMessagePromise: Promise<SendMessage> | undefined;
|
||||
|
||||
async function loadSendMessage(): Promise<SendMessage> {
|
||||
sendMessagePromise ??= import("../infra/outbound/message.js").then(
|
||||
(module) => module.sendMessage,
|
||||
);
|
||||
return sendMessagePromise;
|
||||
}
|
||||
|
||||
type GetChannelPlugin = typeof import("../channels/plugins/index.js").getChannelPlugin;
|
||||
let getChannelPluginPromise: Promise<GetChannelPlugin> | undefined;
|
||||
const loadSendMessage = createLazyRuntimeModule(() =>
|
||||
import("../infra/outbound/message.js").then((module) => module.sendMessage),
|
||||
);
|
||||
|
||||
type AttachmentDeliveryChannelPlugin = {
|
||||
outbound?: {
|
||||
@@ -49,12 +43,9 @@ type AttachmentDeliveryChannelPlugin = {
|
||||
};
|
||||
};
|
||||
|
||||
async function loadGetChannelPlugin(): Promise<GetChannelPlugin> {
|
||||
getChannelPluginPromise ??= import("../channels/plugins/index.js").then(
|
||||
(module) => module.getChannelPlugin,
|
||||
);
|
||||
return getChannelPluginPromise;
|
||||
}
|
||||
const loadGetChannelPlugin = createLazyRuntimeModule(() =>
|
||||
import("../channels/plugins/index.js").then((module) => module.getChannelPlugin),
|
||||
);
|
||||
|
||||
type ResolvedAttachmentDelivery = {
|
||||
parseMode?: "HTML";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createLazyRuntimeModule } from "../../../shared/lazy-runtime.js";
|
||||
// PTY adapter wraps pseudo-terminal processes for the process supervisor.
|
||||
import { signalProcessTree } from "../../kill-tree.js";
|
||||
import { prepareOomScoreAdjustedSpawn } from "../../linux-oom-score.js";
|
||||
@@ -36,12 +37,9 @@ type PtyModule = {
|
||||
|
||||
export type PtyAdapter = SpawnProcessAdapter;
|
||||
|
||||
let ptyModulePromise: Promise<PtyModule> | null = null;
|
||||
|
||||
async function loadPtyModule(): Promise<PtyModule> {
|
||||
ptyModulePromise ??= import("@lydell/node-pty") as Promise<unknown> as Promise<PtyModule>;
|
||||
return ptyModulePromise;
|
||||
}
|
||||
const loadPtyModule = createLazyRuntimeModule(
|
||||
() => import("@lydell/node-pty") as Promise<unknown> as Promise<PtyModule>,
|
||||
);
|
||||
|
||||
export async function createPtyAdapter(params: {
|
||||
shell: string;
|
||||
|
||||
@@ -3,6 +3,7 @@ import crypto from "node:crypto";
|
||||
import { performance } from "node:perf_hooks";
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { getShellConfig } from "../../agents/shell-utils.js";
|
||||
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
|
||||
import { createChildAdapter } from "./adapters/child.js";
|
||||
import { createPtyAdapter } from "./adapters/pty.js";
|
||||
import { createRunRegistry } from "./registry.js";
|
||||
@@ -15,8 +16,6 @@ import type {
|
||||
TerminationReason,
|
||||
} from "./types.js";
|
||||
|
||||
type SupervisorLogRuntime = typeof import("./supervisor-log.runtime.js");
|
||||
|
||||
type ActiveRun = {
|
||||
run: ManagedRun;
|
||||
scopeKey?: string;
|
||||
@@ -25,12 +24,9 @@ type ActiveRun = {
|
||||
const GRACEFUL_CANCEL_TIMEOUT_MS = 5000;
|
||||
const DEFAULT_MAX_CAPTURED_OUTPUT_CHARS = 1024 * 1024;
|
||||
|
||||
let supervisorLogRuntimePromise: Promise<SupervisorLogRuntime> | undefined;
|
||||
|
||||
function loadSupervisorLogRuntime(): Promise<SupervisorLogRuntime> {
|
||||
supervisorLogRuntimePromise ??= import("./supervisor-log.runtime.js");
|
||||
return supervisorLogRuntimePromise;
|
||||
}
|
||||
const loadSupervisorLogRuntime = createLazyRuntimeModule(
|
||||
() => import("./supervisor-log.runtime.js"),
|
||||
);
|
||||
|
||||
function clampTimeout(value?: number): number | undefined {
|
||||
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
||||
|
||||
+7
-11
@@ -12,6 +12,7 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
|
||||
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
|
||||
import type { PluginOrigin } from "../plugins/plugin-origin.types.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import {
|
||||
canUseSecretsRuntimeFastPath,
|
||||
@@ -41,18 +42,13 @@ export type { PreparedSecretsRuntimeSnapshot } from "./runtime-state.js";
|
||||
|
||||
registerSecretsRuntimeStateClearHook(clearRuntimeAuthProfileStoreSnapshots);
|
||||
|
||||
let runtimeManifestPromise: Promise<typeof import("./runtime-manifest.runtime.js")> | null = null;
|
||||
let runtimePreparePromise: Promise<typeof import("./runtime-prepare.runtime.js")> | null = null;
|
||||
const loadRuntimeManifestHelpers = createLazyRuntimeModule(
|
||||
() => import("./runtime-manifest.runtime.js"),
|
||||
);
|
||||
|
||||
function loadRuntimeManifestHelpers() {
|
||||
runtimeManifestPromise ??= import("./runtime-manifest.runtime.js");
|
||||
return runtimeManifestPromise;
|
||||
}
|
||||
|
||||
function loadRuntimePrepareHelpers() {
|
||||
runtimePreparePromise ??= import("./runtime-prepare.runtime.js");
|
||||
return runtimePreparePromise;
|
||||
}
|
||||
const loadRuntimePrepareHelpers = createLazyRuntimeModule(
|
||||
() => import("./runtime-prepare.runtime.js"),
|
||||
);
|
||||
|
||||
async function resolveLoadablePluginOrigins(params: {
|
||||
config: OpenClawConfig;
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
// Audits code paths for deep safety risks that require manual review.
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import type { SecurityAuditFinding } from "./audit.types.js";
|
||||
|
||||
let auditDeepModulePromise: Promise<typeof import("./audit.deep.runtime.js")> | undefined;
|
||||
|
||||
/** Lazily load deep audit code paths so normal audits avoid plugin/skill scans. */
|
||||
async function loadAuditDeepModule() {
|
||||
auditDeepModulePromise ??= import("./audit.deep.runtime.js");
|
||||
return await auditDeepModulePromise;
|
||||
}
|
||||
const loadAuditDeepModule = createLazyRuntimeModule(() => import("./audit.deep.runtime.js"));
|
||||
|
||||
/** Collect plugin and installed-skill code safety findings when deep audit is enabled. */
|
||||
export async function collectDeepCodeSafetyFindings(params: {
|
||||
|
||||
@@ -22,6 +22,7 @@ import type { OpenClawConfig, ConfigFileSnapshot } from "../config/config.js";
|
||||
import { collectIncludePathsRecursive } from "../config/includes-scan.js";
|
||||
import { resolveOAuthDir } from "../config/paths.js";
|
||||
import { normalizeAgentId } from "../routing/session-key.js";
|
||||
import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "../shared/lazy-runtime.js";
|
||||
import type { SkillScanFinding } from "../skills/security/scanner.js";
|
||||
import { shouldIgnoreInstalledPluginDirName } from "./installed-plugin-dirs.js";
|
||||
import { extensionUsesSkippedScannerPath, isPathInside } from "./scan-paths.js";
|
||||
@@ -49,73 +50,42 @@ type ExecDockerRawFn = (
|
||||
const DEFAULT_SANDBOX_BROWSER_DOCKER_PROBE_TIMEOUT_MS = 5000;
|
||||
|
||||
type CodeSafetySummaryCache = Map<string, Promise<unknown>>;
|
||||
let skillsModulePromise: Promise<typeof import("../skills/loading/workspace.js")> | undefined;
|
||||
let configModulePromise: Promise<typeof import("../config/config.js")> | undefined;
|
||||
let agentScopeModulePromise: Promise<typeof import("../agents/agent-scope.js")> | undefined;
|
||||
let agentWorkspaceDirsModulePromise:
|
||||
| Promise<typeof import("../agents/workspace-dirs.js")>
|
||||
| undefined;
|
||||
let skillSourceModulePromise: Promise<typeof import("../skills/loading/source.js")> | undefined;
|
||||
let sandboxDockerModulePromise: Promise<typeof import("../agents/sandbox/docker.js")> | undefined;
|
||||
let sandboxConstantsModulePromise:
|
||||
| Promise<typeof import("../agents/sandbox/constants.js")>
|
||||
| undefined;
|
||||
let auditPluginsTrustModulePromise: Promise<typeof import("./audit-plugins-trust.js")> | undefined;
|
||||
let auditFsModulePromise: Promise<typeof import("./audit-fs.js")> | undefined;
|
||||
let skillScannerModulePromise: Promise<typeof import("../skills/security/scanner.js")> | undefined;
|
||||
const loadSkillsModule = createLazyRuntimeModule(() => import("../skills/loading/workspace.js"));
|
||||
|
||||
function loadSkillsModule() {
|
||||
skillsModulePromise ??= import("../skills/loading/workspace.js");
|
||||
return skillsModulePromise;
|
||||
}
|
||||
const loadConfigModule = createLazyRuntimeModule(() => import("../config/config.js"));
|
||||
|
||||
function loadConfigModule() {
|
||||
configModulePromise ??= import("../config/config.js");
|
||||
return configModulePromise;
|
||||
}
|
||||
const loadAuditFsModule = createLazyRuntimeModule(() => import("./audit-fs.js"));
|
||||
|
||||
function loadAuditFsModule() {
|
||||
auditFsModulePromise ??= import("./audit-fs.js");
|
||||
return auditFsModulePromise;
|
||||
}
|
||||
const loadAgentScopeModule = createLazyRuntimeModule(() => import("../agents/agent-scope.js"));
|
||||
|
||||
function loadAgentScopeModule() {
|
||||
agentScopeModulePromise ??= import("../agents/agent-scope.js");
|
||||
return agentScopeModulePromise;
|
||||
}
|
||||
const loadAgentWorkspaceDirsModule = createLazyRuntimeModule(
|
||||
() => import("../agents/workspace-dirs.js"),
|
||||
);
|
||||
|
||||
function loadAgentWorkspaceDirsModule() {
|
||||
agentWorkspaceDirsModulePromise ??= import("../agents/workspace-dirs.js");
|
||||
return agentWorkspaceDirsModulePromise;
|
||||
}
|
||||
const loadSkillSourceModule = createLazyRuntimeModule(() => import("../skills/loading/source.js"));
|
||||
|
||||
function loadSkillSourceModule() {
|
||||
skillSourceModulePromise ??= import("../skills/loading/source.js");
|
||||
return skillSourceModulePromise;
|
||||
}
|
||||
const loadSkillScannerModule = createLazyRuntimeModule(
|
||||
() => import("../skills/security/scanner.js"),
|
||||
);
|
||||
|
||||
function loadSkillScannerModule() {
|
||||
skillScannerModulePromise ??= import("../skills/security/scanner.js");
|
||||
return skillScannerModulePromise;
|
||||
}
|
||||
const loadExecDockerRaw = createLazyRuntimeNamedExport(
|
||||
() => import("../agents/sandbox/docker.js"),
|
||||
"execDockerRaw",
|
||||
) satisfies () => Promise<ExecDockerRawFn>;
|
||||
|
||||
async function loadExecDockerRaw(): Promise<ExecDockerRawFn> {
|
||||
sandboxDockerModulePromise ??= import("../agents/sandbox/docker.js");
|
||||
const { execDockerRaw } = await sandboxDockerModulePromise;
|
||||
return execDockerRaw;
|
||||
}
|
||||
const loadSandboxBrowserSecurityHashEpoch = createLazyRuntimeNamedExport(
|
||||
() => import("../agents/sandbox/constants.js"),
|
||||
"SANDBOX_BROWSER_SECURITY_HASH_EPOCH",
|
||||
);
|
||||
|
||||
async function loadSandboxBrowserSecurityHashEpoch(): Promise<string> {
|
||||
sandboxConstantsModulePromise ??= import("../agents/sandbox/constants.js");
|
||||
const { SANDBOX_BROWSER_SECURITY_HASH_EPOCH } = await sandboxConstantsModulePromise;
|
||||
return SANDBOX_BROWSER_SECURITY_HASH_EPOCH;
|
||||
}
|
||||
const loadAuditPluginsTrustModule = createLazyRuntimeModule(
|
||||
() => import("./audit-plugins-trust.js"),
|
||||
);
|
||||
|
||||
export async function collectPluginsTrustFindings(
|
||||
params: CollectPluginsTrustFindingsParams,
|
||||
): Promise<SecurityAuditFinding[]> {
|
||||
auditPluginsTrustModulePromise ??= import("./audit-plugins-trust.js");
|
||||
const { collectPluginsTrustFindings: collect } = await auditPluginsTrustModulePromise;
|
||||
const { collectPluginsTrustFindings: collect } = await loadAuditPluginsTrustModule();
|
||||
return await collect(params);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
createPluginRegistryIdNormalizer,
|
||||
loadPluginRegistrySnapshot,
|
||||
} from "../plugins/plugin-registry.js";
|
||||
import { createLazyPromise } from "../shared/lazy-runtime.js";
|
||||
import type { SecurityAuditFinding } from "./audit.types.js";
|
||||
import { shouldIgnoreInstalledPluginDirName } from "./installed-plugin-dirs.js";
|
||||
|
||||
@@ -28,25 +29,24 @@ type PluginTrustPolicyDeps = {
|
||||
resolveToolProfilePolicy: typeof import("../agents/tool-policy.js").resolveToolProfilePolicy;
|
||||
};
|
||||
|
||||
let pluginTrustPolicyDepsPromise: Promise<PluginTrustPolicyDeps> | undefined;
|
||||
|
||||
/** Lazily load tool-policy helpers so basic security imports avoid agent policy modules. */
|
||||
async function loadPluginTrustPolicyDeps(): Promise<PluginTrustPolicyDeps> {
|
||||
pluginTrustPolicyDepsPromise ??= Promise.all([
|
||||
import("../agents/sandbox/config.js"),
|
||||
import("../agents/sandbox/tool-policy.js"),
|
||||
import("../agents/tool-policy-match.js"),
|
||||
import("../agents/tool-policy.js"),
|
||||
import("../agents/sandbox-tool-policy.js"),
|
||||
]).then(([sandboxConfig, sandboxToolPolicy, toolPolicyMatch, toolPolicy, auditToolPolicy]) => ({
|
||||
isToolAllowedByPolicies: toolPolicyMatch.isToolAllowedByPolicies,
|
||||
pickSandboxToolPolicy: auditToolPolicy.pickSandboxToolPolicy,
|
||||
resolveSandboxConfigForAgent: sandboxConfig.resolveSandboxConfigForAgent,
|
||||
resolveSandboxToolPolicyForAgent: sandboxToolPolicy.resolveSandboxToolPolicyForAgent,
|
||||
resolveToolProfilePolicy: toolPolicy.resolveToolProfilePolicy,
|
||||
}));
|
||||
return await pluginTrustPolicyDepsPromise;
|
||||
}
|
||||
const loadPluginTrustPolicyDeps = createLazyPromise(
|
||||
() =>
|
||||
Promise.all([
|
||||
import("../agents/sandbox/config.js"),
|
||||
import("../agents/sandbox/tool-policy.js"),
|
||||
import("../agents/tool-policy-match.js"),
|
||||
import("../agents/tool-policy.js"),
|
||||
import("../agents/sandbox-tool-policy.js"),
|
||||
]).then(([sandboxConfig, sandboxToolPolicy, toolPolicyMatch, toolPolicy, auditToolPolicy]) => ({
|
||||
isToolAllowedByPolicies: toolPolicyMatch.isToolAllowedByPolicies,
|
||||
pickSandboxToolPolicy: auditToolPolicy.pickSandboxToolPolicy,
|
||||
resolveSandboxConfigForAgent: sandboxConfig.resolveSandboxConfigForAgent,
|
||||
resolveSandboxToolPolicyForAgent: sandboxToolPolicy.resolveSandboxToolPolicyForAgent,
|
||||
resolveToolProfilePolicy: toolPolicy.resolveToolProfilePolicy,
|
||||
})),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
|
||||
function readChannelCommandSetting(
|
||||
cfg: OpenClawConfig,
|
||||
|
||||
+22
-60
@@ -40,6 +40,7 @@ import {
|
||||
} from "../infra/exec-safe-bin-runtime-policy.js";
|
||||
import { listRiskyConfiguredSafeBins } from "../infra/exec-safe-bin-semantics.js";
|
||||
import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { collectDeepCodeSafetyFindings } from "./audit-deep-code-safety.js";
|
||||
import { collectDeepProbeFindings } from "./audit-deep-probe-findings.js";
|
||||
import {
|
||||
@@ -147,70 +148,32 @@ export type AuditExecutionContext = {
|
||||
workspaceDir?: string;
|
||||
};
|
||||
|
||||
let readOnlyChannelPluginsModulePromise:
|
||||
| Promise<typeof import("../channels/plugins/read-only.js")>
|
||||
| undefined;
|
||||
let auditNonDeepModulePromise: Promise<typeof import("./audit.nondeep.runtime.js")> | undefined;
|
||||
let auditChannelModulePromise:
|
||||
| Promise<typeof import("./audit-channel.collect.runtime.js")>
|
||||
| undefined;
|
||||
let pluginMetadataRegistryLoaderModulePromise:
|
||||
| Promise<typeof import("../plugins/runtime/metadata-registry-loader.js")>
|
||||
| undefined;
|
||||
let pluginAutoEnableModulePromise:
|
||||
| Promise<typeof import("../config/plugin-auto-enable.js")>
|
||||
| undefined;
|
||||
let channelPluginIdsModulePromise:
|
||||
| Promise<typeof import("../plugins/channel-plugin-ids.js")>
|
||||
| undefined;
|
||||
let pluginRuntimeModulePromise: Promise<typeof import("../plugins/runtime.js")> | undefined;
|
||||
let gatewayProbeDepsPromise:
|
||||
| Promise<{
|
||||
buildGatewayConnectionDetails: typeof import("../gateway/call.js").buildGatewayConnectionDetails;
|
||||
resolveGatewayProbeAuthSafe: typeof import("../gateway/probe-auth.js").resolveGatewayProbeAuthSafe;
|
||||
resolveGatewayProbeTarget: typeof import("../gateway/probe-auth.js").resolveGatewayProbeTarget;
|
||||
probeGateway: typeof import("../gateway/probe.js").probeGateway;
|
||||
}>
|
||||
| undefined;
|
||||
const loadReadOnlyChannelPlugins = createLazyRuntimeModule(
|
||||
() => import("../channels/plugins/read-only.js"),
|
||||
);
|
||||
|
||||
async function loadReadOnlyChannelPlugins() {
|
||||
readOnlyChannelPluginsModulePromise ??= import("../channels/plugins/read-only.js");
|
||||
return await readOnlyChannelPluginsModulePromise;
|
||||
}
|
||||
const loadAuditNonDeepModule = createLazyRuntimeModule(() => import("./audit.nondeep.runtime.js"));
|
||||
|
||||
async function loadAuditNonDeepModule() {
|
||||
auditNonDeepModulePromise ??= import("./audit.nondeep.runtime.js");
|
||||
return await auditNonDeepModulePromise;
|
||||
}
|
||||
const loadAuditChannelModule = createLazyRuntimeModule(
|
||||
() => import("./audit-channel.collect.runtime.js"),
|
||||
);
|
||||
|
||||
async function loadAuditChannelModule() {
|
||||
auditChannelModulePromise ??= import("./audit-channel.collect.runtime.js");
|
||||
return await auditChannelModulePromise;
|
||||
}
|
||||
const loadPluginMetadataRegistryLoaderModule = createLazyRuntimeModule(
|
||||
() => import("../plugins/runtime/metadata-registry-loader.js"),
|
||||
);
|
||||
|
||||
async function loadPluginMetadataRegistryLoaderModule() {
|
||||
pluginMetadataRegistryLoaderModulePromise ??=
|
||||
import("../plugins/runtime/metadata-registry-loader.js");
|
||||
return await pluginMetadataRegistryLoaderModulePromise;
|
||||
}
|
||||
const loadPluginAutoEnableModule = createLazyRuntimeModule(
|
||||
() => import("../config/plugin-auto-enable.js"),
|
||||
);
|
||||
|
||||
async function loadPluginAutoEnableModule() {
|
||||
pluginAutoEnableModulePromise ??= import("../config/plugin-auto-enable.js");
|
||||
return await pluginAutoEnableModulePromise;
|
||||
}
|
||||
const loadChannelPluginIdsModule = createLazyRuntimeModule(
|
||||
() => import("../plugins/channel-plugin-ids.js"),
|
||||
);
|
||||
|
||||
async function loadChannelPluginIdsModule() {
|
||||
channelPluginIdsModulePromise ??= import("../plugins/channel-plugin-ids.js");
|
||||
return await channelPluginIdsModulePromise;
|
||||
}
|
||||
const loadPluginRuntimeModule = createLazyRuntimeModule(() => import("../plugins/runtime.js"));
|
||||
|
||||
async function loadPluginRuntimeModule() {
|
||||
pluginRuntimeModulePromise ??= import("../plugins/runtime.js");
|
||||
return await pluginRuntimeModulePromise;
|
||||
}
|
||||
|
||||
async function loadGatewayProbeDeps() {
|
||||
gatewayProbeDepsPromise ??= Promise.all([
|
||||
const loadGatewayProbeDeps = createLazyRuntimeModule(() =>
|
||||
Promise.all([
|
||||
import("../gateway/call.js"),
|
||||
import("../gateway/probe-auth.js"),
|
||||
import("../gateway/probe.js"),
|
||||
@@ -219,9 +182,8 @@ async function loadGatewayProbeDeps() {
|
||||
resolveGatewayProbeAuthSafe: probeAuthModule.resolveGatewayProbeAuthSafe,
|
||||
resolveGatewayProbeTarget: probeAuthModule.resolveGatewayProbeTarget,
|
||||
probeGateway: probeModule.probeGateway,
|
||||
}));
|
||||
return await gatewayProbeDepsPromise;
|
||||
}
|
||||
})),
|
||||
);
|
||||
|
||||
function countBySeverity(findings: SecurityAuditFinding[]): SecurityAuditSummary {
|
||||
let critical = 0;
|
||||
|
||||
+16
-44
@@ -40,6 +40,7 @@ import {
|
||||
} from "../infra/provider-usage.js";
|
||||
import { normalizeAccountId } from "../routing/account-id.js";
|
||||
import { resolveNormalizedAccountEntry } from "../routing/account-lookup.js";
|
||||
import { createLazyPromise, createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import {
|
||||
listTasksForAgentIdForStatus,
|
||||
listTasksForSessionKeyForStatus,
|
||||
@@ -98,52 +99,23 @@ function resolveStatusChannelFeatureLine(params: {
|
||||
: "Telegram rich messages: off · set channels.telegram.richMessages=true for tables/details/rich media";
|
||||
}
|
||||
|
||||
let statusMessageRuntimePromise: Promise<typeof import("../auto-reply/status.runtime.js")> | null =
|
||||
null;
|
||||
let agentHarnessSelectionRuntimePromise: Promise<
|
||||
typeof import("../agents/harness/selection.js")
|
||||
> | null = null;
|
||||
let statusQueueRuntimePromise: Promise<typeof import("./status-queue.runtime.js")> | null = null;
|
||||
let statusSubagentsRuntimePromise: Promise<typeof import("./status-subagents.runtime.js")> | null =
|
||||
null;
|
||||
let statusPluginHealthRuntimePromise: Promise<
|
||||
typeof import("./status-plugin-health.runtime.js")
|
||||
> | null = null;
|
||||
const loadStatusMessageRuntime = createLazyPromise(
|
||||
() =>
|
||||
import("./status-message.runtime.js").then((module) => module.loadStatusMessageRuntimeModule()),
|
||||
{ cacheRejections: true },
|
||||
);
|
||||
const loadAgentHarnessSelectionRuntime = createLazyRuntimeModule(
|
||||
() => import("../agents/harness/selection.js"),
|
||||
);
|
||||
const loadStatusSubagentsRuntime = createLazyRuntimeModule(
|
||||
() => import("./status-subagents.runtime.js"),
|
||||
);
|
||||
|
||||
function loadStatusMessageRuntime(): Promise<typeof import("../auto-reply/status.runtime.js")> {
|
||||
const runtimePromise = (statusMessageRuntimePromise ??=
|
||||
import("./status-message.runtime.js").then((module) =>
|
||||
module.loadStatusMessageRuntimeModule(),
|
||||
));
|
||||
return runtimePromise;
|
||||
}
|
||||
const loadStatusQueueRuntime = createLazyRuntimeModule(() => import("./status-queue.runtime.js"));
|
||||
|
||||
function loadAgentHarnessSelectionRuntime(): Promise<
|
||||
typeof import("../agents/harness/selection.js")
|
||||
> {
|
||||
const runtimePromise = (agentHarnessSelectionRuntimePromise ??=
|
||||
import("../agents/harness/selection.js"));
|
||||
return runtimePromise;
|
||||
}
|
||||
|
||||
function loadStatusSubagentsRuntime(): Promise<typeof import("./status-subagents.runtime.js")> {
|
||||
const runtimePromise = (statusSubagentsRuntimePromise ??=
|
||||
import("./status-subagents.runtime.js"));
|
||||
return runtimePromise;
|
||||
}
|
||||
|
||||
function loadStatusQueueRuntime(): Promise<typeof import("./status-queue.runtime.js")> {
|
||||
const runtimePromise = (statusQueueRuntimePromise ??= import("./status-queue.runtime.js"));
|
||||
return runtimePromise;
|
||||
}
|
||||
|
||||
function loadStatusPluginHealthRuntime(): Promise<
|
||||
typeof import("./status-plugin-health.runtime.js")
|
||||
> {
|
||||
const runtimePromise = (statusPluginHealthRuntimePromise ??=
|
||||
import("./status-plugin-health.runtime.js"));
|
||||
return runtimePromise;
|
||||
}
|
||||
const loadStatusPluginHealthRuntime = createLazyRuntimeModule(
|
||||
() => import("./status-plugin-health.runtime.js"),
|
||||
);
|
||||
|
||||
// Context lookup stays synchronous/non-refreshing so status output does not
|
||||
// trigger provider/catalog IO while rendering a command response.
|
||||
|
||||
@@ -37,6 +37,7 @@ import { ensureControlUiAssetsBuilt } from "../infra/control-ui-assets.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { formatWindowsGatewayFirewallGuidance } from "../infra/windows-gateway-firewall-diagnostics.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { launchTuiCli } from "../tui/tui-launch.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { listConfiguredWebSearchProviders } from "../web-search/runtime.js";
|
||||
@@ -58,9 +59,6 @@ type FinalizeOnboardingOptions = {
|
||||
runtime: RuntimeEnv;
|
||||
};
|
||||
|
||||
type OnboardSearchModule = typeof import("../commands/onboard-search.js");
|
||||
|
||||
let onboardSearchModulePromise: Promise<OnboardSearchModule> | undefined;
|
||||
const HATCH_TUI_TIMEOUT_MS = 5 * 60 * 1000;
|
||||
|
||||
function buildSessionGatewayAuthOverride(params: {
|
||||
@@ -186,10 +184,9 @@ function getLocalizedGatewayDaemonRuntimeOptions() {
|
||||
}));
|
||||
}
|
||||
|
||||
function loadOnboardSearchModule(): Promise<OnboardSearchModule> {
|
||||
onboardSearchModulePromise ??= import("../commands/onboard-search.js");
|
||||
return onboardSearchModulePromise;
|
||||
}
|
||||
const loadOnboardSearchModule = createLazyRuntimeModule(
|
||||
() => import("../commands/onboard-search.js"),
|
||||
);
|
||||
|
||||
export async function finalizeSetupWizard(
|
||||
options: FinalizeOnboardingOptions,
|
||||
|
||||
@@ -25,6 +25,7 @@ import type {
|
||||
MigrationProviderPlugin,
|
||||
} from "../plugins/types.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { t } from "./i18n/index.js";
|
||||
import { WizardCancelledError, type WizardPrompter } from "./prompts.js";
|
||||
@@ -68,27 +69,15 @@ const MEANINGFUL_WORKSPACE_ENTRIES = [
|
||||
] as const;
|
||||
const MEANINGFUL_STATE_ENTRIES = ["credentials", "sessions", "agents"] as const;
|
||||
|
||||
let migrationProviderRuntimeModulePromise: Promise<
|
||||
typeof import("../plugins/migration-provider-runtime.js")
|
||||
> | null = null;
|
||||
let migrationContextModulePromise: Promise<typeof import("../commands/migrate/context.js")> | null =
|
||||
null;
|
||||
let configPathsModulePromise: Promise<typeof import("../config/paths.js")> | null = null;
|
||||
const loadMigrationProviderRuntimeModule = createLazyRuntimeModule(
|
||||
() => import("../plugins/migration-provider-runtime.js"),
|
||||
);
|
||||
|
||||
const loadMigrationProviderRuntimeModule = async () => {
|
||||
migrationProviderRuntimeModulePromise ??= import("../plugins/migration-provider-runtime.js");
|
||||
return await migrationProviderRuntimeModulePromise;
|
||||
};
|
||||
const loadMigrationContextModule = createLazyRuntimeModule(
|
||||
() => import("../commands/migrate/context.js"),
|
||||
);
|
||||
|
||||
const loadMigrationContextModule = async () => {
|
||||
migrationContextModulePromise ??= import("../commands/migrate/context.js");
|
||||
return await migrationContextModulePromise;
|
||||
};
|
||||
|
||||
const loadConfigPathsModule = async () => {
|
||||
configPathsModulePromise ??= import("../config/paths.js");
|
||||
return await configPathsModulePromise;
|
||||
};
|
||||
const loadConfigPathsModule = createLazyRuntimeModule(() => import("../config/paths.js"));
|
||||
|
||||
async function exists(candidate: string): Promise<boolean> {
|
||||
try {
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
|
||||
import type { PluginConfigUiHint } from "../plugins/types.js";
|
||||
import { getPath, setPathCreateStrict } from "../secrets/path-utils.js";
|
||||
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { t } from "./i18n/index.js";
|
||||
import type { WizardPrompter } from "./prompts.js";
|
||||
|
||||
@@ -20,14 +21,9 @@ export type ConfigurablePlugin = {
|
||||
jsonSchema?: JsonSchemaObject;
|
||||
};
|
||||
|
||||
type PluginMetadataSnapshotModule = typeof import("../plugins/plugin-metadata-snapshot.js");
|
||||
|
||||
let pluginMetadataSnapshotModulePromise: Promise<PluginMetadataSnapshotModule> | undefined;
|
||||
|
||||
function loadPluginMetadataSnapshotModule(): Promise<PluginMetadataSnapshotModule> {
|
||||
pluginMetadataSnapshotModulePromise ??= import("../plugins/plugin-metadata-snapshot.js");
|
||||
return pluginMetadataSnapshotModulePromise;
|
||||
}
|
||||
const loadPluginMetadataSnapshotModule = createLazyRuntimeModule(
|
||||
() => import("../plugins/plugin-metadata-snapshot.js"),
|
||||
);
|
||||
|
||||
type JsonSchemaProperty = {
|
||||
type?: string;
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "../plugin-sdk/migration.js";
|
||||
import type { MigrationProviderPlugin } from "../plugins/types.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import type { WizardPrompter } from "./prompts.js";
|
||||
|
||||
export type PostInstallMigrationOptions = {
|
||||
@@ -34,19 +35,11 @@ type ResolvedProviderCandidate = {
|
||||
source?: string;
|
||||
};
|
||||
|
||||
let migrationContextModulePromise: Promise<typeof import("../commands/migrate/context.js")> | null =
|
||||
null;
|
||||
let configPathsModulePromise: Promise<typeof import("../config/paths.js")> | null = null;
|
||||
const loadMigrationContextModule = createLazyRuntimeModule(
|
||||
() => import("../commands/migrate/context.js"),
|
||||
);
|
||||
|
||||
const loadMigrationContextModule = async () => {
|
||||
migrationContextModulePromise ??= import("../commands/migrate/context.js");
|
||||
return await migrationContextModulePromise;
|
||||
};
|
||||
|
||||
const loadConfigPathsModule = async () => {
|
||||
configPathsModulePromise ??= import("../config/paths.js");
|
||||
return await configPathsModulePromise;
|
||||
};
|
||||
const loadConfigPathsModule = createLazyRuntimeModule(() => import("../config/paths.js"));
|
||||
|
||||
async function resolveCandidates(params: {
|
||||
config: OpenClawConfig;
|
||||
|
||||
+7
-25
@@ -24,6 +24,7 @@ import {
|
||||
} from "../plugins/status.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { t } from "./i18n/index.js";
|
||||
import { runWizardWithPromptNavigation } from "./navigation-prompter.js";
|
||||
@@ -43,37 +44,18 @@ import type { QuickstartGatewayDefaults, WizardFlow } from "./setup.types.js";
|
||||
|
||||
type SetupFlowChoice = WizardFlow | "import" | "keep-model" | `import:${string}`;
|
||||
|
||||
type AuthChoiceModule = typeof import("../commands/auth-choice.js");
|
||||
type ConfigLoggingModule = typeof import("../config/logging.js");
|
||||
type ModelPickerModule = typeof import("../commands/model-picker.js");
|
||||
type OnboardConfigModule = typeof import("../commands/onboard-config.js");
|
||||
type KeepCurrentAuthChoice =
|
||||
typeof import("../commands/auth-choice-prompt.js").KEEP_CURRENT_AUTH_CHOICE;
|
||||
|
||||
let authChoiceModulePromise: Promise<AuthChoiceModule> | undefined;
|
||||
let configLoggingModulePromise: Promise<ConfigLoggingModule> | undefined;
|
||||
let modelPickerModulePromise: Promise<ModelPickerModule> | undefined;
|
||||
let onboardConfigModulePromise: Promise<OnboardConfigModule> | undefined;
|
||||
const loadAuthChoiceModule = createLazyRuntimeModule(() => import("../commands/auth-choice.js"));
|
||||
|
||||
function loadAuthChoiceModule(): Promise<AuthChoiceModule> {
|
||||
authChoiceModulePromise ??= import("../commands/auth-choice.js");
|
||||
return authChoiceModulePromise;
|
||||
}
|
||||
const loadConfigLoggingModule = createLazyRuntimeModule(() => import("../config/logging.js"));
|
||||
|
||||
function loadConfigLoggingModule(): Promise<ConfigLoggingModule> {
|
||||
configLoggingModulePromise ??= import("../config/logging.js");
|
||||
return configLoggingModulePromise;
|
||||
}
|
||||
const loadModelPickerModule = createLazyRuntimeModule(() => import("../commands/model-picker.js"));
|
||||
|
||||
function loadModelPickerModule(): Promise<ModelPickerModule> {
|
||||
modelPickerModulePromise ??= import("../commands/model-picker.js");
|
||||
return modelPickerModulePromise;
|
||||
}
|
||||
|
||||
function loadOnboardConfigModule(): Promise<OnboardConfigModule> {
|
||||
onboardConfigModulePromise ??= import("../commands/onboard-config.js");
|
||||
return onboardConfigModulePromise;
|
||||
}
|
||||
const loadOnboardConfigModule = createLazyRuntimeModule(
|
||||
() => import("../commands/onboard-config.js"),
|
||||
);
|
||||
|
||||
async function writeWizardConfigFile(
|
||||
configInput: OpenClawConfig,
|
||||
|
||||
Reference in New Issue
Block a user