fb3a442e73
Add RRF fusion with English word-level lexical scoring, tiered keyword fetch, and vector margin expansion (0.15/200) to fix pre-rank truncation; wire DashScope embedding bench path and update baseline to 28.8% recall@20. Co-authored-by: Cursor <cursoragent@cursor.com>
117 lines
3.3 KiB
JavaScript
117 lines
3.3 KiB
JavaScript
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');
|
|
});
|