@mastra/chroma 0.0.0-vector-sources-20250516175436 → 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.
@@ -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
- expect(results[0].document).toBe(testDocuments[0]);
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].metadata?.source).toBe('pangram1');
1321
- expect(results[0].document).toContain('fox');
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].document).toContain('quick');
1335
- expect(results[0].document).not.toContain('fox');
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].document).toContain('fox');
1347
- expect(results[1].document).toContain('zebras');
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].document).toContain('quick brown');
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
+ });