@mastra/libsql 0.13.4 → 0.13.5-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/dist/index.js CHANGED
@@ -3,8 +3,7 @@ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
3
  import { parseSqlIdentifier, parseFieldKey } from '@mastra/core/utils';
4
4
  import { MastraVector } from '@mastra/core/vector';
5
5
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
6
- import { MastraStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, ScoresStorage, TABLE_SCORERS, safelyParseJSON, TracesStorage, TABLE_TRACES, WorkflowsStorage, MemoryStorage, resolveMessageLimit, TABLE_MESSAGES, TABLE_THREADS, TABLE_RESOURCES, LegacyEvalsStorage, TABLE_EVALS } from '@mastra/core/storage';
7
- import { parseSqlIdentifier as parseSqlIdentifier$1 } from '@mastra/core';
6
+ import { MastraStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, TABLE_AI_SPANS, ScoresStorage, TABLE_SCORERS, safelyParseJSON, TracesStorage, TABLE_TRACES, WorkflowsStorage, MemoryStorage, resolveMessageLimit, TABLE_MESSAGES, TABLE_THREADS, TABLE_RESOURCES, LegacyEvalsStorage, TABLE_EVALS, ObservabilityStorage, TABLE_SCHEMAS, AI_SPAN_SCHEMA } from '@mastra/core/storage';
8
7
  import { MessageList } from '@mastra/core/agent';
9
8
 
10
9
  // src/vector/index.ts
@@ -1390,14 +1389,14 @@ var MemoryLibSQL = class extends MemoryStorage {
1390
1389
  }
1391
1390
  } : {}
1392
1391
  };
1393
- setClauses.push(`${parseSqlIdentifier$1("content", "column name")} = ?`);
1392
+ setClauses.push(`${parseSqlIdentifier("content", "column name")} = ?`);
1394
1393
  args.push(JSON.stringify(newContent));
1395
1394
  delete updatableFields.content;
1396
1395
  }
