@mastra/lance 1.0.0-beta.9 → 1.0.0
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 +906 -0
- package/dist/docs/README.md +33 -0
- package/dist/docs/SKILL.md +34 -0
- package/dist/docs/SOURCE_MAP.json +6 -0
- package/dist/docs/rag/01-vector-databases.md +643 -0
- package/dist/docs/storage/01-reference.md +113 -0
- package/dist/docs/vectors/01-reference.md +149 -0
- package/dist/index.cjs +193 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +194 -75
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +2 -2
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +1 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts +15 -5
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +9 -8
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { connect, Index } from '@lancedb/lancedb';
|
|
2
2
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
-
import { MemoryStorage, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, createStorageErrorId, normalizePerPage, calculatePagination, ScoresStorage, SCORERS_SCHEMA, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT,
|
|
3
|
+
import { MemoryStorage, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, createStorageErrorId, normalizePerPage, calculatePagination, ScoresStorage, SCORERS_SCHEMA, TABLE_SCORERS, WorkflowsStorage, ensureDate, TABLE_WORKFLOW_SNAPSHOT, MastraCompositeStore, createVectorErrorId, getDefaultValue } from '@mastra/core/storage';
|
|
4
4
|
import { MessageList } from '@mastra/core/agent';
|
|
5
5
|
import { MastraBase } from '@mastra/core/base';
|
|
6
6
|
import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
|
|
@@ -797,11 +797,13 @@ var StoreMemoryLance = class extends MemoryStorage {
|
|
|
797
797
|
}
|
|
798
798
|
if (filter?.dateRange?.start) {
|
|
799
799
|
const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
|
|
800
|
-
|
|
800
|
+
const startOp = filter.dateRange.startExclusive ? ">" : ">=";
|
|
801
|
+
conditions.push(`\`createdAt\` ${startOp} ${startTime}`);
|
|
801
802
|
}
|
|
802
803
|
if (filter?.dateRange?.end) {
|
|
803
804
|
const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
|
|
804
|
-
|
|
805
|
+
const endOp = filter.dateRange.endExclusive ? "<" : "<=";
|
|
806
|
+
conditions.push(`\`createdAt\` ${endOp} ${endTime}`);
|
|
805
807
|
}
|
|
806
808
|
const whereClause = conditions.join(" AND ");
|
|
807
809
|
const total = await table.countRows(whereClause);
|
|
@@ -948,27 +950,63 @@ var StoreMemoryLance = class extends MemoryStorage {
|
|
|
948
950
|
);
|
|
949
951
|
}
|
|
950
952
|
}
|
|
951
|
-
async
|
|
953
|
+
async listThreads(args) {
|
|
954
|
+
const { page = 0, perPage: perPageInput, orderBy, filter } = args;
|
|
955
|
+
try {
|
|
956
|
+
this.validatePaginationInput(page, perPageInput ?? 100);
|
|
957
|
+
} catch (error) {
|
|
958
|
+
throw new MastraError(
|
|
959
|
+
{
|
|
960
|
+
id: createStorageErrorId("LANCE", "LIST_THREADS", "INVALID_PAGE"),
|
|
961
|
+
domain: ErrorDomain.STORAGE,
|
|
962
|
+
category: ErrorCategory.USER,
|
|
963
|
+
details: { page, ...perPageInput !== void 0 && { perPage: perPageInput } }
|
|
964
|
+
},
|
|
965
|
+
error instanceof Error ? error : new Error("Invalid pagination parameters")
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
969
|
+
try {
|
|
970
|
+
this.validateMetadataKeys(filter?.metadata);
|
|
971
|
+
} catch (error) {
|
|
972
|
+
throw new MastraError(
|
|
973
|
+
{
|
|
974
|
+
id: createStorageErrorId("LANCE", "LIST_THREADS", "INVALID_METADATA_KEY"),
|
|
975
|
+
domain: ErrorDomain.STORAGE,
|
|
976
|
+
category: ErrorCategory.USER,
|
|
977
|
+
details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
|
|
978
|
+
},
|
|
979
|
+
error instanceof Error ? error : new Error("Invalid metadata key")
|
|
980
|
+
);
|
|
981
|
+
}
|
|
952
982
|
try {
|
|
953
|
-
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
954
|
-
const perPage = normalizePerPage(perPageInput, 100);
|
|
955
|
-
if (page < 0) {
|
|
956
|
-
throw new MastraError(
|
|
957
|
-
{
|
|
958
|
-
id: createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
959
|
-
domain: ErrorDomain.STORAGE,
|
|
960
|
-
category: ErrorCategory.USER,
|
|
961
|
-
details: { page }
|
|
962
|
-
},
|
|
963
|
-
new Error("page must be >= 0")
|
|
964
|
-
);
|
|
965
|
-
}
|
|
966
983
|
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
967
984
|
const { field, direction } = this.parseOrderBy(orderBy);
|
|
968
985
|
const table = await this.client.openTable(TABLE_THREADS);
|
|
969
|
-
const
|
|
970
|
-
|
|
971
|
-
|
|
986
|
+
const whereClauses = [];
|
|
987
|
+
if (filter?.resourceId) {
|
|
988
|
+
whereClauses.push(`\`resourceId\` = '${this.escapeSql(filter.resourceId)}'`);
|
|
989
|
+
}
|
|
990
|
+
const whereClause = whereClauses.length > 0 ? whereClauses.join(" AND ") : "";
|
|
991
|
+
const query = whereClause ? table.query().where(whereClause) : table.query();
|
|
992
|
+
let records = await query.toArray();
|
|
993
|
+
if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
|
|
994
|
+
records = records.filter((record) => {
|
|
995
|
+
if (!record.metadata) return false;
|
|
996
|
+
let recordMeta;
|
|
997
|
+
if (typeof record.metadata === "string") {
|
|
998
|
+
try {
|
|
999
|
+
recordMeta = JSON.parse(record.metadata);
|
|
1000
|
+
} catch {
|
|
1001
|
+
return false;
|
|
1002
|
+
}
|
|
1003
|
+
} else {
|
|
1004
|
+
recordMeta = record.metadata;
|
|
1005
|
+
}
|
|
1006
|
+
return Object.entries(filter.metadata).every(([key, value]) => recordMeta[key] === value);
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
const total = records.length;
|
|
972
1010
|
records.sort((a, b) => {
|
|
973
1011
|
const aValue = ["createdAt", "updatedAt"].includes(field) ? new Date(a[field]).getTime() : a[field];
|
|
974
1012
|
const bValue = ["createdAt", "updatedAt"].includes(field) ? new Date(b[field]).getTime() : b[field];
|
|
@@ -995,7 +1033,7 @@ var StoreMemoryLance = class extends MemoryStorage {
|
|
|
995
1033
|
} catch (error) {
|
|
996
1034
|
throw new MastraError(
|
|
997
1035
|
{
|
|
998
|
-
id: createStorageErrorId("LANCE", "
|
|
1036
|
+
id: createStorageErrorId("LANCE", "LIST_THREADS", "FAILED"),
|
|
999
1037
|
domain: ErrorDomain.STORAGE,
|
|
1000
1038
|
category: ErrorCategory.THIRD_PARTY
|
|
1001
1039
|
},
|
|
@@ -1601,24 +1639,6 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1601
1639
|
function escapeSql(str) {
|
|
1602
1640
|
return str.replace(/'/g, "''");
|
|
1603
1641
|
}
|
|
1604
|
-
function parseWorkflowRun(row) {
|
|
1605
|
-
let parsedSnapshot = row.snapshot;
|
|
1606
|
-
if (typeof parsedSnapshot === "string") {
|
|
1607
|
-
try {
|
|
1608
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1609
|
-
} catch (e) {
|
|
1610
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
return {
|
|
1614
|
-
workflowName: row.workflow_name,
|
|
1615
|
-
runId: row.run_id,
|
|
1616
|
-
snapshot: parsedSnapshot,
|
|
1617
|
-
createdAt: ensureDate(row.createdAt),
|
|
1618
|
-
updatedAt: ensureDate(row.updatedAt),
|
|
1619
|
-
resourceId: row.resourceId
|
|
1620
|
-
};
|
|
1621
|
-
}
|
|
1622
1642
|
var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
1623
1643
|
client;
|
|
1624
1644
|
#db;
|
|
@@ -1628,6 +1648,24 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1628
1648
|
this.client = client;
|
|
1629
1649
|
this.#db = new LanceDB({ client });
|
|
1630
1650
|
}
|
|
1651
|
+
parseWorkflowRun(row) {
|
|
1652
|
+
let parsedSnapshot = row.snapshot;
|
|
1653
|
+
if (typeof parsedSnapshot === "string") {
|
|
1654
|
+
try {
|
|
1655
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1656
|
+
} catch (e) {
|
|
1657
|
+
this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return {
|
|
1661
|
+
workflowName: row.workflow_name,
|
|
1662
|
+
runId: row.run_id,
|
|
1663
|
+
snapshot: parsedSnapshot,
|
|
1664
|
+
createdAt: ensureDate(row.createdAt),
|
|
1665
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
1666
|
+
resourceId: row.resourceId
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1631
1669
|
async init() {
|
|
1632
1670
|
const schema = TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT];
|
|
1633
1671
|
await this.#db.createTable({ tableName: TABLE_WORKFLOW_SNAPSHOT, schema });
|
|
@@ -1759,7 +1797,7 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1759
1797
|
const records = await query.toArray();
|
|
1760
1798
|
if (records.length === 0) return null;
|
|
1761
1799
|
const record = records[0];
|
|
1762
|
-
return parseWorkflowRun(record);
|
|
1800
|
+
return this.parseWorkflowRun(record);
|
|
1763
1801
|
} catch (error) {
|
|
1764
1802
|
throw new MastraError(
|
|
1765
1803
|
{
|
|
@@ -1836,7 +1874,7 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1836
1874
|
}
|
|
1837
1875
|
const records = await query.toArray();
|
|
1838
1876
|
return {
|
|
1839
|
-
runs: records.map((record) => parseWorkflowRun(record)),
|
|
1877
|
+
runs: records.map((record) => this.parseWorkflowRun(record)),
|
|
1840
1878
|
total: total || records.length
|
|
1841
1879
|
};
|
|
1842
1880
|
} catch (error) {
|
|
@@ -1854,7 +1892,7 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1854
1892
|
};
|
|
1855
1893
|
|
|
1856
1894
|
// src/storage/index.ts
|
|
1857
|
-
var LanceStorage = class _LanceStorage extends
|
|
1895
|
+
var LanceStorage = class _LanceStorage extends MastraCompositeStore {
|
|
1858
1896
|
stores;
|
|
1859
1897
|
lanceClient;
|
|
1860
1898
|
/**
|
|
@@ -2326,6 +2364,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2326
2364
|
}
|
|
2327
2365
|
async query({
|
|
2328
2366
|
tableName,
|
|
2367
|
+
indexName,
|
|
2329
2368
|
queryVector,
|
|
2330
2369
|
filter,
|
|
2331
2370
|
includeVector = false,
|
|
@@ -2333,12 +2372,13 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2333
2372
|
columns = [],
|
|
2334
2373
|
includeAllColumns = false
|
|
2335
2374
|
}) {
|
|
2375
|
+
const resolvedTableName = tableName ?? indexName;
|
|
2336
2376
|
try {
|
|
2337
2377
|
if (!this.lanceClient) {
|
|
2338
2378
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2339
2379
|
}
|
|
2340
|
-
if (!
|
|
2341
|
-
throw new Error("tableName is required");
|
|
2380
|
+
if (!resolvedTableName) {
|
|
2381
|
+
throw new Error("tableName or indexName is required");
|
|
2342
2382
|
}
|
|
2343
2383
|
if (!queryVector) {
|
|
2344
2384
|
throw new Error("queryVector is required");
|
|
@@ -2349,25 +2389,30 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2349
2389
|
id: createVectorErrorId("LANCE", "QUERY", "INVALID_ARGS"),
|
|
2350
2390
|
domain: ErrorDomain.STORAGE,
|
|
2351
2391
|
category: ErrorCategory.USER,
|
|
2352
|
-
text:
|
|
2353
|
-
details: { tableName }
|
|
2392
|
+
text: error instanceof Error ? error.message : "Invalid query arguments",
|
|
2393
|
+
details: { tableName: resolvedTableName }
|
|
2354
2394
|
},
|
|
2355
2395
|
error
|
|
2356
2396
|
);
|
|
2357
2397
|
}
|
|
2358
2398
|
try {
|
|
2359
|
-
const
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2399
|
+
const tables = await this.lanceClient.tableNames();
|
|
2400
|
+
if (!tables.includes(resolvedTableName)) {
|
|
2401
|
+
this.logger.debug(`Table ${resolvedTableName} does not exist. Returning empty results.`);
|
|
2402
|
+
return [];
|
|
2363
2403
|
}
|
|
2404
|
+
const table = await this.lanceClient.openTable(resolvedTableName);
|
|
2364
2405
|
let query = table.search(queryVector);
|
|
2365
2406
|
if (filter && Object.keys(filter).length > 0) {
|
|
2366
2407
|
const whereClause = this.filterTranslator(filter);
|
|
2367
2408
|
this.logger.debug(`Where clause generated: ${whereClause}`);
|
|
2368
2409
|
query = query.where(whereClause);
|
|
2369
2410
|
}
|
|
2370
|
-
if (!includeAllColumns &&
|
|
2411
|
+
if (!includeAllColumns && columns.length > 0) {
|
|
2412
|
+
const selectColumns = [...columns];
|
|
2413
|
+
if (!selectColumns.includes("id")) {
|
|
2414
|
+
selectColumns.push("id");
|
|
2415
|
+
}
|
|
2371
2416
|
query = query.select(selectColumns);
|
|
2372
2417
|
}
|
|
2373
2418
|
query = query.limit(topK);
|
|
@@ -2397,7 +2442,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2397
2442
|
id: createVectorErrorId("LANCE", "QUERY", "FAILED"),
|
|
2398
2443
|
domain: ErrorDomain.STORAGE,
|
|
2399
2444
|
category: ErrorCategory.THIRD_PARTY,
|
|
2400
|
-
details: { tableName, includeVector, columnsCount: columns?.length, includeAllColumns }
|
|
2445
|
+
details: { tableName: resolvedTableName, includeVector, columnsCount: columns?.length, includeAllColumns }
|
|
2401
2446
|
},
|
|
2402
2447
|
error
|
|
2403
2448
|
);
|
|
@@ -2432,13 +2477,14 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2432
2477
|
const translator = new LanceFilterTranslator();
|
|
2433
2478
|
return translator.translate(prefixedFilter);
|
|
2434
2479
|
}
|
|
2435
|
-
async upsert({ tableName, vectors, metadata = [], ids = [] }) {
|
|
2480
|
+
async upsert({ tableName, indexName, vectors, metadata = [], ids = [] }) {
|
|
2481
|
+
const resolvedTableName = tableName ?? indexName;
|
|
2436
2482
|
try {
|
|
2437
2483
|
if (!this.lanceClient) {
|
|
2438
2484
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2439
2485
|
}
|
|
2440
|
-
if (!
|
|
2441
|
-
throw new Error("tableName is required");
|
|
2486
|
+
if (!resolvedTableName) {
|
|
2487
|
+
throw new Error("tableName or indexName is required");
|
|
2442
2488
|
}
|
|
2443
2489
|
if (!vectors || !Array.isArray(vectors) || vectors.length === 0) {
|
|
2444
2490
|
throw new Error("vectors array is required and must not be empty");
|
|
@@ -2449,18 +2495,21 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2449
2495
|
id: createVectorErrorId("LANCE", "UPSERT", "INVALID_ARGS"),
|
|
2450
2496
|
domain: ErrorDomain.STORAGE,
|
|
2451
2497
|
category: ErrorCategory.USER,
|
|
2452
|
-
text:
|
|
2453
|
-
details: { tableName }
|
|
2498
|
+
text: error instanceof Error ? error.message : "Invalid upsert arguments",
|
|
2499
|
+
details: { tableName: resolvedTableName }
|
|
2454
2500
|
},
|
|
2455
2501
|
error
|
|
2456
2502
|
);
|
|
2457
2503
|
}
|
|
2458
2504
|
try {
|
|
2459
2505
|
const tables = await this.lanceClient.tableNames();
|
|
2460
|
-
|
|
2461
|
-
|
|
2506
|
+
const tableExists = tables.includes(resolvedTableName);
|
|
2507
|
+
let table = null;
|
|
2508
|
+
if (!tableExists) {
|
|
2509
|
+
this.logger.debug(`Table ${resolvedTableName} does not exist. Creating it with the first upsert data.`);
|
|
2510
|
+
} else {
|
|
2511
|
+
table = await this.lanceClient.openTable(resolvedTableName);
|
|
2462
2512
|
}
|
|
2463
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
2464
2513
|
const vectorIds = ids.length === vectors.length ? ids : vectors.map((_, i) => ids[i] || crypto.randomUUID());
|
|
2465
2514
|
const data = vectors.map((vector, i) => {
|
|
2466
2515
|
const id = String(vectorIds[i]);
|
|
@@ -2477,7 +2526,42 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2477
2526
|
}
|
|
2478
2527
|
return rowData;
|
|
2479
2528
|
});
|
|
2480
|
-
|
|
2529
|
+
if (table !== null) {
|
|
2530
|
+
const rowCount = await table.countRows();
|
|
2531
|
+
const schema = await table.schema();
|
|
2532
|
+
const existingColumns = new Set(schema.fields.map((f) => f.name));
|
|
2533
|
+
const dataColumns = new Set(Object.keys(data[0] || {}));
|
|
2534
|
+
const extraColumns = [...dataColumns].filter((col) => !existingColumns.has(col));
|
|
2535
|
+
const missingSchemaColumns = [...existingColumns].filter((col) => !dataColumns.has(col));
|
|
2536
|
+
const hasSchemaMismatch = extraColumns.length > 0 || missingSchemaColumns.length > 0;
|
|
2537
|
+
if (rowCount === 0 && extraColumns.length > 0) {
|
|
2538
|
+
this.logger.warn(
|
|
2539
|
+
`Table ${resolvedTableName} is empty and data has extra columns ${extraColumns.join(", ")}. Recreating with new schema.`
|
|
2540
|
+
);
|
|
2541
|
+
await this.lanceClient.dropTable(resolvedTableName);
|
|
2542
|
+
await this.lanceClient.createTable(resolvedTableName, data);
|
|
2543
|
+
} else if (hasSchemaMismatch) {
|
|
2544
|
+
if (extraColumns.length > 0) {
|
|
2545
|
+
this.logger.warn(
|
|
2546
|
+
`Table ${resolvedTableName} has ${rowCount} rows. Columns ${extraColumns.join(", ")} will be dropped from upsert.`
|
|
2547
|
+
);
|
|
2548
|
+
}
|
|
2549
|
+
const schemaFieldNames = schema.fields.map((f) => f.name);
|
|
2550
|
+
const normalizedData = data.map((row) => {
|
|
2551
|
+
const normalized = {};
|
|
2552
|
+
for (const col of schemaFieldNames) {
|
|
2553
|
+
normalized[col] = col in row ? row[col] : null;
|
|
2554
|
+
}
|
|
2555
|
+
return normalized;
|
|
2556
|
+
});
|
|
2557
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(normalizedData);
|
|
2558
|
+
} else {
|
|
2559
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(data);
|
|
2560
|
+
}
|
|
2561
|
+
} else {
|
|
2562
|
+
this.logger.debug(`Creating table ${resolvedTableName} with initial data`);
|
|
2563
|
+
await this.lanceClient.createTable(resolvedTableName, data);
|
|
2564
|
+
}
|
|
2481
2565
|
return vectorIds;
|
|
2482
2566
|
} catch (error) {
|
|
2483
2567
|
throw new MastraError(
|
|
@@ -2485,7 +2569,12 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2485
2569
|
id: createVectorErrorId("LANCE", "UPSERT", "FAILED"),
|
|
2486
2570
|
domain: ErrorDomain.STORAGE,
|
|
2487
2571
|
category: ErrorCategory.THIRD_PARTY,
|
|
2488
|
-
details: {
|
|
2572
|
+
details: {
|
|
2573
|
+
tableName: resolvedTableName,
|
|
2574
|
+
vectorCount: vectors.length,
|
|
2575
|
+
metadataCount: metadata.length,
|
|
2576
|
+
idsCount: ids.length
|
|
2577
|
+
}
|
|
2489
2578
|
},
|
|
2490
2579
|
error
|
|
2491
2580
|
);
|
|
@@ -2582,7 +2671,17 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2582
2671
|
}
|
|
2583
2672
|
}
|
|
2584
2673
|
/**
|
|
2585
|
-
*
|
|
2674
|
+
* Creates a vector index on a table.
|
|
2675
|
+
*
|
|
2676
|
+
* The behavior of `indexName` depends on whether `tableName` is provided:
|
|
2677
|
+
* - With `tableName`: `indexName` is the column to index (advanced use case)
|
|
2678
|
+
* - Without `tableName`: `indexName` becomes the table name, and 'vector' is used as the column (Memory compatibility)
|
|
2679
|
+
*
|
|
2680
|
+
* @param tableName - Optional table name. If not provided, defaults to indexName.
|
|
2681
|
+
* @param indexName - The index/column name, or table name if tableName is not provided.
|
|
2682
|
+
* @param dimension - Vector dimension size.
|
|
2683
|
+
* @param metric - Distance metric: 'cosine', 'euclidean', or 'dotproduct'.
|
|
2684
|
+
* @param indexConfig - Optional index configuration.
|
|
2586
2685
|
*/
|
|
2587
2686
|
async createIndex({
|
|
2588
2687
|
tableName,
|
|
@@ -2591,13 +2690,12 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2591
2690
|
metric = "cosine",
|
|
2592
2691
|
indexConfig = {}
|
|
2593
2692
|
}) {
|
|
2693
|
+
const resolvedTableName = tableName ?? indexName;
|
|
2694
|
+
const columnToIndex = tableName ? indexName : "vector";
|
|
2594
2695
|
try {
|
|
2595
2696
|
if (!this.lanceClient) {
|
|
2596
2697
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2597
2698
|
}
|
|
2598
|
-
if (!tableName) {
|
|
2599
|
-
throw new Error("tableName is required");
|
|
2600
|
-
}
|
|
2601
2699
|
if (!indexName) {
|
|
2602
2700
|
throw new Error("indexName is required");
|
|
2603
2701
|
}
|
|
@@ -2610,19 +2708,33 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2610
2708
|
id: createVectorErrorId("LANCE", "CREATE_INDEX", "INVALID_ARGS"),
|
|
2611
2709
|
domain: ErrorDomain.STORAGE,
|
|
2612
2710
|
category: ErrorCategory.USER,
|
|
2613
|
-
details: { tableName:
|
|
2711
|
+
details: { tableName: resolvedTableName, indexName, dimension, metric }
|
|
2614
2712
|
},
|
|
2615
2713
|
err
|
|
2616
2714
|
);
|
|
2617
2715
|
}
|
|
2618
2716
|
try {
|
|
2619
2717
|
const tables = await this.lanceClient.tableNames();
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2718
|
+
let table;
|
|
2719
|
+
if (!tables.includes(resolvedTableName)) {
|
|
2720
|
+
this.logger.debug(
|
|
2721
|
+
`Table ${resolvedTableName} does not exist. Creating empty table with dimension ${dimension}.`
|
|
2623
2722
|
);
|
|
2723
|
+
const initVector = new Array(dimension).fill(0);
|
|
2724
|
+
table = await this.lanceClient.createTable(resolvedTableName, [{ id: "__init__", vector: initVector }]);
|
|
2725
|
+
try {
|
|
2726
|
+
await table.delete("id = '__init__'");
|
|
2727
|
+
} catch (deleteError) {
|
|
2728
|
+
this.logger.warn(
|
|
2729
|
+
`Failed to delete initialization row from ${resolvedTableName}. Subsequent queries may include '__init__' row.`,
|
|
2730
|
+
deleteError
|
|
2731
|
+
);
|
|
2732
|
+
}
|
|
2733
|
+
this.logger.debug(`Table ${resolvedTableName} created. Index creation deferred until data is available.`);
|
|
2734
|
+
return;
|
|
2735
|
+
} else {
|
|
2736
|
+
table = await this.lanceClient.openTable(resolvedTableName);
|
|
2624
2737
|
}
|
|
2625
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
2626
2738
|
let metricType;
|
|
2627
2739
|
if (metric === "euclidean") {
|
|
2628
2740
|
metricType = "l2";
|
|
@@ -2631,8 +2743,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2631
2743
|
} else if (metric === "cosine") {
|
|
2632
2744
|
metricType = "cosine";
|
|
2633
2745
|
}
|
|
2746
|
+
const rowCount = await table.countRows();
|
|
2747
|
+
if (rowCount < 256) {
|
|
2748
|
+
this.logger.warn(
|
|
2749
|
+
`Table ${resolvedTableName} has ${rowCount} rows, which is below the 256 row minimum for index creation. Skipping index creation.`
|
|
2750
|
+
);
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2634
2753
|
if (indexConfig.type === "ivfflat") {
|
|
2635
|
-
await table.createIndex(
|
|
2754
|
+
await table.createIndex(columnToIndex, {
|
|
2636
2755
|
config: Index.ivfPq({
|
|
2637
2756
|
numPartitions: indexConfig.numPartitions || 128,
|
|
2638
2757
|
numSubVectors: indexConfig.numSubVectors || 16,
|
|
@@ -2641,7 +2760,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2641
2760
|
});
|
|
2642
2761
|
} else {
|
|
2643
2762
|
this.logger.debug("Creating HNSW PQ index with config:", indexConfig);
|
|
2644
|
-
await table.createIndex(
|
|
2763
|
+
await table.createIndex(columnToIndex, {
|
|
2645
2764
|
config: Index.hnswPq({
|
|
2646
2765
|
m: indexConfig?.hnsw?.m || 16,
|
|
2647
2766
|
efConstruction: indexConfig?.hnsw?.efConstruction || 100,
|
|
@@ -2655,7 +2774,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2655
2774
|
id: createVectorErrorId("LANCE", "CREATE_INDEX", "FAILED"),
|
|
2656
2775
|
domain: ErrorDomain.STORAGE,
|
|
2657
2776
|
category: ErrorCategory.THIRD_PARTY,
|
|
2658
|
-
details: { tableName:
|
|
2777
|
+
details: { tableName: resolvedTableName, indexName, dimension }
|
|
2659
2778
|
},
|
|
2660
2779
|
error
|
|
2661
2780
|
);
|
|
@@ -2953,7 +3072,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2953
3072
|
}
|
|
2954
3073
|
return rowData;
|
|
2955
3074
|
});
|
|
2956
|
-
await table.
|
|
3075
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(updatedRecords);
|
|
2957
3076
|
return;
|
|
2958
3077
|
}
|
|
2959
3078
|
} catch (err) {
|