@opensaas/stack-rag 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +10 -0
- package/CLAUDE.md +565 -0
- package/LICENSE +21 -0
- package/README.md +406 -0
- package/dist/config/index.d.ts +63 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +94 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/plugin.d.ts +38 -0
- package/dist/config/plugin.d.ts.map +1 -0
- package/dist/config/plugin.js +215 -0
- package/dist/config/plugin.js.map +1 -0
- package/dist/config/plugin.test.d.ts +2 -0
- package/dist/config/plugin.test.d.ts.map +1 -0
- package/dist/config/plugin.test.js +554 -0
- package/dist/config/plugin.test.js.map +1 -0
- package/dist/config/types.d.ts +249 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -0
- package/dist/fields/embedding.d.ts +85 -0
- package/dist/fields/embedding.d.ts.map +1 -0
- package/dist/fields/embedding.js +81 -0
- package/dist/fields/embedding.js.map +1 -0
- package/dist/fields/embedding.test.d.ts +2 -0
- package/dist/fields/embedding.test.d.ts.map +1 -0
- package/dist/fields/embedding.test.js +323 -0
- package/dist/fields/embedding.test.js.map +1 -0
- package/dist/fields/index.d.ts +6 -0
- package/dist/fields/index.d.ts.map +1 -0
- package/dist/fields/index.js +5 -0
- package/dist/fields/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +19 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +18 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/providers/index.d.ts +38 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +68 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/ollama.d.ts +49 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +151 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/providers/openai.d.ts +41 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +126 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/providers.test.d.ts +2 -0
- package/dist/providers/providers.test.d.ts.map +1 -0
- package/dist/providers/providers.test.js +224 -0
- package/dist/providers/providers.test.js.map +1 -0
- package/dist/providers/types.d.ts +88 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/runtime/batch.d.ts +183 -0
- package/dist/runtime/batch.d.ts.map +1 -0
- package/dist/runtime/batch.js +240 -0
- package/dist/runtime/batch.js.map +1 -0
- package/dist/runtime/batch.test.d.ts +2 -0
- package/dist/runtime/batch.test.d.ts.map +1 -0
- package/dist/runtime/batch.test.js +251 -0
- package/dist/runtime/batch.test.js.map +1 -0
- package/dist/runtime/chunking.d.ts +42 -0
- package/dist/runtime/chunking.d.ts.map +1 -0
- package/dist/runtime/chunking.js +264 -0
- package/dist/runtime/chunking.js.map +1 -0
- package/dist/runtime/chunking.test.d.ts +2 -0
- package/dist/runtime/chunking.test.d.ts.map +1 -0
- package/dist/runtime/chunking.test.js +212 -0
- package/dist/runtime/chunking.test.js.map +1 -0
- package/dist/runtime/embeddings.d.ts +147 -0
- package/dist/runtime/embeddings.d.ts.map +1 -0
- package/dist/runtime/embeddings.js +201 -0
- package/dist/runtime/embeddings.js.map +1 -0
- package/dist/runtime/embeddings.test.d.ts +2 -0
- package/dist/runtime/embeddings.test.d.ts.map +1 -0
- package/dist/runtime/embeddings.test.js +366 -0
- package/dist/runtime/embeddings.test.js.map +1 -0
- package/dist/runtime/index.d.ts +14 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +18 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/search.d.ts +135 -0
- package/dist/runtime/search.d.ts.map +1 -0
- package/dist/runtime/search.js +101 -0
- package/dist/runtime/search.js.map +1 -0
- package/dist/storage/index.d.ts +41 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +73 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/json.d.ts +34 -0
- package/dist/storage/json.d.ts.map +1 -0
- package/dist/storage/json.js +82 -0
- package/dist/storage/json.js.map +1 -0
- package/dist/storage/pgvector.d.ts +53 -0
- package/dist/storage/pgvector.d.ts.map +1 -0
- package/dist/storage/pgvector.js +168 -0
- package/dist/storage/pgvector.js.map +1 -0
- package/dist/storage/sqlite-vss.d.ts +49 -0
- package/dist/storage/sqlite-vss.d.ts.map +1 -0
- package/dist/storage/sqlite-vss.js +148 -0
- package/dist/storage/sqlite-vss.js.map +1 -0
- package/dist/storage/storage.test.d.ts +2 -0
- package/dist/storage/storage.test.d.ts.map +1 -0
- package/dist/storage/storage.test.js +440 -0
- package/dist/storage/storage.test.js.map +1 -0
- package/dist/storage/types.d.ts +79 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +49 -0
- package/dist/storage/types.js.map +1 -0
- package/package.json +82 -0
- package/src/config/index.ts +116 -0
- package/src/config/plugin.test.ts +664 -0
- package/src/config/plugin.ts +257 -0
- package/src/config/types.ts +283 -0
- package/src/fields/embedding.test.ts +408 -0
- package/src/fields/embedding.ts +150 -0
- package/src/fields/index.ts +6 -0
- package/src/index.ts +33 -0
- package/src/mcp/index.ts +21 -0
- package/src/providers/index.ts +81 -0
- package/src/providers/ollama.ts +186 -0
- package/src/providers/openai.ts +161 -0
- package/src/providers/providers.test.ts +275 -0
- package/src/providers/types.ts +100 -0
- package/src/runtime/batch.test.ts +332 -0
- package/src/runtime/batch.ts +424 -0
- package/src/runtime/chunking.test.ts +258 -0
- package/src/runtime/chunking.ts +334 -0
- package/src/runtime/embeddings.test.ts +441 -0
- package/src/runtime/embeddings.ts +380 -0
- package/src/runtime/index.ts +51 -0
- package/src/runtime/search.ts +243 -0
- package/src/storage/index.ts +86 -0
- package/src/storage/json.ts +106 -0
- package/src/storage/pgvector.ts +206 -0
- package/src/storage/sqlite-vss.ts +193 -0
- package/src/storage/storage.test.ts +521 -0
- package/src/storage/types.ts +126 -0
- package/tsconfig.json +13 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +18 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { cosineSimilarity as calculateCosineSimilarity } from './types.js';
|
|
2
|
+
import { getDbKey } from '@opensaas/stack-core';
|
|
3
|
+
/**
|
|
4
|
+
* SQLite VSS storage backend
|
|
5
|
+
* Uses sqlite-vss extension for vector similarity search
|
|
6
|
+
* Requires: sqlite-vss extension to be loaded
|
|
7
|
+
*/
|
|
8
|
+
export class SqliteVssStorage {
|
|
9
|
+
type = 'sqlite-vss';
|
|
10
|
+
distanceFunction;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.distanceFunction = config.distanceFunction || 'cosine';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Convert distance to similarity score (0-1, higher is more similar)
|
|
16
|
+
*/
|
|
17
|
+
distanceToScore(distance) {
|
|
18
|
+
if (this.distanceFunction === 'cosine') {
|
|
19
|
+
// Cosine distance is 1 - similarity
|
|
20
|
+
return 1 - distance;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// L2 distance: convert to similarity using 1 / (1 + distance)
|
|
24
|
+
return 1 / (1 + distance);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Search for similar vectors using sqlite-vss
|
|
29
|
+
*/
|
|
30
|
+
async search(listKey, fieldName, queryVector, options) {
|
|
31
|
+
const { limit = 10, minScore = 0.0, context, where = {} } = options;
|
|
32
|
+
const dbKey = getDbKey(listKey);
|
|
33
|
+
const model = context.db[dbKey];
|
|
34
|
+
if (!model) {
|
|
35
|
+
throw new Error(`List '${listKey}' not found in context.db`);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
// Get the underlying Prisma client
|
|
39
|
+
const prisma = context.prisma;
|
|
40
|
+
if (!prisma) {
|
|
41
|
+
// Fallback: if we can't access Prisma directly, use JSON storage approach
|
|
42
|
+
console.warn('sqlite-vss: Could not access Prisma client directly. ' +
|
|
43
|
+
'Falling back to JSON-based search. ' +
|
|
44
|
+
'For full sqlite-vss support, ensure the context exposes _prisma.');
|
|
45
|
+
return this.fallbackSearch(listKey, fieldName, queryVector, options);
|
|
46
|
+
}
|
|
47
|
+
// Build JSON array string for the vector
|
|
48
|
+
// Note: vectorString would be used for native sqlite-vss queries
|
|
49
|
+
// Currently using fallback JS-based search
|
|
50
|
+
// const vectorString = JSON.stringify(queryVector)
|
|
51
|
+
// Table name (Prisma uses PascalCase in schema but lowercases in DB)
|
|
52
|
+
// Note: tableName would be used for native sqlite-vss queries
|
|
53
|
+
// const tableName = listKey
|
|
54
|
+
// SQLite VSS query
|
|
55
|
+
// We need to create a virtual table for VSS search
|
|
56
|
+
// For now, we'll use a simpler approach: extract vectors and compute in JS
|
|
57
|
+
// Full sqlite-vss integration would require creating virtual tables at schema generation time
|
|
58
|
+
// Query to get all items with embeddings
|
|
59
|
+
const items = await model.findMany({
|
|
60
|
+
where: {
|
|
61
|
+
...where,
|
|
62
|
+
[fieldName]: {
|
|
63
|
+
not: null,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
// Calculate similarity for each item (JavaScript fallback)
|
|
68
|
+
const results = [];
|
|
69
|
+
for (const item of items) {
|
|
70
|
+
const embeddingData = item[fieldName];
|
|
71
|
+
if (!embeddingData || !embeddingData.vector) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const storedVector = embeddingData.vector;
|
|
75
|
+
// Validate vector dimensions
|
|
76
|
+
if (storedVector.length !== queryVector.length) {
|
|
77
|
+
console.warn(`Vector dimension mismatch for ${listKey}.${item.id}.${fieldName}: ` +
|
|
78
|
+
`expected ${queryVector.length}, got ${storedVector.length}. Skipping.`);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// Calculate similarity
|
|
82
|
+
let distance;
|
|
83
|
+
if (this.distanceFunction === 'cosine') {
|
|
84
|
+
const similarity = this.cosineSimilarity(queryVector, storedVector);
|
|
85
|
+
distance = 1 - similarity;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// L2 distance
|
|
89
|
+
distance = Math.sqrt(storedVector.reduce((sum, val, i) => {
|
|
90
|
+
const diff = val - queryVector[i];
|
|
91
|
+
return sum + diff * diff;
|
|
92
|
+
}, 0));
|
|
93
|
+
}
|
|
94
|
+
const score = this.distanceToScore(distance);
|
|
95
|
+
if (score >= minScore) {
|
|
96
|
+
results.push({
|
|
97
|
+
item: item,
|
|
98
|
+
score,
|
|
99
|
+
distance,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Sort by score (descending) and limit results
|
|
104
|
+
results.sort((a, b) => b.score - a.score);
|
|
105
|
+
return results.slice(0, limit);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new Error(`sqlite-vss search failed: ${error.message}\n` +
|
|
109
|
+
'Ensure sqlite-vss extension is loaded in your SQLite connection.');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Fallback to JSON-based search if we can't access Prisma directly
|
|
114
|
+
*/
|
|
115
|
+
async fallbackSearch(listKey, fieldName, queryVector, options) {
|
|
116
|
+
const { JsonVectorStorage } = await import('./json.js');
|
|
117
|
+
const jsonStorage = new JsonVectorStorage();
|
|
118
|
+
return jsonStorage.search(listKey, fieldName, queryVector, options);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Calculate cosine similarity between two vectors
|
|
122
|
+
*/
|
|
123
|
+
cosineSimilarity(a, b) {
|
|
124
|
+
return calculateCosineSimilarity(a, b);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create a SQLite VSS storage instance
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* import { createSqliteVssStorage } from '@opensaas/stack-rag/storage'
|
|
133
|
+
*
|
|
134
|
+
* const storage = createSqliteVssStorage({
|
|
135
|
+
* type: 'sqlite-vss',
|
|
136
|
+
* distanceFunction: 'cosine'
|
|
137
|
+
* })
|
|
138
|
+
*
|
|
139
|
+
* const results = await storage.search('Article', 'contentEmbedding', queryVector, {
|
|
140
|
+
* limit: 10,
|
|
141
|
+
* context
|
|
142
|
+
* })
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
export function createSqliteVssStorage(config) {
|
|
146
|
+
return new SqliteVssStorage(config);
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=sqlite-vss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-vss.js","sourceRoot":"","sources":["../../src/storage/sqlite-vss.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.test.d.ts","sourceRoot":"","sources":["../../src/storage/storage.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { JsonVectorStorage } from './json.js';
|
|
3
|
+
import { createVectorStorage } from './index.js';
|
|
4
|
+
import { cosineSimilarity, dotProduct, l2Distance } from './types.js';
|
|
5
|
+
// Helper to create mock context
|
|
6
|
+
function createMockContext(dbOverrides = {}) {
|
|
7
|
+
return {
|
|
8
|
+
db: dbOverrides,
|
|
9
|
+
session: null,
|
|
10
|
+
sudo: vi.fn(),
|
|
11
|
+
prisma: {},
|
|
12
|
+
storage: {},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
describe('Vector Storage', () => {
|
|
16
|
+
describe('JsonVectorStorage', () => {
|
|
17
|
+
let storage;
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
storage = new JsonVectorStorage();
|
|
20
|
+
});
|
|
21
|
+
describe('constructor', () => {
|
|
22
|
+
it('should initialize with correct type', () => {
|
|
23
|
+
expect(storage.type).toBe('json');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
describe('search', () => {
|
|
27
|
+
it('should throw error for non-existent list', async () => {
|
|
28
|
+
const mockContext = createMockContext({});
|
|
29
|
+
const queryVector = [0.1, 0.2, 0.3];
|
|
30
|
+
await expect(storage.search('NonExistentList', 'embedding', queryVector, {
|
|
31
|
+
context: mockContext,
|
|
32
|
+
})).rejects.toThrow(/List 'NonExistentList' not found/);
|
|
33
|
+
});
|
|
34
|
+
it('should return empty results when no items match', async () => {
|
|
35
|
+
const mockContext = createMockContext({
|
|
36
|
+
article: {
|
|
37
|
+
findMany: vi.fn().mockResolvedValue([]),
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const queryVector = [0.1, 0.2, 0.3];
|
|
41
|
+
const results = await storage.search('Article', 'embedding', queryVector, {
|
|
42
|
+
context: mockContext,
|
|
43
|
+
});
|
|
44
|
+
expect(results).toEqual([]);
|
|
45
|
+
});
|
|
46
|
+
it('should filter items with null embeddings', async () => {
|
|
47
|
+
const mockItems = [
|
|
48
|
+
{
|
|
49
|
+
id: '1',
|
|
50
|
+
title: 'Article 1',
|
|
51
|
+
embedding: null,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: '2',
|
|
55
|
+
title: 'Article 2',
|
|
56
|
+
embedding: {
|
|
57
|
+
vector: [0.1, 0.2, 0.3],
|
|
58
|
+
metadata: {
|
|
59
|
+
model: 'test',
|
|
60
|
+
provider: 'test',
|
|
61
|
+
dimensions: 3,
|
|
62
|
+
generatedAt: new Date().toISOString(),
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
const mockContext = createMockContext({
|
|
68
|
+
article: {
|
|
69
|
+
findMany: vi.fn().mockResolvedValue(mockItems),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
const queryVector = [0.1, 0.2, 0.3];
|
|
73
|
+
const results = await storage.search('Article', 'embedding', queryVector, {
|
|
74
|
+
context: mockContext,
|
|
75
|
+
});
|
|
76
|
+
expect(results).toHaveLength(1);
|
|
77
|
+
expect(results[0].item.id).toBe('2');
|
|
78
|
+
});
|
|
79
|
+
it('should calculate cosine similarity correctly', async () => {
|
|
80
|
+
const embedding1 = {
|
|
81
|
+
vector: [1.0, 0.0, 0.0],
|
|
82
|
+
metadata: {
|
|
83
|
+
model: 'test',
|
|
84
|
+
provider: 'test',
|
|
85
|
+
dimensions: 3,
|
|
86
|
+
generatedAt: new Date().toISOString(),
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
const embedding2 = {
|
|
90
|
+
vector: [0.0, 1.0, 0.0],
|
|
91
|
+
metadata: {
|
|
92
|
+
model: 'test',
|
|
93
|
+
provider: 'test',
|
|
94
|
+
dimensions: 3,
|
|
95
|
+
generatedAt: new Date().toISOString(),
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const embedding3 = {
|
|
99
|
+
vector: [1.0, 0.0, 0.0],
|
|
100
|
+
metadata: {
|
|
101
|
+
model: 'test',
|
|
102
|
+
provider: 'test',
|
|
103
|
+
dimensions: 3,
|
|
104
|
+
generatedAt: new Date().toISOString(),
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
const mockItems = [
|
|
108
|
+
{ id: '1', embedding: embedding1 },
|
|
109
|
+
{ id: '2', embedding: embedding2 },
|
|
110
|
+
{ id: '3', embedding: embedding3 },
|
|
111
|
+
];
|
|
112
|
+
const mockContext = createMockContext({
|
|
113
|
+
article: {
|
|
114
|
+
findMany: vi.fn().mockResolvedValue(mockItems),
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
const queryVector = [1.0, 0.0, 0.0]; // Same as embedding1 and embedding3
|
|
118
|
+
const results = await storage.search('Article', 'embedding', queryVector, {
|
|
119
|
+
context: mockContext,
|
|
120
|
+
limit: 10,
|
|
121
|
+
});
|
|
122
|
+
expect(results).toHaveLength(3);
|
|
123
|
+
// Items 1 and 3 should have perfect similarity (score = 1.0)
|
|
124
|
+
expect(results[0].score).toBeCloseTo(1.0, 5);
|
|
125
|
+
expect(results[1].score).toBeCloseTo(1.0, 5);
|
|
126
|
+
// Item 2 should have perpendicular vectors (cosine similarity normalized to 0.5)
|
|
127
|
+
expect(results[2].score).toBeCloseTo(0.5, 5);
|
|
128
|
+
});
|
|
129
|
+
it('should respect limit parameter', async () => {
|
|
130
|
+
const mockItems = Array.from({ length: 20 }, (_, i) => ({
|
|
131
|
+
id: String(i + 1),
|
|
132
|
+
embedding: {
|
|
133
|
+
vector: [Math.random(), Math.random(), Math.random()],
|
|
134
|
+
metadata: {
|
|
135
|
+
model: 'test',
|
|
136
|
+
provider: 'test',
|
|
137
|
+
dimensions: 3,
|
|
138
|
+
generatedAt: new Date().toISOString(),
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
}));
|
|
142
|
+
const mockContext = createMockContext({
|
|
143
|
+
article: {
|
|
144
|
+
findMany: vi.fn().mockResolvedValue(mockItems),
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
const queryVector = [0.5, 0.5, 0.5];
|
|
148
|
+
const results = await storage.search('Article', 'embedding', queryVector, {
|
|
149
|
+
context: mockContext,
|
|
150
|
+
limit: 5,
|
|
151
|
+
});
|
|
152
|
+
expect(results).toHaveLength(5);
|
|
153
|
+
});
|
|
154
|
+
it('should respect minScore parameter', async () => {
|
|
155
|
+
const mockItems = [
|
|
156
|
+
{
|
|
157
|
+
id: '1',
|
|
158
|
+
embedding: {
|
|
159
|
+
vector: [1.0, 0.0, 0.0], // Perfect match
|
|
160
|
+
metadata: {
|
|
161
|
+
model: 'test',
|
|
162
|
+
provider: 'test',
|
|
163
|
+
dimensions: 3,
|
|
164
|
+
generatedAt: new Date().toISOString(),
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: '2',
|
|
170
|
+
embedding: {
|
|
171
|
+
vector: [0.0, 1.0, 0.0], // No match (perpendicular)
|
|
172
|
+
metadata: {
|
|
173
|
+
model: 'test',
|
|
174
|
+
provider: 'test',
|
|
175
|
+
dimensions: 3,
|
|
176
|
+
generatedAt: new Date().toISOString(),
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
const mockContext = createMockContext({
|
|
182
|
+
article: {
|
|
183
|
+
findMany: vi.fn().mockResolvedValue(mockItems),
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
const queryVector = [1.0, 0.0, 0.0];
|
|
187
|
+
const results = await storage.search('Article', 'embedding', queryVector, {
|
|
188
|
+
context: mockContext,
|
|
189
|
+
minScore: 0.9, // Only items with >90% similarity
|
|
190
|
+
});
|
|
191
|
+
expect(results).toHaveLength(1);
|
|
192
|
+
expect(results[0].item.id).toBe('1');
|
|
193
|
+
});
|
|
194
|
+
it('should sort results by score descending', async () => {
|
|
195
|
+
const mockItems = [
|
|
196
|
+
{
|
|
197
|
+
id: '1',
|
|
198
|
+
score: 0.5,
|
|
199
|
+
embedding: {
|
|
200
|
+
vector: [0.5, 0.5, 0.5],
|
|
201
|
+
metadata: {
|
|
202
|
+
model: 'test',
|
|
203
|
+
provider: 'test',
|
|
204
|
+
dimensions: 3,
|
|
205
|
+
generatedAt: new Date().toISOString(),
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: '2',
|
|
211
|
+
score: 0.9,
|
|
212
|
+
embedding: {
|
|
213
|
+
vector: [0.9, 0.9, 0.9],
|
|
214
|
+
metadata: {
|
|
215
|
+
model: 'test',
|
|
216
|
+
provider: 'test',
|
|
217
|
+
dimensions: 3,
|
|
218
|
+
generatedAt: new Date().toISOString(),
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
id: '3',
|
|
224
|
+
score: 0.7,
|
|
225
|
+
embedding: {
|
|
226
|
+
vector: [0.7, 0.7, 0.7],
|
|
227
|
+
metadata: {
|
|
228
|
+
model: 'test',
|
|
229
|
+
provider: 'test',
|
|
230
|
+
dimensions: 3,
|
|
231
|
+
generatedAt: new Date().toISOString(),
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
];
|
|
236
|
+
const mockContext = createMockContext({
|
|
237
|
+
article: {
|
|
238
|
+
findMany: vi.fn().mockResolvedValue(mockItems),
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
const queryVector = [1.0, 1.0, 1.0];
|
|
242
|
+
const results = await storage.search('Article', 'embedding', queryVector, {
|
|
243
|
+
context: mockContext,
|
|
244
|
+
});
|
|
245
|
+
// Results should be sorted by similarity score descending
|
|
246
|
+
expect(results[0].score).toBeGreaterThanOrEqual(results[1].score);
|
|
247
|
+
expect(results[1].score).toBeGreaterThanOrEqual(results[2].score);
|
|
248
|
+
});
|
|
249
|
+
it('should skip items with dimension mismatch', async () => {
|
|
250
|
+
const mockItems = [
|
|
251
|
+
{
|
|
252
|
+
id: '1',
|
|
253
|
+
embedding: {
|
|
254
|
+
vector: [0.1, 0.2], // 2 dimensions
|
|
255
|
+
metadata: {
|
|
256
|
+
model: 'test',
|
|
257
|
+
provider: 'test',
|
|
258
|
+
dimensions: 2,
|
|
259
|
+
generatedAt: new Date().toISOString(),
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
id: '2',
|
|
265
|
+
embedding: {
|
|
266
|
+
vector: [0.1, 0.2, 0.3], // 3 dimensions - correct
|
|
267
|
+
metadata: {
|
|
268
|
+
model: 'test',
|
|
269
|
+
provider: 'test',
|
|
270
|
+
dimensions: 3,
|
|
271
|
+
generatedAt: new Date().toISOString(),
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
];
|
|
276
|
+
const mockContext = createMockContext({
|
|
277
|
+
article: {
|
|
278
|
+
findMany: vi.fn().mockResolvedValue(mockItems),
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
const queryVector = [0.1, 0.2, 0.3]; // 3 dimensions
|
|
282
|
+
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
283
|
+
const results = await storage.search('Article', 'embedding', queryVector, {
|
|
284
|
+
context: mockContext,
|
|
285
|
+
});
|
|
286
|
+
expect(results).toHaveLength(1);
|
|
287
|
+
expect(results[0].item.id).toBe('2');
|
|
288
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(expect.stringContaining('Vector dimension mismatch'));
|
|
289
|
+
consoleWarnSpy.mockRestore();
|
|
290
|
+
});
|
|
291
|
+
it('should pass through where clause to Prisma', async () => {
|
|
292
|
+
const mockContext = createMockContext({
|
|
293
|
+
article: {
|
|
294
|
+
findMany: vi.fn().mockResolvedValue([]),
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
const queryVector = [0.1, 0.2, 0.3];
|
|
298
|
+
const whereClause = { published: true };
|
|
299
|
+
await storage.search('Article', 'embedding', queryVector, {
|
|
300
|
+
context: mockContext,
|
|
301
|
+
where: whereClause,
|
|
302
|
+
});
|
|
303
|
+
expect(mockContext.db.article
|
|
304
|
+
.findMany).toHaveBeenCalledWith({
|
|
305
|
+
where: {
|
|
306
|
+
published: true,
|
|
307
|
+
embedding: { not: null },
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
it('should include distance in results', async () => {
|
|
312
|
+
const mockItems = [
|
|
313
|
+
{
|
|
314
|
+
id: '1',
|
|
315
|
+
embedding: {
|
|
316
|
+
vector: [1.0, 0.0, 0.0],
|
|
317
|
+
metadata: {
|
|
318
|
+
model: 'test',
|
|
319
|
+
provider: 'test',
|
|
320
|
+
dimensions: 3,
|
|
321
|
+
generatedAt: new Date().toISOString(),
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
];
|
|
326
|
+
const mockContext = createMockContext({
|
|
327
|
+
article: {
|
|
328
|
+
findMany: vi.fn().mockResolvedValue(mockItems),
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
const queryVector = [1.0, 0.0, 0.0];
|
|
332
|
+
const results = await storage.search('Article', 'embedding', queryVector, {
|
|
333
|
+
context: mockContext,
|
|
334
|
+
});
|
|
335
|
+
expect(results[0]).toHaveProperty('distance');
|
|
336
|
+
expect(results[0].distance).toBeCloseTo(0.0, 5); // distance = 1 - score, perfect match = 0 distance
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
describe('cosineSimilarity', () => {
|
|
340
|
+
it('should calculate similarity for identical vectors', () => {
|
|
341
|
+
const vec1 = [1.0, 2.0, 3.0];
|
|
342
|
+
const vec2 = [1.0, 2.0, 3.0];
|
|
343
|
+
const similarity = storage.cosineSimilarity(vec1, vec2);
|
|
344
|
+
expect(similarity).toBeCloseTo(1.0, 5);
|
|
345
|
+
});
|
|
346
|
+
it('should calculate similarity for perpendicular vectors', () => {
|
|
347
|
+
const vec1 = [1.0, 0.0, 0.0];
|
|
348
|
+
const vec2 = [0.0, 1.0, 0.0];
|
|
349
|
+
const similarity = storage.cosineSimilarity(vec1, vec2);
|
|
350
|
+
// Cosine similarity is normalized to 0-1 range in the implementation
|
|
351
|
+
// Perpendicular vectors have cosine 0, which becomes 0.5 after normalization
|
|
352
|
+
expect(similarity).toBeCloseTo(0.5, 5);
|
|
353
|
+
});
|
|
354
|
+
it('should calculate similarity for opposite vectors', () => {
|
|
355
|
+
const vec1 = [1.0, 0.0, 0.0];
|
|
356
|
+
const vec2 = [-1.0, 0.0, 0.0];
|
|
357
|
+
const similarity = storage.cosineSimilarity(vec1, vec2);
|
|
358
|
+
// Cosine similarity is normalized to 0-1 range in the implementation
|
|
359
|
+
// Opposite vectors have cosine -1, which becomes 0.0 after normalization
|
|
360
|
+
expect(similarity).toBeCloseTo(0.0, 5);
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
describe('Similarity utility functions', () => {
|
|
365
|
+
describe('cosineSimilarity', () => {
|
|
366
|
+
it('should calculate cosine similarity correctly', () => {
|
|
367
|
+
const vec1 = [1.0, 0.0, 0.0];
|
|
368
|
+
const vec2 = [1.0, 0.0, 0.0];
|
|
369
|
+
expect(cosineSimilarity(vec1, vec2)).toBeCloseTo(1.0, 5);
|
|
370
|
+
});
|
|
371
|
+
it('should handle zero vectors', () => {
|
|
372
|
+
const vec1 = [0.0, 0.0, 0.0];
|
|
373
|
+
const vec2 = [1.0, 0.0, 0.0];
|
|
374
|
+
expect(cosineSimilarity(vec1, vec2)).toBe(0);
|
|
375
|
+
});
|
|
376
|
+
it('should throw for mismatched dimensions', () => {
|
|
377
|
+
const vec1 = [1.0, 0.0];
|
|
378
|
+
const vec2 = [1.0, 0.0, 0.0];
|
|
379
|
+
expect(() => cosineSimilarity(vec1, vec2)).toThrow('Vector dimension mismatch');
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
describe('dotProduct', () => {
|
|
383
|
+
it('should calculate dot product correctly', () => {
|
|
384
|
+
const vec1 = [1.0, 2.0, 3.0];
|
|
385
|
+
const vec2 = [4.0, 5.0, 6.0];
|
|
386
|
+
// 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
|
|
387
|
+
expect(dotProduct(vec1, vec2)).toBe(32);
|
|
388
|
+
});
|
|
389
|
+
it('should return 0 for perpendicular vectors', () => {
|
|
390
|
+
const vec1 = [1.0, 0.0, 0.0];
|
|
391
|
+
const vec2 = [0.0, 1.0, 0.0];
|
|
392
|
+
expect(dotProduct(vec1, vec2)).toBe(0);
|
|
393
|
+
});
|
|
394
|
+
it('should throw for mismatched dimensions', () => {
|
|
395
|
+
const vec1 = [1.0, 0.0];
|
|
396
|
+
const vec2 = [1.0, 0.0, 0.0];
|
|
397
|
+
expect(() => dotProduct(vec1, vec2)).toThrow('Vector dimension mismatch');
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
describe('l2Distance', () => {
|
|
401
|
+
it('should calculate L2 distance correctly', () => {
|
|
402
|
+
const vec1 = [0.0, 0.0, 0.0];
|
|
403
|
+
const vec2 = [3.0, 4.0, 0.0];
|
|
404
|
+
// sqrt((3-0)^2 + (4-0)^2 + (0-0)^2) = sqrt(9 + 16) = 5
|
|
405
|
+
expect(l2Distance(vec1, vec2)).toBe(5);
|
|
406
|
+
});
|
|
407
|
+
it('should return 0 for identical vectors', () => {
|
|
408
|
+
const vec1 = [1.0, 2.0, 3.0];
|
|
409
|
+
const vec2 = [1.0, 2.0, 3.0];
|
|
410
|
+
expect(l2Distance(vec1, vec2)).toBe(0);
|
|
411
|
+
});
|
|
412
|
+
it('should throw for mismatched dimensions', () => {
|
|
413
|
+
const vec1 = [1.0, 0.0];
|
|
414
|
+
const vec2 = [1.0, 0.0, 0.0];
|
|
415
|
+
expect(() => l2Distance(vec1, vec2)).toThrow('Vector dimension mismatch');
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
describe('createVectorStorage factory', () => {
|
|
420
|
+
it('should create JSON storage', () => {
|
|
421
|
+
const storage = createVectorStorage({ type: 'json' });
|
|
422
|
+
expect(storage).toBeInstanceOf(JsonVectorStorage);
|
|
423
|
+
expect(storage.type).toBe('json');
|
|
424
|
+
});
|
|
425
|
+
it('should throw error for unknown storage type', () => {
|
|
426
|
+
expect(() => {
|
|
427
|
+
createVectorStorage({ type: 'unknown' });
|
|
428
|
+
}).toThrow(/Unknown vector storage type/);
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
describe('Storage interface compliance', () => {
|
|
432
|
+
it('JSON storage should implement VectorStorage interface', () => {
|
|
433
|
+
const storage = new JsonVectorStorage();
|
|
434
|
+
expect(storage).toHaveProperty('type');
|
|
435
|
+
expect(storage).toHaveProperty('search');
|
|
436
|
+
expect(typeof storage.search).toBe('function');
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
//# sourceMappingURL=storage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.test.js","sourceRoot":"","sources":["../../src/storage/storage.test.ts"],"names":[],"mappings":"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"}
|