import assert from 'node:assert/strict'; import test from 'node:test'; import { __resetEmbeddingCacheForTests, embedQuery, embedText, probeEmbeddingAvailability, } from './embed-memory-v2-openai-compat.mjs'; function mockFetch(responseFactory) { return async (url, init) => { const call = { url: String(url), init }; return responseFactory(call); }; } test('embedText uses OpenAI-compatible /embeddings and caches by text hash', async () => { __resetEmbeddingCacheForTests(); const calls = []; const fetchImpl = mockFetch(({ url, init }) => { calls.push({ url, body: JSON.parse(String(init.body)) }); return { ok: true, async json() { return { data: [{ embedding: [0.1, 0.2, 0.3] }] }; }, }; }); const first = await embedText('Sarah closed the curtains', { env: { MEMIND_EMBEDDING_PROVIDER: 'openai', MEMIND_EMBEDDING_API_KEY: 'test-key', MEMIND_EMBEDDING_BASE_URL: 'https://example.com/v1', MEMIND_EMBEDDING_MODEL: 'text-embedding-3-small', MEMIND_EMBEDDING_CACHE_PATH: '', }, fetchImpl, persist: false, }); const second = await embedText('Sarah closed the curtains', { env: { MEMIND_EMBEDDING_PROVIDER: 'openai', MEMIND_EMBEDDING_API_KEY: 'test-key', MEMIND_EMBEDDING_BASE_URL: 'https://example.com/v1', MEMIND_EMBEDDING_MODEL: 'text-embedding-3-small', MEMIND_EMBEDDING_CACHE_PATH: '', }, fetchImpl, persist: false, }); assert.deepEqual(first, [0.1, 0.2, 0.3]); assert.deepEqual(second, first); assert.equal(calls.length, 1); assert.equal(calls[0].url, 'https://example.com/v1/embeddings'); assert.equal(calls[0].body.model, 'text-embedding-3-small'); }); test('embedQuery delegates to embedText', async () => { __resetEmbeddingCacheForTests(); const vector = await embedQuery('probe question', {}, { env: { MEMIND_EMBEDDING_PROVIDER: 'openai', MEMIND_EMBEDDING_API_KEY: 'test-key', MEMIND_EMBEDDING_BASE_URL: 'https://example.com/v1', MEMIND_EMBEDDING_CACHE_PATH: '', }, fetchImpl: mockFetch(() => ({ ok: true, async json() { return { data: [{ embedding: [0.5, 0.6] }] }; }, })), persist: false, }); assert.deepEqual(vector, [0.5, 0.6]); }); test('ollama provider uses /api/embed without API key', async () => { __resetEmbeddingCacheForTests(); let seenUrl = null; const vector = await embedText('local semantic probe', { env: { MEMIND_EMBEDDING_PROVIDER: 'ollama', MEMIND_EMBEDDING_BASE_URL: 'http://127.0.0.1:11434', MEMIND_EMBEDDING_MODEL: 'nomic-embed-text', MEMIND_EMBEDDING_CACHE_PATH: '', }, fetchImpl: async (url) => { seenUrl = String(url); return { ok: true, async json() { return { embeddings: [[0.9, 0.1, 0.4]] }; }, }; }, persist: false, }); assert.equal(seenUrl, 'http://127.0.0.1:11434/api/embed'); assert.deepEqual(vector, [0.9, 0.1, 0.4]); }); test('probeEmbeddingAvailability reports missing API key for openai provider', async () => { __resetEmbeddingCacheForTests(); const probe = await probeEmbeddingAvailability({ env: { MEMIND_EMBEDDING_PROVIDER: 'openai', MEMIND_EMBEDDING_CACHE_PATH: '', }, }); assert.equal(probe.available, false); assert.equal(probe.reason, 'embedding_api_key_missing'); });