UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

218 lines (217 loc) • 10.1 kB
import { o as resolveUserPath } from "./home-dir-CjKH62jd.mjs"; import "./utils-DUAwk2p5.mjs"; import { t as formatErrorMessage } from "./errors-BSdPMFao.mjs"; import { d as resolveAgentWorkspaceDir } from "./agent-scope-config-BU4qc9bA.mjs"; import { l as normalizePluginsConfig } from "./config-state-1t-kMQI9.mjs"; import "./agent-scope-DWB4x52T.mjs"; import { a as getPluginValueInstance, u as runPluginCleanup } from "./plugin-instance-scope-C4zdRFkI.mjs"; import { et as withPluginHostCleanupTimeout } from "./runtime-zG-NbNbr.mjs"; import { r as loadPluginRegistryHandle } from "./loader-DPiNpDHK.mjs"; import { _ as resolveMemoryCapabilityRegistration, b as setStandaloneMemoryManagerActive, o as getMemoryRuntime } from "./memory-state-BwoQoRPf.mjs"; //#region src/plugins/memory-runtime.ts const enrolledStandaloneMemoryRuntimes = /* @__PURE__ */ new WeakSet(); let standaloneMemoryRegistrySlot; const registeredMemoryManagerAdapters = /* @__PURE__ */ new WeakMap(); function normalizeRegisteredMemoryReadResult(result) { if (result.status === "ok" || result.status === "not_found") return result; return { ...result, status: "ok" }; } function normalizeRegisteredMemoryManager(manager) { const existing = registeredMemoryManagerAdapters.get(manager); if (existing) return existing; const readFile = async (params) => normalizeRegisteredMemoryReadResult(await manager.readFile(params)); const adapter = new Proxy({ readFile }, { get(_target, property) { if (property === "readFile") return readFile; const value = Reflect.get(manager, property, manager); if (typeof value !== "function") return value; return value.bind(manager); } }); registeredMemoryManagerAdapters.set(manager, adapter); return adapter; } /** Resolves the configured memory slot to the single runtime plugin that may load memory. */ function resolveMemoryRuntimePluginIds(config) { const plugins = normalizePluginsConfig(config.plugins); const memorySlot = plugins.slots.memory; if (!plugins.enabled || typeof memorySlot !== "string" || memorySlot.trim().length === 0) return []; const pluginId = memorySlot.trim(); if (plugins.deny.includes(pluginId) || plugins.entries[pluginId]?.enabled === false) return []; return [pluginId]; } function resolveMemoryRuntimeWorkspaceDir(cfg, agentId) { const dir = resolveAgentWorkspaceDir(cfg, agentId); if (typeof dir !== "string" || !dir.trim()) return; return resolveUserPath(dir); } function listCurrentMemoryRuntimes() { const runtimes = new Set(standaloneMemoryRegistrySlot?.retiredRuntimes); const current = getMemoryRuntime(); if (current) runtimes.add(current); if (standaloneMemoryRegistrySlot?.runtime) runtimes.add(standaloneMemoryRegistrySlot.runtime); return [...runtimes]; } function ensureMemoryRuntime(params) { const current = getMemoryRuntime(); if (current || !params) return current ? { runtime: current, searchRuntimeRegistered: true } : void 0; const onlyPluginIds = resolveMemoryRuntimePluginIds(params.cfg); if (onlyPluginIds.length === 0) return; const workspaceDir = resolveMemoryRuntimeWorkspaceDir(params.cfg, params.agentId); const registry = loadPluginRegistryHandle({ config: params.cfg, onlyPluginIds, workspaceDir, activate: false }); const runtime = resolveMemoryCapabilityRegistration(registry.memoryCapabilities)?.capability.runtime; const record = runtime ? void 0 : registry.plugins.find((entry) => entry.id === onlyPluginIds[0]); const owner = runtime ? { runtime, standalone: true, searchRuntimeRegistered: true } : record?.status === "error" ? { error: record.error ?? `Memory plugin "${record.id}" failed to load` } : record?.status === "loaded" && record.memorySlotSelected === true ? { searchRuntimeRegistered: false } : void 0; const previousSlot = standaloneMemoryRegistrySlot; if (previousSlot?.runtime === runtime) return owner; const retiredRuntimes = new Set(previousSlot?.retiredRuntimes); if (previousSlot?.runtime) retiredRuntimes.add(previousSlot.runtime); standaloneMemoryRegistrySlot = { runtime, retiredRuntimes }; if (runtime && !enrolledStandaloneMemoryRuntimes.has(runtime)) { const lifecycle = getPluginValueInstance(runtime)?.lifecycle; if (lifecycle) { lifecycle.onDispose(() => { const slot = standaloneMemoryRegistrySlot; slot?.retiredRuntimes.delete(runtime); if (slot?.runtime === runtime) delete slot.runtime; }); enrolledStandaloneMemoryRuntimes.add(runtime); } } return owner; } /** Returns the active plugin-backed memory search manager for an agent. */ async function getActiveMemorySearchManagerCore(params) { const owner = ensureMemoryRuntime(params); if (!owner?.runtime) return { manager: null, error: owner?.error ?? "memory plugin unavailable", searchRuntimeRegistered: owner?.searchRuntimeRegistered }; if (owner.standalone) setStandaloneMemoryManagerActive(true); const result = await owner.runtime.getMemorySearchManager(params); return { ...result, manager: result.manager ? normalizeRegisteredMemoryManager(result.manager) : null, searchRuntimeRegistered: true }; } /** Applies the selected memory plugin's authorization policy to raw search hits. */ async function authorizeActiveMemorySearchHits(params) { const owner = ensureMemoryRuntime(params); return owner?.runtime?.authorizeSearchHits ? await owner.runtime.authorizeSearchHits(params) : params.hits.filter((hit) => hit.source !== "sessions"); } /** Classifies workspace memory paths through the selected memory plugin's provenance owner. */ async function classifyActiveMemoryWorkspacePaths(params) { const owner = ensureMemoryRuntime(params); if (!owner?.runtime) return { status: "unavailable" }; if (!owner.runtime.classifyWorkspaceMemoryPaths || params.readSources !== void 0 && !owner.runtime.supportsWorkspaceMemoryReadSources) return { status: "unsupported" }; return { status: "classified", classifications: await owner.runtime.classifyWorkspaceMemoryPaths(params) }; } /** Resolves current memory backend config without constructing a manager. */ function resolveActiveMemoryBackendConfig(params) { const owner = ensureMemoryRuntime(params); return owner?.runtime ? owner.runtime.resolveMemoryBackendConfig(params) : null; } /** Closes all active plugin-backed memory search managers. */ async function closeActiveMemorySearchManagersCore(cfg) { await Promise.all(listCurrentMemoryRuntimes().map(async (runtime) => runPluginCleanup(runtime, () => runtime.closeAllMemorySearchManagers?.()))); standaloneMemoryRegistrySlot?.retiredRuntimes.clear(); setStandaloneMemoryManagerActive(false); } /** Closes the plugin-backed memory search manager for one agent. */ async function closeActiveMemorySearchManagerCore(params) { await Promise.all(listCurrentMemoryRuntimes().map(async (runtime) => runPluginCleanup(runtime, () => runtime.closeMemorySearchManager?.(params)))); } function resetStandaloneMemoryRegistrySlot() { standaloneMemoryRegistrySlot = void 0; setStandaloneMemoryManagerActive(false); } if (process.env.VITEST || false) globalThis[Symbol.for("openclaw.memoryRuntimeTestApi")] = { resetStandaloneMemoryRegistrySlot }; /** Prepare memory consumers before any changed plugin loses ordinary call admission. */ function prepareMemoryRuntimeReload(previousRegistry, nextRegistry) { const runtimes = (registry) => new Set(registry.memoryCapabilities.flatMap(({ capability }) => capability.runtime ? [capability.runtime] : [])); const nextRuntimes = runtimes(nextRegistry); const nextAdapters = new Set(nextRegistry.embeddingProviders.map(({ provider }) => provider)); const retiringEmbeddingProviders = previousRegistry.embeddingProviders.map(({ provider }) => provider).filter((provider) => !nextAdapters.has(provider)); const prepared = []; let cleanup; const resume = (committed, retained = nextRegistry) => { const failures = []; const retainedRuntimes = runtimes(retained); for (const { runtime, handle } of prepared) if (!committed || retainedRuntimes.has(runtime)) try { runPluginCleanup(runtime, () => handle.resume()); } catch (error) { failures.push(error); } if (failures.length) throw new AggregateError(failures, "Memory reload admission recovery failed"); }; try { for (const runtime of runtimes(previousRegistry)) { const retireRuntime = !nextRuntimes.has(runtime); if (!retireRuntime && retiringEmbeddingProviders.length === 0) continue; const handle = runPluginCleanup(runtime, () => { if (runtime.prepareReload) return runtime.prepareReload({ retireRuntime, retiringEmbeddingProviders }); if (runtime.closeAllMemorySearchManagers) return { drain: () => runtime.closeAllMemorySearchManagers(), resume() {} }; }); if (handle) prepared.push({ runtime, handle }); } } catch (error) { try { resume(false); } catch (cleanupError) { throw new AggregateError([error, cleanupError], "Memory reload preparation failed", { cause: cleanupError }); } throw error; } const close = () => { if (!cleanup) cleanup = Promise.allSettled(prepared.map(({ runtime, handle }) => Promise.resolve().then(() => runPluginCleanup(runtime, async () => { try { return await handle.drain(); } catch (error) { return { errors: [error] }; } })))).then((results) => { const failures = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []); if (failures.length) throw new AggregateError(failures, failures.map(formatErrorMessage).join("; ")); return { errors: results.flatMap((result) => result.status === "fulfilled" ? result.value?.errors ?? [] : []) }; }); return cleanup; }; return { drain: () => withPluginHostCleanupTimeout("memory managers", close), close, commit: (retained = nextRegistry) => resume(true, retained), rollback: () => resume(false) }; } //#endregion export { getActiveMemorySearchManagerCore as a, closeActiveMemorySearchManagersCore as i, classifyActiveMemoryWorkspacePaths as n, prepareMemoryRuntimeReload as o, closeActiveMemorySearchManagerCore as r, resolveActiveMemoryBackendConfig as s, authorizeActiveMemorySearchHits as t };