Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions tests/turso-vector-search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,71 @@ describe("turso vector search", () => {
}
expect(observedSql[1]).toContain("m.container_tag = ?");
});

it("returns correct tagged memories from ANN above the k threshold (result-level plan check)", async () => {
baseDir = mkdtempSync(join(tmpdir(), "turso-vector-ann-"));

const { CONFIG } = await import("../src/config.js");
CONFIG.storagePath = baseDir;

const { tursoConnectionManager } = await import("../src/services/turso/connection-manager.js");
const { tursoShardManager } = await import("../src/services/turso/shard-manager.js");
const { tursoVectorSearch } = await import("../src/services/turso/vector-search.js");

const dims = CONFIG.embeddingDimensions;
const scopeHash = "a1b2c3d4e5f67890";
const targetTag = `opencode_project_${scopeHash}`;
const otherTag = "opencode_project_0000000000000000";

const shard = await tursoShardManager.createShard("project", scopeHash, 0);
const db = await tursoConnectionManager.getConnection(shard.dbPath);

// Insert 200 memories across two container tags, well above the k=128
// threshold for container-tagged ANN searches. The target-tag memory at
// index 0 has the query vector itself (similarity 1.0), so it must rank
// first; other-tag memories must never appear in results.
const now = Date.now();
for (let i = 0; i < 200; i++) {
const vec = new Float32Array(dims);
// Spread signal across dimensions so vectors are distinguishable but
// the index-0 vector is closest to the query (also vec[0]=1).
vec[i % dims] = 1;
if (i > 0) vec[0] = 0.001;

const tag = i < 150 ? targetTag : otherTag;
await tursoVectorSearch.insertVector(db, {
id: `mem_ann_${i}`,
content: `Memory ${i}`,
vector: vec,
containerTag: tag,
tags: "",
createdAt: now - (200 - i),
updatedAt: now,
});
}

// Query vector matches mem_ann_0 (vec[0]=1, no other dimensions set).
const queryVector = new Float32Array(dims);
queryVector[0] = 1;

const results = await tursoVectorSearch.searchInShard(
shard,
queryVector,
targetTag,
10,
"turso"
);

expect(results.length).toBeGreaterThan(0);
// The closest target-tag memory must rank first.
expect(results[0]?.id).toBe("mem_ann_0");
expect(results[0]?.similarity).toBeGreaterThan(0.9);
// No other-container-tag memories (indices 150-199) should leak through.
for (const r of results) {
const idx = Number(r.id.replace("mem_ann_", ""));
expect(idx).toBeLessThan(150);
}
// Results should be limited to the requested limit.
expect(results.length).toBeLessThanOrEqual(10);
});
});