@mastra/libsql 1.8.2-alpha.0 → 1.9.0-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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @mastra/libsql
2
2
 
3
+ ## 1.9.0-alpha.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Added `getTraceLight` method to the observability storage, returning only lightweight span fields needed for timeline rendering. This avoids transferring heavy fields like `input`, `output`, `attributes`, and `metadata` when they are not needed. ([#15574](https://github.com/mastra-ai/mastra/pull/15574))
8
+
9
+ - Updated dependencies [[`20f59b8`](https://github.com/mastra-ai/mastra/commit/20f59b876cf91199efbc49a0e36b391240708f08), [`e2687a7`](https://github.com/mastra-ai/mastra/commit/e2687a7408790c384563816a9a28ed06735684c9), [`8f1b280`](https://github.com/mastra-ai/mastra/commit/8f1b280b7fe6999ec654f160cb69c1a8719e7a57), [`12df98c`](https://github.com/mastra-ai/mastra/commit/12df98c4904643d9481f5c78f3bed443725b4c96)]:
10
+ - @mastra/core@1.26.0-alpha.11
11
+
12
+ ## 1.9.0-alpha.1
13
+
14
+ ### Minor Changes
15
+
16
+ - Use DiskANN vector_top_k() index for faster vector queries when available ([#14913](https://github.com/mastra-ai/mastra/pull/14913))
17
+
18
+ LibSQLVector.query() now automatically uses the existing DiskANN index for approximate nearest neighbor search instead of brute-force full table scans, providing 10-25x query speedups on larger datasets. Falls back to brute-force when no index exists.
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [[`16e34ca`](https://github.com/mastra-ai/mastra/commit/16e34caa98b9a114b17a6125e4e3fd87f169d0d0)]:
23
+ - @mastra/core@1.26.0-alpha.9
24
+
3
25
  ## 1.8.2-alpha.0
4
26
 
5
27
  ### Patch Changes
@@ -3,7 +3,7 @@ name: mastra-libsql
3
3
  description: Documentation for @mastra/libsql. Use when working with @mastra/libsql APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/libsql"
6
- version: "1.8.2-alpha.0"
6
+ version: "1.9.0-alpha.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.2-alpha.0",
2
+ "version": "1.9.0-alpha.2",
3
3
  "package": "@mastra/libsql",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -63,4 +63,12 @@ Visit the [Configuration reference](https://mastra.ai/reference/configuration) f
63
63
 
64
64
  **gateways** (`Record<string, MastraModelGateway>`): Custom model gateways to register for accessing AI models through alternative providers or private deployments. Structured as a key-value pair, with keys being the registry key (used for getGateway()) and values being gateway instances. (Default: `{}`)
65
65
 
66
- **memory** (`Record<string, MastraMemory>`): Memory instances to register. These can be referenced by stored agents and resolved at runtime. Structured as a key-value pair, with keys being the registry key and values being memory instances. (Default: `{}`)
66
+ **memory** (`Record<string, MastraMemory>`): Memory instances to register. These can be referenced by stored agents and resolved at runtime. Structured as a key-value pair, with keys being the registry key and values being memory instances. (Default: `{}`)
67
+
68
+ **versions** (`VersionOverrides`): Global version overrides for sub-agent delegation. When a supervisor agent delegates to a sub-agent, these overrides determine which stored version of that sub-agent to use instead of the code-defined default. Requires the editor package to be configured. See \[Sub-agent versioning]\(/docs/editor/overview#sub-agent-versioning) for details.
69
+
70
+ **versions.agents** (`Record<string, VersionSelector>`): A map of agent IDs to their version selectors. Each selector can target a specific version by ID or by publication status.
71
+
72
+ **versions.agents.versionId** (`string`): The ID of a specific version to use.
73
+
74
+ **versions.agents.status** (`'draft' | 'published'`): Select the latest version with this publication status.
package/dist/index.cjs CHANGED
@@ -511,6 +511,9 @@ var LibSQLVector = class extends vector.MastraVector {
511
511
  turso;
512
512
  maxRetries;
513
513
  initialBackoffMs;
514
+ overFetchMultiplier;
515
+ isMemoryDb;
516
+ vectorIndexes;
514
517
  constructor({
515
518
  url,
516
519
  authToken,
@@ -518,6 +521,7 @@ var LibSQLVector = class extends vector.MastraVector {
518
521
  syncInterval,
519
522
  maxRetries = 5,
520
523
  initialBackoffMs = 100,
524
+ vectorTopKOverFetchMultiplier = 10,
521
525
  id
522
526
  }) {
523
527
  super({ id });
@@ -529,10 +533,27 @@ var LibSQLVector = class extends vector.MastraVector {
529
533
  });
530
534
  this.maxRetries = maxRetries;
531
535
  this.initialBackoffMs = initialBackoffMs;
532
- if (url.includes(`file:`) || url.includes(`:memory:`)) {
536
+ if (!Number.isInteger(vectorTopKOverFetchMultiplier) || vectorTopKOverFetchMultiplier < 1) {
537
+ throw new Error("vectorTopKOverFetchMultiplier must be a positive integer");
538
+ }
539
+ this.overFetchMultiplier = vectorTopKOverFetchMultiplier;
540
+ this.isMemoryDb = url.includes(":memory:");
541
+ if (url.includes(`file:`) || this.isMemoryDb) {
533
542
  this.turso.execute("PRAGMA journal_mode=WAL;").then(() => this.logger.debug("LibSQLStore: PRAGMA journal_mode=WAL set.")).catch((err) => this.logger.warn("LibSQLStore: Failed to set PRAGMA journal_mode=WAL.", err));
534
543
  this.turso.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=5000.", err));
535
544
  }
545
+ this.vectorIndexes = this.isMemoryDb ? Promise.resolve(/* @__PURE__ */ new Set()) : this.discoverVectorIndexes();
546
+ }
547
+ async discoverVectorIndexes() {
548
+ try {
549
+ const result = await this.turso.execute({
550
+ sql: `SELECT name FROM sqlite_master WHERE type='index' AND name LIKE '%_vector_idx'`,
551
+ args: []
552
+ });
553
+ return new Set(result.rows.map((row) => row.name));
554
+ } catch {
555
+ return /* @__PURE__ */ new Set();
556
+ }
536
557
  }
537
558
  async executeWriteOperationWithRetry(operation, isTransaction = false) {
538
559
  let attempts = 0;
@@ -566,6 +587,40 @@ var LibSQLVector = class extends vector.MastraVector {
566
587
  const translator = new LibSQLFilterTranslator();
567
588
  return translator.translate(filter);
568
589
  }
590
+ async hasVectorIndex(parsedIndexName) {
591
+ const indexes = await this.vectorIndexes;
592
+ return indexes.has(`${parsedIndexName}_vector_idx`);
593
+ }
594
+ async queryWithIndex(parsedIndexName, vectorStr, topK, filter, includeVector, minScore) {
595
+ const translatedFilter = this.transformFilter(filter);
596
+ const { sql: filterQuery, values: filterValues } = buildFilterQuery(translatedFilter);
597
+ const hasFilter = filterQuery.length > 0;
598
+ const fetchCount = hasFilter ? topK * this.overFetchMultiplier : topK * 2;
599
+ const embeddingSelect = includeVector ? ", vector_extract(t.embedding) as embedding" : "";
600
+ const filterCondition = hasFilter ? filterQuery.replace(/^\s*WHERE\s+/i, "") : "";
601
+ const whereClause = hasFilter ? `WHERE ${filterCondition} AND score > ?` : "WHERE score > ?";
602
+ const query = `
603
+ WITH candidates AS (
604
+ SELECT t.vector_id AS id,
605
+ (1 - vector_distance_cos(t.embedding, vector32(?))) AS score,
606
+ t.metadata
607
+ ${embeddingSelect}
608
+ FROM vector_top_k('${parsedIndexName}_vector_idx', vector32(?), ?) AS v
609
+ JOIN "${parsedIndexName}" AS t ON t.rowid = v.id
610
+ )
611
+ SELECT * FROM candidates
612
+ ${whereClause}
613
+ ORDER BY score DESC
614
+ LIMIT ?`;
615
+ const args = [vectorStr, vectorStr, fetchCount, ...filterValues, minScore, topK];
616
+ const result = await this.turso.execute({ sql: query, args });
617
+ return result.rows.map(({ id, score, metadata, embedding }) => ({
618
+ id,
619
+ score,
620
+ metadata: JSON.parse(metadata ?? "{}"),
621
+ ...includeVector && embedding && { vector: JSON.parse(embedding) }
622
+ }));
623
+ }
569
624
  async query({
570
625
  indexName,
571
626
  queryVector,
@@ -596,6 +651,23 @@ var LibSQLVector = class extends vector.MastraVector {
596
651
  try {
597
652
  const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
598
653
  const vectorStr = `[${queryVector.join(",")}]`;
654
+ if (!this.isMemoryDb && await this.hasVectorIndex(parsedIndexName)) {
655
+ try {
656
+ const indexedResults = await this.queryWithIndex(
657
+ parsedIndexName,
658
+ vectorStr,
659
+ topK,
660
+ filter,
661
+ includeVector,
662
+ minScore
663
+ );
664
+ if (!filter || indexedResults.length >= topK) {
665
+ return indexedResults;
666
+ }
667
+ } catch (err) {
668
+ this.logger.warn("LibSQLVector: indexed query failed, falling back to brute-force", err);
669
+ }
670
+ }
599
671
  const translatedFilter = this.transformFilter(filter);
600
672
  const { sql: filterQuery, values: filterValues } = buildFilterQuery(translatedFilter);
601
673
  filterValues.push(minScore);
@@ -729,6 +801,7 @@ var LibSQLVector = class extends vector.MastraVector {
729
801
  `,
730
802
  args: []
731
803
  });
804
+ void this.vectorIndexes.then((indexes) => indexes.add(`${parsedIndexName}_vector_idx`));
732
805
  }
733
806
  deleteIndex(args) {
734
807
  try {
@@ -751,6 +824,7 @@ var LibSQLVector = class extends vector.MastraVector {
751
824
  sql: `DROP TABLE IF EXISTS ${parsedIndexName}`,
752
825
  args: []
753
826
  });
827
+ void this.vectorIndexes.then((indexes) => indexes.delete(`${parsedIndexName}_vector_idx`));
754
828
  }
755
829
  async listIndexes() {
756
830
  try {
@@ -1287,6 +1361,9 @@ function transformFromSqlRow({
1287
1361
  const dateColumns = new Set(
1288
1362
  Object.keys(storage.TABLE_SCHEMAS[tableName]).filter((key) => storage.TABLE_SCHEMAS[tableName][key].type === "timestamp").map((key) => key)
1289
1363
  );
1364
+ const booleanColumns = new Set(
1365
+ Object.keys(storage.TABLE_SCHEMAS[tableName]).filter((key) => storage.TABLE_SCHEMAS[tableName][key].type === "boolean").map((key) => key)
1366
+ );
1290
1367
  for (const [key, value] of Object.entries(sqlRow)) {
1291
1368
  if (value === null || value === void 0) {
1292
1369
  result[key] = value;
@@ -1300,6 +1377,10 @@ function transformFromSqlRow({
1300
1377
  result[key] = storage.safelyParseJSON(value);
1301
1378
  continue;
1302
1379
  }
1380
+ if (booleanColumns.has(key)) {
1381
+ result[key] = Boolean(value);
1382
+ continue;
1383
+ }
1303
1384
  result[key] = value;
1304
1385
  }
1305
1386
  return result;
@@ -7852,6 +7933,39 @@ var ObservabilityLibSQL = class extends storage.ObservabilityStorage {
7852
7933
  );
7853
7934
  }
7854
7935
  }
7936
+ async getTraceLight(args) {
7937
+ const { traceId } = args;
7938
+ try {
7939
+ const spans = await this.#db.selectMany({
7940
+ tableName: storage.TABLE_SPANS,
7941
+ whereClause: { sql: " WHERE traceId = ?", args: [traceId] },
7942
+ orderBy: "startedAt ASC"
7943
+ });
7944
+ if (!spans || spans.length === 0) {
7945
+ return null;
7946
+ }
7947
+ return {
7948
+ traceId,
7949
+ spans: spans.map((span) => {
7950
+ const transformed = transformFromSqlRow({ tableName: storage.TABLE_SPANS, sqlRow: span });
7951
+ const { input, output, attributes, metadata, tags, links, ...light } = transformed;
7952
+ return light;
7953
+ })
7954
+ };
7955
+ } catch (error$1) {
7956
+ throw new error.MastraError(
7957
+ {
7958
+ id: storage.createStorageErrorId("LIBSQL", "GET_TRACE_LIGHT", "FAILED"),
7959
+ domain: error.ErrorDomain.STORAGE,
7960
+ category: error.ErrorCategory.USER,
7961
+ details: {
7962
+ traceId
7963
+ }
7964
+ },
7965
+ error$1
7966
+ );
7967
+ }
7968
+ }
7855
7969
  async updateSpan(args) {
7856
7970
  const { traceId, spanId, updates } = args;
7857
7971
  try {