@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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +11 -0
- package/dist/index.cjs +679 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +680 -9
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +34 -0
- package/dist/storage/domains/observability/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +50 -1
- package/dist/storage/domains/operations/index.d.ts.map +1 -1
- package/dist/storage/domains/utils.d.ts +45 -1
- package/dist/storage/domains/utils.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +27 -2
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +42 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/storage/domains/memory/index.ts +1 -1
- package/src/storage/domains/observability/index.ts +237 -0
- package/src/storage/domains/operations/index.ts +213 -3
- package/src/storage/domains/utils.ts +207 -2
- package/src/storage/domains/workflows/index.ts +225 -2
- package/src/storage/index.ts +74 -1
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
|
|
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
|
|
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/
|
|
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
|
-
|
|
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
|