@mastra/libsql 0.10.2-alpha.1 → 0.10.2-alpha.2

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,23 +1,23 @@
1
1
 
2
- > @mastra/libsql@0.10.2-alpha.1 build /home/runner/work/mastra/mastra/stores/libsql
2
+ > @mastra/libsql@0.10.2-alpha.2 build /home/runner/work/mastra/mastra/stores/libsql
3
3
  > tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
4
4
 
5
5
  CLI Building entry: src/index.ts
6
6
  CLI Using tsconfig: tsconfig.json
7
7
  CLI tsup v8.5.0
8
8
  TSC Build start
9
- TSC ⚡️ Build success in 10122ms
9
+ TSC ⚡️ Build success in 9592ms
10
10
  DTS Build start
11
11
  CLI Target: es2022
12
12
  Analysis will use the bundled TypeScript version 5.8.3
13
13
  Writing package typings: /home/runner/work/mastra/mastra/stores/libsql/dist/_tsup-dts-rollup.d.ts
14
14
  Analysis will use the bundled TypeScript version 5.8.3
15
15
  Writing package typings: /home/runner/work/mastra/mastra/stores/libsql/dist/_tsup-dts-rollup.d.cts
16
- DTS ⚡️ Build success in 11851ms
16
+ DTS ⚡️ Build success in 10548ms
17
17
  CLI Cleaning output folder
18
18
  ESM Build start
19
19
  CJS Build start
20
- ESM dist/index.js 57.43 KB
21
- ESM ⚡️ Build success in 1740ms
22
- CJS dist/index.cjs 57.72 KB
23
- CJS ⚡️ Build success in 1740ms
20
+ ESM dist/index.js 58.54 KB
21
+ ESM ⚡️ Build success in 1646ms
22
+ CJS dist/index.cjs 58.83 KB
23
+ CJS ⚡️ Build success in 1647ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @mastra/libsql
2
2
 
3
+ ## 0.10.2-alpha.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 48eddb9: update filter logic in Memory class to support semantic recall search scope
8
+ - Updated dependencies [48eddb9]
9
+ - @mastra/core@0.10.4-alpha.2
10
+
3
11
  ## 0.10.2-alpha.1
4
12
 
5
13
  ### Patch Changes
