@mastra/lance 1.0.3 → 1.0.4-alpha.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 +13 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-rag-vector-databases.md +2 -2
- package/dist/docs/references/reference-storage-lance.md +5 -5
- package/dist/docs/references/reference-vectors-lance.md +46 -38
- package/dist/index.cjs +133 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +133 -25
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +13 -0
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +2 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @mastra/lance
|
|
2
2
|
|
|
3
|
+
## 1.0.4-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. ([#14021](https://github.com/mastra-ai/mastra/pull/14021))
|
|
8
|
+
|
|
9
|
+
For example, calling `db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } })` will silently ignore `futureField` if it doesn't exist in the database table, rather than throwing. The same applies to `update` — unknown fields in the data payload are dropped before building the SQL statement.
|
|
10
|
+
|
|
11
|
+
- Improved semantic recall performance for large message histories. Semantic recall no longer loads entire threads when only the recalled messages are needed, eliminating delays that previously scaled with total message count. (Fixes #11702) ([#14022](https://github.com/mastra-ai/mastra/pull/14022))
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [[`4f71b43`](https://github.com/mastra-ai/mastra/commit/4f71b436a4a6b8839842d8da47b57b84509af56c), [`a070277`](https://github.com/mastra-ai/mastra/commit/a07027766ce195ba74d0783116d894cbab25d44c), [`b628b91`](https://github.com/mastra-ai/mastra/commit/b628b9128b372c0f54214d902b07279f03443900), [`332c014`](https://github.com/mastra-ai/mastra/commit/332c014e076b81edf7fe45b58205882726415e90), [`6b63153`](https://github.com/mastra-ai/mastra/commit/6b63153878ea841c0f4ce632ba66bb33e57e9c1b), [`4246e34`](https://github.com/mastra-ai/mastra/commit/4246e34cec9c26636d0965942268e6d07c346671), [`b8837ee`](https://github.com/mastra-ai/mastra/commit/b8837ee77e2e84197609762bfabd8b3da326d30c), [`5d950f7`](https://github.com/mastra-ai/mastra/commit/5d950f7bf426a215a1808f0abef7de5c8336ba1c), [`28c85b1`](https://github.com/mastra-ai/mastra/commit/28c85b184fc32b40f7f160483c982da6d388ecbd), [`e9a08fb`](https://github.com/mastra-ai/mastra/commit/e9a08fbef1ada7e50e961e2f54f55e8c10b4a45c), [`631ffd8`](https://github.com/mastra-ai/mastra/commit/631ffd82fed108648b448b28e6a90e38c5f53bf5), [`aae2295`](https://github.com/mastra-ai/mastra/commit/aae2295838a2d329ad6640829e87934790ffe5b8), [`aa61f29`](https://github.com/mastra-ai/mastra/commit/aa61f29ff8095ce46a4ae16e46c4d8c79b2b685b), [`7ff3714`](https://github.com/mastra-ai/mastra/commit/7ff37148515439bb3be009a60e02c3e363299760), [`41d79a1`](https://github.com/mastra-ai/mastra/commit/41d79a14bd8cb6de1e2565fd0a04786bae2f211b), [`e673376`](https://github.com/mastra-ai/mastra/commit/e6733763ad1321aa7e5ae15096b9c2104f93b1f3), [`b2204c9`](https://github.com/mastra-ai/mastra/commit/b2204c98a42848bbfb6f0440f005dc2b6354f1cd), [`a1bf1e3`](https://github.com/mastra-ai/mastra/commit/a1bf1e385ed4c0ef6f11b56c5887442970d127f2), [`b6f647a`](https://github.com/mastra-ai/mastra/commit/b6f647ae2388e091f366581595feb957e37d5b40), [`0c57b8b`](https://github.com/mastra-ai/mastra/commit/0c57b8b0a69a97b5a4ae3f79be6c610f29f3cf7b), [`b081f27`](https://github.com/mastra-ai/mastra/commit/b081f272cf411716e1d6bd72ceac4bcee2657b19), [`0c09eac`](https://github.com/mastra-ai/mastra/commit/0c09eacb1926f64cfdc9ae5c6d63385cf8c9f72c), [`6b9b93d`](https://github.com/mastra-ai/mastra/commit/6b9b93d6f459d1ba6e36f163abf62a085ddb3d64), [`31b6067`](https://github.com/mastra-ai/mastra/commit/31b6067d0cc3ab10e1b29c36147f3b5266bc714a), [`797ac42`](https://github.com/mastra-ai/mastra/commit/797ac4276de231ad2d694d9aeca75980f6cd0419), [`0bc289e`](https://github.com/mastra-ai/mastra/commit/0bc289e2d476bf46c5b91c21969e8d0c6864691c), [`9b75a06`](https://github.com/mastra-ai/mastra/commit/9b75a06e53ebb0b950ba7c1e83a0142047185f46), [`4c3a1b1`](https://github.com/mastra-ai/mastra/commit/4c3a1b122ea083e003d71092f30f3b31680b01c0), [`85cc3b3`](https://github.com/mastra-ai/mastra/commit/85cc3b3b6f32ae4b083c26498f50d5b250ba944b), [`97ea28c`](https://github.com/mastra-ai/mastra/commit/97ea28c746e9e4147d56047bbb1c4a92417a3fec), [`d567299`](https://github.com/mastra-ai/mastra/commit/d567299cf81e02bd9d5221d4bc05967d6c224161), [`716ffe6`](https://github.com/mastra-ai/mastra/commit/716ffe68bed81f7c2690bc8581b9e140f7bf1c3d), [`8296332`](https://github.com/mastra-ai/mastra/commit/8296332de21c16e3dfc3d0b2d615720a6dc88f2f), [`4df2116`](https://github.com/mastra-ai/mastra/commit/4df211619dd922c047d396ca41cd7027c8c4c8e7), [`2219c1a`](https://github.com/mastra-ai/mastra/commit/2219c1acbd21da116da877f0036ffb985a9dd5a3), [`17c4145`](https://github.com/mastra-ai/mastra/commit/17c4145166099354545582335b5252bdfdfd908b)]:
|
|
14
|
+
- @mastra/core@1.11.0-alpha.0
|
|
15
|
+
|
|
3
16
|
## 1.0.3
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -359,7 +359,7 @@ The dimension size must match the output dimension of your chosen embedding mode
|
|
|
359
359
|
- Cohere embed-multilingual-v3: 1024 dimensions
|
|
360
360
|
- Google gemini-embedding-001: 768 dimensions (or custom)
|
|
361
361
|
|
|
362
|
-
> **Warning:** Index dimensions
|
|
362
|
+
> **Warning:** Index dimensions can't be changed after creation. To use a different model, delete and recreate the index with the new dimension size.
|
|
363
363
|
|
|
364
364
|
### Naming Rules for Databases
|
|
365
365
|
|
|
@@ -583,7 +583,7 @@ Key metadata considerations:
|
|
|
583
583
|
|
|
584
584
|
## Deleting Vectors
|
|
585
585
|
|
|
586
|
-
When building RAG applications, you often need to clean up stale vectors when documents are deleted or updated. Mastra provides the `deleteVectors` method that supports deleting vectors by metadata filters, making it
|
|
586
|
+
When building RAG applications, you often need to clean up stale vectors when documents are deleted or updated. Mastra provides the `deleteVectors` method that supports deleting vectors by metadata filters, making it straightforward to remove all embeddings associated with a specific document.
|
|
587
587
|
|
|
588
588
|
### Delete by Metadata Filter
|
|
589
589
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The LanceDB storage implementation provides a high-performance storage solution using the LanceDB database system, which excels at handling both traditional data storage and vector operations.
|
|
4
4
|
|
|
5
|
-
> **Observability Not Supported:** LanceDB storage **
|
|
5
|
+
> **Observability Not Supported:** LanceDB storage **doesn't support the observability domain**. Traces from the `DefaultExporter` can't be persisted to LanceDB, and Mastra Studio's observability features won't work with LanceDB as your only storage provider. To enable observability, use [composite storage](https://mastra.ai/reference/storage/composite) to route observability data to a supported provider like ClickHouse or PostgreSQL.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -53,11 +53,11 @@ const storage = await LanceStorage.create('my-storage', 's3://bucket/db', {
|
|
|
53
53
|
|
|
54
54
|
### LanceStorage.create()
|
|
55
55
|
|
|
56
|
-
**name
|
|
56
|
+
**name** (`string`): Name identifier for the storage instance
|
|
57
57
|
|
|
58
|
-
**uri
|
|
58
|
+
**uri** (`string`): URI to connect to the LanceDB database. Can be a local path, cloud DB URL, or S3 bucket URL
|
|
59
59
|
|
|
60
|
-
**options
|
|
60
|
+
**options** (`ConnectionOptions`): Connection options for LanceDB, such as timeout settings, authentication, etc.
|
|
61
61
|
|
|
62
62
|
## Additional Notes
|
|
63
63
|
|
|
@@ -101,7 +101,7 @@ const memoryStore = await storage.getStore('memory')
|
|
|
101
101
|
const thread = await memoryStore?.getThreadById({ threadId: '...' })
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
> **Warning:** If `init()`
|
|
104
|
+
> **Warning:** If `init()` isn't called, tables won't be created and storage operations will fail silently or throw errors.
|
|
105
105
|
|
|
106
106
|
### Deployment Options
|
|
107
107
|
|
|
@@ -6,9 +6,9 @@ The LanceVectorStore class provides vector search using [LanceDB](https://lanced
|
|
|
6
6
|
|
|
7
7
|
The LanceVectorStore uses a factory pattern for creation. You should use the static `create()` method rather than the constructor directly.
|
|
8
8
|
|
|
9
|
-
**uri
|
|
9
|
+
**uri** (`string`): Path to LanceDB database or URI for cloud deployments
|
|
10
10
|
|
|
11
|
-
**options
|
|
11
|
+
**options** (`ConnectionOptions`): Additional connection options for LanceDB
|
|
12
12
|
|
|
13
13
|
## Constructor Examples
|
|
14
14
|
|
|
@@ -33,59 +33,67 @@ const s3Store = await LanceVectorStore.create('s3://bucket/db', {
|
|
|
33
33
|
|
|
34
34
|
### createIndex()
|
|
35
35
|
|
|
36
|
-
**tableName
|
|
36
|
+
**tableName** (`string`): Name of the table to create index in
|
|
37
37
|
|
|
38
|
-
**indexName
|
|
38
|
+
**indexName** (`string`): Name of the index (column name) to create
|
|
39
39
|
|
|
40
|
-
**dimension
|
|
40
|
+
**dimension** (`number`): Vector dimension (must match your embedding model)
|
|
41
41
|
|
|
42
|
-
**metric
|
|
42
|
+
**metric** (`'cosine' | 'euclidean' | 'dotproduct'`): Distance metric for similarity search (Default: `cosine`)
|
|
43
43
|
|
|
44
|
-
**indexConfig
|
|
44
|
+
**indexConfig** (`LanceIndexConfig`): Index configuration (Default: `{ type: 'hnsw' }`)
|
|
45
45
|
|
|
46
46
|
#### LanceIndexConfig
|
|
47
47
|
|
|
48
|
-
**type
|
|
48
|
+
**type** (`'ivfflat' | 'hnsw'`): Index type (Default: `hnsw`)
|
|
49
49
|
|
|
50
|
-
**
|
|
50
|
+
**type.ivfflat** (`ivfflat`): Clusters vectors into lists for approximate search.
|
|
51
51
|
|
|
52
|
-
**
|
|
52
|
+
**type.hnsw** (`hnsw`): Graph-based index offering fast search times and high recall.
|
|
53
53
|
|
|
54
|
-
**
|
|
54
|
+
**numPartitions** (`number`): Number of partitions for IVF indexes (Default: `128`)
|
|
55
|
+
|
|
56
|
+
**numSubVectors** (`number`): Number of sub-vectors for product quantization (Default: `16`)
|
|
57
|
+
|
|
58
|
+
**hnsw** (`HNSWConfig`): HNSW configuration
|
|
59
|
+
|
|
60
|
+
**hnsw\.m** (`number`): Maximum number of connections per node (default: 16)
|
|
61
|
+
|
|
62
|
+
**hnsw\.efConstruction** (`number`): Build-time complexity (default: 100)
|
|
55
63
|
|
|
56
64
|
### createTable()
|
|
57
65
|
|
|
58
|
-
**tableName
|
|
66
|
+
**tableName** (`string`): Name of the table to create
|
|
59
67
|
|
|
60
|
-
**data
|
|
68
|
+
**data** (`Record<string, unknown>[] | TableLike`): Initial data for the table
|
|
61
69
|
|
|
62
|
-
**options
|
|
70
|
+
**options** (`Partial<CreateTableOptions>`): Additional table creation options
|
|
63
71
|
|
|
64
72
|
### upsert()
|
|
65
73
|
|
|
66
|
-
**tableName
|
|
74
|
+
**tableName** (`string`): Name of the table to upsert vectors into
|
|
67
75
|
|
|
68
|
-
**vectors
|
|
76
|
+
**vectors** (`number[][]`): Array of embedding vectors
|
|
69
77
|
|
|
70
|
-
**metadata
|
|
78
|
+
**metadata** (`Record<string, any>[]`): Metadata for each vector
|
|
71
79
|
|
|
72
|
-
**ids
|
|
80
|
+
**ids** (`string[]`): Optional vector IDs (auto-generated if not provided)
|
|
73
81
|
|
|
74
82
|
### query()
|
|
75
83
|
|
|
76
|
-
**tableName
|
|
84
|
+
**tableName** (`string`): Name of the table to query
|
|
77
85
|
|
|
78
|
-
**queryVector
|
|
86
|
+
**queryVector** (`number[]`): Query vector
|
|
79
87
|
|
|
80
|
-
**topK
|
|
88
|
+
**topK** (`number`): Number of results to return (Default: `10`)
|
|
81
89
|
|
|
82
|
-
**filter
|
|
90
|
+
**filter** (`Record<string, any>`): Metadata filters
|
|
83
91
|
|
|
84
|
-
**includeVector
|
|
92
|
+
**includeVector** (`boolean`): Whether to include the vector in the result (Default: `false`)
|
|
85
93
|
|
|
86
|
-
**columns
|
|
94
|
+
**columns** (`string[]`): Specific columns to include in the result (Default: `[]`)
|
|
87
95
|
|
|
88
|
-
**includeAllColumns
|
|
96
|
+
**includeAllColumns** (`boolean`): Whether to include all columns in the result (Default: `false`)
|
|
89
97
|
|
|
90
98
|
### listTables()
|
|
91
99
|
|
|
@@ -98,13 +106,13 @@ const tables = await vectorStore.listTables()
|
|
|
98
106
|
|
|
99
107
|
### getTableSchema()
|
|
100
108
|
|
|
101
|
-
**tableName
|
|
109
|
+
**tableName** (`string`): Name of the table to describe
|
|
102
110
|
|
|
103
111
|
Returns the schema of the specified table.
|
|
104
112
|
|
|
105
113
|
### deleteTable()
|
|
106
114
|
|
|
107
|
-
**tableName
|
|
115
|
+
**tableName** (`string`): Name of the table to delete
|
|
108
116
|
|
|
109
117
|
### deleteAllTables()
|
|
110
118
|
|
|
@@ -116,7 +124,7 @@ Returns an array of index names as strings.
|
|
|
116
124
|
|
|
117
125
|
### describeIndex()
|
|
118
126
|
|
|
119
|
-
**indexName
|
|
127
|
+
**indexName** (`string`): Name of the index to describe
|
|
120
128
|
|
|
121
129
|
Returns information about the index:
|
|
122
130
|
|
|
@@ -137,35 +145,35 @@ interface IndexStats {
|
|
|
137
145
|
|
|
138
146
|
### deleteIndex()
|
|
139
147
|
|
|
140
|
-
**indexName
|
|
148
|
+
**indexName** (`string`): Name of the index to delete
|
|
141
149
|
|
|
142
150
|
### updateVector()
|
|
143
151
|
|
|
144
152
|
Update a single vector by ID or by metadata filter. Either `id` or `filter` must be provided, but not both.
|
|
145
153
|
|
|
146
|
-
**indexName
|
|
154
|
+
**indexName** (`string`): Name of the index containing the vector
|
|
147
155
|
|
|
148
|
-
**id
|
|
156
|
+
**id** (`string`): ID of the vector to update (mutually exclusive with filter)
|
|
149
157
|
|
|
150
|
-
**filter
|
|
158
|
+
**filter** (`Record<string, any>`): Metadata filter to identify vector(s) to update (mutually exclusive with id)
|
|
151
159
|
|
|
152
|
-
**update
|
|
160
|
+
**update** (`{ vector?: number[]; metadata?: Record<string, any>; }`): Object containing the vector and/or metadata to update
|
|
153
161
|
|
|
154
162
|
### deleteVector()
|
|
155
163
|
|
|
156
|
-
**indexName
|
|
164
|
+
**indexName** (`string`): Name of the index containing the vector
|
|
157
165
|
|
|
158
|
-
**id
|
|
166
|
+
**id** (`string`): ID of the vector to delete
|
|
159
167
|
|
|
160
168
|
### deleteVectors()
|
|
161
169
|
|
|
162
170
|
Delete multiple vectors by IDs or by metadata filter. Either `ids` or `filter` must be provided, but not both.
|
|
163
171
|
|
|
164
|
-
**indexName
|
|
172
|
+
**indexName** (`string`): Name of the index containing the vectors to delete
|
|
165
173
|
|
|
166
|
-
**ids
|
|
174
|
+
**ids** (`string[]`): Array of vector IDs to delete (mutually exclusive with filter)
|
|
167
175
|
|
|
168
|
-
**filter
|
|
176
|
+
**filter** (`Record<string, any>`): Metadata filter to identify vectors to delete (mutually exclusive with ids)
|
|
169
177
|
|
|
170
178
|
### close()
|
|
171
179
|
|
package/dist/index.cjs
CHANGED
|
@@ -131,10 +131,52 @@ function resolveLanceConfig(config) {
|
|
|
131
131
|
}
|
|
132
132
|
var LanceDB = class extends base.MastraBase {
|
|
133
133
|
client;
|
|
134
|
+
/** Cache of actual table columns: tableName -> Set<columnName> */
|
|
135
|
+
/** Cache of actual table columns: tableName -> Promise<Set<columnName>> (stores in-flight promise to coalesce concurrent calls) */
|
|
136
|
+
tableColumnsCache = /* @__PURE__ */ new Map();
|
|
134
137
|
constructor({ client }) {
|
|
135
138
|
super({ name: "lance-db" });
|
|
136
139
|
this.client = client;
|
|
137
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Gets the set of column names that actually exist in the database table.
|
|
143
|
+
* Results are cached; the cache is invalidated when alterTable() adds new columns.
|
|
144
|
+
*/
|
|
145
|
+
async getTableColumns(tableName) {
|
|
146
|
+
const cached = this.tableColumnsCache.get(tableName);
|
|
147
|
+
if (cached) return cached;
|
|
148
|
+
const promise = (async () => {
|
|
149
|
+
try {
|
|
150
|
+
const table = await this.client.openTable(tableName);
|
|
151
|
+
const schema = await table.schema();
|
|
152
|
+
const columns = new Set(schema.fields.map((f) => f.name));
|
|
153
|
+
if (columns.size === 0) {
|
|
154
|
+
this.tableColumnsCache.delete(tableName);
|
|
155
|
+
}
|
|
156
|
+
return columns;
|
|
157
|
+
} catch {
|
|
158
|
+
this.tableColumnsCache.delete(tableName);
|
|
159
|
+
return /* @__PURE__ */ new Set();
|
|
160
|
+
}
|
|
161
|
+
})();
|
|
162
|
+
this.tableColumnsCache.set(tableName, promise);
|
|
163
|
+
return promise;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Filters a record to only include columns that exist in the actual database table.
|
|
167
|
+
* Unknown columns are silently dropped to ensure forward compatibility.
|
|
168
|
+
*/
|
|
169
|
+
async filterRecordToKnownColumns(tableName, record) {
|
|
170
|
+
const knownColumns = await this.getTableColumns(tableName);
|
|
171
|
+
if (knownColumns.size === 0) return record;
|
|
172
|
+
const filtered = {};
|
|
173
|
+
for (const [key, value] of Object.entries(record)) {
|
|
174
|
+
if (knownColumns.has(key)) {
|
|
175
|
+
filtered[key] = value;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return filtered;
|
|
179
|
+
}
|
|
138
180
|
getDefaultValue(type) {
|
|
139
181
|
switch (type) {
|
|
140
182
|
case "text":
|
|
@@ -234,6 +276,8 @@ var LanceDB = class extends base.MastraBase {
|
|
|
234
276
|
},
|
|
235
277
|
error$1
|
|
236
278
|
);
|
|
279
|
+
} finally {
|
|
280
|
+
this.tableColumnsCache.delete(tableName);
|
|
237
281
|
}
|
|
238
282
|
}
|
|
239
283
|
async dropTable({ tableName }) {
|
|
@@ -272,6 +316,8 @@ var LanceDB = class extends base.MastraBase {
|
|
|
272
316
|
},
|
|
273
317
|
error$1
|
|
274
318
|
);
|
|
319
|
+
} finally {
|
|
320
|
+
this.tableColumnsCache.delete(tableName);
|
|
275
321
|
}
|
|
276
322
|
}
|
|
277
323
|
async alterTable({
|
|
@@ -338,6 +384,8 @@ var LanceDB = class extends base.MastraBase {
|
|
|
338
384
|
},
|
|
339
385
|
error$1
|
|
340
386
|
);
|
|
387
|
+
} finally {
|
|
388
|
+
this.tableColumnsCache.delete(tableName);
|
|
341
389
|
}
|
|
342
390
|
}
|
|
343
391
|
async clearTable({ tableName }) {
|
|
@@ -408,7 +456,9 @@ var LanceDB = class extends base.MastraBase {
|
|
|
408
456
|
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
409
457
|
}
|
|
410
458
|
}
|
|
411
|
-
await
|
|
459
|
+
const filteredRecord = await this.filterRecordToKnownColumns(tableName, processedRecord);
|
|
460
|
+
if (Object.keys(filteredRecord).length === 0) return;
|
|
461
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([filteredRecord]);
|
|
412
462
|
} catch (error$1) {
|
|
413
463
|
throw new error.MastraError(
|
|
414
464
|
{
|
|
@@ -457,7 +507,12 @@ var LanceDB = class extends base.MastraBase {
|
|
|
457
507
|
}
|
|
458
508
|
return processedRecord;
|
|
459
509
|
});
|
|
460
|
-
await
|
|
510
|
+
const filteredRecords = await Promise.all(
|
|
511
|
+
processedRecords.map((r) => this.filterRecordToKnownColumns(tableName, r))
|
|
512
|
+
);
|
|
513
|
+
const nonEmptyRecords = filteredRecords.filter((r) => Object.keys(r).length > 0);
|
|
514
|
+
if (nonEmptyRecords.length === 0) return;
|
|
515
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(nonEmptyRecords);
|
|
461
516
|
} catch (error$1) {
|
|
462
517
|
throw new error.MastraError(
|
|
463
518
|
{
|
|
@@ -808,6 +863,20 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
808
863
|
conditions.push(`\`createdAt\` ${endOp} ${endTime}`);
|
|
809
864
|
}
|
|
810
865
|
const whereClause = conditions.join(" AND ");
|
|
866
|
+
if (perPage === 0 && (!include || include.length === 0)) {
|
|
867
|
+
return { messages: [], total: 0, page, perPage: perPageForResponse, hasMore: false };
|
|
868
|
+
}
|
|
869
|
+
if (perPage === 0 && include && include.length > 0) {
|
|
870
|
+
const includedMessages = await this._getIncludedMessages(table, include);
|
|
871
|
+
const list2 = new agent.MessageList().add(includedMessages, "memory");
|
|
872
|
+
return {
|
|
873
|
+
messages: this._sortMessages(list2.get.all.db(), field, direction),
|
|
874
|
+
total: 0,
|
|
875
|
+
page,
|
|
876
|
+
perPage: perPageForResponse,
|
|
877
|
+
hasMore: false
|
|
878
|
+
};
|
|
879
|
+
}
|
|
811
880
|
const total = await table.countRows(whereClause);
|
|
812
881
|
const query = table.query().where(whereClause);
|
|
813
882
|
let allRecords = await query.toArray();
|
|
@@ -835,16 +904,7 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
835
904
|
}
|
|
836
905
|
const messageIds = new Set(messages.map((m) => m.id));
|
|
837
906
|
if (include && include.length > 0) {
|
|
838
|
-
const
|
|
839
|
-
const allThreadMessages = [];
|
|
840
|
-
for (const tid of threadIds2) {
|
|
841
|
-
const threadQuery = table.query().where(`thread_id = '${tid}'`);
|
|
842
|
-
let threadRecords = await threadQuery.toArray();
|
|
843
|
-
allThreadMessages.push(...threadRecords);
|
|
844
|
-
}
|
|
845
|
-
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
846
|
-
const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
|
|
847
|
-
const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
|
|
907
|
+
const includedMessages = await this._getIncludedMessages(table, include);
|
|
848
908
|
for (const includeMsg of includedMessages) {
|
|
849
909
|
if (!messageIds.has(includeMsg.id)) {
|
|
850
910
|
messages.push(includeMsg);
|
|
@@ -854,17 +914,7 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
854
914
|
}
|
|
855
915
|
const list = new agent.MessageList().add(messages, "memory");
|
|
856
916
|
let finalMessages = list.get.all.db();
|
|
857
|
-
finalMessages =
|
|
858
|
-
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
859
|
-
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
860
|
-
if (aValue == null && bValue == null) return 0;
|
|
861
|
-
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
862
|
-
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
863
|
-
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
864
|
-
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
865
|
-
}
|
|
866
|
-
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
867
|
-
});
|
|
917
|
+
finalMessages = this._sortMessages(finalMessages, field, direction);
|
|
868
918
|
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
869
919
|
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
870
920
|
const fetchedAll = perPageInput === false || allThreadMessagesReturned;
|
|
@@ -1043,6 +1093,62 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
1043
1093
|
);
|
|
1044
1094
|
}
|
|
1045
1095
|
}
|
|
1096
|
+
_sortMessages(messages, field, direction) {
|
|
1097
|
+
return messages.sort((a, b) => {
|
|
1098
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
1099
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
1100
|
+
if (aValue == null && bValue == null) return 0;
|
|
1101
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
1102
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
1103
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
1104
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
1105
|
+
}
|
|
1106
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
async _getIncludedMessages(table, include) {
|
|
1110
|
+
if (include.length === 0) return [];
|
|
1111
|
+
const targetIds = include.map((item) => item.id);
|
|
1112
|
+
const idCondition = targetIds.length === 1 ? `id = '${this.escapeSql(targetIds[0])}'` : `id IN (${targetIds.map((id) => `'${this.escapeSql(id)}'`).join(", ")})`;
|
|
1113
|
+
const targetRecords = await table.query().where(idCondition).toArray();
|
|
1114
|
+
const needsContext = include.some((item) => item.withPreviousMessages || item.withNextMessages);
|
|
1115
|
+
if (!needsContext) {
|
|
1116
|
+
return targetRecords.map((row) => this.normalizeMessage(row));
|
|
1117
|
+
}
|
|
1118
|
+
const threadIdsToFetch = [...new Set(targetRecords.map((r) => r.thread_id))];
|
|
1119
|
+
const threadCache = /* @__PURE__ */ new Map();
|
|
1120
|
+
for (const tid of threadIdsToFetch) {
|
|
1121
|
+
const threadRecords = await table.query().where(`thread_id = '${this.escapeSql(tid)}'`).toArray();
|
|
1122
|
+
threadRecords.sort((a, b) => a.createdAt - b.createdAt);
|
|
1123
|
+
threadCache.set(tid, threadRecords);
|
|
1124
|
+
}
|
|
1125
|
+
const targetThreadMap = /* @__PURE__ */ new Map();
|
|
1126
|
+
for (const r of targetRecords) {
|
|
1127
|
+
targetThreadMap.set(r.id, r.thread_id);
|
|
1128
|
+
}
|
|
1129
|
+
const includeByThread = /* @__PURE__ */ new Map();
|
|
1130
|
+
for (const item of include) {
|
|
1131
|
+
const tid = targetThreadMap.get(item.id);
|
|
1132
|
+
if (!tid) continue;
|
|
1133
|
+
const items = includeByThread.get(tid) ?? [];
|
|
1134
|
+
items.push(item);
|
|
1135
|
+
includeByThread.set(tid, items);
|
|
1136
|
+
}
|
|
1137
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1138
|
+
const allContextMessages = [];
|
|
1139
|
+
for (const [tid, threadInclude] of includeByThread) {
|
|
1140
|
+
const threadMessages = threadCache.get(tid) ?? [];
|
|
1141
|
+
const contextMessages = this.processMessagesWithContext(threadMessages, threadInclude);
|
|
1142
|
+
for (const msg of contextMessages) {
|
|
1143
|
+
if (!seen.has(msg.id)) {
|
|
1144
|
+
seen.add(msg.id);
|
|
1145
|
+
allContextMessages.push(msg);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
allContextMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
1150
|
+
return allContextMessages.map((row) => this.normalizeMessage(row));
|
|
1151
|
+
}
|
|
1046
1152
|
/**
|
|
1047
1153
|
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
1048
1154
|
* @param records - The sorted array of records to process
|
|
@@ -1052,7 +1158,8 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
1052
1158
|
processMessagesWithContext(records, include) {
|
|
1053
1159
|
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
1054
1160
|
if (messagesWithContext.length === 0) {
|
|
1055
|
-
|
|
1161
|
+
const targetIds = new Set(include.map((item) => item.id));
|
|
1162
|
+
return records.filter((record) => targetIds.has(record.id));
|
|
1056
1163
|
}
|
|
1057
1164
|
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
1058
1165
|
records.forEach((message, index) => {
|
|
@@ -1077,7 +1184,8 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
1077
1184
|
}
|
|
1078
1185
|
}
|
|
1079
1186
|
if (additionalIndices.size === 0) {
|
|
1080
|
-
|
|
1187
|
+
const targetIds = new Set(include.map((item) => item.id));
|
|
1188
|
+
return records.filter((record) => targetIds.has(record.id));
|
|
1081
1189
|
}
|
|
1082
1190
|
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
1083
1191
|
const allIndices = /* @__PURE__ */ new Set();
|