@mastra/libsql 0.11.2 → 0.11.3-alpha.1

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.11.1 build /home/runner/work/mastra/mastra/stores/libsql
2
+ > @mastra/libsql@0.11.3-alpha.1 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 10836ms
9
+ TSC ⚡️ Build success in 10968ms
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 12706ms
16
+ DTS ⚡️ Build success in 13655ms
17
17
  CLI Cleaning output folder
18
18
  ESM Build start
19
19
  CJS Build start
20
- CJS dist/index.cjs 88.28 KB
21
- CJS ⚡️ Build success in 2514ms
22
- ESM dist/index.js 87.22 KB
23
- ESM ⚡️ Build success in 2514ms
20
+ CJS dist/index.cjs 90.83 KB
21
+ CJS ⚡️ Build success in 2374ms
22
+ ESM dist/index.js 89.73 KB
23
+ ESM ⚡️ Build success in 2376ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @mastra/libsql
2
2
 
3
+ ## 0.11.3-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - ff9c125: enhance thread retrieval with sorting options in libsql and pg
8
+ - b8efbb9: feat: add flexible deleteMessages method to memory API
9
+ - Added `memory.deleteMessages(input)` method that accepts multiple input types:
10
+ - Single message ID as string: `deleteMessages('msg-123')`
11
+ - Array of message IDs: `deleteMessages(['msg-1', 'msg-2'])`
12
+ - Message object with id property: `deleteMessages({ id: 'msg-123' })`
13
+ - Array of message objects: `deleteMessages([{ id: 'msg-1' }, { id: 'msg-2' }])`
14
+ - Implemented in all storage adapters (LibSQL, PostgreSQL, Upstash, InMemory)
15
+ - Added REST API endpoint: `POST /api/memory/messages/delete`
16
+ - Updated client SDK: `thread.deleteMessages()` accepts all input types
17
+ - Updates thread timestamps when messages are deleted
18
+ - Added comprehensive test coverage and documentation
19
+
20
+ - Updated dependencies [27cc97a]
21
+ - Updated dependencies [41daa63]
22
+ - Updated dependencies [254a36b]
23
+ - Updated dependencies [0b89602]
24
+ - Updated dependencies [4d37822]
25
+ - Updated dependencies [ff9c125]
26
+ - Updated dependencies [b8efbb9]
27
+ - Updated dependencies [71466e7]
28
+ - Updated dependencies [0c99fbe]
29
+ - @mastra/core@0.12.0-alpha.2
30
+
31
+ ## 0.11.3-alpha.0
32
+
33
+ ### Patch Changes
34
+
35
+ - 24ac5ff: dependencies updates:
36
+ - Updated dependency [`@libsql/client@^0.15.10` ↗︎](https://www.npmjs.com/package/@libsql/client/v/0.15.10) (from `^0.15.9`, in `dependencies`)
37
+ - a3ca14c: `LibSQLVector.doUpsert`: check if transaction is open before attempting rollback
38
+ - Updated dependencies [510e2c8]
39
+ - Updated dependencies [2f72fb2]
40
+ - Updated dependencies [3f89307]
41
+ - Updated dependencies [9eda7d4]
42
+ - Updated dependencies [9d49408]
43
+ - Updated dependencies [2ecf658]
44
+ - Updated dependencies [7a7754f]
45
+ - Updated dependencies [fc92d80]
46
+ - Updated dependencies [23a6a7c]
47
+ - Updated dependencies [09bca64]
48
+ - @mastra/core@0.12.0-alpha.0
49
+
3
50
  ## 0.11.2
4
51
 
5
52
  ### Patch Changes
@@ -34,6 +34,7 @@ import type { StorageResourceType } from '@mastra/core/storage';
34
34
  import type { StorageThreadType } from '@mastra/core/memory';
35
35
  import { StoreOperations } from '@mastra/core/storage';
36
36
  import type { TABLE_NAMES } from '@mastra/core/storage';
37
+ import type { ThreadSortOptions } from '@mastra/core/storage';
37
38
  import type { Trace } from '@mastra/core/telemetry';
38
39
  import { TracesStorage } from '@mastra/core/storage';
39
40
  import type { UpdateVectorParams } from '@mastra/core/vector';
@@ -147,6 +148,7 @@ declare class LibSQLStore extends MastraStorage {
147
148
  resourceWorkingMemory: boolean;
148
149
  hasColumn: boolean;
149
150
  createTable: boolean;
151
+ deleteMessages: boolean;
150
152
  };
151
153
  createTable({ tableName, schema, }: {
152
154
  tableName: TABLE_NAMES;
@@ -189,12 +191,12 @@ declare class LibSQLStore extends MastraStorage {
189
191
  */
190
192
  getThreadsByResourceId(args: {
191
193
  resourceId: string;
192
- }): Promise<StorageThreadType[]>;
194
+ } & ThreadSortOptions): Promise<StorageThreadType[]>;
193
195
  getThreadsByResourceIdPaginated(args: {
194
196
  resourceId: string;
195
197
  page: number;
196
198
  perPage: number;
197
- }): Promise<PaginationInfo & {
199
+ } & ThreadSortOptions): Promise<PaginationInfo & {
198
200
  threads: StorageThreadType[];
199
201
  }>;
200
202
  saveThread({ thread }: {
@@ -239,6 +241,7 @@ declare class LibSQLStore extends MastraStorage {
239
241
  };
240
242
  })[];
241
243
  }): Promise<MastraMessageV2[]>;
