import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const resolveRuntimePluginRegistryMock = vi.fn(); const applyPluginAutoEnableMock = vi.fn(); const getMemoryRuntimeMock = vi.fn(); vi.mock("../config/plugin-auto-enable.js", () => ({ applyPluginAutoEnable: (...args: unknown[]) => applyPluginAutoEnableMock(...args), })); vi.mock("./loader.js", () => ({ resolveRuntimePluginRegistry: (...args: unknown[]) => resolveRuntimePluginRegistryMock(...args), })); vi.mock("./memory-state.js", () => ({ getMemoryRuntime: () => getMemoryRuntimeMock(), })); let getActiveMemorySearchManager: typeof import("./memory-runtime.js").getActiveMemorySearchManager; let resolveActiveMemoryBackendConfig: typeof import("./memory-runtime.js").resolveActiveMemoryBackendConfig; let closeActiveMemorySearchManagers: typeof import("./memory-runtime.js").closeActiveMemorySearchManagers; function createMemoryAutoEnableFixture() { const rawConfig = { plugins: {}, channels: { memory: { enabled: true } }, }; const autoEnabledConfig = { ...rawConfig, plugins: { entries: { memory: { enabled: true }, }, }, }; return { rawConfig, autoEnabledConfig }; } function createMemoryRuntimeFixture() { return { getMemorySearchManager: vi.fn(async () => ({ manager: null, error: "no index" })), resolveMemoryBackendConfig: vi.fn(() => ({ backend: "builtin" as const })), }; } function expectMemoryRuntimeLoaded(autoEnabledConfig: unknown) { expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith({ config: autoEnabledConfig, }); } function expectMemoryAutoEnableApplied(rawConfig: unknown, autoEnabledConfig: unknown) { expect(applyPluginAutoEnableMock).toHaveBeenCalledWith({ config: rawConfig, env: process.env, }); expectMemoryRuntimeLoaded(autoEnabledConfig); } function setAutoEnabledMemoryRuntime() { const { rawConfig, autoEnabledConfig } = createMemoryAutoEnableFixture(); const runtime = createMemoryRuntimeFixture(); applyPluginAutoEnableMock.mockReturnValue({ config: autoEnabledConfig, changes: [] }); getMemoryRuntimeMock.mockReturnValueOnce(undefined).mockReturnValue(runtime); return { rawConfig, autoEnabledConfig, runtime }; } function expectNoMemoryRuntimeBootstrap() { expect(applyPluginAutoEnableMock).not.toHaveBeenCalled(); expect(resolveRuntimePluginRegistryMock).not.toHaveBeenCalled(); } async function expectAutoEnabledMemoryRuntimeCase(params: { run: (rawConfig: unknown) => Promise; expectedResult: unknown; }) { const { rawConfig, autoEnabledConfig } = setAutoEnabledMemoryRuntime(); const result = await params.run(rawConfig); if (params.expectedResult !== undefined) { expect(result).toEqual(params.expectedResult); } expectMemoryAutoEnableApplied(rawConfig, autoEnabledConfig); } async function expectCloseMemoryRuntimeCase(params: { config: unknown; setup: () => { closeAllMemorySearchManagers: ReturnType } | undefined; }) { const runtime = params.setup(); await closeActiveMemorySearchManagers(params.config as never); if (runtime) { expect(runtime.closeAllMemorySearchManagers).toHaveBeenCalledTimes(1); } expectNoMemoryRuntimeBootstrap(); } describe("memory runtime auto-enable loading", () => { beforeAll(async () => { ({ getActiveMemorySearchManager, resolveActiveMemoryBackendConfig, closeActiveMemorySearchManagers, } = await import("./memory-runtime.js")); }); beforeEach(() => { resolveRuntimePluginRegistryMock.mockReset(); applyPluginAutoEnableMock.mockReset(); getMemoryRuntimeMock.mockReset(); applyPluginAutoEnableMock.mockImplementation((params: { config: unknown }) => ({ config: params.config, changes: [], })); }); it.each([ { name: "loads memory runtime from the auto-enabled config snapshot", run: async (rawConfig: unknown) => getActiveMemorySearchManager({ cfg: rawConfig as never, agentId: "main", }), expectedResult: undefined, }, { name: "reuses the same auto-enabled load path for backend config resolution", run: async (rawConfig: unknown) => resolveActiveMemoryBackendConfig({ cfg: rawConfig as never, agentId: "main", }), expectedResult: { backend: "builtin" }, }, ] as const)("$name", async ({ run, expectedResult }) => { await expectAutoEnabledMemoryRuntimeCase({ run, expectedResult }); }); it.each([ { name: "does not bootstrap the memory runtime just to close managers", config: { plugins: {}, channels: { memory: { enabled: true } }, }, setup: () => { getMemoryRuntimeMock.mockReturnValue(undefined); return undefined; }, }, { name: "closes an already-registered memory runtime without reloading plugins", config: {}, setup: () => { const runtime = { closeAllMemorySearchManagers: vi.fn(async () => {}), }; getMemoryRuntimeMock.mockReturnValue(runtime); return runtime; }, }, ] as const)("$name", async ({ config, setup }) => { await expectCloseMemoryRuntimeCase({ config, setup }); }); });