import type { MemorySearchRuntimeDebug } from "openclaw/plugin-sdk/memory-core-host-runtime-files"; import { vi } from "vitest"; type SearchImpl = (opts?: { maxResults?: number; minScore?: number; sessionKey?: string; qmdSearchModeOverride?: "query" | "search" | "vsearch"; onDebug?: (debug: MemorySearchRuntimeDebug) => void; }) => Promise; export type MemoryReadParams = { relPath: string; from?: number; lines?: number }; type MemoryReadResult = { text: string; path: string; truncated?: boolean; from?: number; lines?: number; nextFrom?: number; }; type MemoryBackend = "builtin" | "qmd"; let backend: MemoryBackend = "builtin"; let workspaceDir = "/workspace"; let customStatus: Record | undefined; let searchImpl: SearchImpl = async () => []; let readFileImpl: (params: MemoryReadParams) => Promise = async (params) => ({ text: "", path: params.relPath, from: params.from ?? 1, lines: params.lines ?? 120, }); const stubManager = { search: vi.fn(async (_query: string, opts?: Parameters[0]) => await searchImpl(opts)), readFile: vi.fn(async (params: MemoryReadParams) => await readFileImpl(params)), status: () => ({ backend, files: 1, chunks: 1, dirty: false, workspaceDir, dbPath: "/workspace/.memory/index.sqlite", provider: "builtin", model: "builtin", requestedProvider: "builtin", sources: ["memory" as const], sourceCounts: [{ source: "memory" as const, files: 1, chunks: 1 }], custom: customStatus, }), sync: vi.fn(), probeVectorAvailability: vi.fn(async () => true), close: vi.fn(), }; const getMemorySearchManagerMock = vi.fn(async (_params: { cfg?: unknown; agentId?: string }) => ({ manager: stubManager, })); const readAgentMemoryFileMock = vi.fn( async (params: MemoryReadParams) => await readFileImpl(params), ); vi.mock("./tools.runtime.js", () => ({ resolveMemoryBackendConfig: ({ cfg, }: { cfg?: { memory?: { backend?: string; qmd?: unknown } }; }) => ({ backend, qmd: cfg?.memory?.qmd, }), getMemorySearchManager: getMemorySearchManagerMock, readAgentMemoryFile: readAgentMemoryFileMock, })); export function setMemoryBackend(next: MemoryBackend): void { backend = next; } export function setMemoryWorkspaceDir(next: string): void { workspaceDir = next; } export function setMemorySearchImpl(next: SearchImpl): void { searchImpl = next; } export function setMemoryReadFileImpl( next: (params: MemoryReadParams) => Promise, ): void { readFileImpl = next; } export function resetMemoryToolMockState(overrides?: { backend?: MemoryBackend; searchImpl?: SearchImpl; readFileImpl?: (params: MemoryReadParams) => Promise; }): void { backend = overrides?.backend ?? "builtin"; workspaceDir = "/workspace"; customStatus = undefined; searchImpl = overrides?.searchImpl ?? (async () => []); readFileImpl = overrides?.readFileImpl ?? (async (params: MemoryReadParams) => ({ text: "", path: params.relPath, from: params.from ?? 1, lines: params.lines ?? 120, })); vi.clearAllMocks(); } export function getMemorySearchManagerMockCalls(): number { return getMemorySearchManagerMock.mock.calls.length; } export function getMemorySearchManagerMockConfigs(): unknown[] { return getMemorySearchManagerMock.mock.calls.map(([params]) => params.cfg); } export function getMemorySearchManagerMockParams(): Array<{ cfg?: unknown; agentId?: string }> { return getMemorySearchManagerMock.mock.calls.map(([params]) => params); } export function getReadAgentMemoryFileMockCalls(): number { return readAgentMemoryFileMock.mock.calls.length; }