244
+ deleteMessages(messageIds: string[]): Promise<void>;
242
245
  /** @deprecated use getEvals instead */
243
246
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
244
247
  getEvals(options?: {
@@ -443,6 +446,7 @@ export declare class MemoryLibSQL extends MemoryStorage {
443
446
  };
444
447
  })[];
445
448
  }): Promise<MastraMessageV2_2[]>;
449
+ deleteMessages(messageIds: string[]): Promise<void>;
446
450
  getResourceById({ resourceId }: {
447
451
  resourceId: string;
448
452
  }): Promise<StorageResourceType | null>;
@@ -462,12 +466,12 @@ export declare class MemoryLibSQL extends MemoryStorage {
462
466
  */
463
467
  getThreadsByResourceId(args: {
464
468
  resourceId: string;
465
- }): Promise<StorageThreadType[]>;
469
+ } & ThreadSortOptions): Promise<StorageThreadType[]>;
466
470
  getThreadsByResourceIdPaginated(args: {
467
471
  resourceId: string;
468
472
  page: number;
469
473
  perPage: number;
470
- }): Promise<PaginationInfo & {
474
+ } & ThreadSortOptions): Promise<PaginationInfo & {
471
475
  threads: StorageThreadType[];
472
476
  }>;
473
477
  saveThread({ thread }: {
@@ -34,6 +34,7 @@ import type { StorageResourceType } from '@mastra/core/storage';
34
34
  import type { StorageThreadType } from '@mastra/core/memory';
35
35
  import { StoreOperations } from '@mastra/core/storage';
36
36
  import type { TABLE_NAMES } from '@mastra/core/storage';
37
+ import type { ThreadSortOptions } from '@mastra/core/storage';
37
38
  import type { Trace } from '@mastra/core/telemetry';
38
39
  import { TracesStorage } from '@mastra/core/storage';
39
40
  import type { UpdateVectorParams } from '@mastra/core/vector';
@@ -147,6 +148,7 @@ declare class LibSQLStore extends MastraStorage {
147
148
  resourceWorkingMemory: boolean;
148
149
  hasColumn: boolean;
149
150
  createTable: boolean;
151
+ deleteMessages: boolean;
150
152
  };
151
153
  createTable({ tableName, schema, }: {
152
154
  tableName: TABLE_NAMES;
@@ -189,12 +191,12 @@ declare class LibSQLStore extends MastraStorage {
189
191
  */
190
192
  getThreadsByResourceId(args: {
191
193
  resourceId: string;
192
- }): Promise<StorageThreadType[]>;
194
+ } & ThreadSortOptions): Promise<StorageThreadType[]>;
193
195
  getThreadsByResourceIdPaginated(args: {
194
196
  resourceId: string;
195
197
  page: number;
196
198
  perPage: number;
197
- }): Promise<PaginationInfo & {
199
+ } & ThreadSortOptions): Promise<PaginationInfo & {
198
200
  threads: StorageThreadType[];
199
201
  }>;
200
202
  saveThread({ thread }: {
@@ -239,6 +241,7 @@ declare class LibSQLStore extends MastraStorage {
239
241
  };
240
242
  })[];
241
243
  }): Promise<MastraMessageV2[]>;
244
+ deleteMessages(messageIds: string[]): Promise<void>;
242
245
  /** @deprecated use getEvals instead */
243
246
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
244
247
  getEvals(options?: {
@@ -443,6 +446,7 @@ export declare class MemoryLibSQL extends MemoryStorage {
443
446
  };
444
447
  })[];
445
448
  }): Promise<MastraMessageV2_2[]>;
449
+ deleteMessages(messageIds: string[]): Promise<void>;
446
450
  getResourceById({ resourceId }: {
447
451
  resourceId: string;
448
452
  }): Promise<StorageResourceType | null>;