1397
1396
  for (const key in updatableFields) {
1398
1397
  if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
1399
1398
  const dbKey = columnMapping[key] || key;
1400
- setClauses.push(`${parseSqlIdentifier$1(dbKey, "column name")} = ?`);
1399
+ setClauses.push(`${parseSqlIdentifier(dbKey, "column name")} = ?`);
1401
1400
  let value = updatableFields[key];
1402
1401
  if (typeof value === "object" && value !== null) {
1403
1402
  value = JSON.stringify(value);
@@ -1799,7 +1798,7 @@ function prepareStatement({ tableName, record }) {
1799
1798
  const parsedTableName = parseSqlIdentifier(tableName, "table name");
1800
1799
  const columns = Object.keys(record).map((col) => parseSqlIdentifier(col, "column name"));
1801
1800
  const values = Object.values(record).map((v) => {
1802
- if (typeof v === `undefined`) {
1801
+ if (typeof v === `undefined` || v === null) {
1803
1802
  return null;
1804
1803
  }
1805
1804
  if (v instanceof Date) {
@@ -1813,8 +1812,338 @@ function prepareStatement({ tableName, record }) {
1813
1812
  args: values
1814
1813
  };
1815
1814
  }
1815
+ function prepareUpdateStatement({
1816
+ tableName,
1817
+ updates,
1818
+ keys
1819
+ }) {
1820
+ const parsedTableName = parseSqlIdentifier(tableName, "table name");
1821
+ const schema = TABLE_SCHEMAS[tableName];
1822
+ const updateColumns = Object.keys(updates).map((col) => parseSqlIdentifier(col, "column name"));
1823
+ const updateValues = Object.values(updates).map(transformToSqlValue);
1824
+ const setClause = updateColumns.map((col) => `${col} = ?`).join(", ");
1825
+ const whereClause = prepareWhereClause(keys, schema);
1826
+ return {
1827
+ sql: `UPDATE ${parsedTableName} SET ${setClause}${whereClause.sql}`,
1828
+ args: [...updateValues, ...whereClause.args]
1829
+ };
1830
+ }
1831
+ function transformToSqlValue(value) {
1832
+ if (typeof value === "undefined" || value === null) {
1833
+ return null;
1834
+ }
1835
+ if (value instanceof Date) {
1836
+ return value.toISOString();
1837
+ }
1838
+ return typeof value === "object" ? JSON.stringify(value) : value;
1839
+ }
1840
+ function prepareDeleteStatement({ tableName, keys }) {
1841
+ const parsedTableName = parseSqlIdentifier(tableName, "table name");
1842
+ const whereClause = prepareWhereClause(keys, TABLE_SCHEMAS[tableName]);
1843
+ return {
1844
+ sql: `DELETE FROM ${parsedTableName}${whereClause.sql}`,
1845
+ args: whereClause.args
1846
+ };
1847
+ }
1848
+ function prepareWhereClause(filters, schema) {
1849
+ const conditions = [];
1850
+ const args = [];
1851
+ for (const [columnName, filterValue] of Object.entries(filters)) {
1852
+ const column = schema[columnName];
1853
+ if (!column) {
1854
+ throw new Error(`Unknown column: ${columnName}`);
1855
+ }
1856
+ const parsedColumn = parseSqlIdentifier(columnName, "column name");
1857
+ const result = buildCondition2(parsedColumn, filterValue);
1858
+ conditions.push(result.condition);
1859
+ args.push(...result.args);
1860
+ }
1861
+ return {
1862
+ sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
1863
+ args
1864
+ };
1865
+ }
1866
+ function buildCondition2(columnName, filterValue) {
1867
+ if (filterValue === null) {
1868
+ return { condition: `${columnName} IS NULL`, args: [] };
1869
+ }
1870
+ if (typeof filterValue === "object" && filterValue !== null && ("startAt" in filterValue || "endAt" in filterValue)) {
1871
+ return buildDateRangeCondition(columnName, filterValue);
1872
+ }
1873
+ return {
1874
+ condition: `${columnName} = ?`,
1875
+ args: [transformToSqlValue(filterValue)]
1876
+ };
1877
+ }
1878
+ function buildDateRangeCondition(columnName, range) {
1879
+ const conditions = [];
1880
+ const args = [];
1881
+ if (range.startAt !== void 0) {
1882
+ conditions.push(`${columnName} >= ?`);
1883
+ args.push(transformToSqlValue(range.startAt));
1884
+ }
1885
+ if (range.endAt !== void 0) {
1886
+ conditions.push(`${columnName} <= ?`);
1887
+ args.push(transformToSqlValue(range.endAt));
1888
+ }
1889
+ if (conditions.length === 0) {
1890
+ throw new Error("Date range must specify at least startAt or endAt");
1891
+ }
1892
+ return {
1893
+ condition: conditions.join(" AND "),
1894
+ args
1895
+ };
1896
+ }
1897
+ function buildDateRangeFilter(dateRange, columnName = "createdAt") {
1898
+ if (!dateRange?.start && !dateRange?.end) {
1899
+ return {};
1900
+ }
1901
+ const filter = {};
1902
+ if (dateRange.start) {
1903
+ filter.startAt = new Date(dateRange.start).toISOString();
1904
+ }
1905
+ if (dateRange.end) {
1906
+ filter.endAt = new Date(dateRange.end).toISOString();
1907
+ }
1908
+ return { [columnName]: filter };
1909
+ }
1910
+ function transformFromSqlRow({
1911
+ tableName,
1912
+ sqlRow
1913
+ }) {
1914
+ const result = {};
1915
+ const jsonColumns = new Set(
1916
+ Object.keys(TABLE_SCHEMAS[tableName]).filter((key) => TABLE_SCHEMAS[tableName][key].type === "jsonb").map((key) => key)
1917
+ );
1918
+ const dateColumns = new Set(
1919
+ Object.keys(TABLE_SCHEMAS[tableName]).filter((key) => TABLE_SCHEMAS[tableName][key].type === "timestamp").map((key) => key)
1920
+ );
1921
+ for (const [key, value] of Object.entries(sqlRow)) {
1922
+ if (value === null || value === void 0) {
1923
+ result[key] = value;
1924
+ continue;
1925
+ }
1926
+ if (dateColumns.has(key) && typeof value === "string") {
1927
+ result[key] = new Date(value);
1928
+ continue;
1929
+ }
1930
+ if (jsonColumns.has(key) && typeof value === "string") {
1931
+ result[key] = safelyParseJSON(value);
1932
+ continue;
1933
+ }
1934
+ result[key] = value;
1935
+ }
1936
+ return result;
1937
+ }
1816
1938
 
1817
- // src/storage/domains/operations/index.ts
1939
+ // src/storage/domains/observability/index.ts
1940
+ var ObservabilityLibSQL = class extends ObservabilityStorage {
1941
+ operations;
1942
+ constructor({ operations }) {
1943
+ super();
1944
+ this.operations = operations;
1945
+ }
1946
+ async createAISpan(span) {
1947
+ try {
1948
+ return this.operations.insert({ tableName: TABLE_AI_SPANS, record: span });
1949
+ } catch (error) {
1950
+ throw new MastraError(
1951
+ {
1952
+ id: "LIBSQL_STORE_CREATE_AI_SPAN_FAILED",
1953
+ domain: ErrorDomain.STORAGE,
1954
+ category: ErrorCategory.USER,
1955
+ details: {
1956
+ spanId: span.spanId,
1957
+ traceId: span.traceId,
1958
+ spanType: span.spanType,
1959
+ spanName: span.name
1960
+ }
1961
+ },
1962
+ error
1963
+ );
1964
+ }
1965
+ }
1966
+ async getAITrace(traceId) {
1967
+ try {
1968
+ const spans = await this.operations.loadMany({
1969
+ tableName: TABLE_AI_SPANS,
1970
+ whereClause: { sql: " WHERE traceId = ?", args: [traceId] },
1971
+ orderBy: "startedAt DESC"
1972
+ });
1973
+ if (!spans || spans.length === 0) {
1974
+ return null;
1975
+ }
1976
+ return {
1977
+ traceId,
1978
+ spans: spans.map((span) => transformFromSqlRow({ tableName: TABLE_AI_SPANS, sqlRow: span }))
1979
+ };
1980
+ } catch (error) {
1981
+ throw new MastraError(
1982
+ {
1983
+ id: "LIBSQL_STORE_GET_AI_TRACE_FAILED",
1984
+ domain: ErrorDomain.STORAGE,
1985
+ category: ErrorCategory.USER,
1986
+ details: {
1987
+ traceId
1988
+ }
1989
+ },
1990
+ error
1991
+ );
1992
+ }
1993
+ }
1994
+ async updateAISpan({
1995
+ spanId,
1996
+ traceId,
1997
+ updates
1998
+ }) {
1999
+ try {
2000
+ await this.operations.update({
2001
+ tableName: TABLE_AI_SPANS,
2002
+ keys: { spanId, traceId },
2003
+ data: { ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
2004
+ });
2005
+ } catch (error) {
2006
+ throw new MastraError(
2007
+ {
2008
+ id: "LIBSQL_STORE_UPDATE_AI_SPAN_FAILED",
2009
+ domain: ErrorDomain.STORAGE,
2010
+ category: ErrorCategory.USER,
2011
+ details: {
2012
+ spanId,
2013
+ traceId
2014
+ }
2015
+ },
2016
+ error
2017
+ );
2018
+ }
2019
+ }
2020
+ async getAITracesPaginated({
2021
+ filters,
2022
+ pagination
2023
+ }) {
2024
+ const page = pagination?.page ?? 0;
2025
+ const perPage = pagination?.perPage ?? 10;
2026
+ const filtersWithDateRange = {
2027
+ ...filters,
2028
+ ...buildDateRangeFilter(pagination?.dateRange, "startedAt")
2029
+ };
2030
+ const whereClause = prepareWhereClause(filtersWithDateRange, AI_SPAN_SCHEMA);
2031
+ const orderBy = "startedAt DESC";
2032
+ let count = 0;
2033
+ try {
2034
+ count = await this.operations.loadTotalCount({
2035
+ tableName: TABLE_AI_SPANS,
2036
+ whereClause: { sql: whereClause.sql, args: whereClause.args }
2037
+ });
2038
+ } catch (error) {
2039
+ throw new MastraError(
2040
+ {
2041
+ id: "LIBSQL_STORE_GET_AI_TRACES_PAGINATED_COUNT_FAILED",
2042
+ domain: ErrorDomain.STORAGE,
2043
+ category: ErrorCategory.USER
2044
+ },
2045
+ error
2046
+ );
2047
+ }
2048
+ if (count === 0) {
2049
+ return {
2050
+ pagination: {
2051
+ total: 0,
2052
+ page,
2053
+ perPage,
2054
+ hasMore: false
2055
+ },
2056
+ spans: []
2057
+ };
2058
+ }
2059
+ try {
2060
+ const spans = await this.operations.loadMany({
2061
+ tableName: TABLE_AI_SPANS,
2062
+ whereClause,
2063
+ orderBy,
2064
+ offset: page * perPage,
2065
+ limit: perPage
2066
+ });
2067
+ return {
2068
+ pagination: {
2069
+ total: count,
2070
+ page,
2071
+ perPage,
2072
+ hasMore: spans.length === perPage
2073
+ },
2074
+ spans: spans.map((span) => transformFromSqlRow({ tableName: TABLE_AI_SPANS, sqlRow: span }))
2075
+ };
2076
+ } catch (error) {
2077
+ throw new MastraError(
2078
+ {
2079
+ id: "LIBSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
2080
+ domain: ErrorDomain.STORAGE,
2081
+ category: ErrorCategory.USER
2082
+ },
2083
+ error
2084
+ );
2085
+ }
2086
+ }
2087
+ async batchCreateAISpans(args) {
2088
+ try {
2089
+ return this.operations.batchInsert({
2090
+ tableName: TABLE_AI_SPANS,
2091
+ records: args.records.map((record) => ({
2092
+ ...record,
2093
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2094
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2095
+ }))
2096
+ });
2097
+ } catch (error) {
2098
+ throw new MastraError(
2099
+ {
2100
+ id: "LIBSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
2101
+ domain: ErrorDomain.STORAGE,
2102
+ category: ErrorCategory.USER
2103
+ },
2104
+ error
2105
+ );
2106
+ }
2107
+ }
2108
+ async batchUpdateAISpans(args) {
2109
+ try {
2110
+ return this.operations.batchUpdate({
2111
+ tableName: TABLE_AI_SPANS,
2112
+ updates: args.records.map((record) => ({
2113
+ keys: { spanId: record.spanId, traceId: record.traceId },
2114
+ data: { ...record.updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
2115
+ }))
2116
+ });
2117
+ } catch (error) {
2118
+ throw new MastraError(
2119
+ {
2120
+ id: "LIBSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
2121
+ domain: ErrorDomain.STORAGE,
2122
+ category: ErrorCategory.USER
2123
+ },
2124
+ error
2125
+ );
2126
+ }
2127
+ }
2128
+ async batchDeleteAITraces(args) {
2129
+ try {
2130
+ const keys = args.traceIds.map((traceId) => ({ traceId }));
2131
+ return this.operations.batchDelete({
2132
+ tableName: TABLE_AI_SPANS,
2133
+ keys
2134
+ });
2135
+ } catch (error) {
2136
+ throw new MastraError(
2137
+ {
2138
+ id: "LIBSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
2139
+ domain: ErrorDomain.STORAGE,
2140
+ category: ErrorCategory.USER
2141
+ },
2142
+ error
2143
+ );
2144
+ }
2145
+ }
2146
+ };
1818
2147
  var StoreOperationsLibSQL = class extends StoreOperations {
1819
2148
  client;
1820
2149
  /**
@@ -1862,6 +2191,13 @@ var StoreOperationsLibSQL = class extends StoreOperations {
1862
2191
  )`;
1863
2192
  return stmnt;
1864
2193
  }
2194
+ if (tableName === TABLE_AI_SPANS) {
2195
+ const stmnt = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (
2196
+ ${columns.join(",\n")},
2197
+ PRIMARY KEY (traceId, spanId)
2198
+ )`;
2199
+ return stmnt;
2200
+ }
1865
2201
  return `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns.join(", ")})`;
1866
2202
  }
1867
2203
  async createTable({
@@ -1941,6 +2277,64 @@ var StoreOperationsLibSQL = class extends StoreOperations {
1941
2277
  );
1942
2278
  return parsed;
1943
2279
  }
2280
+ async loadMany({
2281
+ tableName,
2282
+ whereClause,
2283
+ orderBy,
2284
+ offset,
2285
+ limit,
2286
+ args
2287
+ }) {
2288
+ const parsedTableName = parseSqlIdentifier(tableName, "table name");
2289
+ let statement = `SELECT * FROM ${parsedTableName}`;
2290
+ if (whereClause?.sql) {
2291
+ statement += `${whereClause.sql}`;
2292
+ }
2293
+ if (orderBy) {
2294
+ statement += ` ORDER BY ${orderBy}`;
2295
+ }
2296
+ if (limit) {
2297
+ statement += ` LIMIT ${limit}`;
2298
+ }
2299
+ if (offset) {
2300
+ statement += ` OFFSET ${offset}`;
2301
+ }
2302
+ const result = await this.client.execute({
2303
+ sql: statement,
2304
+ args: [...whereClause?.args ?? [], ...args ?? []]
2305
+ });
2306
+ return result.rows;
2307
+ }
2308
+ async loadTotalCount({
2309
+ tableName,
2310
+ whereClause
2311
+ }) {
2312
+ const parsedTableName = parseSqlIdentifier(tableName, "table name");
2313
+ const statement = `SELECT COUNT(*) as count FROM ${parsedTableName} ${whereClause ? `${whereClause.sql}` : ""}`;
2314
+ const result = await this.client.execute({
2315
+ sql: statement,
2316
+ args: whereClause?.args ?? []
2317
+ });
2318
+ if (!result.rows || result.rows.length === 0) {
2319
+ return 0;
2320
+ }
2321
+ return result.rows[0]?.count ?? 0;
2322
+ }
2323
+ update(args) {
2324
+ const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
2325
+ logger: this.logger,
2326
+ maxRetries: this.maxRetries,
2327
+ initialBackoffMs: this.initialBackoffMs
2328
+ });
2329
+ return executeWriteOperationWithRetry(() => this.executeUpdate(args), `update table ${args.tableName}`);
2330
+ }
2331
+ async executeUpdate({
2332
+ tableName,
2333
+ keys,
2334
+ data
2335
+ }) {
2336
+ await this.client.execute(prepareUpdateStatement({ tableName, updates: data, keys }));
2337
+ }
1944
2338
  async doBatchInsert({
1945
2339
  tableName,
1946
2340
  records
@@ -1972,6 +2366,91 @@ var StoreOperationsLibSQL = class extends StoreOperations {
1972
2366
  );
1973
2367
  });
1974
2368
  }
2369
+ /**
2370
+ * Public batch update method with retry logic
2371
+ */
2372
+ batchUpdate(args) {
2373
+ const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
2374
+ logger: this.logger,
2375
+ maxRetries: this.maxRetries,
2376
+ initialBackoffMs: this.initialBackoffMs
2377
+ });
2378
+ return executeWriteOperationWithRetry(
2379
+ () => this.executeBatchUpdate(args),
2380
+ `batch update in table ${args.tableName}`
2381
+ ).catch((error) => {
2382
+ throw new MastraError(
2383
+ {
2384
+ id: "LIBSQL_STORE_BATCH_UPDATE_FAILED",
2385
+ domain: ErrorDomain.STORAGE,
2386
+ category: ErrorCategory.THIRD_PARTY,
2387
+ details: {
2388
+ tableName: args.tableName
2389
+ }
2390
+ },
2391
+ error
2392
+ );
2393
+ });
2394
+ }
2395
+ /**
2396
+ * Updates multiple records in batch. Each record can be updated based on single or composite keys.
2397
+ */
2398
+ async executeBatchUpdate({
2399
+ tableName,
2400
+ updates
2401
+ }) {
2402
+ if (updates.length === 0) return;
2403
+ const batchStatements = updates.map(
2404
+ ({ keys, data }) => prepareUpdateStatement({
2405
+ tableName,
2406
+ updates: data,
2407
+ keys
2408
+ })
2409
+ );
2410
+ await this.client.batch(batchStatements, "write");
2411
+ }
2412
+ /**
2413
+ * Public batch delete method with retry logic
2414
+ */
2415
+ batchDelete({ tableName, keys }) {
2416
+ const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
2417
+ logger: this.logger,
2418
+ maxRetries: this.maxRetries,
2419
+ initialBackoffMs: this.initialBackoffMs
2420
+ });
2421
+ return executeWriteOperationWithRetry(
2422
+ () => this.executeBatchDelete({ tableName, keys }),
2423
+ `batch delete from table ${tableName}`
2424
+ ).catch((error) => {
2425
+ throw new MastraError(
2426
+ {
2427
+ id: "LIBSQL_STORE_BATCH_DELETE_FAILED",
2428
+ domain: ErrorDomain.STORAGE,
2429
+ category: ErrorCategory.THIRD_PARTY,
2430
+ details: {
2431
+ tableName
2432
+ }
2433
+ },
2434
+ error
2435
+ );
2436
+ });
2437
+ }
2438
+ /**
2439
+ * Deletes multiple records in batch. Each record can be deleted based on single or composite keys.
2440
+ */
2441
+ async executeBatchDelete({
2442
+ tableName,
2443
+ keys
2444
+ }) {
2445
+ if (keys.length === 0) return;
2446
+ const batchStatements = keys.map(
2447
+ (keyObj) => prepareDeleteStatement({
2448
+ tableName,
2449
+ keys: keyObj
2450
+ })
2451
+ );
2452
+ await this.client.batch(batchStatements, "write");
2453
+ }
1975
2454
  /**
1976
2455
  * Alters table schema to add columns if they don't exist
1977
2456
  * @param tableName Name of the table
@@ -2391,10 +2870,165 @@ function parseWorkflowRun(row) {
2391
2870
  var WorkflowsLibSQL = class extends WorkflowsStorage {
2392
2871
  operations;
2393
2872
  client;
2394
- constructor({ operations, client }) {
2873
+ maxRetries;
2874
+ initialBackoffMs;
2875
+ constructor({
2876
+ operations,
2877
+ client,
2878
+ maxRetries = 5,
2879
+ initialBackoffMs = 500
2880
+ }) {
2395
2881
  super();
2396
2882
  this.operations = operations;
2397
2883
  this.client = client;
2884
+ this.maxRetries = maxRetries;
2885
+ this.initialBackoffMs = initialBackoffMs;
2886
+ this.setupPragmaSettings().catch(
2887
+ (err) => this.logger.warn("LibSQL Workflows: Failed to setup PRAGMA settings.", err)
2888
+ );
2889
+ }
2890
+ async setupPragmaSettings() {
2891
+ try {
2892
+ await this.client.execute("PRAGMA busy_timeout = 10000;");
2893
+ this.logger.debug("LibSQL Workflows: PRAGMA busy_timeout=10000 set.");
2894
+ try {
2895
+ await this.client.execute("PRAGMA journal_mode = WAL;");
2896
+ this.logger.debug("LibSQL Workflows: PRAGMA journal_mode=WAL set.");
2897
+ } catch {
2898
+ this.logger.debug("LibSQL Workflows: WAL mode not supported, using default journal mode.");
2899
+ }
2900
+ try {
2901
+ await this.client.execute("PRAGMA synchronous = NORMAL;");
2902
+ this.logger.debug("LibSQL Workflows: PRAGMA synchronous=NORMAL set.");
2903
+ } catch {
2904
+ this.logger.debug("LibSQL Workflows: Failed to set synchronous mode.");
2905
+ }
2906
+ } catch (err) {
2907
+ this.logger.warn("LibSQL Workflows: Failed to set PRAGMA settings.", err);
2908
+ }
2909
+ }
2910
+ async executeWithRetry(operation) {
2911
+ let attempts = 0;
2912
+ let backoff = this.initialBackoffMs;
2913
+ while (attempts < this.maxRetries) {
2914
+ try {
2915
+ return await operation();
2916
+ } catch (error) {
2917
+ this.logger.debug("LibSQL Workflows: Error caught in retry loop", {
2918
+ errorType: error.constructor.name,
2919
+ errorCode: error.code,
2920
+ errorMessage: error.message,
2921
+ attempts,
2922
+ maxRetries: this.maxRetries
2923
+ });
2924
+ const isLockError = error.code === "SQLITE_BUSY" || error.code === "SQLITE_LOCKED" || error.message?.toLowerCase().includes("database is locked") || error.message?.toLowerCase().includes("database table is locked") || error.message?.toLowerCase().includes("table is locked") || error.constructor.name === "SqliteError" && error.message?.toLowerCase().includes("locked");
2925
+ if (isLockError) {
2926
+ attempts++;
2927
+ if (attempts >= this.maxRetries) {
2928
+ this.logger.error(
2929
+ `LibSQL Workflows: Operation failed after ${this.maxRetries} attempts due to database lock: ${error.message}`,
2930
+ { error, attempts, maxRetries: this.maxRetries }
2931
+ );
2932
+ throw error;
2933
+ }
2934
+ this.logger.warn(
2935
+ `LibSQL Workflows: Attempt ${attempts} failed due to database lock. Retrying in ${backoff}ms...`,
2936
+ { errorMessage: error.message, attempts, backoff, maxRetries: this.maxRetries }
2937
+ );
2938
+ await new Promise((resolve) => setTimeout(resolve, backoff));
2939
+ backoff *= 2;
2940
+ } else {
2941
+ this.logger.error("LibSQL Workflows: Non-lock error occurred, not retrying", { error });
2942
+ throw error;
2943
+ }
2944
+ }
2945
+ }
2946
+ throw new Error("LibSQL Workflows: Max retries reached, but no error was re-thrown from the loop.");
2947
+ }
2948
+ async updateWorkflowResults({
2949
+ workflowName,
2950
+ runId,
2951
+ stepId,
2952
+ result,
2953
+ runtimeContext
2954
+ }) {
2955
+ return this.executeWithRetry(async () => {
2956
+ const tx = await this.client.transaction("write");
2957
+ try {
2958
+ const existingSnapshotResult = await tx.execute({
2959
+ sql: `SELECT snapshot FROM ${TABLE_WORKFLOW_SNAPSHOT} WHERE workflow_name = ? AND run_id = ?`,
2960
+ args: [workflowName, runId]
2961
+ });
2962
+ let snapshot;
2963
+ if (!existingSnapshotResult.rows?.[0]) {
2964
+ snapshot = {
2965
+ context: {},
2966
+ activePaths: [],
2967
+ timestamp: Date.now(),
2968
+ suspendedPaths: {},
2969
+ serializedStepGraph: [],
2970
+ value: {},
2971
+ waitingPaths: {},
2972
+ status: "pending",
2973
+ runId,
2974
+ runtimeContext: {}
2975
+ };
2976
+ } else {
2977
+ const existingSnapshot = existingSnapshotResult.rows[0].snapshot;
2978
+ snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
2979
+ }
2980
+ snapshot.context[stepId] = result;
2981
+ snapshot.runtimeContext = { ...snapshot.runtimeContext, ...runtimeContext };
2982
+ await tx.execute({
2983
+ sql: `UPDATE ${TABLE_WORKFLOW_SNAPSHOT} SET snapshot = ? WHERE workflow_name = ? AND run_id = ?`,
2984
+ args: [JSON.stringify(snapshot), workflowName, runId]
2985
+ });
2986
+ await tx.commit();
2987
+ return snapshot.context;
2988
+ } catch (error) {
2989
+ if (!tx.closed) {
2990
+ await tx.rollback();
2991
+ }
2992
+ throw error;
2993
+ }
2994
+ });
2995
+ }
2996
+ async updateWorkflowState({
2997
+ workflowName,
2998
+ runId,
2999
+ opts
3000
+ }) {
3001
+ return this.executeWithRetry(async () => {
3002
+ const tx = await this.client.transaction("write");
3003
+ try {
3004
+ const existingSnapshotResult = await tx.execute({
3005
+ sql: `SELECT snapshot FROM ${TABLE_WORKFLOW_SNAPSHOT} WHERE workflow_name = ? AND run_id = ?`,
3006
+ args: [workflowName, runId]
3007
+ });
3008
+ if (!existingSnapshotResult.rows?.[0]) {
3009
+ await tx.rollback();
3010
+ return void 0;
3011
+ }
3012
+ const existingSnapshot = existingSnapshotResult.rows[0].snapshot;
3013
+ const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
3014
+ if (!snapshot || !snapshot?.context) {
3015
+ await tx.rollback();
3016
+ throw new Error(`Snapshot not found for runId ${runId}`);
3017
+ }
3018
+ const updatedSnapshot = { ...snapshot, ...opts };
3019
+ await tx.execute({
3020
+ sql: `UPDATE ${TABLE_WORKFLOW_SNAPSHOT} SET snapshot = ? WHERE workflow_name = ? AND run_id = ?`,
3021
+ args: [JSON.stringify(updatedSnapshot), workflowName, runId]
3022
+ });
3023
+ await tx.commit();
3024
+ return updatedSnapshot;
3025
+ } catch (error) {
3026
+ if (!tx.closed) {
3027
+ await tx.rollback();
3028
+ }
3029
+ throw error;
3030
+ }
3031
+ });
2398
3032
  }
2399
3033
  async persistWorkflowSnapshot({
2400
3034
  workflowName,
@@ -2555,13 +3189,15 @@ var LibSQLStore = class extends MastraStorage {
2555
3189
  const workflows = new WorkflowsLibSQL({ client: this.client, operations });
2556
3190
  const memory = new MemoryLibSQL({ client: this.client, operations });
2557
3191
  const legacyEvals = new LegacyEvalsLibSQL({ client: this.client });
3192
+ const observability = new ObservabilityLibSQL({ operations });
2558
3193
  this.stores = {
2559
3194
  operations,
2560
3195
  scores,
2561
3196
  traces,
2562
3197
  workflows,
2563
3198
  memory,
2564
- legacyEvals
3199
+ legacyEvals,
3200
+ observability
2565
3201
  };
2566
3202
  }
2567
3203
  get supports() {
@@ -2570,7 +3206,8 @@ var LibSQLStore = class extends MastraStorage {
2570
3206
  resourceWorkingMemory: true,
2571
3207
  hasColumn: true,
2572
3208
  createTable: true,
2573
- deleteMessages: true
3209
+ deleteMessages: true,
3210
+ aiTracing: true
2574
3211
  };
2575
3212
  }
2576
3213
  async createTable({
@@ -2712,6 +3349,22 @@ var LibSQLStore = class extends MastraStorage {
2712
3349
  /**
2713
3350
  * WORKFLOWS
2714
3351
  */
3352
+ async updateWorkflowResults({
3353
+ workflowName,
3354
+ runId,
3355
+ stepId,
3356
+ result,
3357
+ runtimeContext
3358
+ }) {
3359
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
3360
+ }
3361
+ async updateWorkflowState({
3362
+ workflowName,
3363
+ runId,
3364
+ opts
3365
+ }) {
3366
+ return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
3367
+ }
2715
3368
  async persistWorkflowSnapshot({
2716
3369
  workflowName,
2717
3370
  runId,
@@ -2754,6 +3407,24 @@ var LibSQLStore = class extends MastraStorage {
2754
3407
  }) {
2755
3408
  return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2756
3409
  }
3410
+ async createAISpan(span) {
3411
+ return this.stores.observability.createAISpan(span);
3412
+ }
3413
+ async updateAISpan(params) {
3414
+ return this.stores.observability.updateAISpan(params);
3415
+ }
3416
+ async getAITrace(traceId) {
3417
+ return this.stores.observability.getAITrace(traceId);
3418
+ }
3419
+ async getAITracesPaginated(args) {
3420
+ return this.stores.observability.getAITracesPaginated(args);
3421
+ }
3422
+ async batchCreateAISpans(args) {
3423
+ return this.stores.observability.batchCreateAISpans(args);
3424
+ }
3425
+ async batchUpdateAISpans(args) {
3426
+ return this.stores.observability.batchUpdateAISpans(args);
3427
+ }
2757
3428
  };
2758
3429
 
2759
3430
  // src/vector/prompt.ts