Skip to content
Merged
Show file tree
Hide file tree
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
14 changes: 12 additions & 2 deletions src/services/turso/shard-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,23 @@ export class TursoShardManager {
{
sql: `
CREATE INDEX IF NOT EXISTS memories_vec_idx
ON memories (libsql_vector_idx(vector, 'metric=cosine'))
ON memories (libsql_vector_idx(
vector,
'metric=cosine',
'compress_neighbors=float8',
'max_neighbors=20'
))
`,
},
{
sql: `
CREATE INDEX IF NOT EXISTS memories_tags_vec_idx
ON memories (libsql_vector_idx(tags_vector, 'metric=cosine'))
ON memories (libsql_vector_idx(
tags_vector,
'metric=cosine',
'compress_neighbors=float8',
'max_neighbors=20'
))
WHERE tags_vector IS NOT NULL
`,
},
Expand Down
31 changes: 31 additions & 0 deletions tests/turso-vector-search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ describe("turso vector search", () => {
const shard = await tursoShardManager.createShard("project", scopeHash, 0);
const db = await tursoConnectionManager.getConnection(shard.dbPath);

const indexDefinitions = await db.all<{ name: string; sql: string }>(`
SELECT name, sql
FROM sqlite_schema
WHERE type = 'index' AND name IN ('memories_vec_idx', 'memories_tags_vec_idx')
`);
expect(indexDefinitions).toHaveLength(2);
for (const index of indexDefinitions) {
expect(index.sql).toContain("'metric=cosine'");
expect(index.sql).toContain("'compress_neighbors=float8'");
expect(index.sql).toContain("'max_neighbors=20'");
}

await tursoVectorSearch.insertVector(db, {
id: "mem_test_1",
content: "Turso native vector search",
Expand All @@ -44,6 +56,25 @@ describe("turso vector search", () => {
updatedAt: Date.now(),
});

const contentIndexHit = await db.get<{ id: string }>(
`
SELECT m.id AS id
FROM vector_top_k('memories_vec_idx', vector32(?), 1) AS v
CROSS JOIN memories m ON m.rowid = v.id
`,
[JSON.stringify(Array.from(vector))]
);
const tagsIndexHit = await db.get<{ id: string }>(
`
SELECT m.id AS id
FROM vector_top_k('memories_tags_vec_idx', vector32(?), 1) AS v
CROSS JOIN memories m ON m.rowid = v.id
`,
[JSON.stringify(Array.from(tagsVector))]
);
expect(contentIndexHit?.id).toBe("mem_test_1");
expect(tagsIndexHit?.id).toBe("mem_test_1");

await tursoVectorSearch.insertVector(db, {
id: "mem_test_no_tags",
content: "Content only vector",
Expand Down