@@ -462,12 +466,12 @@ export declare class MemoryLibSQL extends MemoryStorage {
462
466
  */
463
467
  getThreadsByResourceId(args: {
464
468
  resourceId: string;
465
- }): Promise<StorageThreadType[]>;
469
+ } & ThreadSortOptions): Promise<StorageThreadType[]>;
466
470
  getThreadsByResourceIdPaginated(args: {
467
471
  resourceId: string;
468
472
  page: number;
469
473
  perPage: number;
470
- }): Promise<PaginationInfo & {
474
+ } & ThreadSortOptions): Promise<PaginationInfo & {
471
475
  threads: StorageThreadType[];
472
476
  }>;
473
477
  saveThread({ thread }: {
package/dist/index.cjs CHANGED
@@ -652,7 +652,7 @@ var LibSQLVector = class extends vector.MastraVector {
652
652
  await tx.commit();
653
653
  return vectorIds;
654
654
  } catch (error) {
655
- await tx.rollback();
655
+ !tx.closed && await tx.rollback();
656
656
  if (error instanceof Error && error.message?.includes("dimensions are different")) {
657
657
  const match = error.message.match(/dimensions are different: (\d+) != (\d+)/);
658
658
  if (match) {
@@ -1249,14 +1249,14 @@ var MemoryLibSQL = class extends storage.MemoryStorage {
1249
1249
  );
1250
1250
  }
1251
1251
  return {
1252
- sql: `INSERT INTO ${storage.TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt, resourceId)
1252
+ sql: `INSERT INTO "${storage.TABLE_MESSAGES}" (id, thread_id, content, role, type, "createdAt", "resourceId")
1253
1253
  VALUES (?, ?, ?, ?, ?, ?, ?)
1254
1254
  ON CONFLICT(id) DO UPDATE SET
1255
1255
  thread_id=excluded.thread_id,
1256
1256
  content=excluded.content,
1257
1257
  role=excluded.role,
1258
1258
  type=excluded.type,
1259
- resourceId=excluded.resourceId
1259
+ "resourceId"=excluded."resourceId"
1260
1260
  `,
1261
1261
  args: [
1262
1262
  message.id,
@@ -1271,10 +1271,21 @@ var MemoryLibSQL = class extends storage.MemoryStorage {
1271
1271
  });
1272
1272
  const now = (/* @__PURE__ */ new Date()).toISOString();
1273
1273
  batchStatements.push({
1274
- sql: `UPDATE ${storage.TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
1274
+ sql: `UPDATE "${storage.TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
1275
1275
  args: [now, threadId]
1276
1276
  });
1277
- await this.client.batch(batchStatements, "write");
1277
+ const BATCH_SIZE = 50;
1278
+ const messageStatements = batchStatements.slice(0, -1);
1279
+ const threadUpdateStatement = batchStatements[batchStatements.length - 1];
1280
+ for (let i = 0; i < messageStatements.length; i += BATCH_SIZE) {
1281
+ const batch = messageStatements.slice(i, i + BATCH_SIZE);
1282
+ if (batch.length > 0) {
1283
+ await this.client.batch(batch, "write");
1284
+ }
1285
+ }
1286
+ if (threadUpdateStatement) {
1287
+ await this.client.execute(threadUpdateStatement);
1288
+ }
1278
1289
  const list = new agent.MessageList().add(messages, "memory");
1279
1290
  if (format === `v2`) return list.get.all.v2();
1280
1291
  return list.get.all.v1();
@@ -1368,6 +1379,56 @@ var MemoryLibSQL = class extends storage.MemoryStorage {
1368
1379
  const updatedResult = await this.client.execute({ sql: selectSql, args: messageIds });
1369
1380
  return updatedResult.rows.map((row) => this.parseRow(row));
1370
1381
  }
1382
+ async deleteMessages(messageIds) {
1383
+ if (!messageIds || messageIds.length === 0) {
1384
+ return;
1385
+ }
1386
+ try {
1387
+ const BATCH_SIZE = 100;
1388
+ const threadIds = /* @__PURE__ */ new Set();
1389
+ const tx = await this.client.transaction("write");
1390
+ try {
1391
+ for (let i = 0; i < messageIds.length; i += BATCH_SIZE) {
1392
+ const batch = messageIds.slice(i, i + BATCH_SIZE);
1393
+ const placeholders = batch.map(() => "?").join(",");
1394
+ const result = await tx.execute({
1395
+ sql: `SELECT DISTINCT thread_id FROM "${storage.TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
1396
+ args: batch
1397
+ });
1398
+ result.rows?.forEach((row) => {
1399
+ if (row.thread_id) threadIds.add(row.thread_id);
1400
+ });
1401
+ await tx.execute({
1402
+ sql: `DELETE FROM "${storage.TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
1403
+ args: batch
1404
+ });
1405
+ }
1406
+ if (threadIds.size > 0) {
1407
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1408
+ for (const threadId of threadIds) {
1409
+ await tx.execute({
1410
+ sql: `UPDATE "${storage.TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
1411
+ args: [now, threadId]
1412
+ });
1413
+ }
1414
+ }
1415
+ await tx.commit();
1416
+ } catch (error) {
1417
+ await tx.rollback();
1418
+ throw error;
1419
+ }
1420
+ } catch (error$1) {
1421
+ throw new error.MastraError(
1422
+ {
1423
+ id: "LIBSQL_STORE_DELETE_MESSAGES_FAILED",
1424
+ domain: error.ErrorDomain.STORAGE,
1425
+ category: error.ErrorCategory.THIRD_PARTY,
1426
+ details: { messageIds: messageIds.join(", ") }
1427
+ },
1428
+ error$1
1429
+ );
1430
+ }
1431
+ }
1371
1432
  async getResourceById({ resourceId }) {
1372
1433
  const result = await this.operations.load({
1373
1434
  tableName: storage.TABLE_RESOURCES,
@@ -1471,7 +1532,9 @@ var MemoryLibSQL = class extends storage.MemoryStorage {
1471
1532
  * @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
1472
1533
  */
1473
1534
  async getThreadsByResourceId(args) {
1474
- const { resourceId } = args;
1535
+ const resourceId = args.resourceId;
1536
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1537
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1475
1538
  try {
1476
1539
  const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
1477
1540
  const queryParams = [resourceId];
@@ -1486,7 +1549,7 @@ var MemoryLibSQL = class extends storage.MemoryStorage {
1486
1549
  metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
1487
1550
  });
1488
1551
  const result = await this.client.execute({
1489
- sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC`,
1552
+ sql: `SELECT * ${baseQuery} ORDER BY ${orderBy} ${sortDirection}`,
1490
1553
  args: queryParams
1491
1554
  });
1492
1555
  if (!result.rows) {
@@ -1510,6 +1573,8 @@ var MemoryLibSQL = class extends storage.MemoryStorage {
1510
1573
  }
1511
1574
  async getThreadsByResourceIdPaginated(args) {
1512
1575
  const { resourceId, page = 0, perPage = 100 } = args;
1576
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1577
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1513
1578
  try {
1514
1579
  const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
1515
1580
  const queryParams = [resourceId];
@@ -1539,7 +1604,7 @@ var MemoryLibSQL = class extends storage.MemoryStorage {
1539
1604
  };
1540
1605
  }
1541
1606
  const dataResult = await this.client.execute({
1542
- sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
1607
+ sql: `SELECT * ${baseQuery} ORDER BY ${orderBy} ${sortDirection} LIMIT ? OFFSET ?`,
1543
1608
  args: [...queryParams, perPage, currentOffset]
1544
1609
  });
1545
1610
  const threads = (dataResult.rows || []).map(mapRowToStorageThreadType);
@@ -2451,7 +2516,8 @@ var LibSQLStore = class extends storage.MastraStorage {
2451
2516
  selectByIncludeResourceScope: true,
2452
2517
  resourceWorkingMemory: true,
2453
2518
  hasColumn: true,
2454
- createTable: true
2519
+ createTable: true,
2520
+ deleteMessages: true
2455
2521
  };
2456
2522
  }
2457
2523
  async createTable({
@@ -2531,6 +2597,9 @@ var LibSQLStore = class extends storage.MastraStorage {
2531
2597
  }) {
2532
2598
  return this.stores.memory.updateMessages({ messages });
2533
2599
  }
2600
+ async deleteMessages(messageIds) {
2601
+ return this.stores.memory.deleteMessages(messageIds);
2602
+ }
2534
2603
  /** @deprecated use getEvals instead */
2535
2604
  async getEvalsByAgentName(agentName, type) {
2536
2605
  return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
package/dist/index.js CHANGED
@@ -650,7 +650,7 @@ var LibSQLVector = class extends MastraVector {
650
650
  await tx.commit();
651
651
  return vectorIds;
652
652
  } catch (error) {
653
- await tx.rollback();
653
+ !tx.closed && await tx.rollback();
654
654
  if (error instanceof Error && error.message?.includes("dimensions are different")) {
655
655
  const match = error.message.match(/dimensions are different: (\d+) != (\d+)/);
656
656
  if (match) {
@@ -1247,14 +1247,14 @@ var MemoryLibSQL = class extends MemoryStorage {
1247
1247
  );
1248
1248
  }
1249
1249
  return {
1250
- sql: `INSERT INTO ${TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt, resourceId)
1250
+ sql: `INSERT INTO "${TABLE_MESSAGES}" (id, thread_id, content, role, type, "createdAt", "resourceId")
1251
1251
  VALUES (?, ?, ?, ?, ?, ?, ?)
1252
1252
  ON CONFLICT(id) DO UPDATE SET
1253
1253
  thread_id=excluded.thread_id,
1254
1254
  content=excluded.content,
1255
1255
  role=excluded.role,
1256
1256
  type=excluded.type,
1257
- resourceId=excluded.resourceId
1257
+ "resourceId"=excluded."resourceId"
1258
1258
  `,
1259
1259
  args: [
1260
1260
  message.id,
@@ -1269,10 +1269,21 @@ var MemoryLibSQL = class extends MemoryStorage {
1269
1269
  });
1270
1270
  const now = (/* @__PURE__ */ new Date()).toISOString();
1271
1271
  batchStatements.push({
1272
- sql: `UPDATE ${TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
1272
+ sql: `UPDATE "${TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
1273
1273
  args: [now, threadId]
1274
1274
  });
1275
- await this.client.batch(batchStatements, "write");
1275
+ const BATCH_SIZE = 50;
1276
+ const messageStatements = batchStatements.slice(0, -1);
1277
+ const threadUpdateStatement = batchStatements[batchStatements.length - 1];
1278
+ for (let i = 0; i < messageStatements.length; i += BATCH_SIZE) {
1279
+ const batch = messageStatements.slice(i, i + BATCH_SIZE);
1280
+ if (batch.length > 0) {
1281
+ await this.client.batch(batch, "write");
1282
+ }
1283
+ }
1284
+ if (threadUpdateStatement) {
1285
+ await this.client.execute(threadUpdateStatement);
1286
+ }
1276
1287
  const list = new MessageList().add(messages, "memory");
1277
1288
  if (format === `v2`) return list.get.all.v2();
1278
1289
  return list.get.all.v1();
@@ -1366,6 +1377,56 @@ var MemoryLibSQL = class extends MemoryStorage {
1366
1377
  const updatedResult = await this.client.execute({ sql: selectSql, args: messageIds });
1367
1378
  return updatedResult.rows.map((row) => this.parseRow(row));
1368
1379
  }
1380
+ async deleteMessages(messageIds) {
1381
+ if (!messageIds || messageIds.length === 0) {
1382
+ return;
1383
+ }
1384
+ try {
1385
+ const BATCH_SIZE = 100;
1386
+ const threadIds = /* @__PURE__ */ new Set();
1387
+ const tx = await this.client.transaction("write");
1388
+ try {
1389
+ for (let i = 0; i < messageIds.length; i += BATCH_SIZE) {
1390
+ const batch = messageIds.slice(i, i + BATCH_SIZE);
1391
+ const placeholders = batch.map(() => "?").join(",");
1392
+ const result = await tx.execute({
1393
+ sql: `SELECT DISTINCT thread_id FROM "${TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
1394
+ args: batch
1395
+ });
1396
+ result.rows?.forEach((row) => {
1397
+ if (row.thread_id) threadIds.add(row.thread_id);
1398
+ });
1399
+ await tx.execute({
1400
+ sql: `DELETE FROM "${TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
1401
+ args: batch
1402
+ });
1403
+ }
1404
+ if (threadIds.size > 0) {
1405
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1406
+ for (const threadId of threadIds) {
1407
+ await tx.execute({
1408
+ sql: `UPDATE "${TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
1409
+ args: [now, threadId]
1410
+ });
1411
+ }
1412
+ }
1413
+ await tx.commit();
1414
+ } catch (error) {
1415
+ await tx.rollback();
1416
+ throw error;
1417
+ }
1418
+ } catch (error) {
1419
+ throw new MastraError(
1420
+ {
1421
+ id: "LIBSQL_STORE_DELETE_MESSAGES_FAILED",
1422
+ domain: ErrorDomain.STORAGE,
1423
+ category: ErrorCategory.THIRD_PARTY,
1424
+ details: { messageIds: messageIds.join(", ") }
1425
+ },
1426
+ error
1427
+ );
1428
+ }
1429
+ }
1369
1430
  async getResourceById({ resourceId }) {
1370
1431
  const result = await this.operations.load({
1371
1432
  tableName: TABLE_RESOURCES,
@@ -1469,7 +1530,9 @@ var MemoryLibSQL = class extends MemoryStorage {
1469
1530
  * @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
1470
1531
  */
1471
1532
  async getThreadsByResourceId(args) {
1472
- const { resourceId } = args;
1533
+ const resourceId = args.resourceId;
1534
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1535
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1473
1536
  try {
1474
1537
  const baseQuery = `FROM ${TABLE_THREADS} WHERE resourceId = ?`;
1475
1538
  const queryParams = [resourceId];
@@ -1484,7 +1547,7 @@ var MemoryLibSQL = class extends MemoryStorage {
1484
1547
  metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
1485
1548
  });
1486
1549
  const result = await this.client.execute({
1487
- sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC`,
1550
+ sql: `SELECT * ${baseQuery} ORDER BY ${orderBy} ${sortDirection}`,
1488
1551
  args: queryParams
1489
1552
  });
1490
1553
  if (!result.rows) {
@@ -1508,6 +1571,8 @@ var MemoryLibSQL = class extends MemoryStorage {
1508
1571
  }
1509
1572
  async getThreadsByResourceIdPaginated(args) {
1510
1573
  const { resourceId, page = 0, perPage = 100 } = args;
1574
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1575
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1511
1576
  try {
1512
1577
  const baseQuery = `FROM ${TABLE_THREADS} WHERE resourceId = ?`;
1513
1578
  const queryParams = [resourceId];
@@ -1537,7 +1602,7 @@ var MemoryLibSQL = class extends MemoryStorage {
1537
1602
  };
1538
1603
  }
1539
1604
  const dataResult = await this.client.execute({
1540
- sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
1605
+ sql: `SELECT * ${baseQuery} ORDER BY ${orderBy} ${sortDirection} LIMIT ? OFFSET ?`,
1541
1606
  args: [...queryParams, perPage, currentOffset]
1542
1607
  });
1543
1608
  const threads = (dataResult.rows || []).map(mapRowToStorageThreadType);
@@ -2449,7 +2514,8 @@ var LibSQLStore = class extends MastraStorage {
2449
2514
  selectByIncludeResourceScope: true,
2450
2515
  resourceWorkingMemory: true,
2451
2516
  hasColumn: true,
2452
- createTable: true
2517
+ createTable: true,
2518
+ deleteMessages: true
2453
2519
  };
2454
2520
  }
2455
2521
  async createTable({
@@ -2529,6 +2595,9 @@ var LibSQLStore = class extends MastraStorage {
2529
2595
  }) {
2530
2596
  return this.stores.memory.updateMessages({ messages });
2531
2597
  }
2598
+ async deleteMessages(messageIds) {
2599
+ return this.stores.memory.deleteMessages(messageIds);
2600
+ }
2532
2601
  /** @deprecated use getEvals instead */
2533
2602
  async getEvalsByAgentName(agentName, type) {
2534
2603
  return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/libsql",
3
- "version": "0.11.2",
3
+ "version": "0.11.3-alpha.1",
4
4
  "description": "Libsql provider for Mastra - includes both vector and db storage capabilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
- "@libsql/client": "^0.15.9"
23
+ "@libsql/client": "^0.15.10"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@microsoft/api-extractor": "^7.52.8",
@@ -29,9 +29,9 @@
29
29
  "tsup": "^8.5.0",
30
30
  "typescript": "^5.8.3",
31
31
  "vitest": "^3.2.4",
32
- "@internal/lint": "0.0.22",
33
- "@internal/storage-test-utils": "0.0.18",
34
- "@mastra/core": "0.11.1"
32
+ "@internal/lint": "0.0.23",
33
+ "@mastra/core": "0.12.0-alpha.2",
34
+ "@internal/storage-test-utils": "0.0.19"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@mastra/core": ">=0.10.7-0 <0.12.0-0"
@@ -4,7 +4,12 @@ import type { MastraMessageContentV2 } from '@mastra/core/agent';
4
4
  import { MessageList } from '@mastra/core/agent';
5
5
  import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
6
6
  import type { MastraMessageV1, MastraMessageV2, StorageThreadType } from '@mastra/core/memory';
7
- import type { PaginationInfo, StorageGetMessagesArg, StorageResourceType } from '@mastra/core/storage';
7
+ import type {
8
+ PaginationInfo,
9
+ StorageGetMessagesArg,
10
+ StorageResourceType,
11
+ ThreadSortOptions,
12
+ } from '@mastra/core/storage';
8
13
  import {
9
14
  MemoryStorage,
10
15
  resolveMessageLimit,
@@ -288,14 +293,14 @@ export class MemoryLibSQL extends MemoryStorage {
288
293
  );
289
294
  }
290
295
  return {
291
- sql: `INSERT INTO ${TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt, resourceId)
296
+ sql: `INSERT INTO "${TABLE_MESSAGES}" (id, thread_id, content, role, type, "createdAt", "resourceId")
292
297
  VALUES (?, ?, ?, ?, ?, ?, ?)
293
298
  ON CONFLICT(id) DO UPDATE SET
294
299
  thread_id=excluded.thread_id,
295
300
  content=excluded.content,
296
301
  role=excluded.role,
297
302
  type=excluded.type,
298
- resourceId=excluded.resourceId
303
+ "resourceId"=excluded."resourceId"
299
304
  `,
300
305
  args: [
301
306
  message.id,
@@ -311,12 +316,29 @@ export class MemoryLibSQL extends MemoryStorage {
311
316
 
312
317
  const now = new Date().toISOString();
313
318
  batchStatements.push({
314
- sql: `UPDATE ${TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
319
+ sql: `UPDATE "${TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
315
320
  args: [now, threadId],
316
321
  });
317
322
 
318
- // Execute all inserts in a single batch
319
- await this.client.batch(batchStatements, 'write');
323
+ // Execute in batches to avoid potential limitations
324
+ const BATCH_SIZE = 50; // Safe batch size for libsql
325
+
326
+ // Separate message statements from thread update
327
+ const messageStatements = batchStatements.slice(0, -1);
328
+ const threadUpdateStatement = batchStatements[batchStatements.length - 1];
329
+
330
+ // Process message statements in batches
331
+ for (let i = 0; i < messageStatements.length; i += BATCH_SIZE) {
332
+ const batch = messageStatements.slice(i, i + BATCH_SIZE);
333
+ if (batch.length > 0) {
334
+ await this.client.batch(batch, 'write');
335
+ }
336
+ }
337
+
338
+ // Execute thread update separately
339
+ if (threadUpdateStatement) {
340
+ await this.client.execute(threadUpdateStatement);
341
+ }
320
342
 
321
343
  const list = new MessageList().add(messages, 'memory');
322
344
  if (format === `v2`) return list.get.all.v2();
@@ -439,6 +461,74 @@ export class MemoryLibSQL extends MemoryStorage {
439
461
  return updatedResult.rows.map(row => this.parseRow(row));
440
462
  }
441
463
 
464
+ async deleteMessages(messageIds: string[]): Promise<void> {
465
+ if (!messageIds || messageIds.length === 0) {
466
+ return;
467
+ }
468
+
469
+ try {
470
+ // Process in batches to avoid SQL parameter limits
471
+ const BATCH_SIZE = 100;
472
+ const threadIds = new Set<string>();
473
+
474
+ // Use a transaction to ensure consistency
475
+ const tx = await this.client.transaction('write');
476
+
477
+ try {
478
+ for (let i = 0; i < messageIds.length; i += BATCH_SIZE) {
479
+ const batch = messageIds.slice(i, i + BATCH_SIZE);
480
+ const placeholders = batch.map(() => '?').join(',');
481
+
482
+ // Get thread IDs for this batch
483
+ const result = await tx.execute({
484
+ sql: `SELECT DISTINCT thread_id FROM "${TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
485
+ args: batch,
486
+ });
487
+
488
+ result.rows?.forEach(row => {
489
+ if (row.thread_id) threadIds.add(row.thread_id as string);
490
+ });
491
+
492
+ // Delete messages in this batch
493
+ await tx.execute({
494
+ sql: `DELETE FROM "${TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
495
+ args: batch,
496
+ });
497
+ }
498
+
499
+ // Update thread timestamps within the transaction
500
+ if (threadIds.size > 0) {
501
+ const now = new Date().toISOString();
502
+ for (const threadId of threadIds) {
503
+ await tx.execute({
504
+ sql: `UPDATE "${TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
505
+ args: [now, threadId],
506
+ });
507
+ }
508
+ }
509
+
510
+ // Commit the transaction
511
+ await tx.commit();
512
+ } catch (error) {
513
+ // Rollback on error
514
+ await tx.rollback();
515
+ throw error;
516
+ }
517
+
518
+ // TODO: Delete from vector store if semantic recall is enabled
519
+ } catch (error) {
520
+ throw new MastraError(
521
+ {
522
+ id: 'LIBSQL_STORE_DELETE_MESSAGES_FAILED',
523
+ domain: ErrorDomain.STORAGE,
524
+ category: ErrorCategory.THIRD_PARTY,
525
+ details: { messageIds: messageIds.join(', ') },
526
+ },
527
+ error,
528
+ );
529
+ }
530
+ }
531
+
442
532
  async getResourceById({ resourceId }: { resourceId: string }): Promise<StorageResourceType | null> {
443
533
  const result = await this.operations.load<StorageResourceType>({
444
534
  tableName: TABLE_RESOURCES,
@@ -569,8 +659,10 @@ export class MemoryLibSQL extends MemoryStorage {
569
659
  /**
570
660
  * @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
571
661
  */
572
- public async getThreadsByResourceId(args: { resourceId: string }): Promise<StorageThreadType[]> {
573
- const { resourceId } = args;
662
+ public async getThreadsByResourceId(args: { resourceId: string } & ThreadSortOptions): Promise<StorageThreadType[]> {
663
+ const resourceId = args.resourceId;
664
+ const orderBy = this.castThreadOrderBy(args.orderBy);
665
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
574
666
 
575
667
  try {
576
668
  const baseQuery = `FROM ${TABLE_THREADS} WHERE resourceId = ?`;
@@ -587,7 +679,7 @@ export class MemoryLibSQL extends MemoryStorage {
587
679
 
588
680
  // Non-paginated path
589
681
  const result = await this.client.execute({
590
- sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC`,
682
+ sql: `SELECT * ${baseQuery} ORDER BY ${orderBy} ${sortDirection}`,
591
683
  args: queryParams,
592
684
  });
593
685
 
@@ -611,12 +703,16 @@ export class MemoryLibSQL extends MemoryStorage {
611
703
  }
612
704
  }
613
705
 
614
- public async getThreadsByResourceIdPaginated(args: {
615
- resourceId: string;
616
- page: number;
617
- perPage: number;
618
- }): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
706
+ public async getThreadsByResourceIdPaginated(
707
+ args: {
708
+ resourceId: string;
709
+ page: number;
710
+ perPage: number;
711
+ } & ThreadSortOptions,
712
+ ): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
619
713
  const { resourceId, page = 0, perPage = 100 } = args;
714
+ const orderBy = this.castThreadOrderBy(args.orderBy);
715
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
620
716
 
621
717
  try {
622
718
  const baseQuery = `FROM ${TABLE_THREADS} WHERE resourceId = ?`;
@@ -650,7 +746,7 @@ export class MemoryLibSQL extends MemoryStorage {
650
746
  }
651
747
 
652
748
  const dataResult = await this.client.execute({
653
- sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
749
+ sql: `SELECT * ${baseQuery} ORDER BY ${orderBy} ${sortDirection} LIMIT ? OFFSET ?`,
654
750
  args: [...queryParams, perPage, currentOffset],
655
751
  });
656
752
 
@@ -17,6 +17,7 @@ import type {
17
17
  WorkflowRuns,
18
18
  StorageGetTracesArg,
19
19
  StorageDomains,
20
+ ThreadSortOptions,
20
21
  } from '@mastra/core/storage';
21
22
 
22
23
  import type { Trace } from '@mastra/core/telemetry';
@@ -117,6 +118,7 @@ export class LibSQLStore extends MastraStorage {
117
118
  resourceWorkingMemory: true,
118
119
  hasColumn: true,
119
120
  createTable: true,
121
+ deleteMessages: true,
120
122
  };
121
123
  }
122
124
 
@@ -175,15 +177,17 @@ export class LibSQLStore extends MastraStorage {
175
177
  /**
176
178
  * @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
177
179
  */
178
- public async getThreadsByResourceId(args: { resourceId: string }): Promise<StorageThreadType[]> {
180
+ public async getThreadsByResourceId(args: { resourceId: string } & ThreadSortOptions): Promise<StorageThreadType[]> {
179
181
  return this.stores.memory.getThreadsByResourceId(args);
180
182
  }
181
183
 
182
- public async getThreadsByResourceIdPaginated(args: {
183
- resourceId: string;
184
- page: number;
185
- perPage: number;
186
- }): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
184
+ public async getThreadsByResourceIdPaginated(
185
+ args: {
186
+ resourceId: string;
187
+ page: number;
188
+ perPage: number;
189
+ } & ThreadSortOptions,
190
+ ): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
187
191
  return this.stores.memory.getThreadsByResourceIdPaginated(args);
188
192
  }
189
193
 
@@ -249,6 +253,10 @@ export class LibSQLStore extends MastraStorage {
249
253
  return this.stores.memory.updateMessages({ messages });
250
254
  }
251
255
 
256
+ async deleteMessages(messageIds: string[]): Promise<void> {
257
+ return this.stores.memory.deleteMessages(messageIds);
258
+ }
259
+
252
260
  /** @deprecated use getEvals instead */
253
261
  async getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]> {
254
262
  return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
@@ -232,7 +232,7 @@ export class LibSQLVector extends MastraVector<LibSQLVectorFilter> {
232
232
  await tx.commit();
233
233
  return vectorIds;
234
234
  } catch (error) {
235
- await tx.rollback();
235
+ !tx.closed && (await tx.rollback());
236
236
  if (error instanceof Error && error.message?.includes('dimensions are different')) {
237
237
  const match = error.message.match(/dimensions are different: (\d+) != (\d+)/);
238
238
  if (match) {