@@ -84,6 +84,9 @@ declare class LibSQLStore extends MastraStorage {
84
84
  private readonly maxRetries;
85
85
  private readonly initialBackoffMs;
86
86
  constructor(config: LibSQLConfig);
87
+ get supports(): {
88
+ selectByIncludeResourceScope: boolean;
89
+ };
87
90
  private getCreateTableSQL;
88
91
  createTable({ tableName, schema, }: {
89
92
  tableName: TABLE_NAMES;
@@ -84,6 +84,9 @@ declare class LibSQLStore extends MastraStorage {
84
84
  private readonly maxRetries;
85
85
  private readonly initialBackoffMs;
86
86
  constructor(config: LibSQLConfig);
87
+ get supports(): {
88
+ selectByIncludeResourceScope: boolean;
89
+ };
87
90
  private getCreateTableSQL;
88
91
  createTable({ tableName, schema, }: {
89
92
  tableName: TABLE_NAMES;
package/dist/index.cjs CHANGED
@@ -818,6 +818,11 @@ var LibSQLStore = class extends storage.MastraStorage {
818
818
  this.client.execute("PRAGMA busy_timeout = 5000;").then(() => this.logger.debug("LibSQLStore: PRAGMA busy_timeout=5000 set.")).catch((err) => this.logger.warn("LibSQLStore: Failed to set PRAGMA busy_timeout.", err));
819
819
  }
820
820
  }
821
+ get supports() {
822
+ return {
823
+ selectByIncludeResourceScope: true
824
+ };
825
+ }
821
826
  getCreateTableSQL(tableName, schema) {
822
827
  const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
823
828
  const columns = Object.entries(schema).map(([name, col]) => {
@@ -1148,35 +1153,55 @@ var LibSQLStore = class extends storage.MastraStorage {
1148
1153
  if (row.type && row.type !== `v2`) result.type = row.type;
1149
1154
  return result;
1150
1155
  }
1151
- async _getIncludedMessages(threadId, selectBy) {
1156
+ async _getIncludedMessages({
1157
+ threadId,
1158
+ selectBy
1159
+ }) {
1152
1160
  const include = selectBy?.include;
1153
1161
  if (!include) return null;
1154
- const includeIds = include.map((i) => i.id);
1155
- const maxPrev = Math.max(...include.map((i) => i.withPreviousMessages || 0));
1156
- const maxNext = Math.max(...include.map((i) => i.withNextMessages || 0));
1157
- const includeResult = await this.client.execute({
1158
- sql: `
1159
- WITH numbered_messages AS (
1160
- SELECT
1161
- id, content, role, type, "createdAt", thread_id,
1162
- ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
1163
- FROM "${storage.TABLE_MESSAGES}"
1164
- WHERE thread_id = ?
1165
- ),
1166
- target_positions AS (
1167
- SELECT row_num as target_pos
1168
- FROM numbered_messages
1169
- WHERE id IN (${includeIds.map(() => "?").join(", ")})
1170
- )
1171
- SELECT DISTINCT m.*
1172
- FROM numbered_messages m
1173
- CROSS JOIN target_positions t
1174
- WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
1175
- ORDER BY m."createdAt" ASC
1176
- `,
1177
- args: [threadId, ...includeIds, maxPrev, maxNext]
1178
- });
1179
- return includeResult.rows?.map((row) => this.parseRow(row));
1162
+ const unionQueries = [];
1163
+ const params = [];
1164
+ for (const inc of include) {
1165
+ const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
1166
+ const searchId = inc.threadId || threadId;
1167
+ unionQueries.push(
1168
+ `
1169
+ SELECT * FROM (
1170
+ WITH numbered_messages AS (
1171
+ SELECT
1172
+ id, content, role, type, "createdAt", thread_id, "resourceId",
1173
+ ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
1174
+ FROM "${storage.TABLE_MESSAGES}"
1175
+ WHERE thread_id = ?
1176
+ ),
1177
+ target_positions AS (
1178
+ SELECT row_num as target_pos
1179
+ FROM numbered_messages
1180
+ WHERE id = ?
1181
+ )
1182
+ SELECT DISTINCT m.*
1183
+ FROM numbered_messages m
1184
+ CROSS JOIN target_positions t
1185
+ WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
1186
+ )
1187
+ `
1188
+ // Keep ASC for final sorting after fetching context
1189
+ );
1190
+ params.push(searchId, id, withPreviousMessages, withNextMessages);
1191
+ }
1192
+ const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
1193
+ const includedResult = await this.client.execute({ sql: finalQuery, args: params });
1194
+ const includedRows = includedResult.rows?.map((row) => this.parseRow(row));
1195
+ const dedupedRows = Object.values(
1196
+ includedRows.reduce(
1197
+ (acc, row) => {
1198
+ acc[row.id] = row;
1199
+ return acc;
1200
+ },
1201
+ {}
1202
+ )
1203
+ );
1204
+ return dedupedRows;
1180
1205
  }
1181
1206
  async getMessages({
1182
1207
  threadId,
@@ -1187,19 +1212,27 @@ var LibSQLStore = class extends storage.MastraStorage {
1187
1212
  const messages = [];
1188
1213
  const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
1189
1214
  if (selectBy?.include?.length) {
1190
- const includeMessages = await this._getIncludedMessages(threadId, selectBy);
1215
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
1191
1216
  if (includeMessages) {
1192
1217
  messages.push(...includeMessages);
1193
1218
  }
1194
1219
  }
1195
1220
  const excludeIds = messages.map((m) => m.id);
1196
1221
  const remainingSql = `
1197
- SELECT id, content, role, type, "createdAt", thread_id
1198
- FROM "${storage.TABLE_MESSAGES}"
1199
- WHERE thread_id = ?
1200
- ${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
1201
- ORDER BY "createdAt" DESC LIMIT ?
1202
- `;
1222
+ SELECT
1223
+ id,
1224
+ content,
1225
+ role,
1226
+ type,
1227
+ "createdAt",
1228
+ thread_id,
1229
+ "resourceId"
1230
+ FROM "${storage.TABLE_MESSAGES}"
1231
+ WHERE thread_id = ?
1232
+ ${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
1233
+ ORDER BY "createdAt" DESC
1234
+ LIMIT ?
1235
+ `;
1203
1236
  const remainingArgs = [threadId, ...excludeIds.length ? excludeIds : [], limit];
1204
1237
  const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
1205
1238
  if (remainingResult.rows) {
@@ -1221,7 +1254,7 @@ var LibSQLStore = class extends storage.MastraStorage {
1221
1254
  const toDate = dateRange?.end;
1222
1255
  const messages = [];
1223
1256
  if (selectBy?.include?.length) {
1224
- const includeMessages = await this._getIncludedMessages(threadId, selectBy);
1257
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
1225
1258
  if (includeMessages) {
1226
1259
  messages.push(...includeMessages);
1227
1260
  }
@@ -1283,16 +1316,27 @@ var LibSQLStore = class extends storage.MastraStorage {
1283
1316
  }
1284
1317
  const batchStatements = messages.map((message) => {
1285
1318
  const time = message.createdAt || /* @__PURE__ */ new Date();
1319
+ if (!message.threadId) {
1320
+ throw new Error(
1321
+ `Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
1322
+ );
1323
+ }
1324
+ if (!message.resourceId) {
1325
+ throw new Error(
1326
+ `Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
1327
+ );
1328
+ }
1286
1329
  return {
1287
- sql: `INSERT INTO ${storage.TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt)
1288
- VALUES (?, ?, ?, ?, ?, ?)`,
1330
+ sql: `INSERT INTO ${storage.TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt, resourceId)
1331
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,
1289
1332
  args: [
1290
1333
  message.id,
1291
- threadId,
1334
+ message.threadId,
1292
1335
  typeof message.content === "object" ? JSON.stringify(message.content) : message.content,
1293
1336
  message.role,
1294
1337
  message.type || "v2",
1295
- time instanceof Date ? time.toISOString() : time
1338
+ time instanceof Date ? time.toISOString() : time,
1339
+ message.resourceId
1296
1340
  ]
1297
1341
  };
1298
1342
  });
package/dist/index.js CHANGED
@@ -816,6 +816,11 @@ var LibSQLStore = class extends MastraStorage {
816
816
  this.client.execute("PRAGMA busy_timeout = 5000;").then(() => this.logger.debug("LibSQLStore: PRAGMA busy_timeout=5000 set.")).catch((err) => this.logger.warn("LibSQLStore: Failed to set PRAGMA busy_timeout.", err));
817
817
  }
818
818
  }
819
+ get supports() {
820
+ return {
821
+ selectByIncludeResourceScope: true
822
+ };
823
+ }
819
824
  getCreateTableSQL(tableName, schema) {
820
825
  const parsedTableName = parseSqlIdentifier(tableName, "table name");
821
826
  const columns = Object.entries(schema).map(([name, col]) => {
@@ -1146,35 +1151,55 @@ var LibSQLStore = class extends MastraStorage {
1146
1151
  if (row.type && row.type !== `v2`) result.type = row.type;
1147
1152
  return result;
1148
1153
  }
1149
- async _getIncludedMessages(threadId, selectBy) {
1154
+ async _getIncludedMessages({
1155
+ threadId,
1156
+ selectBy
1157
+ }) {
1150
1158
  const include = selectBy?.include;
1151
1159
  if (!include) return null;
1152
- const includeIds = include.map((i) => i.id);
1153
- const maxPrev = Math.max(...include.map((i) => i.withPreviousMessages || 0));
1154
- const maxNext = Math.max(...include.map((i) => i.withNextMessages || 0));
1155
- const includeResult = await this.client.execute({
1156
- sql: `
1157
- WITH numbered_messages AS (
1158
- SELECT
1159
- id, content, role, type, "createdAt", thread_id,
1160
- ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
1161
- FROM "${TABLE_MESSAGES}"
1162
- WHERE thread_id = ?
1163
- ),
1164
- target_positions AS (
1165
- SELECT row_num as target_pos
1166
- FROM numbered_messages
1167
- WHERE id IN (${includeIds.map(() => "?").join(", ")})
1168
- )
1169
- SELECT DISTINCT m.*
1170
- FROM numbered_messages m
1171
- CROSS JOIN target_positions t
1172
- WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
1173
- ORDER BY m."createdAt" ASC
1174
- `,
1175
- args: [threadId, ...includeIds, maxPrev, maxNext]
1176
- });
1177
- return includeResult.rows?.map((row) => this.parseRow(row));
1160
+ const unionQueries = [];
1161
+ const params = [];
1162
+ for (const inc of include) {
1163
+ const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
1164
+ const searchId = inc.threadId || threadId;
1165
+ unionQueries.push(
1166
+ `
1167
+ SELECT * FROM (
1168
+ WITH numbered_messages AS (
1169
+ SELECT
1170
+ id, content, role, type, "createdAt", thread_id, "resourceId",
1171
+ ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
1172
+ FROM "${TABLE_MESSAGES}"
1173
+ WHERE thread_id = ?
1174
+ ),
1175
+ target_positions AS (
1176
+ SELECT row_num as target_pos
1177
+ FROM numbered_messages
1178
+ WHERE id = ?
1179
+ )
1180
+ SELECT DISTINCT m.*
1181
+ FROM numbered_messages m
1182
+ CROSS JOIN target_positions t
1183
+ WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
1184
+ )
1185
+ `
1186
+ // Keep ASC for final sorting after fetching context
1187
+ );
1188
+ params.push(searchId, id, withPreviousMessages, withNextMessages);
1189
+ }
1190
+ const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
1191
+ const includedResult = await this.client.execute({ sql: finalQuery, args: params });
1192
+ const includedRows = includedResult.rows?.map((row) => this.parseRow(row));
1193
+ const dedupedRows = Object.values(
1194
+ includedRows.reduce(
1195
+ (acc, row) => {
1196
+ acc[row.id] = row;
1197
+ return acc;
1198
+ },
1199
+ {}
1200
+ )
1201
+ );
1202
+ return dedupedRows;
1178
1203
  }
1179
1204
  async getMessages({
1180
1205
  threadId,
@@ -1185,19 +1210,27 @@ var LibSQLStore = class extends MastraStorage {
1185
1210
  const messages = [];
1186
1211
  const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
1187
1212
  if (selectBy?.include?.length) {
1188
- const includeMessages = await this._getIncludedMessages(threadId, selectBy);
1213
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
1189
1214
  if (includeMessages) {
1190
1215
  messages.push(...includeMessages);
1191
1216
  }
1192
1217
  }
1193
1218
  const excludeIds = messages.map((m) => m.id);
1194
1219
  const remainingSql = `
1195
- SELECT id, content, role, type, "createdAt", thread_id
1196
- FROM "${TABLE_MESSAGES}"
1197
- WHERE thread_id = ?
1198
- ${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
1199
- ORDER BY "createdAt" DESC LIMIT ?
1200
- `;
1220
+ SELECT
1221
+ id,
1222
+ content,
1223
+ role,
1224
+ type,
1225
+ "createdAt",
1226
+ thread_id,
1227
+ "resourceId"
1228
+ FROM "${TABLE_MESSAGES}"
1229
+ WHERE thread_id = ?
1230
+ ${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
1231
+ ORDER BY "createdAt" DESC
1232
+ LIMIT ?
1233
+ `;
1201
1234
  const remainingArgs = [threadId, ...excludeIds.length ? excludeIds : [], limit];
1202
1235
  const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
1203
1236
  if (remainingResult.rows) {
@@ -1219,7 +1252,7 @@ var LibSQLStore = class extends MastraStorage {
1219
1252
  const toDate = dateRange?.end;
1220
1253
  const messages = [];
1221
1254
  if (selectBy?.include?.length) {
1222
- const includeMessages = await this._getIncludedMessages(threadId, selectBy);
1255
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
1223
1256
  if (includeMessages) {
1224
1257
  messages.push(...includeMessages);
1225
1258
  }
@@ -1281,16 +1314,27 @@ var LibSQLStore = class extends MastraStorage {
1281
1314
  }
1282
1315
  const batchStatements = messages.map((message) => {
1283
1316
  const time = message.createdAt || /* @__PURE__ */ new Date();
1317
+ if (!message.threadId) {
1318
+ throw new Error(
1319
+ `Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
1320
+ );
1321
+ }
1322
+ if (!message.resourceId) {
1323
+ throw new Error(
1324
+ `Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
1325
+ );
1326
+ }
1284
1327
  return {
1285
- sql: `INSERT INTO ${TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt)
1286
- VALUES (?, ?, ?, ?, ?, ?)`,
1328
+ sql: `INSERT INTO ${TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt, resourceId)
1329
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,
1287
1330
  args: [
1288
1331
  message.id,
1289
- threadId,
1332
+ message.threadId,
1290
1333
  typeof message.content === "object" ? JSON.stringify(message.content) : message.content,
1291
1334
  message.role,
1292
1335
  message.type || "v2",
1293
- time instanceof Date ? time.toISOString() : time
1336
+ time instanceof Date ? time.toISOString() : time,
1337
+ message.resourceId
1294
1338
  ]
1295
1339
  };
1296
1340
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/libsql",
3
- "version": "0.10.2-alpha.1",
3
+ "version": "0.10.2-alpha.2",
4
4
  "description": "Libsql provider for Mastra - includes both vector and db storage capabilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,9 +29,9 @@
29
29
  "tsup": "^8.5.0",
30
30
  "typescript": "^5.8.3",
31
31
  "vitest": "^3.2.2",
32
- "@mastra/core": "0.10.4-alpha.1",
33
- "@internal/storage-test-utils": "0.0.6",
34
- "@internal/lint": "0.0.10"
32
+ "@internal/lint": "0.0.10",
33
+ "@mastra/core": "0.10.4-alpha.2",
34
+ "@internal/storage-test-utils": "0.0.6"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@mastra/core": "^0.10.2-alpha.0"
@@ -81,6 +81,14 @@ export class LibSQLStore extends MastraStorage {
81
81
  }
82
82
  }
83
83
 
84
+ public get supports(): {
85
+ selectByIncludeResourceScope: boolean;
86
+ } {
87
+ return {
88
+ selectByIncludeResourceScope: true,
89
+ };
90
+ }
91
+
84
92
  private getCreateTableSQL(tableName: TABLE_NAMES, schema: Record<string, StorageColumn>): string {
85
93
  const parsedTableName = parseSqlIdentifier(tableName, 'table name');
86
94
  const columns = Object.entries(schema).map(([name, col]) => {
@@ -476,7 +484,6 @@ export class LibSQLStore extends MastraStorage {
476
484
  sql: `DELETE FROM ${TABLE_MESSAGES} WHERE thread_id = ?`,
477
485
  args: [threadId],
478
486
  });
479
-
480
487
  await this.client.execute({
481
488
  sql: `DELETE FROM ${TABLE_THREADS} WHERE id = ?`,
482
489
  args: [threadId],
@@ -503,37 +510,60 @@ export class LibSQLStore extends MastraStorage {
503
510
  return result;
504
511
  }
505
512
 
506
- private async _getIncludedMessages(threadId: string, selectBy: StorageGetMessagesArg['selectBy']) {
513
+ private async _getIncludedMessages({
514
+ threadId,
515
+ selectBy,
516
+ }: {
517
+ threadId: string;
518
+ selectBy: StorageGetMessagesArg['selectBy'];
519
+ }) {
507
520
  const include = selectBy?.include;
508
521
  if (!include) return null;
509
522
 
510
- const includeIds = include.map(i => i.id);
511
- const maxPrev = Math.max(...include.map(i => i.withPreviousMessages || 0));
512
- const maxNext = Math.max(...include.map(i => i.withNextMessages || 0));
513
-
514
- const includeResult = await this.client.execute({
515
- sql: `
516
- WITH numbered_messages AS (
517
- SELECT
518
- id, content, role, type, "createdAt", thread_id,
519
- ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
520
- FROM "${TABLE_MESSAGES}"
521
- WHERE thread_id = ?
522
- ),
523
- target_positions AS (
524
- SELECT row_num as target_pos
525
- FROM numbered_messages
526
- WHERE id IN (${includeIds.map(() => '?').join(', ')})
527
- )
528
- SELECT DISTINCT m.*
529
- FROM numbered_messages m
530
- CROSS JOIN target_positions t
531
- WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
532
- ORDER BY m."createdAt" ASC
533
- `,
534
- args: [threadId, ...includeIds, maxPrev, maxNext],
535
- });
536
- return includeResult.rows?.map((row: any) => this.parseRow(row));
523
+ const unionQueries: string[] = [];
524
+ const params: any[] = [];
525
+
526
+ for (const inc of include) {
527
+ const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
528
+ // if threadId is provided, use it, otherwise use threadId from args
529
+ const searchId = inc.threadId || threadId;
530
+ unionQueries.push(
531
+ `
532
+ SELECT * FROM (
533
+ WITH numbered_messages AS (
534
+ SELECT
535
+ id, content, role, type, "createdAt", thread_id, "resourceId",
536
+ ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
537
+ FROM "${TABLE_MESSAGES}"
538
+ WHERE thread_id = ?
539
+ ),
540
+ target_positions AS (
541
+ SELECT row_num as target_pos
542
+ FROM numbered_messages
543
+ WHERE id = ?
544
+ )
545
+ SELECT DISTINCT m.*
546
+ FROM numbered_messages m
547
+ CROSS JOIN target_positions t
548
+ WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
549
+ )
550
+ `, // Keep ASC for final sorting after fetching context
551
+ );
552
+ params.push(searchId, id, withPreviousMessages, withNextMessages);
553
+ }
554
+ const finalQuery = unionQueries.join(' UNION ALL ') + ' ORDER BY "createdAt" ASC';
555
+ const includedResult = await this.client.execute({ sql: finalQuery, args: params });
556
+ const includedRows = includedResult.rows?.map(row => this.parseRow(row));
557
+ const dedupedRows = Object.values(
558
+ includedRows.reduce(
559
+ (acc, row) => {
560
+ acc[row.id] = row;
561
+ return acc;
562
+ },
563
+ {} as Record<string, MastraMessageV2>,
564
+ ),
565
+ );
566
+ return dedupedRows;
537
567
  }
538
568
 
539
569
  /**
@@ -553,7 +583,7 @@ export class LibSQLStore extends MastraStorage {
553
583
  const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
554
584
 
555
585
  if (selectBy?.include?.length) {
556
- const includeMessages = await this._getIncludedMessages(threadId, selectBy);
586
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
557
587
  if (includeMessages) {
558
588
  messages.push(...includeMessages);
559
589
  }
@@ -561,12 +591,20 @@ export class LibSQLStore extends MastraStorage {
561
591
 
562
592
  const excludeIds = messages.map(m => m.id);
563
593
  const remainingSql = `
564
- SELECT id, content, role, type, "createdAt", thread_id
565
- FROM "${TABLE_MESSAGES}"
566
- WHERE thread_id = ?
567
- ${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => '?').join(', ')})` : ''}
568
- ORDER BY "createdAt" DESC LIMIT ?
569
- `;
594
+ SELECT
595
+ id,
596
+ content,
597
+ role,
598
+ type,
599
+ "createdAt",
600
+ thread_id,
601
+ "resourceId"
602
+ FROM "${TABLE_MESSAGES}"
603
+ WHERE thread_id = ?
604
+ ${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => '?').join(', ')})` : ''}
605
+ ORDER BY "createdAt" DESC
606
+ LIMIT ?
607
+ `;
570
608
  const remainingArgs = [threadId, ...(excludeIds.length ? excludeIds : []), limit];
571
609
  const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
572
610
  if (remainingResult.rows) {
@@ -595,7 +633,7 @@ export class LibSQLStore extends MastraStorage {
595
633
  const messages: MastraMessageV2[] = [];
596
634
 
597
635
  if (selectBy?.include?.length) {
598
- const includeMessages = await this._getIncludedMessages(threadId, selectBy);
636
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
599
637
  if (includeMessages) {
600
638
  messages.push(...includeMessages);
601
639
  }
@@ -677,16 +715,27 @@ export class LibSQLStore extends MastraStorage {
677
715
  // Prepare batch statements for all messages
678
716
  const batchStatements = messages.map(message => {
679
717
  const time = message.createdAt || new Date();
718
+ if (!message.threadId) {
719
+ throw new Error(
720
+ `Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`,
721
+ );
722
+ }
723
+ if (!message.resourceId) {
724
+ throw new Error(
725
+ `Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`,
726
+ );
727
+ }
680
728
  return {
681
- sql: `INSERT INTO ${TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt)
682
- VALUES (?, ?, ?, ?, ?, ?)`,
729
+ sql: `INSERT INTO ${TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt, resourceId)
730
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,
683
731
  args: [
684
732
  message.id,
685
- threadId,
733
+ message.threadId!,
686
734
  typeof message.content === 'object' ? JSON.stringify(message.content) : message.content,
687
735
  message.role,
688
736
  message.type || 'v2',
689
737
  time instanceof Date ? time.toISOString() : time,
738
+ message.resourceId,
690
739
  ],
691
740
  };
692
741
  });