feat: add local vector recall fallback

This commit is contained in:
Yahya Alhinai
2026-06-28 02:27:45 +00:00
parent 146d7e4bd2
commit 39a06499af
2 changed files with 48 additions and 6 deletions
+41 -6
View File
@@ -49,6 +49,22 @@ function memoryText(collision: Collision): string {
.join('\n');
}
function cosine(a: number[], b: number[]): number {
const n = Math.min(a.length, b.length);
let dot = 0;
let aNorm = 0;
let bNorm = 0;
for (let i = 0; i < n; i++) {
const av = a[i] ?? 0;
const bv = b[i] ?? 0;
dot += av * bv;
aNorm += av * av;
bNorm += bv * bv;
}
if (!aNorm || !bNorm) return -1;
return dot / (Math.sqrt(aNorm) * Math.sqrt(bNorm));
}
async function embed(text: string, inputType: 'document' | 'query'): Promise<number[] | null> {
return (await embedWithVoyage(text, inputType)) ?? embedWithGemini(text, inputType);
}
@@ -159,8 +175,8 @@ async function recallByVector(collision: Collision): Promise<RecalledCollision |
const queryVector = await embed(memoryText(collision), 'query');
if (!queryVector) return null;
try {
const db = await getDb();
try {
const [match] = await db
.collection<StoredCollision>('collisions')
.aggregate<StoredCollision>([
@@ -180,9 +196,27 @@ async function recallByVector(collision: Collision): Promise<RecalledCollision |
.toArray();
return match ? attachOutcome(match) : null;
} catch (err) {
console.warn(`[memory] vector recall unavailable: ${(err as Error).message}`);
return null;
console.warn(`[memory] atlas vector recall unavailable: ${(err as Error).message}`);
}
const candidates = await db
.collection<StoredCollision>('collisions')
.find(
{
podId: collision.podId,
id: { $ne: collision.id },
embedding: { $exists: true },
},
{ projection: { _id: 0 }, limit: 100 },
)
.toArray();
let best: { match: StoredCollision; score: number } | null = null;
for (const candidate of candidates) {
if (!candidate.embedding?.length) continue;
const score = cosine(queryVector, candidate.embedding);
if (!best || score > best.score) best = { match: candidate, score };
}
return best && best.score > 0.5 ? attachOutcome(best.match) : null;
}
async function recallBySignature(collision: Collision): Promise<RecalledCollision | null> {
@@ -212,9 +246,10 @@ async function recallBySignature(collision: Collision): Promise<RecalledCollisio
}
/**
* Recall prior collision patterns. Exact Mongo recall is the MVP path;
* vector search is an optional broader fallback when Atlas is configured.
* Recall prior collision patterns. Atlas Vector Search is preferred when
* available; standalone MongoDB falls back to app-side cosine search over
* stored embeddings, then exact signature/file matching.
*/
export async function recallSimilar(collision: Collision): Promise<RecalledCollision | null> {
return (await recallBySignature(collision)) ?? recallByVector(collision);
return (await recallByVector(collision)) ?? recallBySignature(collision);
}
+7
View File
@@ -163,6 +163,13 @@ async function verifyMemoryRecall() {
}
const recalled = await recallSimilar({ ...seed, id: `${seed.id}_query` });
if (!recalled) fail('memory recall did not find seeded collision');
const vectorRecalled = await recallSimilar({
...seed,
id: `${seed.id}_vector_query`,
file: 'src/nearby-memory.ts',
symbol: 'nearbyMemory',
});
if (!vectorRecalled) fail('vector memory recall did not find semantically similar collision');
}
async function verifyGraph() {