diff --git a/src/memory/embeddings.test.ts b/src/memory/embeddings.test.ts index 699d4e76d81..94ae24dcee6 100644 --- a/src/memory/embeddings.test.ts +++ b/src/memory/embeddings.test.ts @@ -25,6 +25,11 @@ const createFetchMock = () => json: async () => ({ data: [{ embedding: [1, 2, 3] }] }), })); +afterEach(() => { + vi.resetAllMocks(); + vi.unstubAllGlobals(); +}); + function requireProvider(result: Awaited>) { if (!result.provider) { throw new Error("Expected embedding provider"); @@ -32,20 +37,36 @@ function requireProvider(result: Awaited { - afterEach(() => { - vi.resetAllMocks(); - vi.unstubAllGlobals(); +function mockResolvedProviderKey(apiKey = "provider-key") { + vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ + apiKey, + mode: "api-key", + source: "test", }); +} +function mockMissingLocalEmbeddingDependency() { + importNodeLlamaCppMock.mockRejectedValue( + Object.assign(new Error("Cannot find package 'node-llama-cpp'"), { + code: "ERR_MODULE_NOT_FOUND", + }), + ); +} + +function createLocalProvider(options?: { fallback?: "none" | "openai" }) { + return createEmbeddingProvider({ + config: {} as never, + provider: "local", + model: "text-embedding-3-small", + fallback: options?.fallback ?? "none", + }); +} + +describe("embedding provider remote overrides", () => { it("uses remote baseUrl/apiKey and merges headers", async () => { const fetchMock = createFetchMock(); vi.stubGlobal("fetch", fetchMock); - vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ - apiKey: "provider-key", - mode: "api-key", - source: "test", - }); + mockResolvedProviderKey("provider-key"); const cfg = { models: { @@ -94,11 +115,7 @@ describe("embedding provider remote overrides", () => { it("falls back to resolved api key when remote apiKey is blank", async () => { const fetchMock = createFetchMock(); vi.stubGlobal("fetch", fetchMock); - vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ - apiKey: "provider-key", - mode: "api-key", - source: "test", - }); + mockResolvedProviderKey("provider-key"); const cfg = { models: { @@ -137,11 +154,7 @@ describe("embedding provider remote overrides", () => { json: async () => ({ embedding: { values: [1, 2, 3] } }), })); vi.stubGlobal("fetch", fetchMock); - vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ - apiKey: "provider-key", - mode: "api-key", - source: "test", - }); + mockResolvedProviderKey("provider-key"); const cfg = { models: { @@ -178,11 +191,6 @@ describe("embedding provider remote overrides", () => { }); describe("embedding provider auto selection", () => { - afterEach(() => { - vi.resetAllMocks(); - vi.unstubAllGlobals(); - }); - it("prefers openai when a key resolves", async () => { vi.mocked(authModule.resolveApiKeyForProvider).mockImplementation(async ({ provider }) => { if (provider === "openai") { @@ -271,33 +279,15 @@ describe("embedding provider auto selection", () => { }); describe("embedding provider local fallback", () => { - afterEach(() => { - vi.resetAllMocks(); - vi.unstubAllGlobals(); - }); - it("falls back to openai when node-llama-cpp is missing", async () => { - importNodeLlamaCppMock.mockRejectedValue( - Object.assign(new Error("Cannot find package 'node-llama-cpp'"), { - code: "ERR_MODULE_NOT_FOUND", - }), - ); + mockMissingLocalEmbeddingDependency(); const fetchMock = createFetchMock(); vi.stubGlobal("fetch", fetchMock); - vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ - apiKey: "provider-key", - mode: "api-key", - source: "test", - }); + mockResolvedProviderKey("provider-key"); - const result = await createEmbeddingProvider({ - config: {} as never, - provider: "local", - model: "text-embedding-3-small", - fallback: "openai", - }); + const result = await createLocalProvider({ fallback: "openai" }); const provider = requireProvider(result); expect(provider.id).toBe("openai"); @@ -306,46 +296,17 @@ describe("embedding provider local fallback", () => { }); it("throws a helpful error when local is requested and fallback is none", async () => { - importNodeLlamaCppMock.mockRejectedValue( - Object.assign(new Error("Cannot find package 'node-llama-cpp'"), { - code: "ERR_MODULE_NOT_FOUND", - }), - ); - - await expect( - createEmbeddingProvider({ - config: {} as never, - provider: "local", - model: "text-embedding-3-small", - fallback: "none", - }), - ).rejects.toThrow(/optional dependency node-llama-cpp/i); + mockMissingLocalEmbeddingDependency(); + await expect(createLocalProvider()).rejects.toThrow(/optional dependency node-llama-cpp/i); }); it("mentions every remote provider in local setup guidance", async () => { - importNodeLlamaCppMock.mockRejectedValue( - Object.assign(new Error("Cannot find package 'node-llama-cpp'"), { - code: "ERR_MODULE_NOT_FOUND", - }), - ); - - await expect( - createEmbeddingProvider({ - config: {} as never, - provider: "local", - model: "text-embedding-3-small", - fallback: "none", - }), - ).rejects.toThrow(/provider = "gemini"/i); + mockMissingLocalEmbeddingDependency(); + await expect(createLocalProvider()).rejects.toThrow(/provider = "gemini"/i); }); }); describe("local embedding normalization", () => { - afterEach(() => { - vi.resetAllMocks(); - vi.unstubAllGlobals(); - }); - async function createLocalProviderForTest() { return createEmbeddingProvider({ config: {} as never, @@ -456,11 +417,6 @@ describe("local embedding normalization", () => { }); describe("FTS-only fallback when no provider available", () => { - afterEach(() => { - vi.resetAllMocks(); - vi.unstubAllGlobals(); - }); - it("returns null provider with reason when auto mode finds no providers", async () => { vi.mocked(authModule.resolveApiKeyForProvider).mockRejectedValue( new Error('No API key found for provider "openai"'),