mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 19:35:28 -06:00
fix(cli): close standalone memory managers after commands (#118500)
This commit is contained in:
committed by
GitHub
parent
d7ab20a727
commit
133323875f
@@ -31,6 +31,7 @@ import {
|
||||
resolveActiveMemoryBackendConfig,
|
||||
} from "./memory-runtime.js";
|
||||
import { resetStandaloneMemoryRegistrySlot } from "./memory-runtime.test-support.js";
|
||||
import { hasMemoryRuntime } from "./memory-state.js";
|
||||
|
||||
function createRuntime() {
|
||||
return {
|
||||
@@ -95,6 +96,73 @@ describe("memory runtime handles", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("tracks standalone managers without activating config-only lookups and rearms reused handles", async () => {
|
||||
const { registry, runtime } = createRegistry();
|
||||
mocks.loadPluginRegistryHandle.mockReturnValue(registry);
|
||||
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
expect(resolveActiveMemoryBackendConfig({ cfg: memoryConfig, agentId: "main" })).toEqual({
|
||||
backend: "builtin",
|
||||
});
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
|
||||
await getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
await closeActiveMemorySearchManagers();
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
|
||||
await getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
expect(mocks.loadPluginRegistryHandle).toHaveBeenCalledTimes(1);
|
||||
|
||||
await closeActiveMemorySearchManagers();
|
||||
expect(runtime.closeAllMemorySearchManagers).toHaveBeenCalledTimes(2);
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
});
|
||||
|
||||
it("retains standalone ownership across workspace replacement and per-agent cleanup", async () => {
|
||||
const main = createRegistry();
|
||||
const research = createRegistry();
|
||||
mocks.loadPluginRegistryHandle
|
||||
.mockReturnValueOnce(main.registry)
|
||||
.mockReturnValueOnce(research.registry);
|
||||
|
||||
await getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
await getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "research" });
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
await closeActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
await closeActiveMemorySearchManagers();
|
||||
expect(main.runtime.closeAllMemorySearchManagers).toHaveBeenCalledTimes(1);
|
||||
expect(research.runtime.closeAllMemorySearchManagers).toHaveBeenCalledTimes(1);
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
});
|
||||
|
||||
it("retains standalone cleanup ownership when manager acquisition or teardown fails", async () => {
|
||||
const { registry, runtime } = createRegistry();
|
||||
mocks.loadPluginRegistryHandle.mockReturnValue(registry);
|
||||
runtime.getMemorySearchManager.mockRejectedValueOnce(
|
||||
new Error("manager initialization failed"),
|
||||
);
|
||||
|
||||
await expect(
|
||||
getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" }),
|
||||
).rejects.toThrow("manager initialization failed");
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
runtime.closeAllMemorySearchManagers.mockRejectedValueOnce(
|
||||
new Error("manager teardown failed"),
|
||||
);
|
||||
await expect(closeActiveMemorySearchManagers()).rejects.toThrow("manager teardown failed");
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
await closeActiveMemorySearchManagers();
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
});
|
||||
|
||||
it("keys the single slot by the requesting agent workspace", () => {
|
||||
const main = createRegistry();
|
||||
const research = createRegistry();
|
||||
|
||||
@@ -4,7 +4,11 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { normalizePluginsConfig } from "./config-state.js";
|
||||
import { loadPluginRegistryHandle, resolvePluginRegistryLoadCacheKey } from "./loader.js";
|
||||
import { getMemoryRuntime, resolveMemoryCapabilityRegistration } from "./memory-state.js";
|
||||
import {
|
||||
getMemoryRuntime,
|
||||
resolveMemoryCapabilityRegistration,
|
||||
setStandaloneMemoryManagerActive,
|
||||
} from "./memory-state.js";
|
||||
import type { PluginRegistry } from "./registry-types.js";
|
||||
import { withPluginRuntimeRegistryScope } from "./runtime/gateway-request-scope.js";
|
||||
|
||||
@@ -121,6 +125,9 @@ export async function getActiveMemorySearchManager(params: {
|
||||
if (!owner) {
|
||||
return { manager: null, error: "memory plugin unavailable" };
|
||||
}
|
||||
if (owner.registry) {
|
||||
setStandaloneMemoryManagerActive(true);
|
||||
}
|
||||
return await withMemoryRuntimeOwner(
|
||||
owner,
|
||||
async (runtime) => await runtime.getMemorySearchManager(params),
|
||||
@@ -146,6 +153,7 @@ export async function closeActiveMemorySearchManagers(cfg?: OpenClawConfig): Pro
|
||||
),
|
||||
);
|
||||
standaloneMemoryRegistrySlot?.retiredRuntimes.clear();
|
||||
setStandaloneMemoryManagerActive(false);
|
||||
}
|
||||
|
||||
/** Closes the plugin-backed memory search manager for one agent. */
|
||||
@@ -164,6 +172,7 @@ export async function closeActiveMemorySearchManager(params: {
|
||||
|
||||
function resetStandaloneMemoryRegistrySlot(): void {
|
||||
standaloneMemoryRegistrySlot = undefined;
|
||||
setStandaloneMemoryManagerActive(false);
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
|
||||
@@ -266,8 +266,15 @@ export function getMemoryRuntime(): MemoryPluginRuntime | undefined {
|
||||
return getMemoryCapability()?.capability.runtime;
|
||||
}
|
||||
|
||||
let standaloneMemoryManagerActive = false;
|
||||
|
||||
// Standalone managers are intentionally absent from the active plugin registry.
|
||||
export function setStandaloneMemoryManagerActive(active: boolean): void {
|
||||
standaloneMemoryManagerActive = active;
|
||||
}
|
||||
|
||||
export function hasMemoryRuntime(): boolean {
|
||||
return getMemoryRuntime() !== undefined;
|
||||
return standaloneMemoryManagerActive || getMemoryRuntime() !== undefined;
|
||||
}
|
||||
|
||||
function cloneMemoryPublicArtifact(
|
||||
|
||||
Reference in New Issue
Block a user