@mastra/chroma 0.0.0-vector-query-sources-20250516172905 → 0.0.0-vector-query-tool-provider-options-20250828222356
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/CHANGELOG.md +361 -4
- package/LICENSE.md +12 -4
- package/README.md +47 -21
- package/dist/index.cjs +280 -157
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +277 -154
- package/dist/index.js.map +1 -0
- package/dist/vector/filter.d.ts +19 -0
- package/dist/vector/filter.d.ts.map +1 -0
- package/dist/vector/index.d.ts +70 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/prompt.d.ts +6 -0
- package/dist/vector/prompt.d.ts.map +1 -0
- package/package.json +18 -13
- package/src/vector/filter.test.ts +27 -19
- package/src/vector/filter.ts +28 -5
- package/src/vector/index.test.ts +142 -129
- package/src/vector/index.ts +306 -200
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +1 -1
- package/tsup.config.ts +17 -0
- package/dist/_tsup-dts-rollup.d.cts +0 -126
- package/dist/_tsup-dts-rollup.d.ts +0 -126
- package/dist/index.d.cts +0 -2
package/src/vector/index.test.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
+
import { createVectorTestSuite } from '@internal/storage-test-utils';
|
|
1
2
|
import type { QueryResult, IndexStats } from '@mastra/core/vector';
|
|
2
3
|
import { describe, expect, beforeEach, afterEach, it, beforeAll, afterAll, vi } from 'vitest';
|
|
3
4
|
|
|
4
5
|
import { ChromaVector } from './';
|
|
5
6
|
|
|
6
7
|
describe('ChromaVector Integration Tests', () => {
|
|
7
|
-
let vectorDB = new ChromaVector(
|
|
8
|
-
path: 'http://localhost:8000',
|
|
9
|
-
});
|
|
8
|
+
let vectorDB = new ChromaVector();
|
|
10
9
|
|
|
11
10
|
const testIndexName = 'test-index';
|
|
12
11
|
const testIndexName2 = 'test-index-2';
|
|
@@ -122,7 +121,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
122
121
|
const ids = await vectorDB.upsert({ indexName: testIndexName, vectors: testVectors });
|
|
123
122
|
expect(ids).toHaveLength(3);
|
|
124
123
|
|
|
125
|
-
const idToBeUpdated = ids[0];
|
|
124
|
+
const idToBeUpdated = ids[0] as string;
|
|
126
125
|
const newVector = [1, 2, 3];
|
|
127
126
|
const newMetaData = {
|
|
128
127
|
test: 'updates',
|
|
@@ -150,7 +149,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
150
149
|
const ids = await vectorDB.upsert({ indexName: testIndexName, vectors: testVectors });
|
|
151
150
|
expect(ids).toHaveLength(3);
|
|
152
151
|
|
|
153
|
-
const idToBeUpdated = ids[0];
|
|
152
|
+
const idToBeUpdated = ids[0] as string;
|
|
154
153
|
const newMetaData = {
|
|
155
154
|
test: 'updates',
|
|
156
155
|
};
|
|
@@ -163,7 +162,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
163
162
|
|
|
164
163
|
const results: QueryResult[] = await vectorDB.query({
|
|
165
164
|
indexName: testIndexName,
|
|
166
|
-
queryVector: testVectors[0],
|
|
165
|
+
queryVector: testVectors[0] as number[],
|
|
167
166
|
topK: 2,
|
|
168
167
|
includeVector: true,
|
|
169
168
|
});
|
|
@@ -176,7 +175,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
176
175
|
const ids = await vectorDB.upsert({ indexName: testIndexName, vectors: testVectors });
|
|
177
176
|
expect(ids).toHaveLength(3);
|
|
178
177
|
|
|
179
|
-
const idToBeUpdated = ids[0];
|
|
178
|
+
const idToBeUpdated = ids[0] as string;
|
|
180
179
|
const newVector = [1, 2, 3];
|
|
181
180
|
|
|
182
181
|
const update = {
|
|
@@ -204,7 +203,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
204
203
|
it('should delete the vector by id', async () => {
|
|
205
204
|
const ids = await vectorDB.upsert({ indexName: testIndexName, vectors: testVectors });
|
|
206
205
|
expect(ids).toHaveLength(3);
|
|
207
|
-
const idToBeDeleted = ids[0];
|
|
206
|
+
const idToBeDeleted = ids[0] as string;
|
|
208
207
|
|
|
209
208
|
await vectorDB.deleteVector({ indexName: testIndexName, id: idToBeDeleted });
|
|
210
209
|
|
|
@@ -378,7 +377,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
378
377
|
indexName: testIndexName,
|
|
379
378
|
queryVector: [1, 0, 0],
|
|
380
379
|
filter: {
|
|
381
|
-
tags: { $in: null },
|
|
380
|
+
tags: { $in: null } as any,
|
|
382
381
|
},
|
|
383
382
|
}),
|
|
384
383
|
).rejects.toThrow();
|
|
@@ -479,9 +478,9 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
479
478
|
indexName: testIndexName,
|
|
480
479
|
queryVector: [1, 0, 0],
|
|
481
480
|
filter: {
|
|
482
|
-
field1: { $in: 'not-array' },
|
|
483
|
-
field2: { $exists: 'not-boolean' },
|
|
484
|
-
field3: { $gt: 'not-number' },
|
|
481
|
+
field1: { $in: 'not-array' } as any,
|
|
482
|
+
field2: { $exists: 'not-boolean' } as any,
|
|
483
|
+
field3: { $gt: 'not-number' } as any,
|
|
485
484
|
},
|
|
486
485
|
}),
|
|
487
486
|
).rejects.toThrow();
|
|
@@ -1285,7 +1284,8 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1285
1284
|
const results = await vectorDB.query({ indexName: testIndexName3, queryVector: [1.0, 0.0, 0.0], topK: 3 });
|
|
1286
1285
|
expect(results).toHaveLength(3);
|
|
1287
1286
|
// Verify documents are returned
|
|
1288
|
-
|
|
1287
|
+
|
|
1288
|
+
expect(results[0]!.document).toBe(testDocuments[0]);
|
|
1289
1289
|
});
|
|
1290
1290
|
|
|
1291
1291
|
it('should filter documents using $contains', async () => {
|
|
@@ -1317,8 +1317,19 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1317
1317
|
documentFilter: { $contains: 'fox' },
|
|
1318
1318
|
});
|
|
1319
1319
|
expect(results).toHaveLength(1);
|
|
1320
|
-
expect(results[0]
|
|
1321
|
-
expect(results[0]
|
|
1320
|
+
expect(results[0]!.metadata?.source).toBe('pangram1');
|
|
1321
|
+
expect(results[0]!.document).toContain('fox');
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
it('should get records with metadata and document filters', async () => {
|
|
1325
|
+
const results = await vectorDB.get({
|
|
1326
|
+
indexName: testIndexName3,
|
|
1327
|
+
filter: { source: 'pangram1' },
|
|
1328
|
+
documentFilter: { $contains: 'fox' },
|
|
1329
|
+
});
|
|
1330
|
+
expect(results).toHaveLength(1);
|
|
1331
|
+
expect(results[0]!.metadata?.source).toBe('pangram1');
|
|
1332
|
+
expect(results[0]!.document).toContain('fox');
|
|
1322
1333
|
});
|
|
1323
1334
|
});
|
|
1324
1335
|
|
|
@@ -1331,8 +1342,8 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1331
1342
|
documentFilter: { $and: [{ $contains: 'quick' }, { $not_contains: 'fox' }] },
|
|
1332
1343
|
});
|
|
1333
1344
|
expect(results).toHaveLength(1);
|
|
1334
|
-
expect(results[0]
|
|
1335
|
-
expect(results[0]
|
|
1345
|
+
expect(results[0]!.document).toContain('quick');
|
|
1346
|
+
expect(results[0]!.document).not.toContain('fox');
|
|
1336
1347
|
});
|
|
1337
1348
|
|
|
1338
1349
|
it('should handle $or conditions', async () => {
|
|
@@ -1343,8 +1354,8 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1343
1354
|
documentFilter: { $or: [{ $contains: 'fox' }, { $contains: 'zebras' }] },
|
|
1344
1355
|
});
|
|
1345
1356
|
expect(results).toHaveLength(2);
|
|
1346
|
-
expect(results[0]
|
|
1347
|
-
expect(results[1]
|
|
1357
|
+
expect(results[0]!.document).toContain('fox');
|
|
1358
|
+
expect(results[1]!.document).toContain('zebras');
|
|
1348
1359
|
});
|
|
1349
1360
|
});
|
|
1350
1361
|
|
|
@@ -1395,7 +1406,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1395
1406
|
documentFilter: { $contains: 'quick brown' }, // Test multi-word match
|
|
1396
1407
|
});
|
|
1397
1408
|
expect(results.length).toBe(1);
|
|
1398
|
-
expect(results[0]
|
|
1409
|
+
expect(results[0]!.document).toContain('quick brown');
|
|
1399
1410
|
});
|
|
1400
1411
|
|
|
1401
1412
|
it('should handle deeply nested logical operators', async () => {
|
|
@@ -1442,6 +1453,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1442
1453
|
vectorDB.query({
|
|
1443
1454
|
indexName: testIndexName3,
|
|
1444
1455
|
queryVector: [1, 0, 0],
|
|
1456
|
+
// @ts-ignore
|
|
1445
1457
|
documentFilter: {},
|
|
1446
1458
|
}),
|
|
1447
1459
|
).rejects.toThrow();
|
|
@@ -1462,115 +1474,6 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1462
1474
|
});
|
|
1463
1475
|
});
|
|
1464
1476
|
});
|
|
1465
|
-
describe('Deprecation Warnings', () => {
|
|
1466
|
-
const indexName = 'testdeprecationwarnings';
|
|
1467
|
-
|
|
1468
|
-
const indexName2 = 'testdeprecationwarnings2';
|
|
1469
|
-
|
|
1470
|
-
let warnSpy;
|
|
1471
|
-
|
|
1472
|
-
beforeAll(async () => {
|
|
1473
|
-
await vectorDB.createIndex({ indexName, dimension: 3 });
|
|
1474
|
-
});
|
|
1475
|
-
|
|
1476
|
-
afterAll(async () => {
|
|
1477
|
-
try {
|
|
1478
|
-
await vectorDB.deleteIndex({ indexName });
|
|
1479
|
-
} catch {
|
|
1480
|
-
// Ignore errors if index doesn't exist
|
|
1481
|
-
}
|
|
1482
|
-
try {
|
|
1483
|
-
await vectorDB.deleteIndex({ indexName: indexName2 });
|
|
1484
|
-
} catch {
|
|
1485
|
-
// Ignore errors if index doesn't exist
|
|
1486
|
-
}
|
|
1487
|
-
});
|
|
1488
|
-
|
|
1489
|
-
beforeEach(async () => {
|
|
1490
|
-
warnSpy = vi.spyOn(vectorDB['logger'], 'warn');
|
|
1491
|
-
});
|
|
1492
|
-
|
|
1493
|
-
afterEach(async () => {
|
|
1494
|
-
warnSpy.mockRestore();
|
|
1495
|
-
try {
|
|
1496
|
-
await vectorDB.deleteIndex({ indexName: indexName2 });
|
|
1497
|
-
} catch {
|
|
1498
|
-
// Ignore errors if index doesn't exist
|
|
1499
|
-
}
|
|
1500
|
-
});
|
|
1501
|
-
|
|
1502
|
-
it('should show deprecation warning when using individual args for createIndex', async () => {
|
|
1503
|
-
await vectorDB.createIndex(indexName2, 3, 'cosine');
|
|
1504
|
-
|
|
1505
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
1506
|
-
expect.stringContaining('Deprecation Warning: Passing individual arguments to createIndex() is deprecated'),
|
|
1507
|
-
);
|
|
1508
|
-
});
|
|
1509
|
-
|
|
1510
|
-
it('should show deprecation warning when using individual args for upsert', async () => {
|
|
1511
|
-
await vectorDB.upsert(indexName, [[1, 2, 3]], [{ test: 'data' }]);
|
|
1512
|
-
|
|
1513
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
1514
|
-
expect.stringContaining('Deprecation Warning: Passing individual arguments to upsert() is deprecated'),
|
|
1515
|
-
);
|
|
1516
|
-
});
|
|
1517
|
-
|
|
1518
|
-
it('should show deprecation warning when using individual args for query', async () => {
|
|
1519
|
-
await vectorDB.query(indexName, [1, 2, 3], 5);
|
|
1520
|
-
|
|
1521
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
1522
|
-
expect.stringContaining('Deprecation Warning: Passing individual arguments to query() is deprecated'),
|
|
1523
|
-
);
|
|
1524
|
-
});
|
|
1525
|
-
|
|
1526
|
-
it('should not show deprecation warning when using object param for query', async () => {
|
|
1527
|
-
await vectorDB.query({
|
|
1528
|
-
indexName,
|
|
1529
|
-
queryVector: [1, 2, 3],
|
|
1530
|
-
topK: 5,
|
|
1531
|
-
});
|
|
1532
|
-
|
|
1533
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
1534
|
-
});
|
|
1535
|
-
|
|
1536
|
-
it('should not show deprecation warning when using object param for createIndex', async () => {
|
|
1537
|
-
await vectorDB.createIndex({
|
|
1538
|
-
indexName: indexName2,
|
|
1539
|
-
dimension: 3,
|
|
1540
|
-
metric: 'cosine',
|
|
1541
|
-
});
|
|
1542
|
-
|
|
1543
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
1544
|
-
});
|
|
1545
|
-
|
|
1546
|
-
it('should not show deprecation warning when using object param for upsert', async () => {
|
|
1547
|
-
await vectorDB.upsert({
|
|
1548
|
-
indexName,
|
|
1549
|
-
vectors: [[1, 2, 3]],
|
|
1550
|
-
metadata: [{ test: 'data' }],
|
|
1551
|
-
});
|
|
1552
|
-
|
|
1553
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
1554
|
-
});
|
|
1555
|
-
|
|
1556
|
-
it('should maintain backward compatibility with individual args', async () => {
|
|
1557
|
-
// Query
|
|
1558
|
-
const queryResults = await vectorDB.query(indexName, [1, 2, 3], 5);
|
|
1559
|
-
expect(Array.isArray(queryResults)).toBe(true);
|
|
1560
|
-
|
|
1561
|
-
// CreateIndex
|
|
1562
|
-
await expect(vectorDB.createIndex(indexName2, 3, 'cosine')).resolves.not.toThrow();
|
|
1563
|
-
|
|
1564
|
-
// Upsert
|
|
1565
|
-
const upsertResults = await vectorDB.upsert({
|
|
1566
|
-
indexName,
|
|
1567
|
-
vectors: [[1, 2, 3]],
|
|
1568
|
-
metadata: [{ test: 'data' }],
|
|
1569
|
-
});
|
|
1570
|
-
expect(Array.isArray(upsertResults)).toBe(true);
|
|
1571
|
-
expect(upsertResults).toHaveLength(1);
|
|
1572
|
-
});
|
|
1573
|
-
});
|
|
1574
1477
|
|
|
1575
1478
|
describe('Performance and Concurrency', () => {
|
|
1576
1479
|
const perfTestIndex = 'perf-test-index';
|
|
@@ -1657,3 +1560,113 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1657
1560
|
}, 30000);
|
|
1658
1561
|
});
|
|
1659
1562
|
});
|
|
1563
|
+
|
|
1564
|
+
// Metadata filtering tests for Memory system
|
|
1565
|
+
describe('Chroma Metadata Filtering', () => {
|
|
1566
|
+
const chromaVector = new ChromaVector();
|
|
1567
|
+
|
|
1568
|
+
createVectorTestSuite({
|
|
1569
|
+
vector: chromaVector,
|
|
1570
|
+
createIndex: async (indexName: string) => {
|
|
1571
|
+
// Using dimension 4 as required by the metadata filtering test vectors
|
|
1572
|
+
await chromaVector.createIndex({ indexName, dimension: 4 });
|
|
1573
|
+
},
|
|
1574
|
+
deleteIndex: async (indexName: string) => {
|
|
1575
|
+
await chromaVector.deleteIndex({ indexName });
|
|
1576
|
+
},
|
|
1577
|
+
waitForIndexing: async () => {
|
|
1578
|
+
// Chroma may need a short wait for indexing
|
|
1579
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1580
|
+
},
|
|
1581
|
+
});
|
|
1582
|
+
});
|
|
1583
|
+
|
|
1584
|
+
// ChromaCloudVector fork functionality tests (requires CHROMA_API_KEY)
|
|
1585
|
+
describe.skipIf(!process.env.CHROMA_API_KEY)('ChromaCloudVector Fork Tests', () => {
|
|
1586
|
+
let cloudVector: ChromaVector;
|
|
1587
|
+
const testIndexName = 'fork-test-index';
|
|
1588
|
+
const forkedIndexName = 'forked-test-index';
|
|
1589
|
+
const dimension = 3;
|
|
1590
|
+
|
|
1591
|
+
beforeEach(async () => {
|
|
1592
|
+
cloudVector = new ChromaVector({
|
|
1593
|
+
apiKey: process.env.CHROMA_API_KEY,
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
// Clean up any existing test indexes
|
|
1597
|
+
try {
|
|
1598
|
+
await cloudVector.deleteIndex({ indexName: testIndexName });
|
|
1599
|
+
} catch {
|
|
1600
|
+
// Ignore errors if index doesn't exist
|
|
1601
|
+
}
|
|
1602
|
+
try {
|
|
1603
|
+
await cloudVector.deleteIndex({ indexName: forkedIndexName });
|
|
1604
|
+
} catch {
|
|
1605
|
+
// Ignore errors if index doesn't exist
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
afterEach(async () => {
|
|
1610
|
+
// Clean up test indexes
|
|
1611
|
+
try {
|
|
1612
|
+
await cloudVector.deleteIndex({ indexName: testIndexName });
|
|
1613
|
+
} catch {
|
|
1614
|
+
// Ignore cleanup errors
|
|
1615
|
+
}
|
|
1616
|
+
try {
|
|
1617
|
+
await cloudVector.deleteIndex({ indexName: forkedIndexName });
|
|
1618
|
+
} catch {
|
|
1619
|
+
// Ignore cleanup errors
|
|
1620
|
+
}
|
|
1621
|
+
});
|
|
1622
|
+
|
|
1623
|
+
it('should fork an index successfully', async () => {
|
|
1624
|
+
// Create initial index with some data
|
|
1625
|
+
await cloudVector.createIndex({ indexName: testIndexName, dimension });
|
|
1626
|
+
|
|
1627
|
+
const testVectors = [
|
|
1628
|
+
[1.0, 0.0, 0.0],
|
|
1629
|
+
[0.0, 1.0, 0.0],
|
|
1630
|
+
[0.0, 0.0, 1.0],
|
|
1631
|
+
];
|
|
1632
|
+
const testMetadata = [{ label: 'x-axis' }, { label: 'y-axis' }, { label: 'z-axis' }];
|
|
1633
|
+
const testIds = ['vec1', 'vec2', 'vec3'];
|
|
1634
|
+
|
|
1635
|
+
await cloudVector.upsert({
|
|
1636
|
+
indexName: testIndexName,
|
|
1637
|
+
vectors: testVectors,
|
|
1638
|
+
ids: testIds,
|
|
1639
|
+
metadata: testMetadata,
|
|
1640
|
+
});
|
|
1641
|
+
|
|
1642
|
+
// Fork the index
|
|
1643
|
+
await cloudVector.forkIndex({
|
|
1644
|
+
indexName: testIndexName,
|
|
1645
|
+
newIndexName: forkedIndexName,
|
|
1646
|
+
});
|
|
1647
|
+
|
|
1648
|
+
// Verify both indexes exist and have the same data
|
|
1649
|
+
let originalStats = await cloudVector.describeIndex({ indexName: testIndexName });
|
|
1650
|
+
let forkedStats = await cloudVector.describeIndex({ indexName: forkedIndexName });
|
|
1651
|
+
|
|
1652
|
+
expect(originalStats.count).toBe(3);
|
|
1653
|
+
expect(forkedStats.count).toBe(3);
|
|
1654
|
+
|
|
1655
|
+
await cloudVector.deleteVector({ indexName: forkedIndexName, id: 'vec1' });
|
|
1656
|
+
|
|
1657
|
+
originalStats = await cloudVector.describeIndex({ indexName: testIndexName });
|
|
1658
|
+
forkedStats = await cloudVector.describeIndex({ indexName: forkedIndexName });
|
|
1659
|
+
|
|
1660
|
+
expect(originalStats.count).toBe(3);
|
|
1661
|
+
expect(forkedStats.count).toBe(2);
|
|
1662
|
+
});
|
|
1663
|
+
|
|
1664
|
+
it('should throw error when forking non-existent index', async () => {
|
|
1665
|
+
await expect(
|
|
1666
|
+
cloudVector.forkIndex({
|
|
1667
|
+
indexName: 'non-existent-index',
|
|
1668
|
+
newIndexName: forkedIndexName,
|
|
1669
|
+
}),
|
|
1670
|
+
).rejects.toThrow();
|
|
1671
|
+
});
|
|
1672
|
+
});
|