From b3a97df75466c89dbcef99d27fe74d8e90db71e4 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 18 Apr 2026 20:52:17 +0100 Subject: [PATCH] refactor: cache reply and visibility runtimes --- extensions/memory-core/src/memory/search-manager.ts | 8 +++++++- src/agents/tools/web-fetch-visibility.ts | 9 ++++++++- src/auto-reply/reply/commands-compact.ts | 9 ++++++++- src/auto-reply/reply/session-fork.ts | 8 +++++++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/extensions/memory-core/src/memory/search-manager.ts b/extensions/memory-core/src/memory/search-manager.ts index 23bf834678f..fc8d6ed7ed9 100644 --- a/extensions/memory-core/src/memory/search-manager.ts +++ b/extensions/memory-core/src/memory/search-manager.ts @@ -34,12 +34,18 @@ function getMemorySearchManagerCacheStore(): MemorySearchManagerCacheStore { const log = createSubsystemLogger("memory"); const { qmdManagerCache: QMD_MANAGER_CACHE } = getMemorySearchManagerCacheStore(); let managerRuntimePromise: Promise | null = null; +let qmdManagerModulePromise: Promise | null = null; function loadManagerRuntime() { managerRuntimePromise ??= import("../../manager-runtime.js"); return managerRuntimePromise; } +function loadQmdManagerModule() { + qmdManagerModulePromise ??= import("./qmd-manager.js"); + return qmdManagerModulePromise; +} + export type MemorySearchManagerResult = { manager: MemorySearchManager | null; error?: string; @@ -90,7 +96,7 @@ export async function getMemorySearchManager(params: { ); } else { try { - const { QmdMemoryManager } = await import("./qmd-manager.js"); + const { QmdMemoryManager } = await loadQmdManagerModule(); const primary = await QmdMemoryManager.create({ cfg: params.cfg, agentId: params.agentId, diff --git a/src/agents/tools/web-fetch-visibility.ts b/src/agents/tools/web-fetch-visibility.ts index 7c7aa30c849..70ce89bdfc9 100644 --- a/src/agents/tools/web-fetch-visibility.ts +++ b/src/agents/tools/web-fetch-visibility.ts @@ -26,6 +26,13 @@ const HIDDEN_CLASS_NAMES = new Set([ "offscreen", ]); +let parseHtmlPromise: Promise | null = null; + +async function loadParseHTML(): Promise { + parseHtmlPromise ??= import("linkedom").then(({ parseHTML }) => parseHTML); + return parseHtmlPromise; +} + function hasHiddenClass(className: string): boolean { const classes = normalizeLowercaseStringOrEmpty(className).split(/\s+/); return classes.some((cls) => HIDDEN_CLASS_NAMES.has(cls)); @@ -137,7 +144,7 @@ export async function sanitizeHtml(html: string): Promise { let document: Document; try { - const { parseHTML } = await import("linkedom"); + const parseHTML = await loadParseHTML(); ({ document } = parseHTML(sanitized) as { document: Document }); } catch { return sanitized; diff --git a/src/auto-reply/reply/commands-compact.ts b/src/auto-reply/reply/commands-compact.ts index 7ef32650c8e..b1a88017616 100644 --- a/src/auto-reply/reply/commands-compact.ts +++ b/src/auto-reply/reply/commands-compact.ts @@ -9,6 +9,13 @@ import { import type { CommandHandler } from "./commands-types.js"; import { stripMentions, stripStructuralPrefixes } from "./mentions.js"; +let compactRuntimePromise: Promise | null = null; + +function loadCompactRuntime(): Promise { + compactRuntimePromise ??= import("./commands-compact.runtime.js"); + return compactRuntimePromise; +} + function extractCompactInstructions(params: { rawBody?: string; ctx: import("../templating.js").MsgContext; @@ -88,7 +95,7 @@ export const handleCompactCommand: CommandHandler = async (params) => { reply: { text: "⚙️ Compaction unavailable (missing session id)." }, }; } - const runtime = await import("./commands-compact.runtime.js"); + const runtime = await loadCompactRuntime(); const sessionId = targetSessionEntry.sessionId; if (runtime.isEmbeddedPiRunActive(sessionId)) { runtime.abortEmbeddedPiRun(sessionId); diff --git a/src/auto-reply/reply/session-fork.ts b/src/auto-reply/reply/session-fork.ts index fafcd5dc6fe..1090c046456 100644 --- a/src/auto-reply/reply/session-fork.ts +++ b/src/auto-reply/reply/session-fork.ts @@ -7,6 +7,12 @@ import type { OpenClawConfig } from "../../config/types.openclaw.js"; * See #26905. */ const DEFAULT_PARENT_FORK_MAX_TOKENS = 100_000; +let sessionForkRuntimePromise: Promise | null = null; + +function loadSessionForkRuntime(): Promise { + sessionForkRuntimePromise ??= import("./session-fork.runtime.js"); + return sessionForkRuntimePromise; +} export function resolveParentForkMaxTokens(cfg: OpenClawConfig): number { const configured = cfg.session?.parentForkMaxTokens; @@ -21,6 +27,6 @@ export async function forkSessionFromParent(params: { agentId: string; sessionsDir: string; }): Promise<{ sessionId: string; sessionFile: string } | null> { - const runtime = await import("./session-fork.runtime.js"); + const runtime = await loadSessionForkRuntime(); return runtime.forkSessionFromParentRuntime(params); }